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 -----BEGIN PGP SIGNATURE----- Comment: GPGTools - http://gpgtools.org iEYEABECAAYFAl3VMZMACgkQ130UHQKnbvVcJQCcDuiu9iid/zDYnHuJcf3c3gaH QCoAoLamk0k4xthK0Hb5p1rqrTHRXPIk =0loO -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
924ea58dad
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
326
drivers/net/wireless/mediatek/mt76/airtime.c
Normal file
326
drivers/net/wireless/mediatek/mt76/airtime.c
Normal file
@ -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);
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
void mt76_set_channel(struct mt76_dev *dev)
|
||||
static struct mt76_channel_state *
|
||||
mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c)
|
||||
{
|
||||
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;
|
||||
struct mt76_sband *msband;
|
||||
int idx;
|
||||
|
||||
wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout);
|
||||
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;
|
||||
bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
|
||||
int timeout = HZ / 5;
|
||||
|
||||
wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout);
|
||||
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;
|
||||
if (chan == dev->main_chan)
|
||||
survey->filled |= dev->drv->survey_flags;
|
||||
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);
|
||||
if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME)
|
||||
survey->filled |= SURVEY_INFO_TIME_BSS_RX;
|
||||
}
|
||||
|
||||
survey->time_busy = div_u64(state->cc_busy, 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);
|
||||
@ -502,6 +572,7 @@ static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb)
|
||||
status->band = mstat.band;
|
||||
status->signal = mstat.signal;
|
||||
status->chains = mstat.chains;
|
||||
status->ampdu_reference = mstat.ampdu_ref;
|
||||
|
||||
BUILD_BUG_ON(sizeof(mstat) > sizeof(skb->cb));
|
||||
BUILD_BUG_ON(sizeof(status->chain_signal) !=
|
||||
@ -551,6 +622,84 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_airtime_report(struct mt76_dev *dev, struct mt76_rx_status *status,
|
||||
int len)
|
||||
{
|
||||
struct mt76_wcid *wcid = status->wcid;
|
||||
struct ieee80211_sta *sta;
|
||||
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;
|
||||
|
||||
sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
|
||||
ieee80211_sta_register_airtime(sta, status->tid, 0, airtime);
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_airtime_flush_ampdu(struct mt76_dev *dev)
|
||||
{
|
||||
struct mt76_wcid *wcid;
|
||||
int wcid_idx;
|
||||
|
||||
if (!dev->rx_ampdu_len)
|
||||
return;
|
||||
|
||||
wcid_idx = dev->rx_ampdu_status.wcid_idx;
|
||||
if (wcid_idx < ARRAY_SIZE(dev->wcid))
|
||||
wcid = rcu_dereference(dev->wcid[wcid_idx]);
|
||||
else
|
||||
wcid = NULL;
|
||||
dev->rx_ampdu_status.wcid = wcid;
|
||||
|
||||
mt76_airtime_report(dev, &dev->rx_ampdu_status, dev->rx_ampdu_len);
|
||||
|
||||
dev->rx_ampdu_len = 0;
|
||||
dev->rx_ampdu_ref = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
||||
struct mt76_wcid *wcid = status->wcid;
|
||||
|
||||
if (!(dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME))
|
||||
return;
|
||||
|
||||
if (!wcid || !wcid->sta) {
|
||||
if (!ether_addr_equal(hdr->addr1, dev->macaddr))
|
||||
return;
|
||||
|
||||
wcid = NULL;
|
||||
}
|
||||
|
||||
if (!(status->flag & RX_FLAG_AMPDU_DETAILS) ||
|
||||
status->ampdu_ref != dev->rx_ampdu_ref)
|
||||
mt76_airtime_flush_ampdu(dev);
|
||||
|
||||
if (status->flag & RX_FLAG_AMPDU_DETAILS) {
|
||||
if (!dev->rx_ampdu_len ||
|
||||
status->ampdu_ref != dev->rx_ampdu_ref) {
|
||||
dev->rx_ampdu_status = *status;
|
||||
dev->rx_ampdu_status.wcid_idx = wcid ? wcid->idx : 0xff;
|
||||
dev->rx_ampdu_ref = status->ampdu_ref;
|
||||
}
|
||||
|
||||
dev->rx_ampdu_len += skb->len;
|
||||
return;
|
||||
}
|
||||
|
||||
mt76_airtime_report(dev, status, skb->len);
|
||||
}
|
||||
|
||||
static void
|
||||
mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
|
||||
{
|
||||
@ -567,6 +716,8 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
|
||||
wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv;
|
||||
}
|
||||
|
||||
mt76_airtime_check(dev, skb);
|
||||
|
||||
if (!wcid || !wcid->sta)
|
||||
return;
|
||||
|
||||
@ -886,3 +1037,16 @@ void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
clear_bit(MT76_SCANNING, &dev->state);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_sw_scan_complete);
|
||||
|
||||
int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
|
||||
{
|
||||
struct mt76_dev *dev = hw->priv;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
*tx_ant = dev->antenna_mask;
|
||||
*rx_ant = dev->antenna_mask;
|
||||
mutex_unlock(&dev->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_get_antenna);
|
||||
|
@ -49,8 +49,8 @@ struct mt76_bus_ops {
|
||||
enum mt76_bus_type type;
|
||||
};
|
||||
|
||||
#define mt76_is_usb(dev) ((dev)->mt76.bus->type == MT76_BUS_USB)
|
||||
#define mt76_is_mmio(dev) ((dev)->mt76.bus->type == MT76_BUS_MMIO)
|
||||
#define mt76_is_usb(dev) ((dev)->bus->type == MT76_BUS_USB)
|
||||
#define mt76_is_mmio(dev) ((dev)->bus->type == MT76_BUS_MMIO)
|
||||
|
||||
enum mt76_txq_id {
|
||||
MT_TXQ_VO = IEEE80211_AC_VO,
|
||||
@ -152,10 +152,6 @@ struct mt76_queue_ops {
|
||||
int idx, int n_desc, int bufsize,
|
||||
u32 ring_base);
|
||||
|
||||
int (*add_buf)(struct mt76_dev *dev, struct mt76_queue *q,
|
||||
struct mt76_queue_buf *buf, int nbufs, u32 info,
|
||||
struct sk_buff *skb, void *txwi);
|
||||
|
||||
int (*tx_queue_skb)(struct mt76_dev *dev, enum mt76_txq_id qid,
|
||||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
struct ieee80211_sta *sta);
|
||||
@ -191,8 +187,6 @@ DECLARE_EWMA(signal, 10, 8);
|
||||
struct mt76_wcid {
|
||||
struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS];
|
||||
|
||||
struct work_struct aggr_work;
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
struct ewma_signal rssi;
|
||||
@ -282,11 +276,13 @@ struct mt76_hw_cap {
|
||||
bool has_5ghz;
|
||||
};
|
||||
|
||||
#define MT_TXWI_NO_FREE BIT(0)
|
||||
#define MT_DRV_TXWI_NO_FREE BIT(0)
|
||||
#define MT_DRV_TX_ALIGNED4_SKBS BIT(1)
|
||||
#define MT_DRV_SW_RX_AIRTIME BIT(2)
|
||||
|
||||
struct mt76_driver_ops {
|
||||
bool tx_aligned4_skbs;
|
||||
u32 txwi_flags;
|
||||
u32 drv_flags;
|
||||
u32 survey_flags;
|
||||
u16 txwi_size;
|
||||
|
||||
void (*update_survey)(struct mt76_dev *dev);
|
||||
@ -322,6 +318,9 @@ struct mt76_driver_ops {
|
||||
struct mt76_channel_state {
|
||||
u64 cc_active;
|
||||
u64 cc_busy;
|
||||
u64 cc_rx;
|
||||
u64 cc_bss_rx;
|
||||
u64 cc_tx;
|
||||
};
|
||||
|
||||
struct mt76_sband {
|
||||
@ -367,8 +366,8 @@ enum mt76u_in_ep {
|
||||
|
||||
enum mt76u_out_ep {
|
||||
MT_EP_OUT_INBAND_CMD,
|
||||
MT_EP_OUT_AC_BK,
|
||||
MT_EP_OUT_AC_BE,
|
||||
MT_EP_OUT_AC_BK,
|
||||
MT_EP_OUT_AC_VI,
|
||||
MT_EP_OUT_AC_VO,
|
||||
MT_EP_OUT_HCCA,
|
||||
@ -388,7 +387,8 @@ struct mt76_usb {
|
||||
};
|
||||
|
||||
struct tasklet_struct rx_tasklet;
|
||||
struct delayed_work stat_work;
|
||||
struct workqueue_struct *stat_wq;
|
||||
struct work_struct stat_work;
|
||||
|
||||
u8 out_ep[__MT_EP_OUT_MAX];
|
||||
u8 in_ep[__MT_EP_IN_MAX];
|
||||
@ -421,14 +421,49 @@ struct mt76_mmio {
|
||||
u32 irqmask;
|
||||
};
|
||||
|
||||
struct mt76_rx_status {
|
||||
union {
|
||||
struct mt76_wcid *wcid;
|
||||
u8 wcid_idx;
|
||||
};
|
||||
|
||||
unsigned long reorder_time;
|
||||
|
||||
u32 ampdu_ref;
|
||||
|
||||
u8 iv[6];
|
||||
|
||||
u8 aggr:1;
|
||||
u8 tid;
|
||||
u16 seqno;
|
||||
|
||||
u16 freq;
|
||||
u32 flag;
|
||||
u8 enc_flags;
|
||||
u8 encoding:2, bw:3;
|
||||
u8 rate_idx;
|
||||
u8 nss;
|
||||
u8 band;
|
||||
s8 signal;
|
||||
u8 chains;
|
||||
s8 chain_signal[IEEE80211_MAX_CHAINS];
|
||||
};
|
||||
|
||||
struct mt76_dev {
|
||||
struct ieee80211_hw *hw;
|
||||
struct cfg80211_chan_def chandef;
|
||||
struct ieee80211_channel *main_chan;
|
||||
|
||||
struct mt76_channel_state *chan_state;
|
||||
spinlock_t lock;
|
||||
spinlock_t cc_lock;
|
||||
|
||||
u32 cur_cc_bss_rx;
|
||||
|
||||
struct mt76_rx_status rx_ampdu_status;
|
||||
u32 rx_ampdu_len;
|
||||
u32 rx_ampdu_ref;
|
||||
|
||||
struct mutex mutex;
|
||||
|
||||
const struct mt76_bus_ops *bus;
|
||||
@ -440,6 +475,7 @@ struct mt76_dev {
|
||||
spinlock_t rx_lock;
|
||||
struct napi_struct napi[__MT_RXQ_MAX];
|
||||
struct sk_buff_head rx_skb[__MT_RXQ_MAX];
|
||||
u32 ampdu_ref;
|
||||
|
||||
struct list_head txwi_cache;
|
||||
struct mt76_sw_queue q_tx[__MT_TXQ_MAX];
|
||||
@ -463,6 +499,8 @@ struct mt76_dev {
|
||||
u32 rev;
|
||||
unsigned long state;
|
||||
|
||||
u32 aggr_stats[32];
|
||||
|
||||
u8 antenna_mask;
|
||||
u16 chainmask;
|
||||
|
||||
@ -509,29 +547,6 @@ enum mt76_phy_type {
|
||||
MT_PHY_TYPE_VHT,
|
||||
};
|
||||
|
||||
struct mt76_rx_status {
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
unsigned long reorder_time;
|
||||
|
||||
u8 iv[6];
|
||||
|
||||
u8 aggr:1;
|
||||
u8 tid;
|
||||
u16 seqno;
|
||||
|
||||
u16 freq;
|
||||
u32 flag;
|
||||
u8 enc_flags;
|
||||
u8 encoding:2, bw:3;
|
||||
u8 rate_idx;
|
||||
u8 nss;
|
||||
u8 band;
|
||||
s8 signal;
|
||||
u8 chains;
|
||||
s8 chain_signal[IEEE80211_MAX_CHAINS];
|
||||
};
|
||||
|
||||
#define __mt76_rr(dev, ...) (dev)->bus->rr((dev), __VA_ARGS__)
|
||||
#define __mt76_wr(dev, ...) (dev)->bus->wr((dev), __VA_ARGS__)
|
||||
#define __mt76_rmw(dev, ...) (dev)->bus->rmw((dev), __VA_ARGS__)
|
||||
@ -602,21 +617,6 @@ 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];
|
||||
}
|
||||
|
||||
struct mt76_dev *mt76_alloc_device(struct device *pdev, unsigned int size,
|
||||
const struct ieee80211_ops *ops,
|
||||
const struct mt76_driver_ops *drv_ops);
|
||||
@ -626,6 +626,7 @@ void mt76_unregister_device(struct mt76_dev *dev);
|
||||
void mt76_free_device(struct mt76_dev *dev);
|
||||
|
||||
struct dentry *mt76_register_debugfs(struct mt76_dev *dev);
|
||||
int mt76_queues_read(struct seq_file *s, void *data);
|
||||
void mt76_seq_puts_array(struct seq_file *file, const char *str,
|
||||
s8 *val, int len);
|
||||
|
||||
@ -718,6 +719,7 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw,
|
||||
bool more_data);
|
||||
bool mt76_has_tx_pending(struct mt76_dev *dev);
|
||||
void mt76_set_channel(struct mt76_dev *dev);
|
||||
void mt76_update_survey(struct mt76_dev *dev);
|
||||
int mt76_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey);
|
||||
void mt76_set_stream_caps(struct mt76_dev *dev, bool vht);
|
||||
@ -759,6 +761,7 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
void mt76_csa_check(struct mt76_dev *dev);
|
||||
void mt76_csa_finish(struct mt76_dev *dev);
|
||||
|
||||
int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
|
||||
int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set);
|
||||
void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id);
|
||||
int mt76_get_rate(struct mt76_dev *dev,
|
||||
@ -768,6 +771,8 @@ void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
const u8 *mac);
|
||||
void mt76_sw_scan_complete(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
u32 mt76_calc_tx_airtime(struct mt76_dev *dev, struct ieee80211_tx_info *info,
|
||||
int len);
|
||||
|
||||
/* internal */
|
||||
void mt76_tx_free(struct mt76_dev *dev);
|
||||
@ -778,6 +783,8 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
|
||||
void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
|
||||
struct napi_struct *napi);
|
||||
void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames);
|
||||
u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status,
|
||||
int len);
|
||||
|
||||
/* usb */
|
||||
static inline bool mt76u_urb_error(struct urb *urb)
|
||||
@ -799,7 +806,8 @@ static inline int
|
||||
mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,
|
||||
int timeout)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev->dev);
|
||||
struct usb_interface *uintf = to_usb_interface(dev->dev);
|
||||
struct usb_device *udev = interface_to_usbdev(uintf);
|
||||
struct mt76_usb *usb = &dev->usb;
|
||||
unsigned int pipe;
|
||||
|
||||
@ -817,6 +825,7 @@ int mt76u_vendor_request(struct mt76_dev *dev, u8 req,
|
||||
void mt76u_single_wr(struct mt76_dev *dev, const u8 req,
|
||||
const u16 offset, const u32 val);
|
||||
int mt76u_init(struct mt76_dev *dev, struct usb_interface *intf);
|
||||
void mt76u_deinit(struct mt76_dev *dev);
|
||||
int mt76u_alloc_queues(struct mt76_dev *dev);
|
||||
void mt76u_stop_tx(struct mt76_dev *dev);
|
||||
void mt76u_stop_rx(struct mt76_dev *dev);
|
||||
|
@ -69,6 +69,41 @@ mt7603_edcca_get(void *data, u64 *val)
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(fops_edcca, mt7603_edcca_get,
|
||||
mt7603_edcca_set, "%lld\n");
|
||||
|
||||
static int
|
||||
mt7603_ampdu_stat_read(struct seq_file *file, void *data)
|
||||
{
|
||||
struct mt7603_dev *dev = file->private;
|
||||
int bound[3], i, range;
|
||||
|
||||
range = mt76_rr(dev, MT_AGG_ASRCR);
|
||||
for (i = 0; i < ARRAY_SIZE(bound); i++)
|
||||
bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1;
|
||||
|
||||
seq_printf(file, "Length: %8d | ", bound[0]);
|
||||
for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
|
||||
seq_printf(file, "%3d -%3d | ",
|
||||
bound[i], bound[i + 1]);
|
||||
seq_puts(file, "\nCount: ");
|
||||
for (i = 0; i < ARRAY_SIZE(bound); i++)
|
||||
seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]);
|
||||
seq_puts(file, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7603_ampdu_stat_open(struct inode *inode, struct file *f)
|
||||
{
|
||||
return single_open(f, mt7603_ampdu_stat_read, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_ampdu_stat = {
|
||||
.open = mt7603_ampdu_stat_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
void mt7603_init_debugfs(struct mt7603_dev *dev)
|
||||
{
|
||||
struct dentry *dir;
|
||||
@ -77,6 +112,9 @@ void mt7603_init_debugfs(struct mt7603_dev *dev)
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
|
||||
mt76_queues_read);
|
||||
debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca);
|
||||
debugfs_create_u32("reset_test", 0600, dir, &dev->reset_test);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "reset", dir,
|
||||
|
@ -152,6 +152,8 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget)
|
||||
for (i = MT_TXQ_MCU; i >= 0; i--)
|
||||
mt76_queue_tx_cleanup(dev, i, false);
|
||||
|
||||
mt7603_mac_sta_poll(dev);
|
||||
|
||||
tasklet_schedule(&dev->mt76.tx_tasklet);
|
||||
|
||||
return 0;
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
const struct mt76_driver_ops mt7603_drv_ops = {
|
||||
.txwi_size = MT_TXD_SIZE,
|
||||
.drv_flags = MT_DRV_SW_RX_AIRTIME,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX,
|
||||
.tx_prepare_skb = mt7603_tx_prepare_skb,
|
||||
.tx_complete_skb = mt7603_tx_complete_skb,
|
||||
.rx_skb = mt7603_queue_rx_skb,
|
||||
@ -524,6 +526,8 @@ int mt7603_register_device(struct mt7603_dev *dev)
|
||||
bus_ops->rmw = mt7603_rmw;
|
||||
dev->mt76.bus = bus_ops;
|
||||
|
||||
INIT_LIST_HEAD(&dev->sta_poll_list);
|
||||
spin_lock_init(&dev->sta_poll_lock);
|
||||
spin_lock_init(&dev->ps_lock);
|
||||
|
||||
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7603_mac_work);
|
||||
@ -552,7 +556,6 @@ int mt7603_register_device(struct mt7603_dev *dev)
|
||||
wiphy->iface_combinations = if_comb;
|
||||
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
|
||||
|
||||
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
|
||||
ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
|
||||
|
||||
/* init led callbacks */
|
||||
@ -561,16 +564,7 @@ int mt7603_register_device(struct mt7603_dev *dev)
|
||||
dev->mt76.led_cdev.blink_set = mt7603_led_set_blink;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
|
||||
|
||||
wiphy->reg_notifier = mt7603_regd_notifier;
|
||||
|
||||
ret = mt76_register_device(&dev->mt76, true, mt7603_rates,
|
||||
|
@ -31,6 +31,16 @@ mt76_start_tx_ac(struct mt7603_dev *dev, u32 mask)
|
||||
mt76_set(dev, MT_WF_ARB_TX_START_0, mt7603_ac_queue_mask0(mask));
|
||||
}
|
||||
|
||||
void mt7603_mac_reset_counters(struct mt7603_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
mt76_rr(dev, MT_TX_AGG_CNT(i));
|
||||
|
||||
memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats));
|
||||
}
|
||||
|
||||
void mt7603_mac_set_timing(struct mt7603_dev *dev)
|
||||
{
|
||||
u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
|
||||
@ -150,6 +160,8 @@ void mt7603_wtbl_init(struct mt7603_dev *dev, int idx, int vif,
|
||||
addr = mt7603_wtbl4_addr(idx);
|
||||
for (i = 0; i < MT_WTBL4_SIZE; i += 4)
|
||||
mt76_wr(dev, addr + i, 0);
|
||||
|
||||
mt7603_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -370,6 +382,84 @@ void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid,
|
||||
mt76_rmw(dev, addr + (15 * 4), tid_mask, tid_val);
|
||||
}
|
||||
|
||||
void mt7603_mac_sta_poll(struct mt7603_dev *dev)
|
||||
{
|
||||
static const u8 ac_to_tid[4] = {
|
||||
[IEEE80211_AC_BE] = 0,
|
||||
[IEEE80211_AC_BK] = 1,
|
||||
[IEEE80211_AC_VI] = 4,
|
||||
[IEEE80211_AC_VO] = 6
|
||||
};
|
||||
struct ieee80211_sta *sta;
|
||||
struct mt7603_sta *msta;
|
||||
u32 total_airtime = 0;
|
||||
u32 airtime[4];
|
||||
u32 addr;
|
||||
int i;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
while (1) {
|
||||
bool clear = false;
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (list_empty(&dev->sta_poll_list)) {
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
break;
|
||||
}
|
||||
|
||||
msta = list_first_entry(&dev->sta_poll_list, struct mt7603_sta,
|
||||
poll_list);
|
||||
list_del_init(&msta->poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
|
||||
addr = mt7603_wtbl4_addr(msta->wcid.idx);
|
||||
for (i = 0; i < 4; i++) {
|
||||
u32 airtime_last = msta->tx_airtime_ac[i];
|
||||
|
||||
msta->tx_airtime_ac[i] = mt76_rr(dev, addr + i * 8);
|
||||
airtime[i] = msta->tx_airtime_ac[i] - airtime_last;
|
||||
airtime[i] *= 32;
|
||||
total_airtime += airtime[i];
|
||||
|
||||
if (msta->tx_airtime_ac[i] & BIT(22))
|
||||
clear = true;
|
||||
}
|
||||
|
||||
if (clear) {
|
||||
mt7603_wtbl_update(dev, msta->wcid.idx,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
memset(msta->tx_airtime_ac, 0,
|
||||
sizeof(msta->tx_airtime_ac));
|
||||
}
|
||||
|
||||
if (!msta->wcid.sta)
|
||||
continue;
|
||||
|
||||
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
|
||||
for (i = 0; i < 4; i++) {
|
||||
struct mt76_queue *q = dev->mt76.q_tx[i].q;
|
||||
u8 qidx = q->hw_idx;
|
||||
u8 tid = ac_to_tid[i];
|
||||
u32 txtime = airtime[qidx];
|
||||
|
||||
if (!txtime)
|
||||
continue;
|
||||
|
||||
ieee80211_sta_register_airtime(sta, tid, txtime, 0);
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (!total_airtime)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&dev->mt76.cc_lock);
|
||||
dev->mt76.chan_state->cc_tx += total_airtime;
|
||||
spin_unlock_bh(&dev->mt76.cc_lock);
|
||||
}
|
||||
|
||||
static struct mt76_wcid *
|
||||
mt7603_rx_get_wcid(struct mt7603_dev *dev, u8 idx, bool unicast)
|
||||
{
|
||||
@ -435,6 +525,20 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
|
||||
status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
|
||||
}
|
||||
|
||||
if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB |
|
||||
MT_RXD2_NORMAL_NON_AMPDU))) {
|
||||
status->flag |= RX_FLAG_AMPDU_DETAILS;
|
||||
|
||||
/* all subframes of an A-MPDU have the same timestamp */
|
||||
if (dev->rx_ampdu_ts != rxd[12]) {
|
||||
if (!++dev->mt76.ampdu_ref)
|
||||
dev->mt76.ampdu_ref++;
|
||||
}
|
||||
dev->rx_ampdu_ts = rxd[12];
|
||||
|
||||
status->ampdu_ref = dev->mt76.ampdu_ref;
|
||||
}
|
||||
|
||||
remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET;
|
||||
|
||||
if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
|
||||
@ -1032,8 +1136,10 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta,
|
||||
if (idx && (cur_rate->idx != info->status.rates[i].idx ||
|
||||
cur_rate->flags != info->status.rates[i].flags)) {
|
||||
i++;
|
||||
if (i == ARRAY_SIZE(info->status.rates))
|
||||
if (i == ARRAY_SIZE(info->status.rates)) {
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
||||
info->status.rates[i] = *cur_rate;
|
||||
info->status.rates[i].count = 0;
|
||||
@ -1135,6 +1241,12 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
|
||||
msta = container_of(wcid, struct mt7603_sta, wcid);
|
||||
sta = wcid_to_sta(wcid);
|
||||
|
||||
if (list_empty(&msta->poll_list)) {
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data))
|
||||
goto out;
|
||||
|
||||
@ -1461,22 +1573,9 @@ void mt7603_update_channel(struct mt76_dev *mdev)
|
||||
{
|
||||
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
|
||||
struct mt76_channel_state *state;
|
||||
ktime_t cur_time;
|
||||
u32 busy;
|
||||
|
||||
if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state))
|
||||
return;
|
||||
|
||||
state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan);
|
||||
busy = mt76_rr(dev, MT_MIB_STAT_PSCCA);
|
||||
|
||||
spin_lock_bh(&dev->mt76.cc_lock);
|
||||
cur_time = ktime_get_boottime();
|
||||
state->cc_busy += busy;
|
||||
state->cc_active += ktime_to_us(ktime_sub(cur_time,
|
||||
dev->mt76.survey_time));
|
||||
dev->mt76.survey_time = cur_time;
|
||||
spin_unlock_bh(&dev->mt76.cc_lock);
|
||||
state = mdev->chan_state;
|
||||
state->cc_busy += mt76_rr(dev, MT_MIB_STAT_CCA);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1677,15 +1776,23 @@ void mt7603_mac_work(struct work_struct *work)
|
||||
struct mt7603_dev *dev = container_of(work, struct mt7603_dev,
|
||||
mt76.mac_work.work);
|
||||
bool reset = false;
|
||||
int i, idx;
|
||||
|
||||
mt76_tx_status_check(&dev->mt76, NULL, false);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
dev->mac_work_count++;
|
||||
mt7603_update_channel(&dev->mt76);
|
||||
mt76_update_survey(&dev->mt76);
|
||||
mt7603_edcca_check(dev);
|
||||
|
||||
for (i = 0, idx = 0; i < 2; i++) {
|
||||
u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
|
||||
|
||||
dev->mt76.aggr_stats[idx++] += val & 0xffff;
|
||||
dev->mt76.aggr_stats[idx++] += val >> 16;
|
||||
}
|
||||
|
||||
if (dev->mac_work_count == 10)
|
||||
mt7603_false_cca_check(dev);
|
||||
|
||||
|
@ -13,6 +13,7 @@ mt7603_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct mt7603_dev *dev = hw->priv;
|
||||
|
||||
mt7603_mac_reset_counters(dev);
|
||||
mt7603_mac_start(dev);
|
||||
dev->mt76.survey_time = ktime_get_boottime();
|
||||
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
|
||||
@ -65,6 +66,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
|
||||
idx = MT7603_WTBL_RESERVED - 1 - mvif->idx;
|
||||
dev->vif_mask |= BIT(mvif->idx);
|
||||
INIT_LIST_HEAD(&mvif->sta.poll_list);
|
||||
mvif->sta.wcid.idx = idx;
|
||||
mvif->sta.wcid.hw_key_idx = -1;
|
||||
|
||||
@ -86,8 +88,9 @@ static void
|
||||
mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
|
||||
struct mt7603_sta *msta = &mvif->sta;
|
||||
struct mt7603_dev *dev = hw->priv;
|
||||
int idx = mvif->sta.wcid.idx;
|
||||
int idx = msta->wcid.idx;
|
||||
|
||||
mt76_wr(dev, MT_MAC_ADDR0(mvif->idx), 0);
|
||||
mt76_wr(dev, MT_MAC_ADDR1(mvif->idx), 0);
|
||||
@ -98,6 +101,11 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
|
||||
mt76_txq_remove(&dev->mt76, vif->txq);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (!list_empty(&msta->poll_list))
|
||||
list_del_init(&msta->poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
dev->vif_mask &= ~BIT(mvif->idx);
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
@ -324,6 +332,7 @@ mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
||||
if (idx < 0)
|
||||
return -ENOSPC;
|
||||
|
||||
INIT_LIST_HEAD(&msta->poll_list);
|
||||
__skb_queue_head_init(&msta->psq);
|
||||
msta->ps = ~0;
|
||||
msta->smps = ~0;
|
||||
@ -360,6 +369,11 @@ mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
||||
mt7603_filter_tx(dev, wcid->idx, true);
|
||||
spin_unlock_bh(&dev->ps_lock);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (!list_empty(&msta->poll_list))
|
||||
list_del_init(&msta->poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
|
||||
mt7603_wtbl_clear(dev, wcid->idx);
|
||||
}
|
||||
|
||||
@ -561,6 +575,7 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
|
||||
mtxq = (struct mt76_txq *)txq->drv_priv;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn,
|
||||
@ -589,6 +604,7 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -675,6 +691,7 @@ const struct ieee80211_ops mt7603_ops = {
|
||||
.set_coverage_class = mt7603_set_coverage_class,
|
||||
.set_tim = mt76_set_tim,
|
||||
.get_survey = mt76_get_survey,
|
||||
.get_antenna = mt76_get_antenna,
|
||||
};
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
@ -61,6 +61,9 @@ struct mt7603_sta {
|
||||
|
||||
struct mt7603_vif *vif;
|
||||
|
||||
struct list_head poll_list;
|
||||
u32 tx_airtime_ac[4];
|
||||
|
||||
struct sk_buff_head psq;
|
||||
|
||||
struct ieee80211_tx_rate rates[4];
|
||||
@ -103,12 +106,16 @@ struct mt7603_dev {
|
||||
|
||||
u8 vif_mask;
|
||||
|
||||
struct list_head sta_poll_list;
|
||||
spinlock_t sta_poll_lock;
|
||||
|
||||
struct mt7603_sta global_sta;
|
||||
|
||||
u32 agc0, agc3;
|
||||
u32 false_cca_ofdm, false_cca_cck;
|
||||
unsigned long last_cca_adj;
|
||||
|
||||
__le32 rx_ampdu_ts;
|
||||
u8 rssi_offset[3];
|
||||
|
||||
u8 slottime;
|
||||
@ -118,8 +125,6 @@ struct mt7603_dev {
|
||||
|
||||
ktime_t ed_time;
|
||||
|
||||
struct mt76_queue q_rx;
|
||||
|
||||
spinlock_t ps_lock;
|
||||
|
||||
u8 mac_work_count;
|
||||
@ -191,6 +196,7 @@ static inline void mt7603_irq_disable(struct mt7603_dev *dev, u32 mask)
|
||||
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
|
||||
}
|
||||
|
||||
void mt7603_mac_reset_counters(struct mt7603_dev *dev);
|
||||
void mt7603_mac_dma_start(struct mt7603_dev *dev);
|
||||
void mt7603_mac_start(struct mt7603_dev *dev);
|
||||
void mt7603_mac_stop(struct mt7603_dev *dev);
|
||||
@ -202,6 +208,7 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data);
|
||||
void mt7603_mac_rx_ba_reset(struct mt7603_dev *dev, void *addr, u8 tid);
|
||||
void mt7603_mac_tx_ba_reset(struct mt7603_dev *dev, int wcid, int tid,
|
||||
int ba_size);
|
||||
void mt7603_mac_sta_poll(struct mt7603_dev *dev);
|
||||
|
||||
void mt7603_pse_client_reset(struct mt7603_dev *dev);
|
||||
|
||||
|
@ -212,6 +212,9 @@
|
||||
#define MT_AGG_PCR_RTS_THR GENMASK(19, 0)
|
||||
#define MT_AGG_PCR_RTS_PKT_THR GENMASK(31, 25)
|
||||
|
||||
#define MT_AGG_ASRCR MT_WF_AGG(0x060)
|
||||
#define MT_AGG_ASRCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(5, 0))
|
||||
|
||||
#define MT_AGG_CONTROL MT_WF_AGG(0x070)
|
||||
#define MT_AGG_CONTROL_NO_BA_RULE BIT(0)
|
||||
#define MT_AGG_CONTROL_NO_BA_AR_RULE BIT(1)
|
||||
@ -555,6 +558,8 @@ enum {
|
||||
#define MT_MIB_STAT_PSCCA MT_MIB_STAT(16)
|
||||
#define MT_MIB_STAT_PSCCA_MASK GENMASK(23, 0)
|
||||
|
||||
#define MT_TX_AGG_CNT(n) MT_MIB(0xa8 + ((n) << 2))
|
||||
|
||||
#define MT_MIB_STAT_ED MT_MIB_STAT(18)
|
||||
#define MT_MIB_STAT_ED_MASK GENMASK(23, 0)
|
||||
|
||||
|
@ -36,6 +36,44 @@ mt7615_scs_get(void *data, u64 *val)
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(fops_scs, mt7615_scs_get,
|
||||
mt7615_scs_set, "%lld\n");
|
||||
|
||||
static int
|
||||
mt7615_ampdu_stat_read(struct seq_file *file, void *data)
|
||||
{
|
||||
struct mt7615_dev *dev = file->private;
|
||||
int bound[7], i, range;
|
||||
|
||||
range = mt76_rr(dev, MT_AGG_ASRCR0);
|
||||
for (i = 0; i < 4; i++)
|
||||
bound[i] = MT_AGG_ASRCR_RANGE(range, i) + 1;
|
||||
range = mt76_rr(dev, MT_AGG_ASRCR1);
|
||||
for (i = 0; i < 3; i++)
|
||||
bound[i + 4] = MT_AGG_ASRCR_RANGE(range, i) + 1;
|
||||
|
||||
seq_printf(file, "Length: %8d | ", bound[0]);
|
||||
for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
|
||||
seq_printf(file, "%3d -%3d | ",
|
||||
bound[i], bound[i + 1]);
|
||||
seq_puts(file, "\nCount: ");
|
||||
for (i = 0; i < ARRAY_SIZE(bound); i++)
|
||||
seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i]);
|
||||
seq_puts(file, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7615_ampdu_stat_open(struct inode *inode, struct file *f)
|
||||
{
|
||||
return single_open(f, mt7615_ampdu_stat_read, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_ampdu_stat = {
|
||||
.open = mt7615_ampdu_stat_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int
|
||||
mt7615_radio_read(struct seq_file *s, void *data)
|
||||
{
|
||||
@ -61,6 +99,63 @@ static int mt7615_read_temperature(struct seq_file *s, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7615_queues_acq(struct seq_file *s, void *data)
|
||||
{
|
||||
struct mt7615_dev *dev = dev_get_drvdata(s->private);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
int j, acs = i / 4, index = i % 4;
|
||||
u32 ctrl, val, qlen = 0;
|
||||
|
||||
val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index));
|
||||
ctrl = BIT(31) | BIT(15) | (acs << 8);
|
||||
|
||||
for (j = 0; j < 32; j++) {
|
||||
if (val & BIT(j))
|
||||
continue;
|
||||
|
||||
mt76_wr(dev, MT_PLE_FL_Q0_CTRL,
|
||||
ctrl | (j + (index << 5)));
|
||||
qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL,
|
||||
GENMASK(11, 0));
|
||||
}
|
||||
seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mt7615_queues_read(struct seq_file *s, void *data)
|
||||
{
|
||||
struct mt7615_dev *dev = dev_get_drvdata(s->private);
|
||||
static const struct {
|
||||
char *queue;
|
||||
int id;
|
||||
} queue_map[] = {
|
||||
{ "PDMA0", MT_TXQ_BE },
|
||||
{ "MCUQ", MT_TXQ_MCU },
|
||||
{ "MCUFWQ", MT_TXQ_FWDL },
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
|
||||
struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id];
|
||||
|
||||
if (!q->q)
|
||||
continue;
|
||||
|
||||
seq_printf(s,
|
||||
"%s: queued=%d head=%d tail=%d\n",
|
||||
queue_map[i].queue, q->q->queued, q->q->head,
|
||||
q->q->tail);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt7615_init_debugfs(struct mt7615_dev *dev)
|
||||
{
|
||||
struct dentry *dir;
|
||||
@ -69,6 +164,11 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
|
||||
if (!dir)
|
||||
return -ENOMEM;
|
||||
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
|
||||
mt7615_queues_read);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
|
||||
mt7615_queues_acq);
|
||||
debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
|
||||
debugfs_create_file("scs", 0600, dir, dev, &fops_scs);
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir,
|
||||
mt7615_radio_read);
|
||||
|
@ -110,6 +110,8 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget)
|
||||
for (i = 0; i < ARRAY_SIZE(queue_map); i++)
|
||||
mt76_queue_tx_cleanup(dev, queue_map[i], false);
|
||||
|
||||
mt7615_mac_sta_poll(dev);
|
||||
|
||||
tasklet_schedule(&dev->mt76.tx_tasklet);
|
||||
|
||||
return 0;
|
||||
|
@ -93,6 +93,7 @@ static int mt7615_check_eeprom(struct mt76_dev *dev)
|
||||
static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
|
||||
{
|
||||
u8 val, *eeprom = dev->mt76.eeprom.data;
|
||||
u8 tx_mask, rx_mask, max_nss;
|
||||
|
||||
val = FIELD_GET(MT_EE_NIC_WIFI_CONF_BAND_SEL,
|
||||
eeprom[MT_EE_WIFI_CONF]);
|
||||
@ -108,6 +109,23 @@ static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
|
||||
dev->mt76.cap.has_5ghz = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* read tx-rx mask from eeprom */
|
||||
val = mt76_rr(dev, MT_TOP_STRAP_STA);
|
||||
max_nss = val & MT_TOP_3NSS ? 3 : 4;
|
||||
|
||||
rx_mask = FIELD_GET(MT_EE_NIC_CONF_RX_MASK,
|
||||
eeprom[MT_EE_NIC_CONF_0]);
|
||||
if (!rx_mask || rx_mask > max_nss)
|
||||
rx_mask = max_nss;
|
||||
|
||||
tx_mask = FIELD_GET(MT_EE_NIC_CONF_TX_MASK,
|
||||
eeprom[MT_EE_NIC_CONF_0]);
|
||||
if (!tx_mask || tx_mask > max_nss)
|
||||
tx_mask = max_nss;
|
||||
|
||||
dev->mt76.chainmask = tx_mask << 8 | rx_mask;
|
||||
dev->mt76.antenna_mask = BIT(tx_mask) - 1;
|
||||
}
|
||||
|
||||
int mt7615_eeprom_get_power_index(struct mt7615_dev *dev,
|
||||
|
@ -24,6 +24,9 @@ enum mt7615_eeprom_field {
|
||||
__MT_EE_MAX = 0x3bf
|
||||
};
|
||||
|
||||
#define MT_EE_NIC_CONF_TX_MASK GENMASK(7, 4)
|
||||
#define MT_EE_NIC_CONF_RX_MASK GENMASK(3, 0)
|
||||
|
||||
#define MT_EE_NIC_CONF_TSSI_2G BIT(5)
|
||||
#define MT_EE_NIC_CONF_TSSI_5G BIT(6)
|
||||
|
||||
|
@ -20,7 +20,8 @@ static void mt7615_phy_init(struct mt7615_dev *dev)
|
||||
|
||||
static void mt7615_mac_init(struct mt7615_dev *dev)
|
||||
{
|
||||
u32 val;
|
||||
u32 val, mask, set;
|
||||
int i;
|
||||
|
||||
/* enable band 0/1 clk */
|
||||
mt76_set(dev, MT_CFG_CCR,
|
||||
@ -50,7 +51,7 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
|
||||
MT_TMAC_CTCR0_INS_DDLMT_EN);
|
||||
|
||||
mt7615_mcu_set_rts_thresh(dev, 0x92b);
|
||||
mt7615_mac_set_scs(dev, false);
|
||||
mt7615_mac_set_scs(dev, true);
|
||||
|
||||
mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS,
|
||||
MT_AGG_SCR_NLNAV_MID_PTEC_DIS);
|
||||
@ -85,6 +86,24 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
|
||||
MT_AGG_ARCR_RATE_DOWN_RATIO_EN |
|
||||
FIELD_PREP(MT_AGG_ARCR_RATE_DOWN_RATIO, 1) |
|
||||
FIELD_PREP(MT_AGG_ARCR_RATE_UP_EXTRA_TH, 4)));
|
||||
|
||||
mask = MT_DMA_RCFR0_MCU_RX_MGMT |
|
||||
MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR |
|
||||
MT_DMA_RCFR0_MCU_RX_CTL_BAR |
|
||||
MT_DMA_RCFR0_MCU_RX_BYPASS |
|
||||
MT_DMA_RCFR0_RX_DROPPED_UCAST |
|
||||
MT_DMA_RCFR0_RX_DROPPED_MCAST;
|
||||
set = FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_UCAST, 2) |
|
||||
FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_MCAST, 2);
|
||||
mt76_rmw(dev, MT_DMA_BN0RCFR0, mask, set);
|
||||
mt76_rmw(dev, MT_DMA_BN1RCFR0, mask, set);
|
||||
|
||||
for (i = 0; i < MT7615_WTBL_SIZE; i++)
|
||||
mt7615_mac_wtbl_update(dev, i,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
|
||||
mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_EN);
|
||||
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_EN);
|
||||
}
|
||||
|
||||
static int mt7615_init_hardware(struct mt7615_dev *dev)
|
||||
@ -158,6 +177,9 @@ static struct ieee80211_rate mt7615_rates[] = {
|
||||
|
||||
static const struct ieee80211_iface_limit if_limits[] = {
|
||||
{
|
||||
.max = 1,
|
||||
.types = BIT(NL80211_IFTYPE_ADHOC)
|
||||
}, {
|
||||
.max = MT7615_MAX_INTERFACES,
|
||||
.types = BIT(NL80211_IFTYPE_AP) |
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
@ -249,12 +271,14 @@ int mt7615_register_device(struct mt7615_dev *dev)
|
||||
struct wiphy *wiphy = hw->wiphy;
|
||||
int ret;
|
||||
|
||||
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work);
|
||||
INIT_LIST_HEAD(&dev->sta_poll_list);
|
||||
spin_lock_init(&dev->sta_poll_lock);
|
||||
|
||||
ret = mt7615_init_hardware(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7615_mac_work);
|
||||
|
||||
hw->queues = 4;
|
||||
hw->max_rates = 3;
|
||||
hw->max_report_rates = 7;
|
||||
@ -268,7 +292,8 @@ int mt7615_register_device(struct mt7615_dev *dev)
|
||||
wiphy->reg_notifier = mt7615_regd_notifier;
|
||||
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
|
||||
|
||||
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
|
||||
|
||||
ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
|
||||
|
||||
dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
|
||||
@ -278,16 +303,8 @@ int mt7615_register_device(struct mt7615_dev *dev)
|
||||
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
|
||||
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
|
||||
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
|
||||
dev->mt76.chainmask = 0x404;
|
||||
dev->mt76.antenna_mask = 0xf;
|
||||
dev->dfs_state = -1;
|
||||
|
||||
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
|
||||
#ifdef CONFIG_MAC80211_MESH
|
||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
||||
#endif
|
||||
BIT(NL80211_IFTYPE_AP);
|
||||
|
||||
ret = mt76_register_device(&dev->mt76, true, mt7615_rates,
|
||||
ARRAY_SIZE(mt7615_rates));
|
||||
if (ret)
|
||||
|
@ -41,6 +41,25 @@ static struct mt76_wcid *mt7615_rx_get_wcid(struct mt7615_dev *dev,
|
||||
return &sta->vif->sta.wcid;
|
||||
}
|
||||
|
||||
void mt7615_mac_reset_counters(struct mt7615_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
mt76_rr(dev, MT_TX_AGG_CNT(i));
|
||||
|
||||
memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats));
|
||||
|
||||
/* TODO: add DBDC support */
|
||||
|
||||
/* reset airtime counters */
|
||||
mt76_rr(dev, MT_MIB_SDR9(0));
|
||||
mt76_rr(dev, MT_MIB_SDR36(0));
|
||||
mt76_rr(dev, MT_MIB_SDR37(0));
|
||||
mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
|
||||
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
|
||||
}
|
||||
|
||||
int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
|
||||
@ -62,6 +81,16 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
|
||||
idx = FIELD_GET(MT_RXD2_NORMAL_WLAN_IDX, rxd2);
|
||||
status->wcid = mt7615_rx_get_wcid(dev, idx, unicast);
|
||||
|
||||
if (status->wcid) {
|
||||
struct mt7615_sta *msta;
|
||||
|
||||
msta = container_of(status->wcid, struct mt7615_sta, wcid);
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (list_empty(&msta->poll_list))
|
||||
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
/* TODO: properly support DBDC */
|
||||
status->freq = dev->mt76.chandef.chan->center_freq;
|
||||
status->band = dev->mt76.chandef.chan->band;
|
||||
@ -83,6 +112,20 @@ int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
|
||||
status->flag |= RX_FLAG_MMIC_STRIPPED | RX_FLAG_MIC_STRIPPED;
|
||||
}
|
||||
|
||||
if (!(rxd2 & (MT_RXD2_NORMAL_NON_AMPDU_SUB |
|
||||
MT_RXD2_NORMAL_NON_AMPDU))) {
|
||||
status->flag |= RX_FLAG_AMPDU_DETAILS;
|
||||
|
||||
/* all subframes of an A-MPDU have the same timestamp */
|
||||
if (dev->rx_ampdu_ts != rxd[12]) {
|
||||
if (!++dev->mt76.ampdu_ref)
|
||||
dev->mt76.ampdu_ref++;
|
||||
}
|
||||
dev->rx_ampdu_ts = rxd[12];
|
||||
|
||||
status->ampdu_ref = dev->mt76.ampdu_ref;
|
||||
}
|
||||
|
||||
remove_pad = rxd1 & MT_RXD1_NORMAL_HDR_OFFSET;
|
||||
|
||||
if (rxd2 & MT_RXD2_NORMAL_MAX_LEN_ERROR)
|
||||
@ -460,6 +503,91 @@ static u32 mt7615_mac_wtbl_addr(int wcid)
|
||||
return MT_WTBL_BASE + wcid * MT_WTBL_ENTRY_SIZE;
|
||||
}
|
||||
|
||||
bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask)
|
||||
{
|
||||
mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
|
||||
FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask);
|
||||
|
||||
return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY,
|
||||
0, 5000);
|
||||
}
|
||||
|
||||
void mt7615_mac_sta_poll(struct mt7615_dev *dev)
|
||||
{
|
||||
static const u8 ac_to_tid[4] = {
|
||||
[IEEE80211_AC_BE] = 0,
|
||||
[IEEE80211_AC_BK] = 1,
|
||||
[IEEE80211_AC_VI] = 4,
|
||||
[IEEE80211_AC_VO] = 6
|
||||
};
|
||||
static const u8 hw_queue_map[] = {
|
||||
[IEEE80211_AC_BK] = 0,
|
||||
[IEEE80211_AC_BE] = 1,
|
||||
[IEEE80211_AC_VI] = 2,
|
||||
[IEEE80211_AC_VO] = 3,
|
||||
};
|
||||
struct ieee80211_sta *sta;
|
||||
struct mt7615_sta *msta;
|
||||
u32 addr, tx_time[4], rx_time[4];
|
||||
int i;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
while (true) {
|
||||
bool clear = false;
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (list_empty(&dev->sta_poll_list)) {
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
break;
|
||||
}
|
||||
msta = list_first_entry(&dev->sta_poll_list,
|
||||
struct mt7615_sta, poll_list);
|
||||
list_del_init(&msta->poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
|
||||
addr = mt7615_mac_wtbl_addr(msta->wcid.idx) + 19 * 4;
|
||||
|
||||
for (i = 0; i < 4; i++, addr += 8) {
|
||||
u32 tx_last = msta->airtime_ac[i];
|
||||
u32 rx_last = msta->airtime_ac[i + 4];
|
||||
|
||||
msta->airtime_ac[i] = mt76_rr(dev, addr);
|
||||
msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
|
||||
tx_time[i] = msta->airtime_ac[i] - tx_last;
|
||||
rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
|
||||
|
||||
if ((tx_last | rx_last) & BIT(30))
|
||||
clear = true;
|
||||
}
|
||||
|
||||
if (clear) {
|
||||
mt7615_mac_wtbl_update(dev, msta->wcid.idx,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
|
||||
}
|
||||
|
||||
if (!msta->wcid.sta)
|
||||
continue;
|
||||
|
||||
sta = container_of((void *)msta, struct ieee80211_sta,
|
||||
drv_priv);
|
||||
for (i = 0; i < 4; i++) {
|
||||
u32 tx_cur = tx_time[i];
|
||||
u32 rx_cur = rx_time[hw_queue_map[i]];
|
||||
u8 tid = ac_to_tid[i];
|
||||
|
||||
if (!tx_cur && !rx_cur)
|
||||
continue;
|
||||
|
||||
ieee80211_sta_register_airtime(sta, tid, tx_cur,
|
||||
rx_cur);
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void mt7615_mac_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta,
|
||||
struct ieee80211_tx_rate *probe_rate,
|
||||
struct ieee80211_tx_rate *rates)
|
||||
@ -692,11 +820,8 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid,
|
||||
mt76_wr(dev, MT_WTBL_RICR0, w0);
|
||||
mt76_wr(dev, MT_WTBL_RICR1, w1);
|
||||
|
||||
mt76_wr(dev, MT_WTBL_UPDATE,
|
||||
FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid->idx) |
|
||||
MT_WTBL_UPDATE_RXINFO_UPDATE);
|
||||
|
||||
if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
|
||||
if (!mt7615_mac_wtbl_update(dev, wcid->idx,
|
||||
MT_WTBL_UPDATE_RXINFO_UPDATE))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
@ -914,8 +1039,10 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
|
||||
if (idx && (cur_rate->idx != info->status.rates[i].idx ||
|
||||
cur_rate->flags != info->status.rates[i].flags)) {
|
||||
i++;
|
||||
if (i == ARRAY_SIZE(info->status.rates))
|
||||
if (i == ARRAY_SIZE(info->status.rates)) {
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
||||
info->status.rates[i] = *cur_rate;
|
||||
info->status.rates[i].count = 0;
|
||||
@ -1026,6 +1153,11 @@ void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data)
|
||||
msta = container_of(wcid, struct mt7615_sta, wcid);
|
||||
sta = wcid_to_sta(wcid);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (list_empty(&msta->poll_list))
|
||||
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
|
||||
if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data))
|
||||
goto out;
|
||||
|
||||
@ -1239,38 +1371,49 @@ void mt7615_update_channel(struct mt76_dev *mdev)
|
||||
{
|
||||
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
|
||||
struct mt76_channel_state *state;
|
||||
ktime_t cur_time;
|
||||
u32 busy;
|
||||
u64 busy_time, tx_time, rx_time, obss_time;
|
||||
|
||||
if (!test_bit(MT76_STATE_RUNNING, &mdev->state))
|
||||
return;
|
||||
|
||||
state = mt76_channel_state(mdev, mdev->chandef.chan);
|
||||
/* TODO: add DBDC support */
|
||||
busy = mt76_get_field(dev, MT_MIB_SDR16(0), MT_MIB_BUSY_MASK);
|
||||
busy_time = mt76_get_field(dev, MT_MIB_SDR9(0),
|
||||
MT_MIB_SDR9_BUSY_MASK);
|
||||
tx_time = mt76_get_field(dev, MT_MIB_SDR36(0),
|
||||
MT_MIB_SDR36_TXTIME_MASK);
|
||||
rx_time = mt76_get_field(dev, MT_MIB_SDR37(0),
|
||||
MT_MIB_SDR37_RXTIME_MASK);
|
||||
obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_TIME5,
|
||||
MT_MIB_OBSSTIME_MASK);
|
||||
|
||||
spin_lock_bh(&mdev->cc_lock);
|
||||
cur_time = ktime_get_boottime();
|
||||
state->cc_busy += busy;
|
||||
state->cc_active += ktime_to_us(ktime_sub(cur_time,
|
||||
mdev->survey_time));
|
||||
mdev->survey_time = cur_time;
|
||||
spin_unlock_bh(&mdev->cc_lock);
|
||||
state = mdev->chan_state;
|
||||
state->cc_busy += busy_time;
|
||||
state->cc_tx += tx_time;
|
||||
state->cc_rx += rx_time + obss_time;
|
||||
state->cc_bss_rx += rx_time;
|
||||
|
||||
/* reset obss airtime */
|
||||
mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_CLR);
|
||||
}
|
||||
|
||||
void mt7615_mac_work(struct work_struct *work)
|
||||
{
|
||||
struct mt7615_dev *dev;
|
||||
int i, idx;
|
||||
|
||||
dev = (struct mt7615_dev *)container_of(work, struct mt76_dev,
|
||||
mac_work.work);
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
mt7615_update_channel(&dev->mt76);
|
||||
mt76_update_survey(&dev->mt76);
|
||||
if (++dev->mac_work_count == 5) {
|
||||
mt7615_mac_scs_check(dev);
|
||||
dev->mac_work_count = 0;
|
||||
}
|
||||
|
||||
for (i = 0, idx = 0; i < 4; i++) {
|
||||
u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i));
|
||||
|
||||
dev->mt76.aggr_stats[idx++] += val & 0xffff;
|
||||
dev->mt76.aggr_stats[idx++] += val >> 16;
|
||||
}
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
mt76_tx_status_check(&dev->mt76, NULL, false);
|
||||
|
@ -16,6 +16,8 @@ static int mt7615_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct mt7615_dev *dev = hw->priv;
|
||||
|
||||
mt7615_mac_reset_counters(dev);
|
||||
|
||||
dev->mt76.survey_time = ktime_get_boottime();
|
||||
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
|
||||
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
|
||||
@ -39,6 +41,7 @@ static int get_omac_idx(enum nl80211_iftype type, u32 mask)
|
||||
switch (type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
/* ap use hw bssid 0 and ext bssid */
|
||||
if (~mask & BIT(HW_BSSID_0))
|
||||
return HW_BSSID_0;
|
||||
@ -58,7 +61,7 @@ static int get_omac_idx(enum nl80211_iftype type, u32 mask)
|
||||
default:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -97,8 +100,12 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
|
||||
dev->vif_mask |= BIT(mvif->idx);
|
||||
dev->omac_mask |= BIT(mvif->omac_idx);
|
||||
idx = MT7615_WTBL_RESERVED - mvif->idx;
|
||||
|
||||
INIT_LIST_HEAD(&mvif->sta.poll_list);
|
||||
mvif->sta.wcid.idx = idx;
|
||||
mvif->sta.wcid.hw_key_idx = -1;
|
||||
mt7615_mac_wtbl_update(dev, idx,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
|
||||
rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
|
||||
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
|
||||
@ -115,8 +122,9 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
|
||||
struct mt7615_sta *msta = &mvif->sta;
|
||||
struct mt7615_dev *dev = hw->priv;
|
||||
int idx = mvif->sta.wcid.idx;
|
||||
int idx = msta->wcid.idx;
|
||||
|
||||
/* TODO: disable beacon for the bss */
|
||||
|
||||
@ -129,6 +137,11 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
|
||||
dev->vif_mask &= ~BIT(mvif->idx);
|
||||
dev->omac_mask &= ~BIT(mvif->omac_idx);
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (!list_empty(&msta->poll_list))
|
||||
list_del_init(&msta->poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
static int mt7615_set_channel(struct mt7615_dev *dev)
|
||||
@ -151,8 +164,8 @@ static int mt7615_set_channel(struct mt7615_dev *dev)
|
||||
ret = mt7615_dfs_init_radar_detector(dev);
|
||||
mt7615_mac_cca_stats_reset(dev);
|
||||
dev->mt76.survey_time = ktime_get_boottime();
|
||||
/* TODO: add DBDC support */
|
||||
mt76_rr(dev, MT_MIB_SDR16(0));
|
||||
|
||||
mt7615_mac_reset_counters(dev);
|
||||
|
||||
out:
|
||||
clear_bit(MT76_RESET, &dev->mt76.state);
|
||||
@ -263,6 +276,11 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw,
|
||||
u64 multicast)
|
||||
{
|
||||
struct mt7615_dev *dev = hw->priv;
|
||||
u32 ctl_flags = MT_WF_RFCR1_DROP_ACK |
|
||||
MT_WF_RFCR1_DROP_BF_POLL |
|
||||
MT_WF_RFCR1_DROP_BA |
|
||||
MT_WF_RFCR1_DROP_CFEND |
|
||||
MT_WF_RFCR1_DROP_CFACK;
|
||||
u32 flags = 0;
|
||||
|
||||
#define MT76_FILTER(_flag, _hw) do { \
|
||||
@ -296,6 +314,11 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw,
|
||||
|
||||
*total_flags = flags;
|
||||
mt76_wr(dev, MT_WF_RFCR, dev->mt76.rxfilter);
|
||||
|
||||
if (*total_flags & FIF_CONTROL)
|
||||
mt76_clear(dev, MT_WF_RFCR1, ctl_flags);
|
||||
else
|
||||
mt76_set(dev, MT_WF_RFCR1, ctl_flags);
|
||||
}
|
||||
|
||||
static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
|
||||
@ -348,9 +371,12 @@ int mt7615_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
||||
if (idx < 0)
|
||||
return -ENOSPC;
|
||||
|
||||
INIT_LIST_HEAD(&msta->poll_list);
|
||||
msta->vif = mvif;
|
||||
msta->wcid.sta = 1;
|
||||
msta->wcid.idx = idx;
|
||||
mt7615_mac_wtbl_update(dev, idx,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
|
||||
mt7615_mcu_add_wtbl(dev, vif, sta);
|
||||
mt7615_mcu_set_sta_rec(dev, vif, sta, 1);
|
||||
@ -371,9 +397,18 @@ void mt7615_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta)
|
||||
{
|
||||
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
|
||||
struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
|
||||
|
||||
mt7615_mcu_set_sta_rec(dev, vif, sta, 0);
|
||||
mt7615_mcu_del_wtbl(dev, sta);
|
||||
|
||||
mt7615_mac_wtbl_update(dev, msta->wcid.idx,
|
||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
if (!list_empty(&msta->poll_list))
|
||||
list_del_init(&msta->poll_list);
|
||||
spin_unlock_bh(&dev->sta_poll_lock);
|
||||
}
|
||||
|
||||
static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw,
|
||||
@ -455,6 +490,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
|
||||
mtxq = (struct mt76_txq *)txq->drv_priv;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn,
|
||||
@ -484,6 +520,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -510,4 +547,5 @@ const struct ieee80211_ops mt7615_ops = {
|
||||
.get_txpower = mt76_get_txpower,
|
||||
.channel_switch_beacon = mt7615_channel_switch_beacon,
|
||||
.get_survey = mt76_get_survey,
|
||||
.get_antenna = mt76_get_antenna,
|
||||
};
|
||||
|
@ -848,6 +848,11 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
|
||||
conn_type = CONNECTION_INFRA_STA;
|
||||
break;
|
||||
}
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
conn_type = CONNECTION_IBSS_ADHOC;
|
||||
tx_wlan_idx = mvif->sta.wcid.idx;
|
||||
net_type = NETWORK_IBSS;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
@ -1073,10 +1078,13 @@ int mt7615_mcu_set_sta_rec(struct mt7615_dev *dev, struct ieee80211_vif *vif,
|
||||
case NL80211_IFTYPE_STATION:
|
||||
req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
if (en) {
|
||||
req.basic.conn_state = CONN_STATE_PORT_SECURE;
|
||||
@ -1297,8 +1305,10 @@ int mt7615_mcu_set_channel(struct mt7615_dev *dev)
|
||||
};
|
||||
int ret;
|
||||
|
||||
if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
|
||||
chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
|
||||
if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
|
||||
req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
|
||||
else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
|
||||
chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
|
||||
req.switch_reason = CH_SWITCH_DFS;
|
||||
else
|
||||
req.switch_reason = CH_SWITCH_NORMAL;
|
||||
|
@ -56,6 +56,9 @@ struct mt7615_sta {
|
||||
|
||||
struct mt7615_vif *vif;
|
||||
|
||||
struct list_head poll_list;
|
||||
u32 airtime_ac[8];
|
||||
|
||||
struct ieee80211_tx_rate rates[4];
|
||||
|
||||
struct mt7615_rate_set rateset[2];
|
||||
@ -81,6 +84,11 @@ struct mt7615_dev {
|
||||
u32 vif_mask;
|
||||
u32 omac_mask;
|
||||
|
||||
__le32 rx_ampdu_ts;
|
||||
|
||||
struct list_head sta_poll_list;
|
||||
spinlock_t sta_poll_lock;
|
||||
|
||||
struct {
|
||||
u8 n_pulses;
|
||||
u32 period;
|
||||
@ -229,8 +237,11 @@ static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask)
|
||||
}
|
||||
|
||||
void mt7615_update_channel(struct mt76_dev *mdev);
|
||||
bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask);
|
||||
void mt7615_mac_reset_counters(struct mt7615_dev *dev);
|
||||
void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev);
|
||||
void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable);
|
||||
void mt7615_mac_sta_poll(struct mt7615_dev *dev);
|
||||
int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
|
||||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
struct ieee80211_sta *sta, int pid,
|
||||
|
@ -72,7 +72,10 @@ static int mt7615_pci_probe(struct pci_dev *pdev,
|
||||
static const struct mt76_driver_ops drv_ops = {
|
||||
/* txwi_size = txd size + txp size */
|
||||
.txwi_size = MT_TXD_SIZE + sizeof(struct mt7615_txp),
|
||||
.txwi_flags = MT_TXWI_NO_FREE,
|
||||
.drv_flags = MT_DRV_TXWI_NO_FREE,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX |
|
||||
SURVEY_INFO_TIME_RX |
|
||||
SURVEY_INFO_TIME_BSS_RX,
|
||||
.tx_prepare_skb = mt7615_tx_prepare_skb,
|
||||
.tx_complete_skb = mt7615_tx_complete_skb,
|
||||
.rx_skb = mt7615_queue_rx_skb,
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#define MT_HW_REV 0x1000
|
||||
#define MT_HW_CHIPID 0x1008
|
||||
#define MT_TOP_STRAP_STA 0x1010
|
||||
#define MT_TOP_3NSS BIT(24)
|
||||
#define MT_TOP_MISC2 0x1134
|
||||
#define MT_TOP_MISC2_FW_STATE GENMASK(2, 0)
|
||||
|
||||
@ -65,6 +67,17 @@
|
||||
#define MT_WPDMA_ABT_CFG MT_HIF(0x530)
|
||||
#define MT_WPDMA_ABT_CFG1 MT_HIF(0x534)
|
||||
|
||||
#define MT_PLE_BASE 0x8000
|
||||
#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
|
||||
|
||||
#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0)
|
||||
#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4)
|
||||
#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8)
|
||||
#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc)
|
||||
|
||||
#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \
|
||||
((n) << 2))
|
||||
|
||||
#define MT_WF_PHY_BASE 0x10000
|
||||
#define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs))
|
||||
|
||||
@ -125,6 +138,10 @@
|
||||
MT_AGG_ARxCR_LIMIT_SHIFT(_n), \
|
||||
MT_AGG_ARxCR_LIMIT_SHIFT(_n))
|
||||
|
||||
#define MT_AGG_ASRCR0 MT_WF_AGG(0x060)
|
||||
#define MT_AGG_ASRCR1 MT_WF_AGG(0x064)
|
||||
#define MT_AGG_ASRCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(5, 0))
|
||||
|
||||
#define MT_AGG_ACR0 MT_WF_AGG(0x070)
|
||||
#define MT_AGG_ACR1 MT_WF_AGG(0x170)
|
||||
#define MT_AGG_ACR_NO_BA_RULE BIT(0)
|
||||
@ -176,6 +193,22 @@
|
||||
#define MT_WF_RFCR_DROP_NDPA BIT(20)
|
||||
#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21)
|
||||
|
||||
#define MT_WF_RFCR1 MT_WF_RMAC(0x004)
|
||||
#define MT_WF_RFCR1_DROP_ACK BIT(4)
|
||||
#define MT_WF_RFCR1_DROP_BF_POLL BIT(5)
|
||||
#define MT_WF_RFCR1_DROP_BA BIT(6)
|
||||
#define MT_WF_RFCR1_DROP_CFEND BIT(7)
|
||||
#define MT_WF_RFCR1_DROP_CFACK BIT(8)
|
||||
|
||||
#define MT_WF_RMAC_MIB_TIME0 MT_WF_RMAC(0x03c4)
|
||||
#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31)
|
||||
#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30)
|
||||
|
||||
#define MT_WF_RMAC_MIB_AIRTIME0 MT_WF_RMAC(0x0380)
|
||||
|
||||
#define MT_WF_RMAC_MIB_TIME5 MT_WF_RMAC(0x03d8)
|
||||
#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0)
|
||||
|
||||
#define MT_WF_DMA_BASE 0x21800
|
||||
#define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs))
|
||||
|
||||
@ -183,6 +216,15 @@
|
||||
#define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 2)
|
||||
#define MT_DMA_DCR0_RX_VEC_DROP BIT(17)
|
||||
|
||||
#define MT_DMA_BN0RCFR0 MT_WF_DMA(0x070)
|
||||
#define MT_DMA_BN1RCFR0 MT_WF_DMA(0x0b0)
|
||||
#define MT_DMA_RCFR0_MCU_RX_MGMT BIT(2)
|
||||
#define MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR BIT(3)
|
||||
#define MT_DMA_RCFR0_MCU_RX_CTL_BAR BIT(4)
|
||||
#define MT_DMA_RCFR0_MCU_RX_BYPASS BIT(21)
|
||||
#define MT_DMA_RCFR0_RX_DROPPED_UCAST GENMASK(25, 24)
|
||||
#define MT_DMA_RCFR0_RX_DROPPED_MCAST GENMASK(27, 26)
|
||||
|
||||
#define MT_WTBL_BASE 0x30000
|
||||
#define MT_WTBL_ENTRY_SIZE 256
|
||||
|
||||
@ -198,6 +240,7 @@
|
||||
#define MT_WTBL_UPDATE MT_WTBL_OFF(0x030)
|
||||
#define MT_WTBL_UPDATE_WLAN_IDX GENMASK(7, 0)
|
||||
#define MT_WTBL_UPDATE_RXINFO_UPDATE BIT(11)
|
||||
#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12)
|
||||
#define MT_WTBL_UPDATE_RATE_UPDATE BIT(13)
|
||||
#define MT_WTBL_UPDATE_TX_COUNT_CLEAR BIT(14)
|
||||
#define MT_WTBL_UPDATE_BUSY BIT(31)
|
||||
@ -255,8 +298,18 @@
|
||||
#define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16)
|
||||
#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0)
|
||||
|
||||
#define MT_MIB_SDR16(n) MT_WF_MIB(0x48 + ((n) << 9))
|
||||
#define MT_MIB_BUSY_MASK GENMASK(23, 0)
|
||||
#define MT_MIB_SDR9(n) MT_WF_MIB(0x02c + ((n) << 9))
|
||||
#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0)
|
||||
|
||||
#define MT_MIB_SDR16(n) MT_WF_MIB(0x048 + ((n) << 9))
|
||||
#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0)
|
||||
|
||||
#define MT_MIB_SDR36(n) MT_WF_MIB(0x098 + ((n) << 9))
|
||||
#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0)
|
||||
#define MT_MIB_SDR37(n) MT_WF_MIB(0x09c + ((n) << 9))
|
||||
#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0)
|
||||
|
||||
#define MT_TX_AGG_CNT(n) MT_WF_MIB(0xa8 + ((n) << 2))
|
||||
|
||||
#define MT_EFUSE_BASE 0x81070000
|
||||
#define MT_EFUSE_BASE_CTRL 0x000
|
||||
|
@ -212,7 +212,7 @@ void mt76x0_get_tx_power_per_rate(struct mt76x02_dev *dev,
|
||||
void mt76x0_get_power_info(struct mt76x02_dev *dev,
|
||||
struct ieee80211_channel *chan, s8 *tp)
|
||||
{
|
||||
struct mt76x0_chan_map {
|
||||
static const struct mt76x0_chan_map {
|
||||
u8 chan;
|
||||
u8 offset;
|
||||
} chan_map[] = {
|
||||
@ -343,6 +343,7 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev)
|
||||
version, fae);
|
||||
|
||||
mt76x02_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR);
|
||||
mt76_eeprom_override(&dev->mt76);
|
||||
mt76x0_set_chip_cap(dev);
|
||||
mt76x0_set_freq_offset(dev);
|
||||
mt76x0_set_temp_offset(dev);
|
||||
|
@ -150,31 +150,6 @@ static void mt76x0_init_mac_registers(struct mt76x02_dev *dev)
|
||||
mt76_rmw(dev, MT_WMM_CTRL, 0x3ff, 0x201);
|
||||
}
|
||||
|
||||
static void mt76x0_reset_counters(struct mt76x02_dev *dev)
|
||||
{
|
||||
mt76_rr(dev, MT_RX_STAT_0);
|
||||
mt76_rr(dev, MT_RX_STAT_1);
|
||||
mt76_rr(dev, MT_RX_STAT_2);
|
||||
mt76_rr(dev, MT_TX_STA_0);
|
||||
mt76_rr(dev, MT_TX_STA_1);
|
||||
mt76_rr(dev, MT_TX_STA_2);
|
||||
}
|
||||
|
||||
int mt76x0_mac_start(struct mt76x02_dev *dev)
|
||||
{
|
||||
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
|
||||
|
||||
if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
|
||||
mt76_wr(dev, MT_MAC_SYS_CTRL,
|
||||
MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX);
|
||||
|
||||
return !mt76x02_wait_for_wpdma(&dev->mt76, 50) ? -ETIMEDOUT : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x0_mac_start);
|
||||
|
||||
void mt76x0_mac_stop(struct mt76x02_dev *dev)
|
||||
{
|
||||
int i = 200, ok = 0;
|
||||
@ -244,8 +219,6 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev)
|
||||
for (i = 0; i < 256; i++)
|
||||
mt76x02_mac_wcid_setup(dev, i, 0, NULL);
|
||||
|
||||
mt76x0_reset_counters(dev);
|
||||
|
||||
ret = mt76x0_eeprom_init(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -13,19 +13,16 @@ mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
cancel_delayed_work_sync(&dev->cal_work);
|
||||
mt76x02_pre_tbtt_enable(dev, false);
|
||||
if (mt76_is_mmio(dev))
|
||||
if (mt76_is_mmio(&dev->mt76))
|
||||
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
|
||||
|
||||
mt76_set_channel(&dev->mt76);
|
||||
mt76x0_phy_set_channel(dev, chandef);
|
||||
|
||||
/* channel cycle counters read-and-clear */
|
||||
mt76_rr(dev, MT_CH_IDLE);
|
||||
mt76_rr(dev, MT_CH_BUSY);
|
||||
|
||||
mt76x02_mac_cc_reset(dev);
|
||||
mt76x02_edcca_init(dev);
|
||||
|
||||
if (mt76_is_mmio(dev)) {
|
||||
if (mt76_is_mmio(&dev->mt76)) {
|
||||
mt76x02_dfs_init_params(dev);
|
||||
tasklet_enable(&dev->dfs_pd.dfs_tasklet);
|
||||
}
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
static inline bool is_mt7610e(struct mt76x02_dev *dev)
|
||||
{
|
||||
if (!mt76_is_mmio(dev))
|
||||
if (!mt76_is_mmio(&dev->mt76))
|
||||
return false;
|
||||
|
||||
return mt76_chip(&dev->mt76) == 0x7610;
|
||||
@ -46,7 +46,6 @@ int mt76x0_init_hardware(struct mt76x02_dev *dev);
|
||||
int mt76x0_register_device(struct mt76x02_dev *dev);
|
||||
void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset);
|
||||
|
||||
int mt76x0_mac_start(struct mt76x02_dev *dev);
|
||||
void mt76x0_mac_stop(struct mt76x02_dev *dev);
|
||||
|
||||
int mt76x0_config(struct ieee80211_hw *hw, u32 changed);
|
||||
|
@ -51,19 +51,6 @@ static void mt76x0e_stop(struct ieee80211_hw *hw)
|
||||
mt76x0e_stop_hw(dev);
|
||||
}
|
||||
|
||||
static int
|
||||
mt76x0e_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
|
||||
struct ieee80211_key_conf *key)
|
||||
{
|
||||
struct mt76x02_dev *dev = hw->priv;
|
||||
|
||||
if (is_mt7630(dev))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return mt76x02_set_key(hw, cmd, vif, sta, key);
|
||||
}
|
||||
|
||||
static void
|
||||
mt76x0e_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
u32 queues, bool drop)
|
||||
@ -80,7 +67,7 @@ static const struct ieee80211_ops mt76x0e_ops = {
|
||||
.configure_filter = mt76x02_configure_filter,
|
||||
.bss_info_changed = mt76x02_bss_info_changed,
|
||||
.sta_state = mt76_sta_state,
|
||||
.set_key = mt76x0e_set_key,
|
||||
.set_key = mt76x02_set_key,
|
||||
.conf_tx = mt76x02_conf_tx,
|
||||
.sw_scan_start = mt76_sw_scan,
|
||||
.sw_scan_complete = mt76x02_sw_scan_complete,
|
||||
@ -94,6 +81,7 @@ static const struct ieee80211_ops mt76x0e_ops = {
|
||||
.release_buffered_frames = mt76_release_buffered_frames,
|
||||
.set_coverage_class = mt76x02_set_coverage_class,
|
||||
.set_rts_threshold = mt76x02_set_rts_threshold,
|
||||
.get_antenna = mt76_get_antenna,
|
||||
};
|
||||
|
||||
static int mt76x0e_register_device(struct mt76x02_dev *dev)
|
||||
@ -132,15 +120,6 @@ static int mt76x0e_register_device(struct mt76x02_dev *dev)
|
||||
mt76_clear(dev, 0x110, BIT(9));
|
||||
mt76_set(dev, MT_MAX_LEN_CFG, BIT(13));
|
||||
|
||||
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 |
|
||||
MT_CH_CCA_RC_EN |
|
||||
FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1));
|
||||
|
||||
err = mt76x0_register_device(dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -155,7 +134,9 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
static const struct mt76_driver_ops drv_ops = {
|
||||
.txwi_size = sizeof(struct mt76x02_txwi),
|
||||
.tx_aligned4_skbs = true,
|
||||
.drv_flags = MT_DRV_TX_ALIGNED4_SKBS |
|
||||
MT_DRV_SW_RX_AIRTIME,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX,
|
||||
.update_survey = mt76x02_update_channel,
|
||||
.tx_prepare_skb = mt76x02_tx_prepare_skb,
|
||||
.tx_complete_skb = mt76x02_tx_complete_skb,
|
||||
|
@ -102,7 +102,7 @@ out:
|
||||
static int
|
||||
mt76x0_rf_wr(struct mt76x02_dev *dev, u32 offset, u8 val)
|
||||
{
|
||||
if (mt76_is_usb(dev)) {
|
||||
if (mt76_is_usb(&dev->mt76)) {
|
||||
struct mt76_reg_pair pair = {
|
||||
.reg = offset,
|
||||
.value = val,
|
||||
@ -121,7 +121,7 @@ static int mt76x0_rf_rr(struct mt76x02_dev *dev, u32 offset)
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (mt76_is_usb(dev)) {
|
||||
if (mt76_is_usb(&dev->mt76)) {
|
||||
struct mt76_reg_pair pair = {
|
||||
.reg = offset,
|
||||
};
|
||||
@ -176,7 +176,7 @@ mt76x0_phy_rf_csr_wr_rp(struct mt76x02_dev *dev,
|
||||
}
|
||||
|
||||
#define RF_RANDOM_WRITE(dev, tab) do { \
|
||||
if (mt76_is_mmio(dev)) \
|
||||
if (mt76_is_mmio(&dev->mt76)) \
|
||||
mt76x0_phy_rf_csr_wr_rp(dev, tab, ARRAY_SIZE(tab)); \
|
||||
else \
|
||||
mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, tab, ARRAY_SIZE(tab));\
|
||||
@ -744,7 +744,7 @@ mt76x0_phy_get_delta_power(struct mt76x02_dev *dev, u8 tx_mode,
|
||||
|
||||
if (!tx_mode) {
|
||||
data = mt76_rr(dev, MT_BBP(CORE, 1));
|
||||
if (is_mt7630(dev) && mt76_is_mmio(dev)) {
|
||||
if (is_mt7630(dev) && mt76_is_mmio(&dev->mt76)) {
|
||||
int offset;
|
||||
|
||||
/* 2.3 * 8192 or 1.5 * 8192 */
|
||||
@ -899,7 +899,6 @@ void mt76x0_phy_calibrate(struct mt76x02_dev *dev, bool power_on)
|
||||
}
|
||||
|
||||
mt76x02_mcu_calibrate(dev, MCU_CAL_FULL, val);
|
||||
msleep(350);
|
||||
mt76x02_mcu_calibrate(dev, MCU_CAL_LC, is_5ghz);
|
||||
usleep_range(15000, 20000);
|
||||
|
||||
@ -967,7 +966,7 @@ void mt76x0_phy_set_channel(struct mt76x02_dev *dev,
|
||||
break;
|
||||
}
|
||||
|
||||
if (mt76_is_usb(dev)) {
|
||||
if (mt76_is_usb(&dev->mt76)) {
|
||||
mt76x0_phy_bbp_set_bw(dev, chandef->width);
|
||||
} else {
|
||||
if (chandef->width == NL80211_CHAN_WIDTH_80 ||
|
||||
@ -1123,7 +1122,7 @@ static void mt76x0_rf_patch_reg_array(struct mt76x02_dev *dev,
|
||||
|
||||
switch (reg) {
|
||||
case MT_RF(0, 3):
|
||||
if (mt76_is_mmio(dev)) {
|
||||
if (mt76_is_mmio(&dev->mt76)) {
|
||||
if (is_mt7630(dev))
|
||||
val = 0x70;
|
||||
else
|
||||
|
@ -103,7 +103,7 @@ static int mt76x0u_start(struct ieee80211_hw *hw)
|
||||
struct mt76x02_dev *dev = hw->priv;
|
||||
int ret;
|
||||
|
||||
ret = mt76x0_mac_start(dev);
|
||||
ret = mt76x02u_mac_start(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -138,6 +138,7 @@ static const struct ieee80211_ops mt76x0u_ops = {
|
||||
.get_survey = mt76_get_survey,
|
||||
.set_tim = mt76_set_tim,
|
||||
.release_buffered_frames = mt76_release_buffered_frames,
|
||||
.get_antenna = mt76_get_antenna,
|
||||
};
|
||||
|
||||
static int mt76x0u_init_hardware(struct mt76x02_dev *dev, bool reset)
|
||||
@ -165,13 +166,6 @@ static int mt76x0u_init_hardware(struct mt76x02_dev *dev, bool reset)
|
||||
FIELD_PREP(MT_TXOP_TRUN_EN, 0x3f) |
|
||||
FIELD_PREP(MT_TXOP_EXT_CCA_DLY, 0x58));
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -211,6 +205,8 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
static const struct mt76_driver_ops drv_ops = {
|
||||
.drv_flags = MT_DRV_SW_RX_AIRTIME,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX,
|
||||
.update_survey = mt76x02_update_channel,
|
||||
.tx_prepare_skb = mt76x02u_tx_prepare_skb,
|
||||
.tx_complete_skb = mt76x02u_tx_complete_skb,
|
||||
@ -226,7 +222,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
|
||||
u32 mac_rev;
|
||||
int ret;
|
||||
|
||||
mdev = mt76_alloc_device(&usb_dev->dev, sizeof(*dev), &mt76x0u_ops,
|
||||
mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), &mt76x0u_ops,
|
||||
&drv_ops);
|
||||
if (!mdev)
|
||||
return -ENOMEM;
|
||||
@ -278,6 +274,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
|
||||
err:
|
||||
usb_set_intfdata(usb_intf, NULL);
|
||||
usb_put_dev(interface_to_usbdev(usb_intf));
|
||||
mt76u_deinit(&dev->mt76);
|
||||
|
||||
ieee80211_free_hw(mdev->hw);
|
||||
return ret;
|
||||
@ -297,6 +294,7 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf)
|
||||
usb_set_intfdata(usb_intf, NULL);
|
||||
usb_put_dev(interface_to_usbdev(usb_intf));
|
||||
|
||||
mt76u_deinit(&dev->mt76);
|
||||
ieee80211_free_hw(dev->mt76.hw);
|
||||
}
|
||||
|
||||
|
@ -81,6 +81,7 @@ struct mt76x02_dev {
|
||||
u8 txdone_seq;
|
||||
DECLARE_KFIFO_PTR(txstatus_fifo, struct mt76x02_tx_status);
|
||||
spinlock_t txstatus_fifo_lock;
|
||||
u32 tx_airtime;
|
||||
|
||||
struct sk_buff *rx_head;
|
||||
|
||||
@ -92,8 +93,6 @@ struct mt76x02_dev {
|
||||
|
||||
const struct mt76x02_beacon_ops *beacon_ops;
|
||||
|
||||
u32 aggr_stats[32];
|
||||
|
||||
struct sk_buff *beacons[8];
|
||||
u8 beacon_data_mask;
|
||||
|
||||
|
@ -19,7 +19,8 @@ mt76x02_ampdu_stat_read(struct seq_file *file, void *data)
|
||||
seq_puts(file, "\n");
|
||||
seq_puts(file, "Count: ");
|
||||
for (j = 0; j < 8; j++)
|
||||
seq_printf(file, "%8d | ", dev->aggr_stats[i * 8 + j]);
|
||||
seq_printf(file, "%8d | ",
|
||||
dev->mt76.aggr_stats[i * 8 + j]);
|
||||
seq_puts(file, "\n");
|
||||
seq_puts(file, "--------");
|
||||
for (j = 0; j < 8; j++)
|
||||
@ -143,6 +144,8 @@ void mt76x02_init_debugfs(struct mt76x02_dev *dev)
|
||||
if (!dir)
|
||||
return;
|
||||
|
||||
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
|
||||
mt76_queues_read);
|
||||
debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp);
|
||||
debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc);
|
||||
|
||||
|
@ -7,6 +7,27 @@
|
||||
#include "mt76x02.h"
|
||||
#include "mt76x02_trace.h"
|
||||
|
||||
void mt76x02_mac_reset_counters(struct mt76x02_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
mt76_rr(dev, MT_RX_STAT_0);
|
||||
mt76_rr(dev, MT_RX_STAT_1);
|
||||
mt76_rr(dev, MT_RX_STAT_2);
|
||||
mt76_rr(dev, MT_TX_STA_0);
|
||||
mt76_rr(dev, MT_TX_STA_1);
|
||||
mt76_rr(dev, MT_TX_STA_2);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
mt76_rr(dev, MT_TX_AGG_CNT(i));
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
mt76_rr(dev, MT_TX_STAT_FIFO);
|
||||
|
||||
memset(dev->mt76.aggr_stats, 0, sizeof(dev->mt76.aggr_stats));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02_mac_reset_counters);
|
||||
|
||||
static enum mt76x02_cipher_type
|
||||
mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
|
||||
{
|
||||
@ -462,8 +483,8 @@ mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, struct mt76x02_sta *msta,
|
||||
phy = FIELD_GET(MT_RXWI_RATE_PHY, st->rate);
|
||||
|
||||
if (st->pktid & MT_PACKET_ID_HAS_RATE) {
|
||||
first_rate = st->rate & ~MT_RXWI_RATE_INDEX;
|
||||
first_rate |= st->pktid & MT_RXWI_RATE_INDEX;
|
||||
first_rate = st->rate & ~MT_PKTID_RATE;
|
||||
first_rate |= st->pktid & MT_PKTID_RATE;
|
||||
|
||||
mt76x02_mac_process_tx_rate(&rate[0], first_rate,
|
||||
dev->mt76.chandef.chan->band);
|
||||
@ -516,10 +537,20 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
|
||||
struct ieee80211_tx_status status = {
|
||||
.info = &info
|
||||
};
|
||||
static const u8 ac_to_tid[4] = {
|
||||
[IEEE80211_AC_BE] = 0,
|
||||
[IEEE80211_AC_BK] = 1,
|
||||
[IEEE80211_AC_VI] = 4,
|
||||
[IEEE80211_AC_VO] = 6
|
||||
};
|
||||
struct mt76_wcid *wcid = NULL;
|
||||
struct mt76x02_sta *msta = NULL;
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
struct sk_buff_head list;
|
||||
u32 duration = 0;
|
||||
u8 cur_pktid;
|
||||
u32 ac = 0;
|
||||
int len = 0;
|
||||
|
||||
if (stat->pktid == MT_PACKET_ID_NO_ACK)
|
||||
return;
|
||||
@ -549,10 +580,10 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
|
||||
|
||||
if (!status.skb && !(stat->pktid & MT_PACKET_ID_HAS_RATE)) {
|
||||
mt76_tx_status_unlock(mdev, &list);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
if (msta && stat->aggr && !status.skb) {
|
||||
u32 stat_val, stat_cache;
|
||||
|
||||
@ -565,10 +596,10 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
|
||||
stat->wcid == msta->status.wcid && msta->n_frames < 32) {
|
||||
msta->n_frames++;
|
||||
mt76_tx_status_unlock(mdev, &list);
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cur_pktid = msta->status.pktid;
|
||||
mt76x02_mac_fill_tx_status(dev, msta, status.info,
|
||||
&msta->status, msta->n_frames);
|
||||
|
||||
@ -576,16 +607,39 @@ void mt76x02_send_tx_status(struct mt76x02_dev *dev,
|
||||
msta->n_frames = 1;
|
||||
*update = 0;
|
||||
} else {
|
||||
cur_pktid = stat->pktid;
|
||||
mt76x02_mac_fill_tx_status(dev, msta, status.info, stat, 1);
|
||||
*update = 1;
|
||||
}
|
||||
|
||||
if (status.skb)
|
||||
if (status.skb) {
|
||||
info = *status.info;
|
||||
len = status.skb->len;
|
||||
ac = skb_get_queue_mapping(status.skb);
|
||||
mt76_tx_status_skb_done(mdev, status.skb, &list);
|
||||
} else if (msta) {
|
||||
len = status.info->status.ampdu_len * ewma_pktlen_read(&msta->pktlen);
|
||||
ac = FIELD_GET(MT_PKTID_AC, cur_pktid);
|
||||
}
|
||||
|
||||
mt76_tx_status_unlock(mdev, &list);
|
||||
|
||||
if (!status.skb)
|
||||
ieee80211_tx_status_ext(mt76_hw(dev), &status);
|
||||
|
||||
if (!len)
|
||||
goto out;
|
||||
|
||||
duration = mt76_calc_tx_airtime(&dev->mt76, &info, len);
|
||||
|
||||
spin_lock_bh(&dev->mt76.cc_lock);
|
||||
dev->tx_airtime += duration;
|
||||
spin_unlock_bh(&dev->mt76.cc_lock);
|
||||
|
||||
if (msta)
|
||||
ieee80211_sta_register_airtime(status.sta, ac_to_tid[ac], duration, 0);
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
@ -768,6 +822,21 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb,
|
||||
if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL))
|
||||
status->aggr = true;
|
||||
|
||||
if (rxinfo & MT_RXINFO_AMPDU) {
|
||||
status->flag |= RX_FLAG_AMPDU_DETAILS;
|
||||
status->ampdu_ref = dev->mt76.ampdu_ref;
|
||||
|
||||
/*
|
||||
* When receiving an A-MPDU subframe and RSSI info is not valid,
|
||||
* we can assume that more subframes belonging to the same A-MPDU
|
||||
* are coming. The last one will have valid RSSI info
|
||||
*/
|
||||
if (rxinfo & MT_RXINFO_RSSI) {
|
||||
if (!++dev->mt76.ampdu_ref)
|
||||
dev->mt76.ampdu_ref++;
|
||||
}
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(len > skb->len))
|
||||
return -EINVAL;
|
||||
|
||||
@ -948,16 +1017,13 @@ void mt76x02_update_channel(struct mt76_dev *mdev)
|
||||
{
|
||||
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_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);
|
||||
state = mdev->chan_state;
|
||||
state->cc_busy += mt76_rr(dev, MT_CH_BUSY);
|
||||
|
||||
spin_lock_bh(&dev->mt76.cc_lock);
|
||||
state->cc_busy += busy;
|
||||
state->cc_active += active;
|
||||
state->cc_tx += dev->tx_airtime;
|
||||
dev->tx_airtime = 0;
|
||||
spin_unlock_bh(&dev->mt76.cc_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02_update_channel);
|
||||
@ -1094,12 +1160,12 @@ void mt76x02_mac_work(struct work_struct *work)
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
|
||||
mt76x02_update_channel(&dev->mt76);
|
||||
mt76_update_survey(&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;
|
||||
dev->aggr_stats[idx++] += val >> 16;
|
||||
dev->mt76.aggr_stats[idx++] += val & 0xffff;
|
||||
dev->mt76.aggr_stats[idx++] += val >> 16;
|
||||
}
|
||||
|
||||
if (!dev->mt76.beacon_mask)
|
||||
@ -1116,6 +1182,25 @@ void mt76x02_mac_work(struct work_struct *work)
|
||||
MT_MAC_WORK_INTERVAL);
|
||||
}
|
||||
|
||||
void mt76x02_mac_cc_reset(struct mt76x02_dev *dev)
|
||||
{
|
||||
dev->mt76.survey_time = ktime_get_boottime();
|
||||
|
||||
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 |
|
||||
MT_CH_CCA_RC_EN |
|
||||
FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1));
|
||||
|
||||
/* channel cycle counters read-and-clear */
|
||||
mt76_rr(dev, MT_CH_BUSY);
|
||||
mt76_rr(dev, MT_CH_IDLE);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02_mac_cc_reset);
|
||||
|
||||
void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr)
|
||||
{
|
||||
idx &= 7;
|
||||
|
@ -23,11 +23,16 @@ struct mt76x02_tx_status {
|
||||
#define MT_VIF_WCID(_n) (254 - ((_n) & 7))
|
||||
#define MT_MAX_VIFS 8
|
||||
|
||||
#define MT_PKTID_RATE GENMASK(4, 0)
|
||||
#define MT_PKTID_AC GENMASK(6, 5)
|
||||
|
||||
struct mt76x02_vif {
|
||||
struct mt76_wcid group_wcid; /* must be first */
|
||||
u8 idx;
|
||||
};
|
||||
|
||||
DECLARE_EWMA(pktlen, 8, 8);
|
||||
|
||||
struct mt76x02_sta {
|
||||
struct mt76_wcid wcid; /* must be first */
|
||||
|
||||
@ -35,6 +40,7 @@ struct mt76x02_sta {
|
||||
struct mt76x02_tx_status status;
|
||||
int n_frames;
|
||||
|
||||
struct ewma_pktlen pktlen;
|
||||
};
|
||||
|
||||
#define MT_RXINFO_BA BIT(0)
|
||||
@ -161,6 +167,7 @@ static inline bool mt76x02_wait_for_mac(struct mt76_dev *dev)
|
||||
return false;
|
||||
}
|
||||
|
||||
void mt76x02_mac_reset_counters(struct mt76x02_dev *dev);
|
||||
void mt76x02_mac_set_short_preamble(struct mt76x02_dev *dev, bool enable);
|
||||
int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx,
|
||||
u8 key_idx, struct ieee80211_key_conf *key);
|
||||
@ -192,6 +199,7 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
void mt76x02_update_channel(struct mt76_dev *mdev);
|
||||
void mt76x02_mac_work(struct work_struct *work);
|
||||
|
||||
void mt76x02_mac_cc_reset(struct mt76x02_dev *dev);
|
||||
void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr);
|
||||
int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx,
|
||||
struct sk_buff *skb);
|
||||
|
@ -114,7 +114,7 @@ int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param)
|
||||
.id = cpu_to_le32(type),
|
||||
.value = cpu_to_le32(param),
|
||||
};
|
||||
bool is_mt76x2e = mt76_is_mmio(dev) && is_mt76x2(dev);
|
||||
bool is_mt76x2e = mt76_is_mmio(&dev->mt76) && is_mt76x2(dev);
|
||||
int ret;
|
||||
|
||||
if (is_mt76x2e)
|
||||
|
@ -343,6 +343,7 @@ EXPORT_SYMBOL_GPL(mt76x02_dma_disable);
|
||||
|
||||
void mt76x02_mac_start(struct mt76x02_dev *dev)
|
||||
{
|
||||
mt76x02_mac_reset_counters(dev);
|
||||
mt76x02_dma_enable(dev);
|
||||
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
|
||||
mt76_wr(dev, MT_MAC_SYS_CTRL,
|
||||
|
@ -158,7 +158,9 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
||||
/* encode packet rate for no-skb packet id to fix up status reporting */
|
||||
if (pid == MT_PACKET_ID_NO_SKB)
|
||||
pid = MT_PACKET_ID_HAS_RATE |
|
||||
(le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX);
|
||||
(le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX) |
|
||||
FIELD_PREP(MT_PKTID_AC,
|
||||
skb_get_queue_mapping(tx_info->skb));
|
||||
|
||||
txwi->pktid = pid;
|
||||
|
||||
@ -171,6 +173,12 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
|
||||
if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
|
||||
tx_info->info |= MT_TXD_INFO_WIV;
|
||||
|
||||
if (sta) {
|
||||
struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
|
||||
|
||||
ewma_pktlen_add(&msta->pktlen, tx_info->skb->len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02_tx_prepare_skb);
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "mt76x02.h"
|
||||
|
||||
int mt76x02u_mac_start(struct mt76x02_dev *dev);
|
||||
void mt76x02u_init_mcu(struct mt76_dev *dev);
|
||||
void mt76x02u_mcu_fw_reset(struct mt76x02_dev *dev);
|
||||
int mt76x02u_mcu_fw_send_data(struct mt76x02_dev *dev, const void *data,
|
||||
|
@ -23,6 +23,27 @@ void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02u_tx_complete_skb);
|
||||
|
||||
int mt76x02u_mac_start(struct mt76x02_dev *dev)
|
||||
{
|
||||
mt76x02_mac_reset_counters(dev);
|
||||
|
||||
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
|
||||
if (!mt76x02_wait_for_wpdma(&dev->mt76, 200000))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
|
||||
|
||||
mt76_wr(dev, MT_MAC_SYS_CTRL,
|
||||
MT_MAC_SYS_CTRL_ENABLE_TX |
|
||||
MT_MAC_SYS_CTRL_ENABLE_RX);
|
||||
|
||||
if (!mt76x02_wait_for_wpdma(&dev->mt76, 50))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02u_mac_start);
|
||||
|
||||
int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
|
||||
{
|
||||
struct sk_buff *iter, *last = skb;
|
||||
@ -83,7 +104,9 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
|
||||
/* encode packet rate for no-skb packet id to fix up status reporting */
|
||||
if (pid == MT_PACKET_ID_NO_SKB)
|
||||
pid = MT_PACKET_ID_HAS_RATE |
|
||||
(le16_to_cpu(txwi->rate) & MT_RXWI_RATE_INDEX);
|
||||
(le16_to_cpu(txwi->rate) & MT_PKTID_RATE) |
|
||||
FIELD_PREP(MT_PKTID_AC,
|
||||
skb_get_queue_mapping(tx_info->skb));
|
||||
|
||||
txwi->pktid = pid;
|
||||
|
||||
@ -97,6 +120,12 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
|
||||
if (!wcid || wcid->hw_key_idx == 0xff || wcid->sw_iv)
|
||||
flags |= MT_TXD_INFO_WIV;
|
||||
|
||||
if (sta) {
|
||||
struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
|
||||
|
||||
ewma_pktlen_add(&msta->pktlen, tx_info->skb->len);
|
||||
}
|
||||
|
||||
return mt76x02u_skb_dma_info(tx_info->skb, WLAN_PORT, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02u_tx_prepare_skb);
|
||||
|
@ -153,15 +153,7 @@ void mt76x02_init_device(struct mt76x02_dev *dev)
|
||||
hw->max_rate_tries = 1;
|
||||
hw->extra_tx_headroom = 2;
|
||||
|
||||
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 (mt76_is_usb(dev)) {
|
||||
if (mt76_is_usb(&dev->mt76)) {
|
||||
hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) +
|
||||
MT_DMA_HDR_LEN;
|
||||
wiphy->iface_combinations = mt76x02u_if_comb;
|
||||
@ -190,7 +182,6 @@ void mt76x02_init_device(struct mt76x02_dev *dev)
|
||||
hw->vif_data_size = sizeof(struct mt76x02_vif);
|
||||
|
||||
ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
|
||||
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
|
||||
|
||||
dev->mt76.global_wcid.idx = 255;
|
||||
dev->mt76.global_wcid.hw_key_idx = -1;
|
||||
@ -264,6 +255,7 @@ int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
|
||||
msta->wcid.hw_key_idx = -1;
|
||||
mt76x02_mac_wcid_setup(dev, idx, mvif->idx, sta->addr);
|
||||
mt76x02_mac_wcid_set_drop(dev, idx, false);
|
||||
ewma_pktlen_init(&msta->pktlen);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
set_bit(MT_WCID_FLAG_CHECK_PS, &msta->wcid.flags);
|
||||
@ -371,6 +363,7 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
|
||||
mtxq = (struct mt76_txq *)txq->drv_priv;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_RX_START:
|
||||
mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid,
|
||||
@ -399,6 +392,7 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -442,7 +436,7 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
* data registers and sent via HW beacons engine, they require to
|
||||
* be already encrypted.
|
||||
*/
|
||||
if (mt76_is_usb(dev) &&
|
||||
if (mt76_is_usb(&dev->mt76) &&
|
||||
vif->type == NL80211_IFTYPE_AP &&
|
||||
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
|
||||
return -EOPNOTSUPP;
|
||||
@ -623,7 +617,7 @@ void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta,
|
||||
int idx = msta->wcid.idx;
|
||||
|
||||
mt76_stop_tx_queues(&dev->mt76, sta, true);
|
||||
if (mt76_is_mmio(dev))
|
||||
if (mt76_is_mmio(mdev))
|
||||
mt76x02_mac_wcid_set_drop(dev, idx, ps);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76x02_sta_ps);
|
||||
|
@ -12,7 +12,6 @@ struct mt76x02_dev;
|
||||
struct mt76x2_sta;
|
||||
struct mt76x02_vif;
|
||||
|
||||
int mt76x2_mac_start(struct mt76x02_dev *dev);
|
||||
void mt76x2_mac_stop(struct mt76x02_dev *dev, bool force);
|
||||
|
||||
static inline void mt76x2_mac_resume(struct mt76x02_dev *dev)
|
||||
|
@ -24,7 +24,6 @@ void mt76x2u_cleanup(struct mt76x02_dev *dev);
|
||||
void mt76x2u_stop_hw(struct mt76x02_dev *dev);
|
||||
|
||||
int mt76x2u_mac_reset(struct mt76x02_dev *dev);
|
||||
int mt76x2u_mac_start(struct mt76x02_dev *dev);
|
||||
int mt76x2u_mac_stop(struct mt76x02_dev *dev);
|
||||
|
||||
int mt76x2u_phy_set_channel(struct mt76x02_dev *dev,
|
||||
|
@ -21,7 +21,9 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
static const struct mt76_driver_ops drv_ops = {
|
||||
.txwi_size = sizeof(struct mt76x02_txwi),
|
||||
.tx_aligned4_skbs = true,
|
||||
.drv_flags = MT_DRV_TX_ALIGNED4_SKBS |
|
||||
MT_DRV_SW_RX_AIRTIME,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX,
|
||||
.update_survey = mt76x02_update_channel,
|
||||
.tx_prepare_skb = mt76x02_tx_prepare_skb,
|
||||
.tx_complete_skb = mt76x02_tx_complete_skb,
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mt76x2.h"
|
||||
#include "eeprom.h"
|
||||
#include "mcu.h"
|
||||
#include "../mt76x02_mac.h"
|
||||
|
||||
static void
|
||||
mt76x2_mac_pbf_init(struct mt76x02_dev *dev)
|
||||
@ -132,36 +133,11 @@ int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard)
|
||||
for (i = 0; i < 16; i++)
|
||||
mt76_rr(dev, MT_TX_STAT_FIFO);
|
||||
|
||||
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 |
|
||||
MT_CH_CCA_RC_EN |
|
||||
FIELD_PREP(MT_CH_TIME_CFG_CH_TIMER_CLR, 1));
|
||||
|
||||
mt76x02_set_tx_ackto(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt76x2_mac_start(struct mt76x02_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
mt76_rr(dev, MT_TX_AGG_CNT(i));
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
mt76_rr(dev, MT_TX_STAT_FIFO);
|
||||
|
||||
memset(dev->aggr_stats, 0, sizeof(dev->aggr_stats));
|
||||
mt76x02_mac_start(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mt76x2_power_on_rf_patch(struct mt76x02_dev *dev)
|
||||
{
|
||||
@ -264,9 +240,7 @@ static int mt76x2_init_hardware(struct mt76x02_dev *dev)
|
||||
return ret;
|
||||
|
||||
set_bit(MT76_STATE_INITIALIZED, &dev->mt76.state);
|
||||
ret = mt76x2_mac_start(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
mt76x02_mac_start(dev);
|
||||
|
||||
ret = mt76x2_mcu_init(dev);
|
||||
if (ret)
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include "mt76x2.h"
|
||||
#include "../mt76x02_mac.h"
|
||||
|
||||
static int
|
||||
mt76x2_start(struct ieee80211_hw *hw)
|
||||
@ -11,10 +12,7 @@ mt76x2_start(struct ieee80211_hw *hw)
|
||||
struct mt76x02_dev *dev = hw->priv;
|
||||
int ret;
|
||||
|
||||
ret = mt76x2_mac_start(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt76x02_mac_start(dev);
|
||||
ret = mt76x2_phy_start(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -54,10 +52,7 @@ mt76x2_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef)
|
||||
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);
|
||||
|
||||
mt76x02_mac_cc_reset(dev);
|
||||
mt76x02_dfs_init_params(dev);
|
||||
|
||||
mt76x2_mac_resume(dev);
|
||||
@ -140,19 +135,6 @@ static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt76x2_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant,
|
||||
u32 *rx_ant)
|
||||
{
|
||||
struct mt76x02_dev *dev = hw->priv;
|
||||
|
||||
mutex_lock(&dev->mt76.mutex);
|
||||
*tx_ant = dev->mt76.antenna_mask;
|
||||
*rx_ant = dev->mt76.antenna_mask;
|
||||
mutex_unlock(&dev->mt76.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct ieee80211_ops mt76x2_ops = {
|
||||
.tx = mt76x02_tx,
|
||||
.start = mt76x2_start,
|
||||
@ -177,7 +159,7 @@ const struct ieee80211_ops mt76x2_ops = {
|
||||
.get_survey = mt76_get_survey,
|
||||
.set_tim = mt76_set_tim,
|
||||
.set_antenna = mt76x2_set_antenna,
|
||||
.get_antenna = mt76x2_get_antenna,
|
||||
.get_antenna = mt76_get_antenna,
|
||||
.set_rts_threshold = mt76x02_set_rts_threshold,
|
||||
};
|
||||
|
||||
|
@ -25,6 +25,8 @@ static int mt76x2u_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
static const struct mt76_driver_ops drv_ops = {
|
||||
.drv_flags = MT_DRV_SW_RX_AIRTIME,
|
||||
.survey_flags = SURVEY_INFO_TIME_TX,
|
||||
.update_survey = mt76x02_update_channel,
|
||||
.tx_prepare_skb = mt76x02u_tx_prepare_skb,
|
||||
.tx_complete_skb = mt76x02u_tx_complete_skb,
|
||||
@ -39,7 +41,7 @@ static int mt76x2u_probe(struct usb_interface *intf,
|
||||
struct mt76_dev *mdev;
|
||||
int err;
|
||||
|
||||
mdev = mt76_alloc_device(&udev->dev, sizeof(*dev), &mt76x2u_ops,
|
||||
mdev = mt76_alloc_device(&intf->dev, sizeof(*dev), &mt76x2u_ops,
|
||||
&drv_ops);
|
||||
if (!mdev)
|
||||
return -ENOMEM;
|
||||
@ -71,6 +73,7 @@ static int mt76x2u_probe(struct usb_interface *intf,
|
||||
|
||||
err:
|
||||
ieee80211_free_hw(mt76_hw(dev));
|
||||
mt76u_deinit(&dev->mt76);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
usb_put_dev(udev);
|
||||
|
||||
@ -86,6 +89,7 @@ static void mt76x2u_disconnect(struct usb_interface *intf)
|
||||
set_bit(MT76_REMOVED, &dev->mt76.state);
|
||||
ieee80211_unregister_hw(hw);
|
||||
mt76x2u_cleanup(dev);
|
||||
mt76u_deinit(&dev->mt76);
|
||||
|
||||
ieee80211_free_hw(hw);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
|
@ -184,13 +184,6 @@ int mt76x2u_init_hardware(struct mt76x02_dev *dev)
|
||||
mt76x02_phy_set_rxpath(dev);
|
||||
mt76x02_phy_set_txdac(dev);
|
||||
|
||||
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);
|
||||
|
||||
return mt76x2u_mac_stop(dev);
|
||||
}
|
||||
|
||||
|
@ -6,16 +6,6 @@
|
||||
#include "mt76x2u.h"
|
||||
#include "eeprom.h"
|
||||
|
||||
static void mt76x2u_mac_reset_counters(struct mt76x02_dev *dev)
|
||||
{
|
||||
mt76_rr(dev, MT_RX_STAT_0);
|
||||
mt76_rr(dev, MT_RX_STAT_1);
|
||||
mt76_rr(dev, MT_RX_STAT_2);
|
||||
mt76_rr(dev, MT_TX_STA_0);
|
||||
mt76_rr(dev, MT_TX_STA_1);
|
||||
mt76_rr(dev, MT_TX_STA_2);
|
||||
}
|
||||
|
||||
static void mt76x2u_mac_fixup_xtal(struct mt76x02_dev *dev)
|
||||
{
|
||||
s8 offset = 0;
|
||||
@ -102,23 +92,6 @@ int mt76x2u_mac_reset(struct mt76x02_dev *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt76x2u_mac_start(struct mt76x02_dev *dev)
|
||||
{
|
||||
mt76x2u_mac_reset_counters(dev);
|
||||
|
||||
mt76_wr(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX);
|
||||
mt76x02_wait_for_wpdma(&dev->mt76, 1000);
|
||||
usleep_range(50, 100);
|
||||
|
||||
mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter);
|
||||
|
||||
mt76_wr(dev, MT_MAC_SYS_CTRL,
|
||||
MT_MAC_SYS_CTRL_ENABLE_TX |
|
||||
MT_MAC_SYS_CTRL_ENABLE_RX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt76x2u_mac_stop(struct mt76x02_dev *dev)
|
||||
{
|
||||
int i, count = 0, val;
|
||||
|
@ -4,13 +4,14 @@
|
||||
*/
|
||||
|
||||
#include "mt76x2u.h"
|
||||
#include "../mt76x02_usb.h"
|
||||
|
||||
static int mt76x2u_start(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct mt76x02_dev *dev = hw->priv;
|
||||
int ret;
|
||||
|
||||
ret = mt76x2u_mac_start(dev);
|
||||
ret = mt76x02u_mac_start(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -48,10 +49,7 @@ mt76x2u_set_channel(struct mt76x02_dev *dev,
|
||||
|
||||
err = mt76x2u_phy_set_channel(dev, chandef);
|
||||
|
||||
/* channel cycle counters read-and-clear */
|
||||
mt76_rr(dev, MT_CH_IDLE);
|
||||
mt76_rr(dev, MT_CH_BUSY);
|
||||
|
||||
mt76x02_mac_cc_reset(dev);
|
||||
mt76x2_mac_resume(dev);
|
||||
|
||||
clear_bit(MT76_RESET, &dev->mt76.state);
|
||||
@ -121,4 +119,5 @@ const struct ieee80211_ops mt76x2u_ops = {
|
||||
.get_survey = mt76_get_survey,
|
||||
.set_tim = mt76_set_tim,
|
||||
.release_buffered_frames = mt76_release_buffered_frames,
|
||||
.get_antenna = mt76_get_antenna,
|
||||
};
|
||||
|
@ -378,7 +378,7 @@ EXPORT_SYMBOL_GPL(mt76_release_buffered_frames);
|
||||
|
||||
static int
|
||||
mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq,
|
||||
struct mt76_txq *mtxq, bool *empty)
|
||||
struct mt76_txq *mtxq)
|
||||
{
|
||||
struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
|
||||
enum mt76_txq_id qid = mt76_txq_get_qid(txq);
|
||||
@ -392,16 +392,12 @@ mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq,
|
||||
bool probe;
|
||||
int idx;
|
||||
|
||||
if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) {
|
||||
*empty = true;
|
||||
if (test_bit(MT_WCID_FLAG_PS, &wcid->flags))
|
||||
return 0;
|
||||
}
|
||||
|
||||
skb = mt76_txq_dequeue(dev, mtxq, false);
|
||||
if (!skb) {
|
||||
*empty = true;
|
||||
if (!skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
|
||||
@ -431,10 +427,8 @@ mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq,
|
||||
return -EBUSY;
|
||||
|
||||
skb = mt76_txq_dequeue(dev, mtxq, false);
|
||||
if (!skb) {
|
||||
*empty = true;
|
||||
if (!skb)
|
||||
break;
|
||||
}
|
||||
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
cur_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU;
|
||||
@ -481,8 +475,6 @@ mt76_txq_schedule_list(struct mt76_dev *dev, enum mt76_txq_id qid)
|
||||
|
||||
spin_lock_bh(&hwq->lock);
|
||||
while (1) {
|
||||
bool empty = false;
|
||||
|
||||
if (sq->swq_queued >= 4)
|
||||
break;
|
||||
|
||||
@ -513,10 +505,9 @@ mt76_txq_schedule_list(struct mt76_dev *dev, enum mt76_txq_id qid)
|
||||
spin_lock_bh(&hwq->lock);
|
||||
}
|
||||
|
||||
ret += mt76_txq_send_burst(dev, sq, mtxq, &empty);
|
||||
if (skb_queue_empty(&mtxq->retry_q))
|
||||
empty = true;
|
||||
ieee80211_return_txq(dev->hw, txq, !empty);
|
||||
ret += mt76_txq_send_burst(dev, sq, mtxq);
|
||||
ieee80211_return_txq(dev->hw, txq,
|
||||
!skb_queue_empty(&mtxq->retry_q));
|
||||
}
|
||||
spin_unlock_bh(&hwq->lock);
|
||||
|
||||
|
@ -15,15 +15,17 @@ static bool disable_usb_sg;
|
||||
module_param_named(disable_usb_sg, disable_usb_sg, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_usb_sg, "Disable usb scatter-gather support");
|
||||
|
||||
/* should be called with usb_ctrl_mtx locked */
|
||||
static int __mt76u_vendor_request(struct mt76_dev *dev, u8 req,
|
||||
u8 req_type, u16 val, u16 offset,
|
||||
void *buf, size_t len)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev->dev);
|
||||
struct usb_interface *uintf = to_usb_interface(dev->dev);
|
||||
struct usb_device *udev = interface_to_usbdev(uintf);
|
||||
unsigned int pipe;
|
||||
int i, ret;
|
||||
|
||||
lockdep_assert_held(&dev->usb.usb_ctrl_mtx);
|
||||
|
||||
pipe = (req_type & USB_DIR_IN) ? usb_rcvctrlpipe(udev, 0)
|
||||
: usb_sndctrlpipe(udev, 0);
|
||||
for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) {
|
||||
@ -60,7 +62,6 @@ int mt76u_vendor_request(struct mt76_dev *dev, u8 req,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76u_vendor_request);
|
||||
|
||||
/* should be called with usb_ctrl_mtx locked */
|
||||
static u32 __mt76u_rr(struct mt76_dev *dev, u32 addr)
|
||||
{
|
||||
struct mt76_usb *usb = &dev->usb;
|
||||
@ -103,7 +104,6 @@ static u32 mt76u_rr(struct mt76_dev *dev, u32 addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* should be called with usb_ctrl_mtx locked */
|
||||
static void __mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val)
|
||||
{
|
||||
struct mt76_usb *usb = &dev->usb;
|
||||
@ -235,7 +235,8 @@ mt76u_rd_rp(struct mt76_dev *dev, u32 base,
|
||||
|
||||
static bool mt76u_check_sg(struct mt76_dev *dev)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev->dev);
|
||||
struct usb_interface *uintf = to_usb_interface(dev->dev);
|
||||
struct usb_device *udev = interface_to_usbdev(uintf);
|
||||
|
||||
return (!disable_usb_sg && udev->bus->sg_tablesize > 0 &&
|
||||
(udev->bus->no_sg_constraint ||
|
||||
@ -370,7 +371,8 @@ mt76u_fill_bulk_urb(struct mt76_dev *dev, int dir, int index,
|
||||
struct urb *urb, usb_complete_t complete_fn,
|
||||
void *context)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev->dev);
|
||||
struct usb_interface *uintf = to_usb_interface(dev->dev);
|
||||
struct usb_device *udev = interface_to_usbdev(uintf);
|
||||
unsigned int pipe;
|
||||
|
||||
if (dir == USB_DIR_IN)
|
||||
@ -695,10 +697,7 @@ static void mt76u_tx_tasklet(unsigned long data)
|
||||
mt76_txq_schedule(dev, i);
|
||||
|
||||
if (!test_and_set_bit(MT76_READING_STATS, &dev->state))
|
||||
ieee80211_queue_delayed_work(dev->hw,
|
||||
&dev->usb.stat_work,
|
||||
msecs_to_jiffies(10));
|
||||
|
||||
queue_work(dev->usb.stat_wq, &dev->usb.stat_work);
|
||||
if (wake)
|
||||
ieee80211_wake_queue(dev->hw, i);
|
||||
}
|
||||
@ -711,7 +710,7 @@ static void mt76u_tx_status_data(struct work_struct *work)
|
||||
u8 update = 1;
|
||||
u16 count = 0;
|
||||
|
||||
usb = container_of(work, struct mt76_usb, stat_work.work);
|
||||
usb = container_of(work, struct mt76_usb, stat_work);
|
||||
dev = container_of(usb, struct mt76_dev, usb);
|
||||
|
||||
while (true) {
|
||||
@ -724,8 +723,7 @@ static void mt76u_tx_status_data(struct work_struct *work)
|
||||
}
|
||||
|
||||
if (count && test_bit(MT76_STATE_RUNNING, &dev->state))
|
||||
ieee80211_queue_delayed_work(dev->hw, &usb->stat_work,
|
||||
msecs_to_jiffies(10));
|
||||
queue_work(usb->stat_wq, &usb->stat_work);
|
||||
else
|
||||
clear_bit(MT76_READING_STATS, &dev->state);
|
||||
}
|
||||
@ -906,7 +904,7 @@ void mt76u_stop_tx(struct mt76_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
cancel_delayed_work_sync(&dev->usb.stat_work);
|
||||
cancel_work_sync(&dev->usb.stat_work);
|
||||
clear_bit(MT76_READING_STATS, &dev->state);
|
||||
|
||||
mt76_tx_status_check(dev, NULL, true);
|
||||
@ -952,24 +950,40 @@ int mt76u_init(struct mt76_dev *dev,
|
||||
.rd_rp = mt76u_rd_rp,
|
||||
.type = MT76_BUS_USB,
|
||||
};
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct mt76_usb *usb = &dev->usb;
|
||||
|
||||
tasklet_init(&usb->rx_tasklet, mt76u_rx_tasklet, (unsigned long)dev);
|
||||
tasklet_init(&dev->tx_tasklet, mt76u_tx_tasklet, (unsigned long)dev);
|
||||
INIT_DELAYED_WORK(&usb->stat_work, mt76u_tx_status_data);
|
||||
INIT_WORK(&usb->stat_work, mt76u_tx_status_data);
|
||||
skb_queue_head_init(&dev->rx_skb[MT_RXQ_MAIN]);
|
||||
|
||||
usb->stat_wq = alloc_workqueue("mt76u", WQ_UNBOUND, 0);
|
||||
if (!usb->stat_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&usb->mcu.mutex);
|
||||
|
||||
mutex_init(&usb->usb_ctrl_mtx);
|
||||
dev->bus = &mt76u_ops;
|
||||
dev->queue_ops = &usb_queue_ops;
|
||||
|
||||
dev_set_drvdata(&udev->dev, dev);
|
||||
|
||||
usb->sg_en = mt76u_check_sg(dev);
|
||||
|
||||
return mt76u_set_endpoints(intf, usb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76u_init);
|
||||
|
||||
void mt76u_deinit(struct mt76_dev *dev)
|
||||
{
|
||||
if (dev->usb.stat_wq) {
|
||||
destroy_workqueue(dev->usb.stat_wq);
|
||||
dev->usb.stat_wq = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76u_deinit);
|
||||
|
||||
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
|
Loading…
Reference in New Issue
Block a user