diff --git a/mac80211.c b/mac80211.c index 0719fba5..170baae3 100644 --- a/mac80211.c +++ b/mac80211.c @@ -74,10 +74,11 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = { }; static int -mt76_init_sband(struct mt76_dev *dev, struct ieee80211_supported_band *sband, +mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband, const struct ieee80211_channel *chan, int n_chan, struct ieee80211_rate *rates, int n_rates, bool vht) { + struct ieee80211_supported_band *sband = &msband->sband; struct ieee80211_sta_ht_cap *ht_cap; struct ieee80211_sta_vht_cap *vht_cap; void *chanlist; @@ -89,6 +90,11 @@ mt76_init_sband(struct mt76_dev *dev, struct ieee80211_supported_band *sband, if (!chanlist) return -ENOMEM; + msband->chan = devm_kzalloc(dev->dev, n_chan * sizeof(*msband->chan), + GFP_KERNEL); + if (!msband->chan) + return -ENOMEM; + sband->channels = chanlist; sband->n_channels = n_chan; sband->bitrates = rates; @@ -139,7 +145,7 @@ static int mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates, int n_rates) { - dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->sband_2g; + dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->sband_2g.sband; return mt76_init_sband(dev, &dev->sband_2g, mt76_channels_2ghz, @@ -151,7 +157,7 @@ static int mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates, int n_rates, bool vht) { - dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->sband_5g; + dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->sband_5g.sband; return mt76_init_sband(dev, &dev->sband_5g, mt76_channels_5ghz, @@ -169,6 +175,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, dev_set_drvdata(dev->dev, dev); spin_lock_init(&dev->lock); + spin_lock_init(&dev->cc_lock); INIT_LIST_HEAD(&dev->txwi_cache); SET_IEEE80211_DEV(hw, dev->dev); @@ -234,6 +241,67 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(mt76_rx); +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; + + if (dev->drv->update_survey) + dev->drv->update_survey(dev); + + dev->chandef = *chandef; + + 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)); + } +} +EXPORT_SYMBOL_GPL(mt76_set_channel); + +int mt76_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct mt76_dev *dev = hw->priv; + struct mt76_sband *sband; + struct ieee80211_channel *chan; + struct mt76_channel_state *state; + int ret = 0; + + if (idx == 0 && dev->drv->update_survey) + dev->drv->update_survey(dev); + + sband = &dev->sband_2g; + if (idx >= sband->sband.n_channels) { + idx -= sband->sband.n_channels; + sband = &dev->sband_5g; + } + + if (idx >= sband->sband.n_channels) + return -ENOENT; + + chan = &sband->sband.channels[idx]; + state = mt76_channel_state(dev, chan); + + memset(survey, 0, sizeof(*survey)); + survey->channel = chan; + survey->filled = SURVEY_INFO_TIME | SURVEY_INFO_TIME_BUSY; + if (chan == dev->main_chan) + survey->filled |= SURVEY_INFO_IN_USE; + + spin_lock_bh(&dev->cc_lock); + survey->time = div_u64(state->cc_active, 1000); + survey->time_busy = div_u64(state->cc_busy, 1000); + spin_unlock_bh(&dev->cc_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_get_survey); + void mt76_rx_complete(struct mt76_dev *dev, enum mt76_rxq_id q) { struct sk_buff *skb; diff --git a/mt76.h b/mt76.h index 95087d68..706060c4 100644 --- a/mt76.h +++ b/mt76.h @@ -158,6 +158,8 @@ struct mt76_hw_cap { struct mt76_driver_ops { u16 txwi_size; + void (*update_survey)(struct mt76_dev *dev); + int (*tx_prepare_skb)(struct mt76_dev *dev, void *txwi_ptr, struct sk_buff *skb, struct mt76_queue *q, struct mt76_wcid *wcid, @@ -172,11 +174,23 @@ struct mt76_driver_ops { void (*rx_poll_complete)(struct mt76_dev *dev, enum mt76_rxq_id q); }; +struct mt76_channel_state { + u64 cc_active; + u64 cc_busy; +}; + +struct mt76_sband { + struct ieee80211_supported_band sband; + struct mt76_channel_state *chan; +}; + struct mt76_dev { struct ieee80211_hw *hw; struct cfg80211_chan_def chandef; + struct ieee80211_channel *main_chan; spinlock_t lock; + spinlock_t cc_lock; const struct mt76_bus_ops *bus; const struct mt76_driver_ops *drv; void __iomem *regs; @@ -195,8 +209,8 @@ struct mt76_dev { u32 rev; unsigned long state; - struct ieee80211_supported_band sband_2g; - struct ieee80211_supported_band sband_5g; + struct mt76_sband sband_2g; + struct mt76_sband sband_5g; struct debugfs_blob_wrapper eeprom; struct debugfs_blob_wrapper otp; struct mt76_hw_cap cap; @@ -260,6 +274,21 @@ static inline u16 mt76_rev(struct mt76_dev *dev) #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__) +static inline 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]; +} + int mt76_register_device(struct mt76_dev *dev, bool vht, struct ieee80211_rate *rates, int n_rates); void mt76_unregister_device(struct mt76_dev *dev); @@ -295,6 +324,9 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw, u16 tids, int nframes, enum ieee80211_frame_release_type reason, bool more_data); +void mt76_set_channel(struct mt76_dev *dev); +int mt76_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey); /* internal */ void mt76_tx_free(struct mt76_dev *dev); diff --git a/mt7603_mac.c b/mt7603_mac.c index bb302d1e..343f741f 100644 --- a/mt7603_mac.c +++ b/mt7603_mac.c @@ -305,11 +305,11 @@ mt7603_get_rate(struct mt7603_dev *dev, struct ieee80211_supported_band *sband, int i; if (cck) { - if (WARN_ON_ONCE(sband == &dev->mt76.sband_5g)) + if (WARN_ON_ONCE(sband == &dev->mt76.sband_5g.sband)) return 0; idx &= ~BIT(2); /* short preamble */ - } else if (sband == &dev->mt76.sband_2g) { + } else if (sband == &dev->mt76.sband_2g.sband) { offset = 4; } @@ -335,7 +335,7 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb) memset(status, 0, sizeof(*status)); i = MT76_GET(MT_RXD1_NORMAL_CH_FREQ, rxd[1]); - sband = (i & 1) ? &dev->mt76.sband_5g : &dev->mt76.sband_2g; + sband = (i & 1) ? &dev->mt76.sband_5g.sband : &dev->mt76.sband_2g.sband; i >>= 1; status->band = sband->band; diff --git a/mt76x2.h b/mt76x2.h index 2ccc8be5..e5395d9b 100644 --- a/mt76x2.h +++ b/mt76x2.h @@ -217,4 +217,6 @@ void mt76x2_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q); void mt76x2_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb); +void mt76x2_update_channel(struct mt76_dev *dev); + #endif diff --git a/mt76x2_init.c b/mt76x2_init.c index c3fd7944..079ec821 100644 --- a/mt76x2_init.c +++ b/mt76x2_init.c @@ -301,6 +301,15 @@ int mt76x2_mac_reset(struct mt76x2_dev *dev, bool hard) mt76_rr(dev, MT_TX_STAT_FIFO); mt76_set(dev, MT_MAC_APC_BSSID_H(0), MT_MAC_APC_BSSID0_H_EN); + + mt76_wr(dev, MT_CH_TIME_CFG, + MT_CH_TIME_CFG_TIMER_EN | + MT_CH_TIME_CFG_TX_AS_BUSY | + MT_CH_TIME_CFG_RX_AS_BUSY | + MT_CH_TIME_CFG_NAV_AS_BUSY | + MT_CH_TIME_CFG_EIFS_AS_BUSY | + MT76_SET(MT_CH_TIME_CFG_CH_TIMER_CLR, 1)); + mt76x2_init_beacon_offsets(dev); mt76x2_set_tx_ackto(dev); @@ -607,6 +616,7 @@ struct mt76x2_dev *mt76x2_alloc_device(struct device *pdev) { static const struct mt76_driver_ops drv_ops = { .txwi_size = sizeof(struct mt76x2_txwi), + .update_survey = mt76x2_update_channel, .tx_prepare_skb = mt76x2_tx_prepare_skb, .tx_complete_skb = mt76x2_tx_complete_skb, .rx_skb = mt76x2_queue_rx_skb, @@ -731,8 +741,8 @@ int mt76x2_register_device(struct mt76x2_dev *dev) INIT_DELAYED_WORK(&dev->cal_work, mt76x2_phy_calibrate); INIT_DELAYED_WORK(&dev->mac_work, mt76x2_mac_work); - dev->mt76.sband_2g.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; - dev->mt76.sband_5g.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; + dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; + dev->mt76.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; ret = mt76_register_device(&dev->mt76, true, mt76x2_rates, ARRAY_SIZE(mt76x2_rates)); diff --git a/mt76x2_mac.c b/mt76x2_mac.c index 9f715f9e..852a0479 100644 --- a/mt76x2_mac.c +++ b/mt76x2_mac.c @@ -676,12 +676,30 @@ void mt76x2_mac_set_beacon_enable(struct mt76x2_dev *dev, u8 vif_idx, bool val) mt76x2_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); } +void mt76x2_update_channel(struct mt76_dev *mdev) +{ + struct mt76x2_dev *dev = container_of(mdev, struct mt76x2_dev, mt76); + struct mt76_channel_state *state; + u32 active, busy; + + state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan); + + 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); +} + void mt76x2_mac_work(struct work_struct *work) { struct mt76x2_dev *dev = container_of(work, struct mt76x2_dev, mac_work.work); int i, idx; + mt76x2_update_channel(&dev->mt76); for (i = 0, idx = 0; i < 16; i++) { u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); dev->aggr_stats[idx++] += val & 0xffff; @@ -690,5 +708,4 @@ void mt76x2_mac_work(struct work_struct *work) ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, MT_CALIBRATE_INTERVAL); - } diff --git a/mt76x2_main.c b/mt76x2_main.c index eabff8b8..a6b1e8ab 100644 --- a/mt76x2_main.c +++ b/mt76x2_main.c @@ -118,11 +118,18 @@ mt76x2_set_channel(struct mt76x2_dev *dev, struct cfg80211_chan_def *chandef) { int ret; + mt76_set_channel(&dev->mt76); + tasklet_disable(&dev->pre_tbtt_tasklet); cancel_delayed_work_sync(&dev->cal_work); mt76x2_mac_stop(dev, true); ret = mt76x2_phy_set_channel(dev, chandef); + + /* channel cycle counters read-and-clear */ + mt76_rr(dev, MT_CH_IDLE); + mt76_rr(dev, MT_CH_BUSY); + mt76x2_mac_resume(dev); tasklet_enable(&dev->pre_tbtt_tasklet); @@ -504,5 +511,6 @@ const struct ieee80211_ops mt76x2_ops = { .sta_rate_tbl_update = mt76x2_sta_rate_tbl_update, .release_buffered_frames = mt76_release_buffered_frames, .set_coverage_class = mt76x2_set_coverage_class, + .get_survey = mt76_get_survey, }; diff --git a/mt76x2_phy.c b/mt76x2_phy.c index bb1ed2cc..523d4400 100644 --- a/mt76x2_phy.c +++ b/mt76x2_phy.c @@ -487,7 +487,6 @@ int mt76x2_phy_set_channel(struct mt76x2_dev *dev, int ret; u8 sifs = 13; - dev->mt76.chandef = *chandef; dev->cal.channel_cal_done = false; freq = chandef->chan->center_freq; freq1 = chandef->center_freq1; diff --git a/mt76x2_regs.h b/mt76x2_regs.h index a3e10d14..c31e26d4 100644 --- a/mt76x2_regs.h +++ b/mt76x2_regs.h @@ -253,6 +253,16 @@ #define MT_BKOFF_SLOT_CFG_SLOTTIME GENMASK(7, 0) #define MT_BKOFF_SLOT_CFG_CC_DELAY GENMASK(11, 8) +#define MT_CH_TIME_CFG 0x110c +#define MT_CH_TIME_CFG_TIMER_EN BIT(0) +#define MT_CH_TIME_CFG_TX_AS_BUSY BIT(1) +#define MT_CH_TIME_CFG_RX_AS_BUSY BIT(2) +#define MT_CH_TIME_CFG_NAV_AS_BUSY BIT(3) +#define MT_CH_TIME_CFG_EIFS_AS_BUSY BIT(4) +#define MT_CH_TIME_CFG_MDRDY_CNT_EN BIT(5) +#define MT_CH_TIME_CFG_CH_TIMER_CLR GENMASK(9, 8) +#define MT_CH_TIME_CFG_MDRDY_CLR GENMASK(11, 10) + #define MT_BEACON_TIME_CFG 0x1114 #define MT_BEACON_TIME_CFG_INTVAL GENMASK(15, 0) #define MT_BEACON_TIME_CFG_TIMER_EN BIT(16) @@ -272,6 +282,11 @@ #define MT_INT_TIMER_EN_PRE_TBTT_EN BIT(0) #define MT_INT_TIMER_EN_GP_TIMER_EN BIT(1) +#define MT_CH_IDLE 0x1130 +#define MT_CH_BUSY 0x1134 +#define MT_EXT_CH_BUSY 0x1138 +#define MT_ED_CCA_TIMER 0x1140 + #define MT_MAC_STATUS 0x1200 #define MT_MAC_STATUS_TX BIT(0) #define MT_MAC_STATUS_RX BIT(1)