Message ID | 252d75b5139a7acb4bdc28c8131e408c2483d8ac.1571151935.git.lorenzo@kernel.org (mailing list archive) |
---|---|
State | Accepted |
Delegated to: | Felix Fietkau |
Headers | show |
Series | [v2] mt76: refactor cc_lock locking scheme | expand |
On Tue, Oct 15, 2019 at 05:16:43PM +0200, Lorenzo Bianconi wrote: > Read busy counters not holding cc_lock spinlock since usb read can't be > performed in interrupt context. Move cc_active and cc_rx counters out of > cc_lock since they are not modified in interrupt context. > Grab cc_lock updating cur_cc_bss_rx in mt76_airtime_report and do not > hold rx_lock in mt76_update_survey. <snip> > Fixes: 168aea24f4bb ("mt76: mt76x02u: enable survey support") I think problem was introduced currently in mt76 driver version that is not yet in mainline tree, so this is not right commit. On Linus' tree we still read registers outside of cc_lock section. void mt76x02_update_channel(struct mt76_dev *mdev) { ... busy = mt76_rr(dev, MT_CH_BUSY); active = busy + mt76_rr(dev, MT_CH_IDLE); spin_lock_bh(&dev->mt76.cc_lock); state->cc_busy += busy; state->cc_active += active; spin_unlock_bh(&dev->mt76.cc_lock); } > if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { > - spin_lock_bh(&dev->rx_lock); > - spin_lock(&dev->cc_lock); > + spin_lock_bh(&dev->cc_lock); > state->cc_bss_rx += dev->cur_cc_bss_rx; > dev->cur_cc_bss_rx = 0; > - spin_unlock(&dev->cc_lock); > - spin_unlock_bh(&dev->rx_lock); > + spin_unlock_bh(&dev->cc_lock); Why dev->rx_lock was needed before and is not needed now ? Stanislaw
> On Tue, Oct 15, 2019 at 05:16:43PM +0200, Lorenzo Bianconi wrote: > > Read busy counters not holding cc_lock spinlock since usb read can't be > > performed in interrupt context. Move cc_active and cc_rx counters out of > > cc_lock since they are not modified in interrupt context. > > Grab cc_lock updating cur_cc_bss_rx in mt76_airtime_report and do not > > hold rx_lock in mt76_update_survey. > <snip> > > Fixes: 168aea24f4bb ("mt76: mt76x02u: enable survey support") > > I think problem was introduced currently in mt76 driver version > that is not yet in mainline tree, so this is not right commit. > On Linus' tree we still read registers outside of cc_lock section. Hi Stanislaw, yes, you are right. We should drop the Fixes tag. Thx > > void mt76x02_update_channel(struct mt76_dev *mdev) > { > ... > > busy = mt76_rr(dev, MT_CH_BUSY); > active = busy + mt76_rr(dev, MT_CH_IDLE); > > spin_lock_bh(&dev->mt76.cc_lock); > state->cc_busy += busy; > state->cc_active += active; > spin_unlock_bh(&dev->mt76.cc_lock); > } > > > if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { > > - spin_lock_bh(&dev->rx_lock); > > - spin_lock(&dev->cc_lock); > > + spin_lock_bh(&dev->cc_lock); > > state->cc_bss_rx += dev->cur_cc_bss_rx; > > dev->cur_cc_bss_rx = 0; > > - spin_unlock(&dev->cc_lock); > > - spin_unlock_bh(&dev->rx_lock); > > + spin_unlock_bh(&dev->cc_lock); > > Why dev->rx_lock was needed before and is not needed now ? Looking at the code I think rx_lock is not needed here since cur_cc_bss_rx is updated without holding rx_lock in mt76_airtime_report() (we need cc_lock there). Regards, Lorenzo > > Stanislaw
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index a962abce98f8..6535921fcea4 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -432,8 +432,6 @@ void mt76_update_survey(struct mt76_dev *dev) if (!test_bit(MT76_STATE_RUNNING, &dev->state)) return; - spin_lock_bh(&dev->cc_lock); - if (dev->drv->update_survey) dev->drv->update_survey(dev); @@ -442,15 +440,11 @@ void mt76_update_survey(struct mt76_dev *dev) dev->survey_time)); dev->survey_time = cur_time; - spin_unlock_bh(&dev->cc_lock); - if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { - spin_lock_bh(&dev->rx_lock); - spin_lock(&dev->cc_lock); + spin_lock_bh(&dev->cc_lock); state->cc_bss_rx += dev->cur_cc_bss_rx; dev->cur_cc_bss_rx = 0; - spin_unlock(&dev->cc_lock); - spin_unlock_bh(&dev->rx_lock); + spin_unlock_bh(&dev->cc_lock); } } EXPORT_SYMBOL_GPL(mt76_update_survey); @@ -485,6 +479,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct mt76_channel_state *state; int ret = 0; + mutex_lock(&dev->mutex); if (idx == 0 && dev->drv->update_survey) mt76_update_survey(dev); @@ -494,8 +489,10 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, sband = &dev->sband_5g; } - if (idx >= sband->sband.n_channels) - return -ENOENT; + if (idx >= sband->sband.n_channels) { + ret = -ENOENT; + goto out; + } chan = &sband->sband.channels[idx]; state = mt76_channel_state(dev, chan); @@ -511,14 +508,18 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, survey->filled |= SURVEY_INFO_TIME_BSS_RX; } - spin_lock_bh(&dev->cc_lock); - survey->time = div_u64(state->cc_active, 1000); survey->time_busy = div_u64(state->cc_busy, 1000); - survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); survey->time_rx = div_u64(state->cc_rx, 1000); + survey->time = div_u64(state->cc_active, 1000); + + spin_lock_bh(&dev->cc_lock); + survey->time_bss_rx = div_u64(state->cc_bss_rx, 1000); survey->time_tx = div_u64(state->cc_tx, 1000); spin_unlock_bh(&dev->cc_lock); +out: + mutex_unlock(&dev->mutex); + return ret; } EXPORT_SYMBOL_GPL(mt76_get_survey); @@ -622,7 +623,9 @@ mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status, u32 airtime; airtime = mt76_calc_rx_airtime(dev, status, len); + spin_lock(&dev->cc_lock); dev->cur_cc_bss_rx += airtime; + spin_unlock(&dev->cc_lock); if (!wcid || !wcid->sta) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 41f7c01045b8..2c0bd9aa1987 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -1024,8 +1024,11 @@ void mt76x02_update_channel(struct mt76_dev *mdev) state = mdev->chan_state; state->cc_busy += mt76_rr(dev, MT_CH_BUSY); + + spin_lock_bh(&dev->mt76.cc_lock); state->cc_tx += dev->tx_airtime; dev->tx_airtime = 0; + spin_unlock_bh(&dev->mt76.cc_lock); } EXPORT_SYMBOL_GPL(mt76x02_update_channel);