mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 13:26:48 +00:00
mt76x2: implement survey support
Signed-off-by: Felix Fietkau <[email protected]>
This commit is contained in:
+71
-3
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+3
-3
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
+12
-2
@@ -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));
|
||||
|
||||
+18
-1
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user