Message ID | 20191119154746.20821-3-markus.theil@tu-ilmenau.de (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Felix Fietkau |
Headers | show |
Series | mt76: channel switch support for USB devices | expand |
On Tue, Nov 19, 2019 at 04:47:43PM +0100, Markus Theil wrote: > Sending beacons to the hardware always happens in batches. In order to > speed up beacon processing on usb devices, this patch splits out common > code an calls it only once (mt76x02_mac_set_beacon_prepare, > mt76x02_mac_set_beacon_finish). Making this split breaks beacon > enabling/disabling per vif. This is fixed by adding a call to set the > bypass mask, if beaconing should be disabled for a vif. Otherwise the > beacon is send after the next beacon interval. > > The code is also adapted for the mmio part of the driver, but should not > have any performance implication there. > > Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de> > --- > .../wireless/mediatek/mt76/mt76x02_beacon.c | 44 +++++++------------ > .../net/wireless/mediatek/mt76/mt76x02_mac.h | 1 + > .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 5 +++ > .../wireless/mediatek/mt76/mt76x02_usb_core.c | 5 +++ > 4 files changed, 26 insertions(+), 29 deletions(-) > > diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c > index 403866496640..09013adae854 100644 > --- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c > +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c > @@ -47,10 +47,6 @@ __mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx, > int beacon_len = dev->beacon_ops->slot_size; > int beacon_addr = MT_BEACON_BASE + (beacon_len * bcn_idx); > int ret = 0; > - int i; > - > - /* Prevent corrupt transmissions during update */ > - mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx)); > > if (skb) { > ret = mt76x02_write_beacon(dev, beacon_addr, skb); > @@ -60,41 +56,30 @@ __mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx, > dev->beacon_data_mask &= ~BIT(bcn_idx); > } > > - mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); > - > return ret; > } > > -int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, > - struct sk_buff *skb) > +void mt76x02_mac_set_beacon_finish(struct mt76x02_dev *dev) > { > - bool force_update = false; > - int bcn_idx = 0; > int i; > + int bcn_idx = 0; > > - for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) { > - if (vif_idx == i) { > - force_update = !!dev->beacons[i] ^ !!skb; > - dev_kfree_skb(dev->beacons[i]); > - dev->beacons[i] = skb; > - __mt76x02_mac_set_beacon(dev, bcn_idx, skb); > - } else if (force_update && dev->beacons[i]) { > - __mt76x02_mac_set_beacon(dev, bcn_idx, > - dev->beacons[i]); > - } > - > + for (i = 0; i < hweight8(dev->mt76.beacon_mask); ++i) > bcn_idx += !!dev->beacons[i]; This looks wrong since we do not calculate all beacons, only up to hweight8(dev->mt76.beacon_mask). But since we need to calculate number of all beacons we can just use hweight8(dev->mt76.beacon_mask) directly. > - } > - > - for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) { > - if (!(dev->beacon_data_mask & BIT(i))) > - break; > - > - __mt76x02_mac_set_beacon(dev, i, NULL); > - } > > mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, > bcn_idx - 1); > + > + mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); I'm not sure if this is correct for multi bss. In MT7620 manual BCM_BAYPASS_MASK is described as below: " Directly bypasses the Tx Beacon frame with the specified Beacon number. Bit0=Nth Beacon, bit1=(N- 1)th Beacon,... etc. N is the number of Beacons defined in the MULTI_BCN_NUM field in the MAC_BSSID_DW1(offset: 0x1014) register. 0: Disable 1: Enable " Assuming manual is correct (it could be wrong) bypass mask should be calculated differently. Stanislaw
On 11/20/19 10:28 AM, Stanislaw Gruszka wrote: > On Tue, Nov 19, 2019 at 04:47:43PM +0100, Markus Theil wrote: >> Sending beacons to the hardware always happens in batches. In order to >> speed up beacon processing on usb devices, this patch splits out common >> code an calls it only once (mt76x02_mac_set_beacon_prepare, >> mt76x02_mac_set_beacon_finish). Making this split breaks beacon >> enabling/disabling per vif. This is fixed by adding a call to set the >> bypass mask, if beaconing should be disabled for a vif. Otherwise the >> beacon is send after the next beacon interval. >> >> The code is also adapted for the mmio part of the driver, but should not >> have any performance implication there. >> >> Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de> >> --- >> .../wireless/mediatek/mt76/mt76x02_beacon.c | 44 +++++++------------ >> .../net/wireless/mediatek/mt76/mt76x02_mac.h | 1 + >> .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 5 +++ >> .../wireless/mediatek/mt76/mt76x02_usb_core.c | 5 +++ >> 4 files changed, 26 insertions(+), 29 deletions(-) >> >> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c >> index 403866496640..09013adae854 100644 >> --- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c >> +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c >> @@ -47,10 +47,6 @@ __mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx, >> int beacon_len = dev->beacon_ops->slot_size; >> int beacon_addr = MT_BEACON_BASE + (beacon_len * bcn_idx); >> int ret = 0; >> - int i; >> - >> - /* Prevent corrupt transmissions during update */ >> - mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx)); >> >> if (skb) { >> ret = mt76x02_write_beacon(dev, beacon_addr, skb); >> @@ -60,41 +56,30 @@ __mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx, >> dev->beacon_data_mask &= ~BIT(bcn_idx); >> } >> >> - mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); >> - >> return ret; >> } >> >> -int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, >> - struct sk_buff *skb) >> +void mt76x02_mac_set_beacon_finish(struct mt76x02_dev *dev) >> { >> - bool force_update = false; >> - int bcn_idx = 0; >> int i; >> + int bcn_idx = 0; >> >> - for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) { >> - if (vif_idx == i) { >> - force_update = !!dev->beacons[i] ^ !!skb; >> - dev_kfree_skb(dev->beacons[i]); >> - dev->beacons[i] = skb; >> - __mt76x02_mac_set_beacon(dev, bcn_idx, skb); >> - } else if (force_update && dev->beacons[i]) { >> - __mt76x02_mac_set_beacon(dev, bcn_idx, >> - dev->beacons[i]); >> - } >> - >> + for (i = 0; i < hweight8(dev->mt76.beacon_mask); ++i) >> bcn_idx += !!dev->beacons[i]; > This looks wrong since we do not calculate all beacons, only > up to hweight8(dev->mt76.beacon_mask). > > But since we need to calculate number of all beacons we can just > use hweight8(dev->mt76.beacon_mask) directly. You're right that I made a mistake here. Using hweight8(dev->mt76.beacon_mask) would be wrong for usb devices, which may setup buffered broadcast or multicast frames as additional beacons. My updated patch therefore uses hweight8(dev->mt76.beacon_data_mask) directly. >> - } >> - >> - for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) { >> - if (!(dev->beacon_data_mask & BIT(i))) >> - break; >> - >> - __mt76x02_mac_set_beacon(dev, i, NULL); >> - } >> >> mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, >> bcn_idx - 1); >> + >> + mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); > I'm not sure if this is correct for multi bss. > > In MT7620 manual BCM_BAYPASS_MASK is described as below: > > " > Directly bypasses the Tx Beacon frame with the specified > Beacon number. Bit0=Nth Beacon, bit1=(N- 1)th Beacon,... etc. > N is the number of Beacons defined in the MULTI_BCN_NUM field in the > MAC_BSSID_DW1(offset: 0x1014) register. > 0: Disable > 1: Enable > " > > Assuming manual is correct (it could be wrong) bypass mask should be > calculated differently. > > Stanislaw > I tested the updated code with my usb nic and an mbss with 2 ap vifs. Both beacons were transmitted. Maybe the manual is wrong in this place. Markus
On Wed, Nov 20, 2019 at 11:27:55PM +0100, Markus Theil wrote: > >> - } > >> - > >> - for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) { > >> - if (!(dev->beacon_data_mask & BIT(i))) > >> - break; > >> - > >> - __mt76x02_mac_set_beacon(dev, i, NULL); > >> - } > >> > >> mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, > >> bcn_idx - 1); > >> + > >> + mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); > > I'm not sure if this is correct for multi bss. > > > > In MT7620 manual BCM_BAYPASS_MASK is described as below: > > > > " > > Directly bypasses the Tx Beacon frame with the specified > > Beacon number. Bit0=Nth Beacon, bit1=(N- 1)th Beacon,... etc. > > N is the number of Beacons defined in the MULTI_BCN_NUM field in the > > MAC_BSSID_DW1(offset: 0x1014) register. > > 0: Disable > > 1: Enable > > " > > > > Assuming manual is correct (it could be wrong) bypass mask should be > > calculated differently. > > > > Stanislaw > > > I tested the updated code with my usb nic and an mbss with 2 ap vifs. > Both beacons were transmitted. Maybe the manual is wrong in this place. If MAC_BSSID_DW1_MBEACON_N is set to 1 (2 beacons) according to manual bit0 is for second beacon slot and bit1 is for first beacon slot. Those bits are both marked at once, so no problem will happen. Problem may happen when you remove first vif/beacon. Then you will have bit1 marked in ->beacon_data_mask . But bit0 will be expect in BCM_BAYPASS_MASK by hardware (when MAC_BSSID_DW1_MBEACON_N=0) This scenarios can be extended to more vifs. So if you no longer use bcn_idx and use vif_idx directly to point beacon slot/address. (ie. before for vif_idx 0,4,6, bcn_idx were 0,1,2 now there will be 0,4,6). You need to specify 7 (8 beacons) in MT_MAC_BSSID_DW1_MBEACON_N, and set bypass mask accordingly. For example: mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, 7); mask = 0; for (i = 0; i < 8; i++) if (dev->beacons[i]) mask |= BIT(7 - i); mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~mask); But again, this have to be tested. Ideally on mmio hardware which support more bssid's or on usb hardware with temporally increased num of bss limitation. Stanislaw
On 21.11.19 13:58, Stanislaw Gruszka wrote: > On Wed, Nov 20, 2019 at 11:27:55PM +0100, Markus Theil wrote: >>>> - } >>>> - >>>> - for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) { >>>> - if (!(dev->beacon_data_mask & BIT(i))) >>>> - break; >>>> - >>>> - __mt76x02_mac_set_beacon(dev, i, NULL); >>>> - } >>>> >>>> mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, >>>> bcn_idx - 1); >>>> + >>>> + mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); >>> I'm not sure if this is correct for multi bss. >>> >>> In MT7620 manual BCM_BAYPASS_MASK is described as below: >>> >>> " >>> Directly bypasses the Tx Beacon frame with the specified >>> Beacon number. Bit0=Nth Beacon, bit1=(N- 1)th Beacon,... etc. >>> N is the number of Beacons defined in the MULTI_BCN_NUM field in the >>> MAC_BSSID_DW1(offset: 0x1014) register. >>> 0: Disable >>> 1: Enable >>> " >>> >>> Assuming manual is correct (it could be wrong) bypass mask should be >>> calculated differently. >>> >>> Stanislaw >>> >> I tested the updated code with my usb nic and an mbss with 2 ap vifs. >> Both beacons were transmitted. Maybe the manual is wrong in this place. > If MAC_BSSID_DW1_MBEACON_N is set to 1 (2 beacons) according to manual > bit0 is for second beacon slot and bit1 is for first beacon slot. > Those bits are both marked at once, so no problem will happen. > > Problem may happen when you remove first vif/beacon. Then you will > have bit1 marked in ->beacon_data_mask . But bit0 will be expect > in BCM_BAYPASS_MASK by hardware (when MAC_BSSID_DW1_MBEACON_N=0) > > This scenarios can be extended to more vifs. So if you no longer > use bcn_idx and use vif_idx directly to point beacon slot/address. > (ie. before for vif_idx 0,4,6, bcn_idx were 0,1,2 now there > will be 0,4,6). You need to specify 7 (8 beacons) in > MT_MAC_BSSID_DW1_MBEACON_N, and set bypass mask accordingly. > For example: > > mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, 7); > mask = 0; > for (i = 0; i < 8; i++) > if (dev->beacons[i]) > mask |= BIT(7 - i); > > mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~mask); > > But again, this have to be tested. Ideally on mmio hardware which > support more bssid's or on usb hardware with temporally increased > num of bss limitation. > > Stanislaw > I'm currently fixing this. My next version will include the following for this aspect: - clear beacon_data_mask before each round of setting beacons - use ffz(dev->beacon_data_mask) to find next position and put next beacon in the corresponding slot - as usb and mmio always copy the beacon, free_skb directly afterwards and drop the beacons array (the current code could leak memory for beacons in this array) - permanently set the number of additional beacons to 7: mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, 7) - updating the beacon bypass mask then becomes: mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~bitrev8(dev->beacon_data_mask)) When I've tested this, I'll send an updated version. Markus
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c index 403866496640..09013adae854 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c @@ -47,10 +47,6 @@ __mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx, int beacon_len = dev->beacon_ops->slot_size; int beacon_addr = MT_BEACON_BASE + (beacon_len * bcn_idx); int ret = 0; - int i; - - /* Prevent corrupt transmissions during update */ - mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx)); if (skb) { ret = mt76x02_write_beacon(dev, beacon_addr, skb); @@ -60,41 +56,30 @@ __mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx, dev->beacon_data_mask &= ~BIT(bcn_idx); } - mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); - return ret; } -int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, - struct sk_buff *skb) +void mt76x02_mac_set_beacon_finish(struct mt76x02_dev *dev) { - bool force_update = false; - int bcn_idx = 0; int i; + int bcn_idx = 0; - for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) { - if (vif_idx == i) { - force_update = !!dev->beacons[i] ^ !!skb; - dev_kfree_skb(dev->beacons[i]); - dev->beacons[i] = skb; - __mt76x02_mac_set_beacon(dev, bcn_idx, skb); - } else if (force_update && dev->beacons[i]) { - __mt76x02_mac_set_beacon(dev, bcn_idx, - dev->beacons[i]); - } - + for (i = 0; i < hweight8(dev->mt76.beacon_mask); ++i) bcn_idx += !!dev->beacons[i]; - } - - for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) { - if (!(dev->beacon_data_mask & BIT(i))) - break; - - __mt76x02_mac_set_beacon(dev, i, NULL); - } mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, bcn_idx - 1); + + mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); +} +EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon_finish); + +int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, + struct sk_buff *skb) +{ + dev_kfree_skb(dev->beacons[vif_idx]); + dev->beacons[vif_idx] = skb; + __mt76x02_mac_set_beacon(dev, vif_idx, skb); return 0; } EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon); @@ -115,6 +100,7 @@ void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, } else { dev->mt76.beacon_mask &= ~BIT(mvif->idx); mt76x02_mac_set_beacon(dev, mvif->idx, NULL); + mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(mvif->idx)); } if (!!old_mask == !!dev->mt76.beacon_mask) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index efa4ef945e35..e6e585c72f0d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -197,6 +197,7 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, struct sk_buff *skb); void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, struct ieee80211_vif *vif, bool enable); +void mt76x02_mac_set_beacon_finish(struct mt76x02_dev *dev); void mt76x02_edcca_init(struct mt76x02_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index dc773070481d..73c39d03b7f8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -24,10 +24,15 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg) mt76x02_resync_beacon_timer(dev); + /* Prevent corrupt transmissions during update */ + mt76_set(dev, MT_BCN_BYPASS_MASK, 0xffff); + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, mt76x02_update_beacon_iter, dev); + mt76x02_mac_set_beacon_finish(dev); + mt76_csa_check(&dev->mt76); if (dev->mt76.csa_complete) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index 78dfc1e7f27b..8a2a90fb5663 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -179,6 +179,9 @@ static void mt76x02u_pre_tbtt_work(struct work_struct *work) mt76x02_resync_beacon_timer(dev); + /* Prevent corrupt transmissions during update */ + mt76_set(dev, MT_BCN_BYPASS_MASK, 0xffff); + ieee80211_iterate_active_interfaces(mt76_hw(dev), IEEE80211_IFACE_ITER_RESUME_ALL, mt76x02_update_beacon_iter, dev); @@ -191,6 +194,8 @@ static void mt76x02u_pre_tbtt_work(struct work_struct *work) mt76x02_mac_set_beacon(dev, i, skb); } + mt76x02_mac_set_beacon_finish(dev); + mt76x02u_restart_pre_tbtt_timer(dev); }
Sending beacons to the hardware always happens in batches. In order to speed up beacon processing on usb devices, this patch splits out common code an calls it only once (mt76x02_mac_set_beacon_prepare, mt76x02_mac_set_beacon_finish). Making this split breaks beacon enabling/disabling per vif. This is fixed by adding a call to set the bypass mask, if beaconing should be disabled for a vif. Otherwise the beacon is send after the next beacon interval. The code is also adapted for the mmio part of the driver, but should not have any performance implication there. Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de> --- .../wireless/mediatek/mt76/mt76x02_beacon.c | 44 +++++++------------ .../net/wireless/mediatek/mt76/mt76x02_mac.h | 1 + .../net/wireless/mediatek/mt76/mt76x02_mmio.c | 5 +++ .../wireless/mediatek/mt76/mt76x02_usb_core.c | 5 +++ 4 files changed, 26 insertions(+), 29 deletions(-)