Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

wifi: mt76: use atomic iface iteration for pre-TBTT work

In addition to the previous series I posted, over time I'd
also like to get rid of the iflist_mtx in mac80211. That
isn't easy now since lots of places use iteration and would
have to be audited, but even a cursory look suggests that
mt76 might be more problematic than most since holding the
wiphy lock for the latency-sensitive pre-TBTT work could be
an issue.

Convert the pre-TBTT work to use atomic iteration and then
sending the device commands outside of it.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>

authored by

Johannes Berg and committed by
Felix Fietkau
debd133a c2fcc83b

+22 -10
+3 -5
drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c
··· 136 136 void 137 137 mt76x02_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) 138 138 { 139 - struct mt76x02_dev *dev = (struct mt76x02_dev *)priv; 139 + struct beacon_bc_data *data = priv; 140 + struct mt76x02_dev *dev = data->dev; 140 141 struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; 141 142 struct sk_buff *skb = NULL; 142 143 ··· 148 147 if (!skb) 149 148 return; 150 149 151 - mt76x02_mac_set_beacon(dev, skb); 150 + __skb_queue_tail(&data->q, skb); 152 151 } 153 152 EXPORT_SYMBOL_GPL(mt76x02_update_beacon_iter); 154 153 ··· 182 181 int max_nframes) 183 182 { 184 183 int i, nframes; 185 - 186 - data->dev = dev; 187 - __skb_queue_head_init(&data->q); 188 184 189 185 do { 190 186 nframes = skb_queue_len(&data->q);
+9 -2
drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
··· 16 16 struct mt76x02_dev *dev = from_tasklet(dev, t, mt76.pre_tbtt_tasklet); 17 17 struct mt76_dev *mdev = &dev->mt76; 18 18 struct mt76_queue *q = dev->mphy.q_tx[MT_TXQ_PSD]; 19 - struct beacon_bc_data data = {}; 19 + struct beacon_bc_data data = { 20 + .dev = dev, 21 + }; 20 22 struct sk_buff *skb; 21 23 int i; 22 24 23 25 if (mt76_hw(dev)->conf.flags & IEEE80211_CONF_OFFCHANNEL) 24 26 return; 27 + 28 + __skb_queue_head_init(&data.q); 25 29 26 30 mt76x02_resync_beacon_timer(dev); 27 31 ··· 35 31 36 32 ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), 37 33 IEEE80211_IFACE_ITER_RESUME_ALL, 38 - mt76x02_update_beacon_iter, dev); 34 + mt76x02_update_beacon_iter, &data); 35 + 36 + while ((skb = __skb_dequeue(&data.q)) != NULL) 37 + mt76x02_mac_set_beacon(dev, skb); 39 38 40 39 mt76_wr(dev, MT_BCN_BYPASS_MASK, 41 40 0xff00 | ~(0xff00 >> dev->beacon_data_count));
+10 -3
drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
··· 182 182 { 183 183 struct mt76x02_dev *dev = 184 184 container_of(work, struct mt76x02_dev, pre_tbtt_work); 185 - struct beacon_bc_data data = {}; 185 + struct beacon_bc_data data = { 186 + .dev = dev, 187 + }; 186 188 struct sk_buff *skb; 187 189 int nbeacons; 188 190 ··· 194 192 if (mt76_hw(dev)->conf.flags & IEEE80211_CONF_OFFCHANNEL) 195 193 return; 196 194 195 + __skb_queue_head_init(&data.q); 196 + 197 197 mt76x02_resync_beacon_timer(dev); 198 198 199 199 /* Prevent corrupt transmissions during update */ 200 200 mt76_set(dev, MT_BCN_BYPASS_MASK, 0xffff); 201 201 dev->beacon_data_count = 0; 202 202 203 - ieee80211_iterate_active_interfaces(mt76_hw(dev), 203 + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), 204 204 IEEE80211_IFACE_ITER_RESUME_ALL, 205 - mt76x02_update_beacon_iter, dev); 205 + mt76x02_update_beacon_iter, &data); 206 + 207 + while ((skb = __skb_dequeue(&data.q)) != NULL) 208 + mt76x02_mac_set_beacon(dev, skb); 206 209 207 210 mt76_csa_check(&dev->mt76); 208 211