diff options
author | Kalle Valo <kvalo@codeaurora.org> | 2019-11-20 20:11:58 +0200 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2019-11-20 20:11:58 +0200 |
commit | 924ea58dadea23cc28b60d02b9c0896b7b168a6f (patch) | |
tree | 6fb4e7d84992a4320556cf7cedc759d370b81a52 /drivers/net/wireless | |
parent | 54b6416e679d5f255a36fd5a9e148802647cdd65 (diff) | |
parent | 23cb16d2ccb5f819d7acff602e5a153157bf2884 (diff) |
Merge tag 'mt76-for-kvalo-2019-11-20' of https://github.com/nbd168/wireless
mt76 patches for 5.5
* monitor mode fix for mt7615
* fixes for rx aggregation race conditions
* cleanups
* mt7615 smart carrier sense support
* code unification / deduplication
* mt7615 debugfs improvements
* debugfs aggregation statistics
* airtime fairness support
* mt76x0 OF mac address support
* locking fixes
* usb support improvements
* rate control fixes
Diffstat (limited to 'drivers/net/wireless')
53 files changed, 1466 insertions, 399 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index d7a1ddc9e407..99bbc74acda8 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_MT76x02_USB) += mt76x02-usb.o mt76-y := \ mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \ - tx.o agg-rx.o mcu.o + tx.o agg-rx.o mcu.o airtime.o mt76-$(CONFIG_PCI) += pci.o diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index 8f3d36a15e17..53b5a4b2dcc5 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -130,8 +130,10 @@ mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) return; spin_lock_bh(&tid->lock); - mt76_rx_aggr_release_frames(tid, frames, seqno); - mt76_rx_aggr_release_head(tid, frames); + if (!tid->stopped) { + mt76_rx_aggr_release_frames(tid, frames, seqno); + mt76_rx_aggr_release_head(tid, frames); + } spin_unlock_bh(&tid->lock); } @@ -257,8 +259,6 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) u8 size = tid->size; int i; - cancel_delayed_work(&tid->reorder_work); - spin_lock_bh(&tid->lock); tid->stopped = true; @@ -273,21 +273,19 @@ static void mt76_rx_aggr_shutdown(struct mt76_dev *dev, struct mt76_rx_tid *tid) } spin_unlock_bh(&tid->lock); + + cancel_delayed_work_sync(&tid->reorder_work); } void mt76_rx_aggr_stop(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 tidno) { - struct mt76_rx_tid *tid; + struct mt76_rx_tid *tid = NULL; - rcu_read_lock(); - - tid = rcu_dereference(wcid->aggr[tidno]); + rcu_swap_protected(wcid->aggr[tidno], tid, + lockdep_is_held(&dev->mutex)); if (tid) { - rcu_assign_pointer(wcid->aggr[tidno], NULL); mt76_rx_aggr_shutdown(dev, tid); kfree_rcu(tid, rcu_head); } - - rcu_read_unlock(); } EXPORT_SYMBOL_GPL(mt76_rx_aggr_stop); diff --git a/drivers/net/wireless/mediatek/mt76/airtime.c b/drivers/net/wireless/mediatek/mt76/airtime.c new file mode 100644 index 000000000000..55116f395f9a --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/airtime.c @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (C) 2019 Felix Fietkau <nbd@nbd.name> + */ + +#include "mt76.h" + +#define AVG_PKT_SIZE 1024 + +/* Number of bits for an average sized packet */ +#define MCS_NBITS (AVG_PKT_SIZE << 3) + +/* Number of symbols for a packet with (bps) bits per symbol */ +#define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps)) + +/* Transmission time (1024 usec) for a packet containing (syms) * symbols */ +#define MCS_SYMBOL_TIME(sgi, syms) \ + (sgi ? \ + ((syms) * 18 * 1024 + 4 * 1024) / 5 : /* syms * 3.6 us */ \ + ((syms) * 1024) << 2 /* syms * 4 us */ \ + ) + +/* Transmit duration for the raw data part of an average sized packet */ +#define MCS_DURATION(streams, sgi, bps) \ + MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) + +#define BW_20 0 +#define BW_40 1 +#define BW_80 2 + +/* + * Define group sort order: HT40 -> SGI -> #streams + */ +#define MT_MAX_STREAMS 4 +#define MT_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */ +#define MT_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */ + +#define MT_HT_GROUPS_NB (MT_MAX_STREAMS * \ + MT_HT_STREAM_GROUPS) +#define MT_VHT_GROUPS_NB (MT_MAX_STREAMS * \ + MT_VHT_STREAM_GROUPS) +#define MT_GROUPS_NB (MT_HT_GROUPS_NB + \ + MT_VHT_GROUPS_NB) + +#define MT_HT_GROUP_0 0 +#define MT_VHT_GROUP_0 (MT_HT_GROUP_0 + MT_HT_GROUPS_NB) + +#define MCS_GROUP_RATES 10 + +#define HT_GROUP_IDX(_streams, _sgi, _ht40) \ + MT_HT_GROUP_0 + \ + MT_MAX_STREAMS * 2 * _ht40 + \ + MT_MAX_STREAMS * _sgi + \ + _streams - 1 + +#define _MAX(a, b) (((a)>(b))?(a):(b)) + +#define GROUP_SHIFT(duration) \ + _MAX(0, 16 - __builtin_clz(duration)) + +/* MCS rate information for an MCS group */ +#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \ + [HT_GROUP_IDX(_streams, _sgi, _ht40)] = { \ + .shift = _s, \ + .duration = { \ + MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) >> _s \ + } \ +} + +#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \ + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26)) + +#define MCS_GROUP(_streams, _sgi, _ht40) \ + __MCS_GROUP(_streams, _sgi, _ht40, \ + MCS_GROUP_SHIFT(_streams, _sgi, _ht40)) + +#define VHT_GROUP_IDX(_streams, _sgi, _bw) \ + (MT_VHT_GROUP_0 + \ + MT_MAX_STREAMS * 2 * (_bw) + \ + MT_MAX_STREAMS * (_sgi) + \ + (_streams) - 1) + +#define BW2VBPS(_bw, r3, r2, r1) \ + (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) + +#define __VHT_GROUP(_streams, _sgi, _bw, _s) \ + [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ + .shift = _s, \ + .duration = { \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 117, 54, 26)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 234, 108, 52)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 351, 162, 78)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 468, 216, 104)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 702, 324, 156)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 936, 432, 208)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1053, 486, 234)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1170, 540, 260)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1404, 648, 312)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1560, 720, 346)) >> _s \ + } \ +} + +#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \ + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 117, 54, 26))) + +#define VHT_GROUP(_streams, _sgi, _bw) \ + __VHT_GROUP(_streams, _sgi, _bw, \ + VHT_GROUP_SHIFT(_streams, _sgi, _bw)) + +struct mcs_group { + u8 shift; + u16 duration[MCS_GROUP_RATES]; +}; + +static const struct mcs_group airtime_mcs_groups[] = { + MCS_GROUP(1, 0, BW_20), + MCS_GROUP(2, 0, BW_20), + MCS_GROUP(3, 0, BW_20), + MCS_GROUP(4, 0, BW_20), + + MCS_GROUP(1, 1, BW_20), + MCS_GROUP(2, 1, BW_20), + MCS_GROUP(3, 1, BW_20), + MCS_GROUP(4, 1, BW_20), + + MCS_GROUP(1, 0, BW_40), + MCS_GROUP(2, 0, BW_40), + MCS_GROUP(3, 0, BW_40), + MCS_GROUP(4, 0, BW_40), + + MCS_GROUP(1, 1, BW_40), + MCS_GROUP(2, 1, BW_40), + MCS_GROUP(3, 1, BW_40), + MCS_GROUP(4, 1, BW_40), + + VHT_GROUP(1, 0, BW_20), + VHT_GROUP(2, 0, BW_20), + VHT_GROUP(3, 0, BW_20), + VHT_GROUP(4, 0, BW_20), + + VHT_GROUP(1, 1, BW_20), + VHT_GROUP(2, 1, BW_20), + VHT_GROUP(3, 1, BW_20), + VHT_GROUP(4, 1, BW_20), + + VHT_GROUP(1, 0, BW_40), + VHT_GROUP(2, 0, BW_40), + VHT_GROUP(3, 0, BW_40), + VHT_GROUP(4, 0, BW_40), + + VHT_GROUP(1, 1, BW_40), + VHT_GROUP(2, 1, BW_40), + VHT_GROUP(3, 1, BW_40), + VHT_GROUP(4, 1, BW_40), + + VHT_GROUP(1, 0, BW_80), + VHT_GROUP(2, 0, BW_80), + VHT_GROUP(3, 0, BW_80), + VHT_GROUP(4, 0, BW_80), + + VHT_GROUP(1, 1, BW_80), + VHT_GROUP(2, 1, BW_80), + VHT_GROUP(3, 1, BW_80), + VHT_GROUP(4, 1, BW_80), +}; + +static u32 +mt76_calc_legacy_rate_duration(const struct ieee80211_rate *rate, bool short_pre, + int len) +{ + u32 duration; + + switch (rate->hw_value >> 8) { + case MT_PHY_TYPE_CCK: + duration = 144 + 48; /* preamble + PLCP */ + if (short_pre) + duration >>= 1; + + duration += 10; /* SIFS */ + break; + case MT_PHY_TYPE_OFDM: + duration = 20 + 16; /* premable + SIFS */ + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + len <<= 3; + duration += (len * 10) / rate->bitrate; + + return duration; +} + +u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status, + int len) +{ + struct ieee80211_supported_band *sband; + const struct ieee80211_rate *rate; + bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI; + bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE; + int bw, streams; + u32 duration; + int group, idx; + + switch (status->bw) { + case RATE_INFO_BW_20: + bw = BW_20; + break; + case RATE_INFO_BW_40: + bw = BW_40; + break; + case RATE_INFO_BW_80: + bw = BW_80; + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + switch (status->encoding) { + case RX_ENC_LEGACY: + if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ)) + return 0; + + sband = dev->hw->wiphy->bands[status->band]; + if (!sband || status->rate_idx > sband->n_bitrates) + return 0; + + rate = &sband->bitrates[status->rate_idx]; + + return mt76_calc_legacy_rate_duration(rate, sp, len); + case RX_ENC_VHT: + streams = status->nss; + idx = status->rate_idx; + group = VHT_GROUP_IDX(streams, sgi, bw); + break; + case RX_ENC_HT: + streams = ((status->rate_idx >> 3) & 3) + 1; + idx = status->rate_idx & 7; + group = HT_GROUP_IDX(streams, sgi, bw); + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + if (WARN_ON_ONCE(streams > 4)) + return 0; + + duration = airtime_mcs_groups[group].duration[idx]; + duration <<= airtime_mcs_groups[group].shift; + duration *= len; + duration /= AVG_PKT_SIZE; + duration /= 1024; + + duration += 36 + (streams << 2); + + return duration; +} + +u32 mt76_calc_tx_airtime(struct mt76_dev *dev, struct ieee80211_tx_info *info, + int len) +{ + struct mt76_rx_status stat = { + .band = info->band, + }; + u32 duration = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) { + struct ieee80211_tx_rate *rate = &info->status.rates[i]; + u32 cur_duration; + + if (rate->idx < 0 || !rate->count) + break; + + if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + stat.bw = RATE_INFO_BW_80; + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + stat.bw = RATE_INFO_BW_40; + else + stat.bw = RATE_INFO_BW_20; + + stat.enc_flags = 0; + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + stat.enc_flags |= RX_ENC_FLAG_SHORTPRE; + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + stat.enc_flags |= RX_ENC_FLAG_SHORT_GI; + + stat.rate_idx = rate->idx; + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + stat.encoding = RX_ENC_VHT; + stat.rate_idx = ieee80211_rate_get_vht_mcs(rate); + stat.nss = ieee80211_rate_get_vht_nss(rate); + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + stat.encoding = RX_ENC_HT; + } else { + stat.encoding = RX_ENC_LEGACY; + } + + cur_duration = mt76_calc_rx_airtime(dev, &stat, len); + duration += cur_duration * rate->count; + } + + return duration; +} +EXPORT_SYMBOL_GPL(mt76_calc_tx_airtime); diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index d95b73fd0d2b..d2202acb8dc6 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -25,8 +25,7 @@ mt76_reg_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); -static int -mt76_queues_read(struct seq_file *s, void *data) +int mt76_queues_read(struct seq_file *s, void *data) { struct mt76_dev *dev = dev_get_drvdata(s->private); int i; @@ -45,6 +44,7 @@ mt76_queues_read(struct seq_file *s, void *data) return 0; } +EXPORT_SYMBOL_GPL(mt76_queues_read); void mt76_seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len) @@ -90,7 +90,6 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev) debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom); if (dev->otp.data) debugfs_create_blob("otp", 0400, dir, &dev->otp); - debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read); debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir, mt76_read_rate_txpower); diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 8f69d00bd940..6173c80189ba 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -166,7 +166,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush) dev->drv->tx_complete_skb(dev, qid, &entry); if (entry.txwi) { - if (!(dev->drv->txwi_flags & MT_TXWI_NO_FREE)) + if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE)) mt76_put_txwi(dev, entry.txwi); wake = !flush; } @@ -301,7 +301,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid, txwi = mt76_get_txwi_ptr(dev, t); skb->prev = skb->next = NULL; - if (dev->drv->tx_aligned4_skbs) + if (dev->drv->drv_flags & MT_DRV_TX_ALIGNED4_SKBS) mt76_insert_hdr_pad(skb); len = skb_headlen(skb); @@ -365,7 +365,6 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q) int frames = 0; int len = SKB_WITH_OVERHEAD(q->buf_size); int offset = q->buf_offset; - int idx; spin_lock_bh(&q->lock); @@ -384,7 +383,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q) qbuf.addr = addr + offset; qbuf.len = len - offset; - idx = mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, NULL); + mt76_dma_add_buf(dev, q, &qbuf, 1, 0, buf, NULL); frames++; } @@ -539,10 +538,8 @@ mt76_dma_rx_poll(struct napi_struct *napi, int budget) rcu_read_unlock(); - if (done < budget) { - napi_complete(napi); + if (done < budget && napi_complete(napi)) dev->drv->rx_poll_complete(dev, qid); - } return done; } diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 1a2c143b34d0..b9f2a401041a 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -105,7 +105,15 @@ static int mt76_led_init(struct mt76_dev *dev) dev->led_al = of_property_read_bool(np, "led-active-low"); } - return devm_led_classdev_register(dev->dev, &dev->led_cdev); + return led_classdev_register(dev->dev, &dev->led_cdev); +} + +static void mt76_led_cleanup(struct mt76_dev *dev) +{ + if (!dev->led_cdev.brightness_set && !dev->led_cdev.blink_set) + return; + + led_classdev_unregister(&dev->led_cdev); } static void mt76_init_stream_cap(struct mt76_dev *dev, @@ -180,6 +188,7 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, sband->bitrates = rates; sband->n_bitrates = n_rates; dev->chandef.chan = &sband->channels[0]; + dev->chan_state = &msband->chan[0]; ht_cap = &sband->ht_cap; ht_cap->ht_supported = true; @@ -306,6 +315,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); wiphy->available_antennas_tx = dev->antenna_mask; wiphy->available_antennas_rx = dev->antenna_mask; @@ -327,8 +337,16 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, ieee80211_hw_set(hw, AP_LINK_PS); ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); + ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_ADHOC); if (dev->cap.has_2ghz) { ret = mt76_init_sband_2g(dev, rates, n_rates); @@ -360,6 +378,7 @@ void mt76_unregister_device(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; + mt76_led_cleanup(dev); mt76_tx_status_check(dev, NULL, true); ieee80211_unregister_hw(hw); } @@ -398,28 +417,64 @@ bool mt76_has_tx_pending(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76_has_tx_pending); +static struct mt76_channel_state * +mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) +{ + struct mt76_sband *msband; + int idx; + + if (c->band == NL80211_BAND_2GHZ) + msband = &dev->sband_2g; + else + msband = &dev->sband_5g; + + idx = c - &msband->sband.channels[0]; + return &msband->chan[idx]; +} + +void mt76_update_survey(struct mt76_dev *dev) +{ + struct mt76_channel_state *state = dev->chan_state; + ktime_t cur_time; + + if (!test_bit(MT76_STATE_RUNNING, &dev->state)) + return; + + if (dev->drv->update_survey) + dev->drv->update_survey(dev); + + cur_time = ktime_get_boottime(); + state->cc_active += ktime_to_us(ktime_sub(cur_time, + dev->survey_time)); + dev->survey_time = cur_time; + + if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { + spin_lock_bh(&dev->cc_lock); + state->cc_bss_rx += dev->cur_cc_bss_rx; + dev->cur_cc_bss_rx = 0; + spin_unlock_bh(&dev->cc_lock); + } +} +EXPORT_SYMBOL_GPL(mt76_update_survey); + void mt76_set_channel(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; struct cfg80211_chan_def *chandef = &hw->conf.chandef; - struct mt76_channel_state *state; bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; int timeout = HZ / 5; wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout); - - if (dev->drv->update_survey) - dev->drv->update_survey(dev); + mt76_update_survey(dev); dev->chandef = *chandef; + dev->chan_state = mt76_channel_state(dev, chandef->chan); if (!offchannel) dev->main_chan = chandef->chan; - if (chandef->chan != dev->main_chan) { - state = mt76_channel_state(dev, chandef->chan); - memset(state, 0, sizeof(*state)); - } + if (chandef->chan != dev->main_chan) + memset(dev->chan_state, 0, sizeof(*dev->chan_state)); } EXPORT_SYMBOL_GPL(mt76_set_channel); @@ -432,8 +487,9 @@ 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) - dev->drv->update_survey(dev); + mt76_update_survey(dev); sband = &dev->sband_2g; if (idx >= sband->sband.n_channels) { @@ -441,8 +497,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); @@ -450,14 +508,26 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx, memset(survey, 0, sizeof(*survey)); survey->channel = chan; survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; |