Skip to content

Commit

Permalink
mt76x2: implement survey support
Browse files Browse the repository at this point in the history
Signed-off-by: Felix Fietkau <nbd@nbd.name>
  • Loading branch information
nbd168 committed Jun 15, 2016
1 parent 6c4b37b commit 3c8a4bc
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 12 deletions.
74 changes: 71 additions & 3 deletions mac80211.c
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
36 changes: 34 additions & 2 deletions mt76.h
Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions mt7603_mac.c
Expand Up @@ -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;
}

Expand All @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions mt76x2.h
Expand Up @@ -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
14 changes: 12 additions & 2 deletions mt76x2_init.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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));
Expand Down
19 changes: 18 additions & 1 deletion mt76x2_mac.c
Expand Up @@ -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;
Expand All @@ -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);

}
8 changes: 8 additions & 0 deletions mt76x2_main.c
Expand Up @@ -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);

Expand Down Expand Up @@ -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,
};

1 change: 0 additions & 1 deletion mt76x2_phy.c
Expand Up @@ -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;
Expand Down
15 changes: 15 additions & 0 deletions mt76x2_regs.h
Expand Up @@ -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)
Expand All @@ -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)
Expand Down

0 comments on commit 3c8a4bc

Please sign in to comment.