diff options
Diffstat (limited to 'drivers/net/wireless/mediatek')
109 files changed, 3384 insertions, 1891 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile index 4d03596e891f..99bbc74acda8 100644 --- a/drivers/net/wireless/mediatek/mt76/Makefile +++ b/drivers/net/wireless/mediatek/mt76/Makefile @@ -6,7 +6,9 @@ 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 mt76-usb-y := usb.o usb_trace.o diff --git a/drivers/net/wireless/mediatek/mt76/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index 27e3ff039c48..59c187898132 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76.h" @@ -34,8 +23,9 @@ mt76_aggr_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames, int idx) } static void -mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid, struct sk_buff_head *frames, - u16 head) +mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid, + struct sk_buff_head *frames, + u16 head) { int idx; @@ -74,15 +64,14 @@ mt76_rx_aggr_check_release(struct mt76_rx_tid *tid, struct sk_buff_head *frames) for (idx = (tid->head + 1) % tid->size; idx != start && nframes; idx = (idx + 1) % tid->size) { - skb = tid->reorder_buf[idx]; if (!skb) continue; nframes--; - status = (struct mt76_rx_status *) skb->cb; - if (!time_after(jiffies, status->reorder_time + - REORDER_TIMEOUT)) + status = (struct mt76_rx_status *)skb->cb; + if (!time_after(jiffies, + status->reorder_time + REORDER_TIMEOUT)) continue; mt76_rx_aggr_release_frames(tid, frames, status->seqno); @@ -122,8 +111,8 @@ mt76_rx_aggr_reorder_work(struct work_struct *work) static void mt76_rx_aggr_check_ctl(struct sk_buff *skb, struct sk_buff_head *frames) { - struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; - struct ieee80211_bar *bar = (struct ieee80211_bar *) skb->data; + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; struct mt76_wcid *wcid = status->wcid; struct mt76_rx_tid *tid; u16 seqno; @@ -141,15 +130,17 @@ 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); } void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) { - struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct mt76_wcid *wcid = status->wcid; struct ieee80211_sta *sta; struct mt76_rx_tid *tid; @@ -233,7 +224,8 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) tid->nframes++; mt76_rx_aggr_release_head(tid, frames); - ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, REORDER_TIMEOUT); + ieee80211_queue_delayed_work(tid->dev->hw, &tid->reorder_work, + REORDER_TIMEOUT); out: spin_unlock_bh(&tid->lock); @@ -267,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; @@ -283,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; - - rcu_read_lock(); + struct mt76_rx_tid *tid = NULL; - tid = rcu_dereference(wcid->aggr[tidno]); + tid = rcu_replace_pointer(wcid->aggr[tidno], tid, + lockdep_is_held(&dev->mutex)); if (tid) { - rcu_assign_pointer(wcid->aggr[tidno], NULL); mt76_rx_aggr_shutdown(dev, tid); kfree_rcu(tid, rcu_head); } - - rcu_read_unlock(); } EXPORT_SYMBOL_GPL(mt76_rx_aggr_stop); diff --git a/drivers/net/wireless/mediatek/mt76/airtime.c b/drivers/net/wireless/mediatek/mt76/airtime.c new file mode 100644 index 000000000000..a4a785467748 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/airtime.c @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (C) 2019 Felix Fietkau <nbd@nbd.name> + */ + +#include "mt76.h" + +#define AVG_PKT_SIZE 1024 + +/* Number of bits for an average sized packet */ +#define MCS_NBITS (AVG_PKT_SIZE << 3) + +/* Number of symbols for a packet with (bps) bits per symbol */ +#define MCS_NSYMS(bps) DIV_ROUND_UP(MCS_NBITS, (bps)) + +/* Transmission time (1024 usec) for a packet containing (syms) * symbols */ +#define MCS_SYMBOL_TIME(sgi, syms) \ + (sgi ? \ + ((syms) * 18 * 1024 + 4 * 1024) / 5 : /* syms * 3.6 us */ \ + ((syms) * 1024) << 2 /* syms * 4 us */ \ + ) + +/* Transmit duration for the raw data part of an average sized packet */ +#define MCS_DURATION(streams, sgi, bps) \ + MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps))) + +#define BW_20 0 +#define BW_40 1 +#define BW_80 2 + +/* + * Define group sort order: HT40 -> SGI -> #streams + */ +#define MT_MAX_STREAMS 4 +#define MT_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */ +#define MT_VHT_STREAM_GROUPS 6 /* BW(=3) * SGI(=2) */ + +#define MT_HT_GROUPS_NB (MT_MAX_STREAMS * \ + MT_HT_STREAM_GROUPS) +#define MT_VHT_GROUPS_NB (MT_MAX_STREAMS * \ + MT_VHT_STREAM_GROUPS) +#define MT_GROUPS_NB (MT_HT_GROUPS_NB + \ + MT_VHT_GROUPS_NB) + +#define MT_HT_GROUP_0 0 +#define MT_VHT_GROUP_0 (MT_HT_GROUP_0 + MT_HT_GROUPS_NB) + +#define MCS_GROUP_RATES 10 + +#define HT_GROUP_IDX(_streams, _sgi, _ht40) \ + MT_HT_GROUP_0 + \ + MT_MAX_STREAMS * 2 * _ht40 + \ + MT_MAX_STREAMS * _sgi + \ + _streams - 1 + +#define _MAX(a, b) (((a)>(b))?(a):(b)) + +#define GROUP_SHIFT(duration) \ + _MAX(0, 16 - __builtin_clz(duration)) + +/* MCS rate information for an MCS group */ +#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \ + [HT_GROUP_IDX(_streams, _sgi, _ht40)] = { \ + .shift = _s, \ + .duration = { \ + MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234) >> _s, \ + MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) >> _s \ + } \ +} + +#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \ + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26)) + +#define MCS_GROUP(_streams, _sgi, _ht40) \ + __MCS_GROUP(_streams, _sgi, _ht40, \ + MCS_GROUP_SHIFT(_streams, _sgi, _ht40)) + +#define VHT_GROUP_IDX(_streams, _sgi, _bw) \ + (MT_VHT_GROUP_0 + \ + MT_MAX_STREAMS * 2 * (_bw) + \ + MT_MAX_STREAMS * (_sgi) + \ + (_streams) - 1) + +#define BW2VBPS(_bw, r3, r2, r1) \ + (_bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) + +#define __VHT_GROUP(_streams, _sgi, _bw, _s) \ + [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ + .shift = _s, \ + .duration = { \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 117, 54, 26)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 234, 108, 52)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 351, 162, 78)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 468, 216, 104)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 702, 324, 156)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 936, 432, 208)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1053, 486, 234)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1170, 540, 260)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1404, 648, 312)) >> _s, \ + MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 1560, 720, 346)) >> _s \ + } \ +} + +#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \ + GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \ + BW2VBPS(_bw, 117, 54, 26))) + +#define VHT_GROUP(_streams, _sgi, _bw) \ + __VHT_GROUP(_streams, _sgi, _bw, \ + VHT_GROUP_SHIFT(_streams, _sgi, _bw)) + +struct mcs_group { + u8 shift; + u16 duration[MCS_GROUP_RATES]; +}; + +static const struct mcs_group airtime_mcs_groups[] = { + MCS_GROUP(1, 0, BW_20), + MCS_GROUP(2, 0, BW_20), + MCS_GROUP(3, 0, BW_20), + MCS_GROUP(4, 0, BW_20), + + MCS_GROUP(1, 1, BW_20), + MCS_GROUP(2, 1, BW_20), + MCS_GROUP(3, 1, BW_20), + MCS_GROUP(4, 1, BW_20), + + MCS_GROUP(1, 0, BW_40), + MCS_GROUP(2, 0, BW_40), + MCS_GROUP(3, 0, BW_40), + MCS_GROUP(4, 0, BW_40), + + MCS_GROUP(1, 1, BW_40), + MCS_GROUP(2, 1, BW_40), + MCS_GROUP(3, 1, BW_40), + MCS_GROUP(4, 1, BW_40), + + VHT_GROUP(1, 0, BW_20), + VHT_GROUP(2, 0, BW_20), + VHT_GROUP(3, 0, BW_20), + VHT_GROUP(4, 0, BW_20), + + VHT_GROUP(1, 1, BW_20), + VHT_GROUP(2, 1, BW_20), + VHT_GROUP(3, 1, BW_20), + VHT_GROUP(4, 1, BW_20), + + VHT_GROUP(1, 0, BW_40), + VHT_GROUP(2, 0, BW_40), + VHT_GROUP(3, 0, BW_40), + VHT_GROUP(4, 0, BW_40), + + VHT_GROUP(1, 1, BW_40), + VHT_GROUP(2, 1, BW_40), + VHT_GROUP(3, 1, BW_40), + VHT_GROUP(4, 1, BW_40), + + VHT_GROUP(1, 0, BW_80), + VHT_GROUP(2, 0, BW_80), + VHT_GROUP(3, 0, BW_80), + VHT_GROUP(4, 0, BW_80), + + VHT_GROUP(1, 1, BW_80), + VHT_GROUP(2, 1, BW_80), + VHT_GROUP(3, 1, BW_80), + VHT_GROUP(4, 1, BW_80), +}; + +static u32 +mt76_calc_legacy_rate_duration(const struct ieee80211_rate *rate, bool short_pre, + int len) +{ + u32 duration; + + switch (rate->hw_value >> 8) { + case MT_PHY_TYPE_CCK: + duration = 144 + 48; /* preamble + PLCP */ + if (short_pre) + duration >>= 1; + + duration += 10; /* SIFS */ + break; + case MT_PHY_TYPE_OFDM: + duration = 20 + 16; /* premable + SIFS */ + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + len <<= 3; + duration += (len * 10) / rate->bitrate; + + return duration; +} + +u32 mt76_calc_rx_airtime(struct mt76_dev *dev, struct mt76_rx_status *status, + int len) +{ + struct ieee80211_supported_band *sband; + const struct ieee80211_rate *rate; + bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI; + bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE; + int bw, streams; + u32 duration; + int group, idx; + + switch (status->bw) { + case RATE_INFO_BW_20: + bw = BW_20; + break; + case RATE_INFO_BW_40: + bw = BW_40; + break; + case RATE_INFO_BW_80: + bw = BW_80; + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + switch (status->encoding) { + case RX_ENC_LEGACY: + if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ)) + return 0; + + sband = dev->hw->wiphy->bands[status->band]; + if (!sband || status->rate_idx >= sband->n_bitrates) + return 0; + + rate = &sband->bitrates[status->rate_idx]; + + return mt76_calc_legacy_rate_duration(rate, sp, len); + case RX_ENC_VHT: + streams = status->nss; + idx = status->rate_idx; + group = VHT_GROUP_IDX(streams, sgi, bw); + break; + case RX_ENC_HT: + streams = ((status->rate_idx >> 3) & 3) + 1; + idx = status->rate_idx & 7; + group = HT_GROUP_IDX(streams, sgi, bw); + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + if (WARN_ON_ONCE(streams > 4)) + return 0; + + duration = airtime_mcs_groups[group].duration[idx]; + duration <<= airtime_mcs_groups[group].shift; + duration *= len; + duration /= AVG_PKT_SIZE; + duration /= 1024; + + duration += 36 + (streams << 2); + + return duration; +} + +u32 mt76_calc_tx_airtime(struct mt76_dev *dev, struct ieee80211_tx_info *info, + int len) +{ + struct mt76_rx_status stat = { + .band = info->band, + }; + u32 duration = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) { + struct ieee80211_tx_rate *rate = &info->status.rates[i]; + u32 cur_duration; + + if (rate->idx < 0 || !rate->count) + break; + + if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + stat.bw = RATE_INFO_BW_80; + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + stat.bw = RATE_INFO_BW_40; + else + stat.bw = RATE_INFO_BW_20; + + stat.enc_flags = 0; + if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + stat.enc_flags |= RX_ENC_FLAG_SHORTPRE; + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + stat.enc_flags |= RX_ENC_FLAG_SHORT_GI; + + stat.rate_idx = rate->idx; + if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + stat.encoding = RX_ENC_VHT; + stat.rate_idx = ieee80211_rate_get_vht_mcs(rate); + stat.nss = ieee80211_rate_get_vht_nss(rate); + } else if (rate->flags & IEEE80211_TX_RC_MCS) { + stat.encoding = RX_ENC_HT; + } else { + stat.encoding = RX_ENC_LEGACY; + } + + cur_duration = mt76_calc_rx_airtime(dev, &stat, len); + duration += cur_duration * rate->count; + } + + return duration; +} +EXPORT_SYMBOL_GPL(mt76_calc_tx_airtime); diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index c6a9fe2aef9d..d2202acb8dc6 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76.h" @@ -36,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; @@ -56,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) @@ -101,7 +90,6 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev) debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom); if (dev->otp.data) debugfs_create_blob("otp", 0400, dir, &dev->otp); - debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read); debugfs_create_devm_seqfile(dev->dev, "rate_txpower", dir, mt76_read_rate_txpower); diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index d8f61e540bfd..6173c80189ba 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/dma-mapping.h> @@ -64,8 +53,10 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q, u32 ctrl; int i, idx = -1; - if (txwi) + if (txwi) { q->entry[q->head].txwi = DMA_DUMMY_DATA; + q->entry[q->head].skip_buf0 = true; + } for (i = 0; i < nbufs; i += 2, buf += 2) { u32 buf0 = buf[0].addr, buf1 = 0; @@ -108,7 +99,7 @@ mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx, __le32 __ctrl = READ_ONCE(q->desc[idx].ctrl); u32 ctrl = le32_to_cpu(__ctrl); - if (!e->txwi || !e->skb) { + if (!e->skip_buf0) { __le32 addr = READ_ONCE(q->desc[idx].buf0); u32 len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl); @@ -175,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; } @@ -310,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); @@ -374,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); @@ -393,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++; } @@ -442,6 +432,12 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) mt76_dma_rx_cleanup(dev, q); mt76_dma_sync_idx(dev, q); mt76_dma_rx_fill(dev, q); + + if (!q->rx_head) + return; + + dev_kfree_skb(q->rx_head); + q->rx_head = NULL; } static void @@ -504,7 +500,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) skb_reserve(skb, q->buf_offset); if (q == &dev->q_rx[MT_RXQ_MCU]) { - u32 *rxfce = (u32 *) skb->cb; + u32 *rxfce = (u32 *)skb->cb; *rxfce = info; } @@ -542,10 +538,8 @@ mt76_dma_rx_poll(struct napi_struct *napi, int budget) rcu_read_unlock(); - if (done < budget) { - napi_complete(napi); + if (done < budget && napi_complete(napi)) dev->drv->rx_poll_complete(dev, qid); - } return done; } diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index 03dd2bafa4e8..e7c27697ef04 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76_DMA_H #define __MT76_DMA_H diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index b7a49ae6b327..804224e81103 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/of.h> #include <linux/of_net.h> diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index ec9efb79985f..96018fd65779 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/of.h> #include "mt76.h" @@ -116,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, @@ -191,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; @@ -294,6 +292,8 @@ mt76_alloc_device(struct device *pdev, unsigned int size, init_waitqueue_head(&dev->tx_wait); skb_queue_head_init(&dev->status_list); + tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev); + return dev; } EXPORT_SYMBOL_GPL(mt76_alloc_device); @@ -315,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; @@ -336,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); @@ -369,6 +378,8 @@ void mt76_unregister_device(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; + if (IS_ENABLED(CONFIG_MT76_LEDS)) + mt76_led_cleanup(dev); mt76_tx_status_check(dev, NULL, true); ieee80211_unregister_hw(hw); } @@ -407,33 +418,64 @@ bool mt76_has_tx_pending(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76_has_tx_pending); +static struct mt76_channel_state * +mt76_channel_state(struct mt76_dev *dev, struct ieee80211_channel *c) +{ + struct mt76_sband *msband; + int idx; + + if (c->band == NL80211_BAND_2GHZ) + msband = &dev->sband_2g; + else + msband = &dev->sband_5g; + + idx = c - &msband->sband.channels[0]; + return &msband->chan[idx]; +} + +void mt76_update_survey(struct mt76_dev *dev) +{ + struct mt76_channel_state *state = dev->chan_state; + ktime_t cur_time; + + if (!test_bit(MT76_STATE_RUNNING, &dev->state)) + return; + + if (dev->drv->update_survey) + dev->drv->update_survey(dev); + + cur_time = ktime_get_boottime(); + state->cc_active += ktime_to_us(ktime_sub(cur_time, + dev->survey_time)); + dev->survey_time = cur_time; + + if (dev->drv->drv_flags & MT_DRV_SW_RX_AIRTIME) { + spin_lock_bh(&dev->cc_lock); + state->cc_bss_rx += dev->cur_cc_bss_rx; + dev->cur_cc_bss_rx = 0; + spin_unlock_bh(&dev->cc_lock); + } +} +EXPORT_SYMBOL_GPL(mt76_update_survey); + void mt76_set_channel(struct mt76_dev *dev) { struct ieee80211_hw *hw = dev->hw; struct cfg80211_chan_def *chandef = &hw->conf.chandef; - struct mt76_channel_state *state; bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL; int timeout = HZ / 5; - if (offchannel) - set_bit(MT76_OFFCHANNEL, &dev->state); - else - clear_bit(MT76_OFFCHANNEL, &dev->state); - wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), timeout); - - if (dev->drv->update_survey) - dev->drv->update_survey(dev); + mt76_update_survey(dev); dev->chandef = *chandef; + dev->chan_state = mt76_channel_state(dev, chandef->chan); if (!offchannel) dev->main_chan = chandef->chan; - if (chandef->chan != dev->main_chan) { - state = mt76_channel_state(dev, chandef->chan); - memset(state, 0, sizeof(*state)); - } + if (chandef->chan != dev->main_chan) + memset(dev->chan_state, 0, sizeof(*dev->chan_state)); } EXPORT_SYMBOL_GPL(mt76_set_channel); @@ -446,8 +488,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) { @@ -455,8 +498,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); @@ -464,14 +509,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); @@ -487,9 +544,10 @@ void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, if (!key) return; - if (key->cipher == WLAN_CIPHER_SUITE_CCMP) - wcid->rx_check_pn = true; + if (key->cipher != WLAN_CIPHER_SUITE_CCMP) + return; + wcid->rx_check_pn = true; for (i = 0; i < IEEE80211_NUM_TIDS; i++) { ieee80211_get_key_rx_seq(key, i, &seq); memcpy(wcid->rx_key_pn[i], seq.ccmp.pn, sizeof(seq.ccmp.pn)); @@ -497,12 +555,12 @@ void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid, } EXPORT_SYMBOL(mt76_wcid_key_setup); -struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb) +static struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb) { struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct mt76_rx_status mstat; - mstat = *((struct mt76_rx_status *) skb->cb); + mstat = *((struct mt76_rx_status *)skb->cb); memset(status, 0, sizeof(*status)); status->flag = mstat.flag; @@ -515,19 +573,21 @@ 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) != sizeof(mstat.chain_signal)); - memcpy(status->chain_signal, mstat.chain_signal, sizeof(mstat.chain_signal)); + BUILD_BUG_ON(sizeof(status->chain_signal) != + sizeof(mstat.chain_signal)); + memcpy(status->chain_signal, mstat.chain_signal, + sizeof(mstat.chain_signal)); return wcid_to_sta(mstat.wcid); } -EXPORT_SYMBOL(mt76_rx_convert); static int mt76_check_ccmp_pn(struct sk_buff *skb) { - struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_wcid *wcid = status->wcid; struct ieee80211_hdr *hdr; int ret; @@ -543,7 +603,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb) * Validate the first fragment both here and in mac80211 * All further fragments will be validated by mac80211 only. */ - hdr = (struct ieee80211_hdr *) skb->data; + hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_frag(hdr) && !ieee80211_is_first_frag(hdr->frame_control)) return 0; @@ -564,10 +624,88 @@ mt76_check_ccmp_pn(struct sk_buff *skb) } 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) { - struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_sta *sta; struct mt76_wcid *wcid = status->wcid; bool ps; @@ -576,13 +714,15 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) { sta = ieee80211_find_sta_by_ifaddr(dev->hw, hdr->addr2, NULL); if (sta) - wcid = status->wcid = (struct mt76_wcid *) sta->drv_priv; + wcid = status->wcid = (struct mt76_wcid *)sta->drv_priv; } + mt76_airtime_check(dev, skb); + if (!wcid || !wcid->sta) return; - sta = container_of((void *) wcid, struct ieee80211_sta, drv_priv); + sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); if (status->signal <= 0) ewma_signal_add(&wcid->rssi, -status->signal); @@ -598,8 +738,8 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) } if (ieee80211_has_morefrags(hdr->frame_control) || - !(ieee80211_is_mgmt(hdr->frame_control) || - ieee80211_is_data(hdr->frame_control))) + !(ieee80211_is_mgmt(hdr->frame_control) || + ieee80211_is_data(hdr->frame_control))) return; ps = ieee80211_has_pm(hdr->frame_control); @@ -628,7 +768,7 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) if (!sta->txq[i]) continue; - mtxq = (struct mt76_txq *) sta->txq[i]->drv_priv; + mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; if (!skb_queue_empty(&mtxq->retry_q)) ieee80211_schedule_txq(dev->hw, sta->txq[i]); } @@ -714,6 +854,9 @@ void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, rcu_assign_pointer(dev->wcid[idx], NULL); synchronize_rcu(); + for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++) + mt76_rx_aggr_stop(dev, wcid, i); + if (dev->drv->sta_remove) dev->drv->sta_remove(dev, vif, sta); @@ -750,7 +893,7 @@ int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, dev->drv->sta_assoc(dev, vif, sta); if (old_state == IEEE80211_STA_NONE && - new_state == IEEE80211_STA_NOTEXIST) + new_state == IEEE80211_STA_NOTEXIST) mt76_sta_remove(dev, vif, sta); return 0; @@ -790,7 +933,7 @@ static void __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { if (vif->csa_active && ieee80211_csa_is_complete(vif)) - ieee80211_csa_finish(vif); + ieee80211_csa_finish(vif); } void mt76_csa_finish(struct mt76_dev *dev) @@ -878,3 +1021,33 @@ int mt76_get_rate(struct mt76_dev *dev, return 0; } EXPORT_SYMBOL_GPL(mt76_get_rate); + +void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const u8 *mac) +{ + struct mt76_dev *dev = hw->priv; + + set_bit(MT76_SCANNING, &dev->state); +} +EXPORT_SYMBOL_GPL(mt76_sw_scan); + +void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt76_dev *dev = hw->priv; + + 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); diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c index dbb57b593a87..2a976688804d 100644 --- a/drivers/net/wireless/mediatek/mt76/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mcu.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2019 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76.h" diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 38368d19aa6f..1c974df1fe25 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76.h" @@ -40,10 +29,16 @@ static u32 mt76_mmio_rmw(struct mt76_dev *dev, u32 offset, u32 mask, u32 val) return val; } -static void mt76_mmio_copy(struct mt76_dev *dev, u32 offset, const void *data, - int len) +static void mt76_mmio_write_copy(struct mt76_dev *dev, u32 offset, + const void *data, int len) { - __iowrite32_copy(dev->mmio.regs + offset, data, len >> 2); + __iowrite32_copy(dev->mmio.regs + offset, data, DIV_ROUND_UP(len, 4)); +} + +static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset, + void *data, int len) +{ + __ioread32_copy(data, dev->mmio.regs + offset, DIV_ROUND_UP(len, 4)); } static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base, @@ -89,7 +84,8 @@ void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) .rr = mt76_mmio_rr, .rmw = mt76_mmio_rmw, .wr = mt76_mmio_wr, - .copy = mt76_mmio_copy, + .write_copy = mt76_mmio_write_copy, + .read_copy = mt76_mmio_read_copy, .wr_rp = mt76_mmio_wr_rp, .rd_rp = mt76_mmio_rd_rp, .type = MT76_BUS_MMIO, diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 989386ecb5e4..fb077760347a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76_H @@ -49,8 +38,10 @@ struct mt76_bus_ops { u32 (*rr)(struct mt76_dev *dev, u32 offset); void (*wr)(struct mt76_dev *dev, u32 offset, u32 val); u32 (*rmw)(struct mt76_dev *dev, u32 offset, u32 mask, u32 val); - void (*copy)(struct mt76_dev *dev, u32 offset, const void *data, - int len); + void (*write_copy)(struct mt76_dev *dev, u32 offset, const void *data, + int len); + void (*read_copy)(struct mt76_dev *dev, u32 offset, void *data, + int len); int (*wr_rp)(struct mt76_dev *dev, u32 base, const struct mt76_reg_pair *rp, int len); int (*rd_rp)(struct mt76_dev *dev, u32 base, @@ -58,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, @@ -102,8 +93,9 @@ struct mt76_queue_entry { struct urb *urb; }; enum mt76_txq_id qid; - bool schedule; - bool done; + bool skip_buf0:1; + bool schedule:1; + bool done:1; }; struct mt76_queue_regs { @@ -160,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); @@ -199,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; @@ -213,6 +199,7 @@ struct mt76_wcid { u8 rx_check_pn; u8 rx_key_pn[IEEE80211_NUM_TIDS][6]; + u16 cipher; u32 tx_info; bool sw_iv; @@ -280,7 +267,6 @@ enum { MT76_STATE_MCU_RUNNING, MT76_SCANNING, MT76_RESET, - MT76_OFFCHANNEL, MT76_REMOVED, MT76_READING_STATS, }; @@ -290,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); @@ -330,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 { @@ -375,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, @@ -390,10 +381,14 @@ enum mt76u_out_ep { #define MCU_RESP_URB_SIZE 1024 struct mt76_usb { struct mutex usb_ctrl_mtx; - u8 data[32]; + union { + u8 data[32]; + __le32 reg_val; + }; 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]; @@ -426,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; @@ -445,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]; @@ -468,6 +499,8 @@ struct mt76_dev { u32 rev; unsigned long state; + u32 aggr_stats[32]; + u8 antenna_mask; u16 chainmask; @@ -496,6 +529,8 @@ struct mt76_dev { u8 csa_complete; + ktime_t survey_time; + u32 rxfilter; union { @@ -512,33 +547,11 @@ 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__) -#define __mt76_wr_copy(dev, ...) (dev)->bus->copy((dev), __VA_ARGS__) +#define __mt76_wr_copy(dev, ...) (dev)->bus->write_copy((dev), __VA_ARGS__) +#define __mt76_rr_copy(dev, ...) (dev)->bus->read_copy((dev), __VA_ARGS__) #define __mt76_set(dev, offset, val) __mt76_rmw(dev, offset, 0, val) #define __mt76_clear(dev, offset, val) __mt76_rmw(dev, offset, val, 0) @@ -546,7 +559,8 @@ struct mt76_rx_status { #define mt76_rr(dev, ...) (dev)->mt76.bus->rr(&((dev)->mt76), __VA_ARGS__) #define mt76_wr(dev, ...) (dev)->mt76.bus->wr(&((dev)->mt76), __VA_ARGS__) #define mt76_rmw(dev, ...) (dev)->mt76.bus->rmw(&((dev)->mt76), __VA_ARGS__) -#define mt76_wr_copy(dev, ...) (dev)->mt76.bus->copy(&((dev)->mt76), __VA_ARGS__) +#define mt76_wr_copy(dev, ...) (dev)->mt76.bus->write_copy(&((dev)->mt76), __VA_ARGS__) +#define mt76_rr_copy(dev, ...) (dev)->mt76.bus->read_copy(&((dev)->mt76), __VA_ARGS__) #define mt76_wr_rp(dev, ...) (dev)->mt76.bus->wr_rp(&((dev)->mt76), __VA_ARGS__) #define mt76_rd_rp(dev, ...) (dev)->mt76.bus->rd_rp(&((dev)->mt76), __VA_ARGS__) @@ -580,6 +594,7 @@ bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, #define mt76_poll_msec(dev, ...) __mt76_poll_msec(&((dev)->mt76), __VA_ARGS__) void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs); +void mt76_pci_disable_aspm(struct pci_dev *pdev); static inline u16 mt76_chip(struct mt76_dev *dev) { @@ -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); @@ -675,7 +676,7 @@ static inline struct mt76_tx_cb *mt76_tx_skb_cb(struct sk_buff *skb) { BUILD_BUG_ON(sizeof(struct mt76_tx_cb) > sizeof(IEEE80211_SKB_CB(skb)->status.status_driver_data)); - return ((void *) IEEE80211_SKB_CB(skb)->status.status_driver_data); + return ((void *)IEEE80211_SKB_CB(skb)->status.status_driver_data); } static inline void mt76_insert_hdr_pad(struct sk_buff *skb) @@ -710,6 +711,7 @@ void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta, bool send_bar); void mt76_txq_schedule(struct mt76_dev *dev, enum mt76_txq_id qid); void mt76_txq_schedule_all(struct mt76_dev *dev); +void mt76_tx_tasklet(unsigned long data); void mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tids, int nframes, @@ -717,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); @@ -750,8 +753,6 @@ int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); -struct ieee80211_sta *mt76_rx_convert(struct sk_buff *skb); - int mt76_get_min_avg_rssi(struct mt76_dev *dev); int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -760,11 +761,18 @@ 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, struct ieee80211_supported_band *sband, int idx, bool cck); +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); @@ -775,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) @@ -796,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; @@ -814,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig index e108bf881ca8..6a0080f1d91c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig @@ -5,6 +5,8 @@ config MT7603E depends on MAC80211 depends on PCI help - This adds support for MT7603E wireless PCIe devices and the WLAN core on - MT7628/MT7688 SoC devices + This adds support for MT7603E wireless PCIe devices and the WLAN core + on MT7628/MT7688 SoC devices. This family supports IEEE 802.11n 2x2 + to 300Mbps PHY rate + To compile this driver as a module, choose M here. diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c index 58e68fbdbf75..7a41cdf1c4ae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +// SPDX-License-Identifier: ISC #include "mt7603.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/core.c b/drivers/net/wireless/mediatek/mt76/mt7603/core.c index e7ee58e3379c..e5af4f3389cc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/core.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/core.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +// SPDX-License-Identifier: ISC #include "mt7603.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c index a1bc3103cbe9..47c85a9fac28 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +// SPDX-License-Identifier: ISC #include "mt7603.h" @@ -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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c index 58dc511f93c5..a6ab73060aad 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +// SPDX-License-Identifier: ISC #include "mt7603.h" #include "mac.h" @@ -63,7 +63,7 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb) txd[0] = cpu_to_le32(val); sta = container_of(priv, struct ieee80211_sta, drv_priv); - hdr = (struct ieee80211_hdr *) &skb->data[MT_TXD_SIZE]; + hdr = (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE]; tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; ieee80211_sta_set_buffered(sta, tid, true); @@ -135,14 +135,6 @@ mt7603_init_rx_queue(struct mt7603_dev *dev, struct mt76_queue *q, return 0; } -static void -mt7603_tx_tasklet(unsigned long data) -{ - struct mt7603_dev *dev = (struct mt7603_dev *)data; - - mt76_txq_schedule_all(&dev->mt76); -} - static int mt7603_poll_tx(struct napi_struct *napi, int budget) { struct mt7603_dev *dev; @@ -160,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; @@ -178,11 +172,6 @@ int mt7603_dma_init(struct mt7603_dev *dev) mt76_dma_attach(&dev->mt76); - init_waitqueue_head(&dev->mt76.mmio.mcu.wait); - skb_queue_head_init(&dev->mt76.mmio.mcu.res_q); - - tasklet_init(&dev->mt76.tx_tasklet, mt7603_tx_tasklet, (unsigned long)dev); - mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN | MT_WPDMA_GLO_CFG_RX_DMA_EN | diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c index 8c120e4461b0..2b6a4d8a8dc7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +// SPDX-License-Identifier: ISC #include "mt7603.h" #include "eeprom.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c index 38834c7d0891..0696dbf28c5b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +// SPDX-License-Identifier: ISC #include <linux/etherdevice.h> #include "mt7603.h" @@ -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, @@ -248,8 +250,7 @@ mt7603_mac_init(struct mt7603_dev *dev) FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7603_RATE_RETRY - 1)); mt76_wr(dev, MT_AGG_ARCR, - (MT_AGG_ARCR_INIT_RATE1 | - FIELD_PREP(MT_AGG_ARCR_RTS_RATE_THR, 2) | + (FIELD_PREP(MT_AGG_ARCR_RTS_RATE_THR, 2) | 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))); @@ -507,7 +508,6 @@ mt7603_init_txpower(struct mt7603_dev *dev, } } - int mt7603_register_device(struct mt7603_dev *dev) { struct mt76_bus_ops *bus_ops; @@ -526,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); @@ -554,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 */ @@ -563,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, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index 40db1cbc832d..812d081ad943 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +// SPDX-License-Identifier: ISC #include <linux/etherdevice.h> #include <linux/timekeeping.h> @@ -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) @@ -639,9 +743,11 @@ void mt7603_wtbl_set_rates(struct mt7603_dev *dev, struct mt7603_sta *sta, IEEE80211_TX_RC_40_MHZ_WIDTH) continue; + if (!rates[i].idx) + continue; + rates[i].idx--; } - } w9 &= MT_WTBL2_W9_SHORT_GI_20 | MT_WTBL2_W9_SHORT_GI_40 | @@ -1014,8 +1120,9 @@ mt7603_fill_txs(struct mt7603_dev *dev, struct mt7603_sta *sta, sta->rate_probe = false; } spin_unlock_bh(&dev->mt76.lock); - } else + } else { info->status.rates[0] = rs->rates[first_idx / 2]; + } info->status.rates[0].count = 0; for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) { @@ -1029,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; @@ -1132,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; @@ -1458,21 +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->survey_time)); - dev->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 @@ -1673,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index e5d4cb6381a8..962e2822d19f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +// SPDX-License-Identifier: ISC #include <linux/etherdevice.h> #include <linux/platform_device.h> @@ -13,8 +13,9 @@ mt7603_start(struct ieee80211_hw *hw) { struct mt7603_dev *dev = hw->priv; + mt7603_mac_reset_counters(dev); mt7603_mac_start(dev); - dev->survey_time = ktime_get_boottime(); + dev->mt76.survey_time = ktime_get_boottime(); set_bit(MT76_STATE_RUNNING, &dev->mt76.state); mt7603_mac_work(&dev->mt76.mac_work.work); @@ -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); @@ -173,7 +181,7 @@ mt7603_set_channel(struct mt7603_dev *dev, struct cfg80211_chan_def *def) mt76_txq_schedule_all(&dev->mt76); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, - MT7603_WATCHDOG_TIME); + msecs_to_jiffies(MT7603_WATCHDOG_TIME)); /* reset channel stats */ mt76_clear(dev, MT_MIB_CTL, MT_MIB_CTL_READ_CLR_DIS); @@ -182,7 +190,7 @@ mt7603_set_channel(struct mt7603_dev *dev, struct cfg80211_chan_def *def) mt76_rr(dev, MT_MIB_STAT_PSCCA); mt7603_cca_stats_reset(dev); - dev->survey_time = ktime_get_boottime(); + dev->mt76.survey_time = ktime_get_boottime(); mt7603_init_edcca(dev); @@ -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); } @@ -399,7 +413,7 @@ mt7603_ps_set_more_data(struct sk_buff *skb) { struct ieee80211_hdr *hdr; - hdr = (struct ieee80211_hdr *) &skb->data[MT_TXD_SIZE]; + hdr = (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE]; hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); } @@ -537,23 +551,6 @@ mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, } static void -mt7603_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - const u8 *mac) -{ - struct mt7603_dev *dev = hw->priv; - - set_bit(MT76_SCANNING, &dev->mt76.state); -} - -static void -mt7603_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct mt7603_dev *dev = hw->priv; - - clear_bit(MT76_SCANNING, &dev->mt76.state); -} - -static void mt7603_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { @@ -569,18 +566,20 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_txq *txq = sta->txq[params->tid]; struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; u16 tid = params->tid; - u16 *ssn = ¶ms->ssn; + u16 ssn = params->ssn; u8 ba_size = params->buf_size; struct mt76_txq *mtxq; + int ret = 0; if (!txq) return -EINVAL; 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, + mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, params->buf_size); mt7603_mac_rx_ba_reset(dev, sta->addr, tid); break; @@ -595,12 +594,11 @@ mt7603_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; - ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); mt7603_mac_tx_ba_reset(dev, msta->wcid.idx, tid, -1); break; case IEEE80211_AMPDU_TX_START: - mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(*ssn); - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; @@ -608,8 +606,9 @@ 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; + return ret; } static void @@ -647,7 +646,8 @@ mt7603_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) mt7603_mac_set_timing(dev); } -static void mt7603_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, +static void mt7603_tx(struct ieee80211_hw *hw, + struct ieee80211_tx_control *control, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -682,8 +682,8 @@ const struct ieee80211_ops mt7603_ops = { .sta_state = mt76_sta_state, .set_key = mt7603_set_key, .conf_tx = mt7603_conf_tx, - .sw_scan_start = mt7603_sw_scan, - .sw_scan_complete = mt7603_sw_scan_complete, + .sw_scan_start = mt76_sw_scan, + .sw_scan_complete = mt76_sw_scan_complete, .flush = mt7603_flush, .ampdu_action = mt7603_ampdu_action, .get_txpower = mt76_get_txpower, @@ -693,6 +693,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"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c index 343ddc5543c2..02b2bd60d04d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +// SPDX-License-Identifier: ISC #include <linux/firmware.h> #include "mt7603.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 2c6f7b4cf0e9..ab54b0612e98 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -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; @@ -116,11 +123,8 @@ struct mt7603_dev { s8 tx_power_limit; - ktime_t survey_time; ktime_t ed_time; - struct mt76_queue q_rx; - spinlock_t ps_lock; u8 mac_work_count; @@ -192,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); @@ -203,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/pci.c b/drivers/net/wireless/mediatek/mt76/mt7603/pci.c index 4acdbf5d8968..2f2f337e2201 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/pci.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +// SPDX-License-Identifier: ISC #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h index eb9eefe8e125..6e23ed3dfdff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/regs.h @@ -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) diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c index b920be1f5718..68efb300c0d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: ISC */ +// SPDX-License-Identifier: ISC #include <linux/kernel.h> #include <linux/module.h> @@ -9,7 +9,6 @@ static int mt76_wmac_probe(struct platform_device *pdev) { - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct mt7603_dev *dev; void __iomem *mem_base; struct mt76_dev *mdev; @@ -17,12 +16,10 @@ mt76_wmac_probe(struct platform_device *pdev) int ret; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get device IRQ\n"); + if (irq < 0) return irq; - } - mem_base = devm_ioremap_resource(&pdev->dev, res); + mem_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mem_base)) { dev_err(&pdev->dev, "Failed to get memory resource\n"); return PTR_ERR(mem_base); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig index 2ed47b309b6e..4cabba9aa2ea 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig @@ -5,4 +5,9 @@ config MT7615E depends on MAC80211 depends on PCI help - This adds support for MT7615-based wireless PCIe devices. + This adds support for MT7615-based wireless PCIe devices, + which support concurrent dual-band operation at both 5GHz + and 2.4GHz, IEEE 802.11ac 4x4:4SS 1733Mbps PHY rate, wave2 + MU-MIMO up to 4 users/group and 160MHz channels. + + To compile this driver as a module, choose M here. diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile index 6397552f6ee3..5aaac69849d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_MT7615E) += mt7615e.o -mt7615e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o +mt7615e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \ + debugfs.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c new file mode 100644 index 000000000000..f6b75f832e6a --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: ISC + +#include "mt7615.h" + +static int +mt7615_radar_pattern_set(void *data, u64 val) +{ + struct mt7615_dev *dev = data; + + return mt7615_mcu_rdd_send_pattern(dev); +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_pattern, NULL, + mt7615_radar_pattern_set, "%lld\n"); + +static int +mt7615_scs_set(void *data, u64 val) +{ + struct mt7615_dev *dev = data; + + mt7615_mac_set_scs(dev, val); + + return 0; +} + +static int +mt7615_scs_get(void *data, u64 *val) +{ + struct mt7615_dev *dev = data; + + *val = dev->scs_en; + + return 0; +} + +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) +{ + struct mt7615_dev *dev = dev_get_drvdata(s->private); + + seq_printf(s, "Sensitivity: ofdm=%d cck=%d\n", + dev->ofdm_sensitivity, dev->cck_sensitivity); + seq_printf(s, "False CCA: ofdm=%d cck=%d\n", + dev->false_cca_ofdm, dev->false_cca_cck); + + return 0; +} + +static int mt7615_read_temperature(struct seq_file *s, void *data) +{ + struct mt7615_dev *dev = dev_get_drvdata(s->private); + int temp; + + /* cpu */ + temp = mt7615_mcu_get_temperature(dev, 0); + seq_printf(s, "Temperature: %d\n", temp); + + 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; + + dir = mt76_register_debugfs(&dev->mt76); + 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); + debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern); + /* test pattern knobs */ + debugfs_create_u8("pattern_len", 0600, dir, + &dev->radar_pattern.n_pulses); + debugfs_create_u32("pulse_period", 0600, dir, + &dev->radar_pattern.period); + debugfs_create_u16("pulse_width", 0600, dir, + &dev->radar_pattern.width); + debugfs_create_u16("pulse_power", 0600, dir, + &dev->radar_pattern.power); + debugfs_create_file("radar_trigger", 0200, dir, dev, + &fops_radar_pattern); + debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir, + mt7615_read_temperature); + + return 0; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c index 6a70273d4a69..285d4f1d6178 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c @@ -76,7 +76,7 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, mt7615_mac_tx_free(dev, skb); break; case PKT_TYPE_RX_EVENT: - mt76_mcu_rx_event(&dev->mt76, skb); + mt7615_mcu_rx_event(dev, skb); break; case PKT_TYPE_NORMAL: if (!mt7615_mac_fill_rx(dev, skb)) { @@ -90,13 +90,6 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, } } -static void mt7615_tx_tasklet(unsigned long data) -{ - struct mt7615_dev *dev = (struct mt7615_dev *)data; - - mt76_txq_schedule_all(&dev->mt76); -} - static int mt7615_poll_tx(struct napi_struct *napi, int budget) { static const u8 queue_map[] = { @@ -117,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; @@ -128,9 +123,6 @@ int mt7615_dma_init(struct mt7615_dev *dev) mt76_dma_attach(&dev->mt76); - tasklet_init(&dev->mt76.tx_tasklet, mt7615_tx_tasklet, - (unsigned long)dev); - mt76_wr(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE | MT_WPDMA_GLO_CFG_FIFO_LITTLE_ENDIAN | diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index dc94f52e6e8b..17e277bf39e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -92,7 +92,9 @@ 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 *eeprom = dev->mt76.eeprom.data; + u8 tx_mask, rx_mask, max_nss; + u32 val; val = FIELD_GET(MT_EE_NIC_WIFI_CONF_BAND_SEL, eeprom[MT_EE_WIFI_CONF]); @@ -108,6 +110,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, @@ -154,6 +173,42 @@ int mt7615_eeprom_get_power_index(struct mt7615_dev *dev, return index; } +static void mt7615_apply_cal_free_data(struct mt7615_dev *dev) +{ + static const u16 ical[] = { + 0x53, 0x54, 0x55, 0x56, 0x57, 0x5c, 0x5d, 0x62, 0x63, 0x68, + 0x69, 0x6e, 0x6f, 0x73, 0x74, 0x78, 0x79, 0x82, 0x83, 0x87, + 0x88, 0x8c, 0x8d, 0x91, 0x92, 0x96, 0x97, 0x9b, 0x9c, 0xa0, + 0xa1, 0xaa, 0xab, 0xaf, 0xb0, 0xb4, 0xb5, 0xb9, 0xba, 0xf4, + 0xf7, 0xff, + 0x140, 0x141, 0x145, 0x146, 0x14a, 0x14b, 0x154, 0x155, 0x159, + 0x15a, 0x15e, 0x15f, 0x163, 0x164, 0x168, 0x169, 0x16d, 0x16e, + 0x172, 0x173, 0x17c, 0x17d, 0x181, 0x182, 0x186, 0x187, 0x18b, + 0x18c + }; + static const u16 ical_nocheck[] = { + 0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118, + 0x1b5, 0x1b6, 0x1b7, 0x3ac, 0x3ad, 0x3ae, 0x3af, 0x3b0, 0x3b1, + 0x3b2 + }; + u8 *eeprom = dev->mt76.eeprom.data; + u8 *otp = dev->mt76.otp.data; + int i; + + if (!otp) + return; + + for (i = 0; i < ARRAY_SIZE(ical); i++) + if (!otp[ical[i]]) + return; + + for (i = 0; i < ARRAY_SIZE(ical); i++) + eeprom[ical[i]] = otp[ical[i]]; + + for (i = 0; i < ARRAY_SIZE(ical_nocheck); i++) + eeprom[ical_nocheck[i]] = otp[ical_nocheck[i]]; +} + int mt7615_eeprom_init(struct mt7615_dev *dev) { int ret; @@ -166,6 +221,8 @@ int mt7615_eeprom_init(struct mt7615_dev *dev) if (ret && dev->mt76.otp.data) memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data, MT7615_EEPROM_SIZE); + else + mt7615_apply_cal_free_data(dev); mt7615_eeprom_parse_hw_cap(dev); memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h index f4a4280768d2..c3bc69ac210e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h @@ -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) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index 859de2454ec6..553bd4d988f7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -20,10 +20,25 @@ static void mt7615_phy_init(struct mt7615_dev *dev) static void mt7615_mac_init(struct mt7615_dev *dev) { - /* enable band 0 clk */ - mt76_rmw(dev, MT_CFG_CCR, - MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN, - MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN); + u32 val, mask, set; + int i; + + /* enable band 0/1 clk */ + mt76_set(dev, MT_CFG_CCR, + MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN | + MT_CFG_CCR_MAC_D1_1X_GC_EN | MT_CFG_CCR_MAC_D1_2X_GC_EN); + + val = mt76_rmw(dev, MT_TMAC_TRCR0, + MT_TMAC_TRCR_CCA_SEL | MT_TMAC_TRCR_SEC_CCA_SEL, + FIELD_PREP(MT_TMAC_TRCR_CCA_SEL, 2) | + FIELD_PREP(MT_TMAC_TRCR_SEC_CCA_SEL, 0)); + mt76_wr(dev, MT_TMAC_TRCR1, val); + + val = MT_AGG_ACR_PKT_TIME_EN | MT_AGG_ACR_NO_BA_AR_RULE | + FIELD_PREP(MT_AGG_ACR_CFEND_RATE, 0x49) | /* 24M */ + FIELD_PREP(MT_AGG_ACR_BAR_RATE, 0x4b); /* 6M */ + mt76_wr(dev, MT_AGG_ACR0, val); + mt76_wr(dev, MT_AGG_ACR1, val); mt76_rmw_field(dev, MT_TMAC_CTCR0, MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f); @@ -36,6 +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, true); mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS, MT_AGG_SCR_NLNAV_MID_PTEC_DIS); @@ -45,11 +61,19 @@ static void mt7615_mac_init(struct mt7615_dev *dev) mt76_wr(dev, MT_DMA_DCR0, MT_DMA_DCR0_RX_VEC_DROP | FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 3072)); - mt76_wr(dev, MT_AGG_ARUCR, FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 7)); + mt76_wr(dev, MT_AGG_ARUCR, + FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 7) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), 2) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), 2) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), 2) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), 1) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), 1) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), 1) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), 1)); + mt76_wr(dev, MT_AGG_ARDCR, - FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 0) | - FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), - max_t(int, 0, MT7615_RATE_RETRY - 2)) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), MT7615_RATE_RETRY - 1) | + FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), MT7615_RATE_RETRY - 1) | FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), MT7615_RATE_RETRY - 1) | @@ -58,11 +82,28 @@ static void mt7615_mac_init(struct mt7615_dev *dev) FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7615_RATE_RETRY - 1)); mt76_wr(dev, MT_AGG_ARCR, - (MT_AGG_ARCR_INIT_RATE1 | - FIELD_PREP(MT_AGG_ARCR_RTS_RATE_THR, 2) | + (FIELD_PREP(MT_AGG_ARCR_RTS_RATE_THR, 2) | 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) @@ -136,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 @@ -155,17 +199,6 @@ static const struct ieee80211_iface_combination if_comb[] = { } }; -static int mt7615_init_debugfs(struct mt7615_dev *dev) -{ - struct dentry *dir; - - dir = mt76_register_debugfs(&dev->mt76); - if (!dir) - return -ENOMEM; - - return 0; -} - static void mt7615_init_txpower(struct mt7615_dev *dev, struct ieee80211_supported_band *sband) @@ -208,18 +241,44 @@ mt7615_init_txpower(struct mt7615_dev *dev, } } +static void +mt7615_regd_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt7615_dev *dev = hw->priv; + struct cfg80211_chan_def *chandef = &dev->mt76.chandef; + + if (request->dfs_region == dev->mt76.region) + return; + + dev->mt76.region = request->dfs_region; + + if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR)) + return; + + mt7615_dfs_stop_radar_detector(dev); + if (request->dfs_region == NL80211_DFS_UNSET) + mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, MT_HW_RDD0, + MT_RX_SEL0, 0); + else + mt7615_dfs_start_radar_detector(dev); +} + int mt7615_register_device(struct mt7615_dev *dev) { struct ieee80211_hw *hw = mt76_hw(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; @@ -230,8 +289,11 @@ int mt7615_register_device(struct mt7615_dev *dev) wiphy->iface_combinations = if_comb; wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); + wiphy->reg_notifier = mt7615_regd_notifier; + wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); - ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER); ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN); dev->mt76.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING; @@ -241,14 +303,7 @@ 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; - - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | -#ifdef CONFIG_MAC80211_MESH - BIT(NL80211_IFTYPE_MESH_POINT) | -#endif - BIT(NL80211_IFTYPE_AP); + dev->dfs_state = -1; ret = mt76_register_device(&dev->mt76, true, mt7615_rates, ARRAY_SIZE(mt7615_rates)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 1eb0e9c9970c..c77adc5d2552 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -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) @@ -232,11 +275,9 @@ void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, struct mt76_txwi_cache *t; struct mt7615_dev *dev; struct mt7615_txp *txp; - u8 *txwi_ptr; - txwi_ptr = mt76_get_txwi_ptr(mdev, e->txwi); - txp = (struct mt7615_txp *)(txwi_ptr + MT_TXD_SIZE); dev = container_of(mdev, struct mt7615_dev, mt76); + txp = mt7615_txwi_to_txp(mdev, e->txwi); spin_lock_bh(&dev->token_lock); t = idr_remove(&dev->token, le16_to_cpu(txp->token)); @@ -248,12 +289,13 @@ void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, mt76_tx_complete_skb(mdev, e->skb); } -u16 mt7615_mac_tx_rate_val(struct mt7615_dev *dev, - const struct ieee80211_tx_rate *rate, - bool stbc, u8 *bw) +static u16 +mt7615_mac_tx_rate_val(struct mt7615_dev *dev, + const struct ieee80211_tx_rate *rate, + bool stbc, u8 *bw) { u8 phy, nss, rate_idx; - u16 rateval; + u16 rateval = 0; *bw = 0; @@ -291,12 +333,14 @@ u16 mt7615_mac_tx_rate_val(struct mt7615_dev *dev, rate_idx = val & 0xff; } - rateval = (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) | - FIELD_PREP(MT_TX_RATE_MODE, phy) | - FIELD_PREP(MT_TX_RATE_NSS, nss - 1)); - - if (stbc && nss == 1) + if (stbc && nss == 1) { + nss++; rateval |= MT_TX_RATE_STBC; + } + + rateval |= (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) | + FIELD_PREP(MT_TX_RATE_MODE, phy) | + FIELD_PREP(MT_TX_RATE_NSS, nss - 1)); return rateval; } @@ -309,9 +353,10 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rate = &info->control.rates[0]; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + bool multicast = is_multicast_ether_addr(hdr->addr1); struct ieee80211_vif *vif = info->control.vif; int tx_count = 8; - u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0; + u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0; __le16 fc = hdr->frame_control; u16 seqno = 0; u32 val; @@ -320,6 +365,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; omac_idx = mvif->omac_idx; + wmm_idx = mvif->wmm_idx; } if (sta) { @@ -331,8 +377,9 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2; fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4; - if (ieee80211_is_data(fc)) { - q_idx = skb_get_queue_mapping(skb); + if (ieee80211_is_data(fc) || ieee80211_is_bufferable_mmpdu(fc)) { + q_idx = wmm_idx * MT7615_MAX_WMM_SETS + + skb_get_queue_mapping(skb); p_fmt = MT_TX_TYPE_CT; } else if (ieee80211_is_beacon(fc)) { q_idx = MT_LMAC_BCN0; @@ -360,8 +407,18 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) | FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) | - FIELD_PREP(MT_TXD2_MULTICAST, - is_multicast_ether_addr(hdr->addr1)); + FIELD_PREP(MT_TXD2_MULTICAST, multicast); + if (key) { + if (multicast && ieee80211_is_robust_mgmt_frame(skb) && + key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + val |= MT_TXD2_BIP; + txwi[3] = 0; + } else { + txwi[3] = cpu_to_le32(MT_TXD3_PROTECT_FRAME); + } + } else { + txwi[3] = 0; + } txwi[2] = cpu_to_le32(val); if (!(info->flags & IEEE80211_TX_CTL_AMPDU)) @@ -418,14 +475,11 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, } val |= FIELD_PREP(MT_TXD3_SEQ, seqno); - txwi[3] = cpu_to_le32(val); + txwi[3] |= cpu_to_le32(val); if (info->flags & IEEE80211_TX_CTL_NO_ACK) txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK); - if (key) - txwi[3] |= cpu_to_le32(MT_TXD3_PROTECT_FRAME); - txwi[7] = FIELD_PREP(MT_TXD7_TYPE, fc_type) | FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype); @@ -436,16 +490,400 @@ void mt7615_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t) { struct mt7615_txp *txp; - u8 *txwi; int i; - txwi = mt76_get_txwi_ptr(dev, t); - txp = (struct mt7615_txp *)(txwi + MT_TXD_SIZE); + txp = mt7615_txwi_to_txp(dev, t); for (i = 1; i < txp->nbuf; i++) dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]), le16_to_cpu(txp->len[i]), DMA_TO_DEVICE); } +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) +{ + struct ieee80211_tx_rate *ref; + int wcid = sta->wcid.idx; + u32 addr = mt7615_mac_wtbl_addr(wcid); + bool stbc = false; + int n_rates = sta->n_rates; + u8 bw, bw_prev, bw_idx = 0; + u16 val[4]; + u16 probe_val; + u32 w5, w27; + bool rateset; + int i, k; + + if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) + return; + + for (i = n_rates; i < 4; i++) + rates[i] = rates[n_rates - 1]; + + rateset = !(sta->rate_set_tsf & BIT(0)); + memcpy(sta->rateset[rateset].rates, rates, + sizeof(sta->rateset[rateset].rates)); + if (probe_rate) { + sta->rateset[rateset].probe_rate = *probe_rate; + ref = &sta->rateset[rateset].probe_rate; + } else { + sta->rateset[rateset].probe_rate.idx = -1; + ref = &sta->rateset[rateset].rates[0]; + } + + rates = sta->rateset[rateset].rates; + for (i = 0; i < ARRAY_SIZE(sta->rateset[rateset].rates); i++) { + /* + * We don't support switching between short and long GI + * within the rate set. For accurate tx status reporting, we + * need to make sure that flags match. + * For improved performance, avoid duplicate entries by + * decrementing the MCS index if necessary + */ + if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI) + rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI; + + for (k = 0; k < i; k++) { + if (rates[i].idx != rates[k].idx) + continue; + if ((rates[i].flags ^ rates[k].flags) & + (IEEE80211_TX_RC_40_MHZ_WIDTH | + IEEE80211_TX_RC_80_MHZ_WIDTH | + IEEE80211_TX_RC_160_MHZ_WIDTH)) + continue; + + if (!rates[i].idx) + continue; + + rates[i].idx--; + } + } + + val[0] = mt7615_mac_tx_rate_val(dev, &rates[0], stbc, &bw); + bw_prev = bw; + + if (probe_rate) { + probe_val = mt7615_mac_tx_rate_val(dev, probe_rate, stbc, &bw); + if (bw) + bw_idx = 1; + else + bw_prev = 0; + } else { + probe_val = val[0]; + } + + val[1] = mt7615_mac_tx_rate_val(dev, &rates[1], stbc, &bw); + if (bw_prev) { + bw_idx = 3; + bw_prev = bw; + } + + val[2] = mt7615_mac_tx_rate_val(dev, &rates[2], stbc, &bw); + if (bw_prev) { + bw_idx = 5; + bw_prev = bw; + } + + val[3] = mt7615_mac_tx_rate_val(dev, &rates[3], stbc, &bw); + if (bw_prev) + bw_idx = 7; + + w27 = mt76_rr(dev, addr + 27 * 4); + w27 &= ~MT_WTBL_W27_CC_BW_SEL; + w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, bw); + + w5 = mt76_rr(dev, addr + 5 * 4); + w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE | + MT_WTBL_W5_MPDU_OK_COUNT | + MT_WTBL_W5_MPDU_FAIL_COUNT | + MT_WTBL_W5_RATE_IDX); + w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, bw) | + FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, bw_idx ? bw_idx - 1 : 7); + + mt76_wr(dev, MT_WTBL_RIUCR0, w5); + + mt76_wr(dev, MT_WTBL_RIUCR1, + FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) | + FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[1])); + + mt76_wr(dev, MT_WTBL_RIUCR2, + FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[1] >> 8) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[2]) | + FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2])); + + mt76_wr(dev, MT_WTBL_RIUCR3, + FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[3]) | + FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3])); + + mt76_wr(dev, MT_WTBL_UPDATE, + FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) | + MT_WTBL_UPDATE_RATE_UPDATE | + MT_WTBL_UPDATE_TX_COUNT_CLEAR); + + mt76_wr(dev, addr + 27 * 4, w27); + + mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */ + sta->rate_set_tsf = (mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0)) | rateset; + + if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) + mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); + + sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates; + sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; +} + +static enum mt7615_cipher_type +mt7615_mac_get_cipher(int cipher) +{ + switch (cipher) { + case WLAN_CIPHER_SUITE_WEP40: + return MT_CIPHER_WEP40; + case WLAN_CIPHER_SUITE_WEP104: + return MT_CIPHER_WEP104; + case WLAN_CIPHER_SUITE_TKIP: + return MT_CIPHER_TKIP; + case WLAN_CIPHER_SUITE_AES_CMAC: + return MT_CIPHER_BIP_CMAC_128; + case WLAN_CIPHER_SUITE_CCMP: + return MT_CIPHER_AES_CCMP; + case WLAN_CIPHER_SUITE_CCMP_256: + return MT_CIPHER_CCMP_256; + case WLAN_CIPHER_SUITE_GCMP: + return MT_CIPHER_GCMP; + case WLAN_CIPHER_SUITE_GCMP_256: + return MT_CIPHER_GCMP_256; + case WLAN_CIPHER_SUITE_SMS4: + return MT_CIPHER_WAPI; + default: + return MT_CIPHER_NONE; + } +} + +static int +mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, + enum mt7615_cipher_type cipher, + enum set_key_cmd cmd) +{ + u32 addr = mt7615_mac_wtbl_addr(wcid->idx) + 30 * 4; + u8 data[32] = {}; + + if (key->keylen > sizeof(data)) + return -EINVAL; + + mt76_rr_copy(dev, addr, data, sizeof(data)); + if (cmd == SET_KEY) { + if (cipher == MT_CIPHER_TKIP) { + /* Rx/Tx MIC keys are swapped */ + memcpy(data + 16, key->key + 24, 8); + memcpy(data + 24, key->key + 16, 8); + } + if (cipher != MT_CIPHER_BIP_CMAC_128 && wcid->cipher) + memmove(data + 16, data, 16); + if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher) + memcpy(data, key->key, key->keylen); + else if (cipher == MT_CIPHER_BIP_CMAC_128) + memcpy(data + 16, key->key, 16); + } else { + if (wcid->cipher & ~BIT(cipher)) { + if (cipher != MT_CIPHER_BIP_CMAC_128) + memmove(data, data + 16, 16); + memset(data + 16, 0, 16); + } else { + memset(data, 0, sizeof(data)); + } + } + mt76_wr_copy(dev, addr, data, sizeof(data)); + + return 0; +} + +static int +mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid, + enum mt7615_cipher_type cipher, int keyidx, + enum set_key_cmd cmd) +{ + u32 addr = mt7615_mac_wtbl_addr(wcid->idx), w0, w1; + + if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) + return -ETIMEDOUT; + + w0 = mt76_rr(dev, addr); + w1 = mt76_rr(dev, addr + 4); + if (cmd == SET_KEY) { + w0 |= MT_WTBL_W0_RX_KEY_VALID | + FIELD_PREP(MT_WTBL_W0_RX_IK_VALID, + cipher == MT_CIPHER_BIP_CMAC_128); + if (cipher != MT_CIPHER_BIP_CMAC_128 || + !wcid->cipher) + w0 |= FIELD_PREP(MT_WTBL_W0_KEY_IDX, keyidx); + } else { + if (!(wcid->cipher & ~BIT(cipher))) + w0 &= ~(MT_WTBL_W0_RX_KEY_VALID | + MT_WTBL_W0_KEY_IDX); + if (cipher == MT_CIPHER_BIP_CMAC_128) + w0 &= ~MT_WTBL_W0_RX_IK_VALID; + } + mt76_wr(dev, MT_WTBL_RICR0, w0); + mt76_wr(dev, MT_WTBL_RICR1, w1); + + if (!mt7615_mac_wtbl_update(dev, wcid->idx, + MT_WTBL_UPDATE_RXINFO_UPDATE)) + return -ETIMEDOUT; + + return 0; +} + +static void +mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid, + enum mt7615_cipher_type cipher, + enum set_key_cmd cmd) +{ + u32 addr = mt7615_mac_wtbl_addr(wcid->idx); + + if (cmd == SET_KEY) { + if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher) + mt76_rmw(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE, + FIELD_PREP(MT_WTBL_W2_KEY_TYPE, cipher)); + } else { + if (cipher != MT_CIPHER_BIP_CMAC_128 && + wcid->cipher & BIT(MT_CIPHER_BIP_CMAC_128)) + mt76_rmw(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE, + FIELD_PREP(MT_WTBL_W2_KEY_TYPE, + MT_CIPHER_BIP_CMAC_128)); + else if (!(wcid->cipher & ~BIT(cipher))) + mt76_clear(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE); + } +} + +int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, + struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, + enum set_key_cmd cmd) +{ + enum mt7615_cipher_type cipher; + int err; + + cipher = mt7615_mac_get_cipher(key->cipher); + if (cipher == MT_CIPHER_NONE) + return -EOPNOTSUPP; + + spin_lock_bh(&dev->mt76.lock); + + mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cmd); + err = mt7615_mac_wtbl_update_key(dev, wcid, key, cipher, cmd); + if (err < 0) + goto out; + + err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx, + cmd); + if (err < 0) + goto out; + + if (cmd == SET_KEY) + wcid->cipher |= BIT(cipher); + else + wcid->cipher &= ~BIT(cipher); + +out: + spin_unlock_bh(&dev->mt76.lock); + + return err; +} + int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, struct ieee80211_sta *sta, @@ -469,9 +907,9 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { spin_lock_bh(&dev->mt76.lock); - msta->rate_probe = true; - mt7615_mcu_set_rates(dev, msta, &info->control.rates[0], + mt7615_mac_set_rates(dev, msta, &info->control.rates[0], msta->rates); + msta->rate_probe = true; spin_unlock_bh(&dev->mt76.lock); } @@ -523,9 +961,13 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, struct ieee80211_tx_info *info, __le32 *txs_data) { struct ieee80211_supported_band *sband; - int i, idx, count, final_idx = 0; + struct mt7615_rate_set *rs; + int first_idx = 0, last_idx; + int i, idx, count; bool fixed_rate, ack_timeout; bool probe, ampdu, cck = false; + bool rs_idx; + u32 rate_set_tsf; u32 final_rate, final_rate_flags, final_nss, txs; fixed_rate = info->status.rates[0].count; @@ -536,6 +978,7 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, txs = le32_to_cpu(txs_data[3]); count = FIELD_GET(MT_TXS3_TX_COUNT, txs); + last_idx = FIELD_GET(MT_TXS3_LAST_TX_RATE, txs); txs = le32_to_cpu(txs_data[0]); final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs); @@ -557,38 +1000,59 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta, if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU)) info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU; + first_idx = max_t(int, 0, last_idx - (count + 1) / MT7615_RATE_RETRY); + if (fixed_rate && !probe) { info->status.rates[0].count = count; + i = 0; goto out; } - for (i = 0, idx = 0; i < ARRAY_SIZE(info->status.rates); i++) { - int cur_count = min_t(int, count, 2 * MT7615_RATE_RETRY); + rate_set_tsf = READ_ONCE(sta->rate_set_tsf); + rs_idx = !((u32)(FIELD_GET(MT_TXS4_F0_TIMESTAMP, le32_to_cpu(txs_data[4])) - + rate_set_tsf) < 1000000); + rs_idx ^= rate_set_tsf & BIT(0); + rs = &sta->rateset[rs_idx]; - if (!i && probe) { - cur_count = 1; - } else { - info->status.rates[i] = sta->rates[idx]; - idx++; - } + if (!first_idx && rs->probe_rate.idx >= 0) { + info->status.rates[0] = rs->probe_rate; - if (i && info->status.rates[i].idx < 0) { - info->status.rates[i - 1].count += count; - break; + spin_lock_bh(&dev->mt76.lock); + if (sta->rate_probe) { + mt7615_mac_set_rates(dev, sta, NULL, sta->rates); + sta->rate_probe = false; } + spin_unlock_bh(&dev->mt76.lock); + } else { + info->status.rates[0] = rs->rates[first_idx / 2]; + } + info->status.rates[0].count = 0; - if (!count) { - info->status.rates[i].idx = -1; - break; - } + for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) { + struct ieee80211_tx_rate *cur_rate; + int cur_count; - info->status.rates[i].count = cur_count; - final_idx = i; + cur_rate = &rs->rates[idx / 2]; + cur_count = min_t(int, MT7615_RATE_RETRY, count); count -= cur_count; + + 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)) { + i--; + break; + } + + info->status.rates[i] = *cur_rate; + info->status.rates[i].count = 0; + } + + info->status.rates[i].count += cur_count; } out: - final_rate_flags = info->status.rates[final_idx].flags; + final_rate_flags = info->status.rates[i].flags; switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) { case MT_PHY_TYPE_CCK: @@ -613,6 +1077,10 @@ out: break; case MT_PHY_TYPE_VHT: final_nss = FIELD_GET(MT_TX_RATE_NSS, final_rate); + + if ((final_rate & MT_TX_RATE_STBC) && final_nss) + final_nss--; + final_rate_flags |= IEEE80211_TX_RC_VHT_MCS; final_rate = (final_rate & MT_TX_RATE_IDX) | (final_nss << 4); break; @@ -620,8 +1088,8 @@ out: return false; } - info->status.rates[final_idx].idx = final_rate; - info->status.rates[final_idx].flags = final_rate_flags; + info->status.rates[i].idx = final_rate; + info->status.rates[i].flags = final_rate_flags; return true; } @@ -642,16 +1110,6 @@ static bool mt7615_mac_add_txs_skb(struct mt7615_dev *dev, if (skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) { - spin_lock_bh(&dev->mt76.lock); - if (sta->rate_probe) { - mt7615_mcu_set_rates(dev, sta, NULL, - sta->rates); - sta->rate_probe = false; - } - spin_unlock_bh(&dev->mt76.lock); - } - if (!mt7615_fill_txs(dev, sta, info, txs_data)) { ieee80211_tx_info_clear_status(info); info->status.rates[0].idx = -1; @@ -695,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; @@ -735,14 +1198,313 @@ void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb) dev_kfree_skb(skb); } +static void +mt7615_mac_set_default_sensitivity(struct mt7615_dev *dev) +{ + mt76_rmw(dev, MT_WF_PHY_B0_MIN_PRI_PWR, + MT_WF_PHY_B0_PD_OFDM_MASK, + MT_WF_PHY_B0_PD_OFDM(0x13c)); + mt76_rmw(dev, MT_WF_PHY_B1_MIN_PRI_PWR, + MT_WF_PHY_B1_PD_OFDM_MASK, + MT_WF_PHY_B1_PD_OFDM(0x13c)); + + mt76_rmw(dev, MT_WF_PHY_B0_RXTD_CCK_PD, + MT_WF_PHY_B0_PD_CCK_MASK, + MT_WF_PHY_B0_PD_CCK(0x92)); + mt76_rmw(dev, MT_WF_PHY_B1_RXTD_CCK_PD, + MT_WF_PHY_B1_PD_CCK_MASK, + MT_WF_PHY_B1_PD_CCK(0x92)); + + dev->ofdm_sensitivity = -98; + dev->cck_sensitivity = -110; + dev->last_cca_adj = jiffies; +} + +void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable) +{ + mutex_lock(&dev->mt76.mutex); + + if (dev->scs_en == enable) + goto out; + + if (enable) { + /* DBDC not supported */ + mt76_set(dev, MT_WF_PHY_B0_MIN_PRI_PWR, + MT_WF_PHY_B0_PD_BLK); + if (is_mt7622(&dev->mt76)) { + mt76_set(dev, MT_MIB_M0_MISC_CR, 0x7 << 8); + mt76_set(dev, MT_MIB_M0_MISC_CR, 0x7); + } + } else { + mt76_clear(dev, MT_WF_PHY_B0_MIN_PRI_PWR, + MT_WF_PHY_B0_PD_BLK); + mt76_clear(dev, MT_WF_PHY_B1_MIN_PRI_PWR, + MT_WF_PHY_B1_PD_BLK); + } + + mt7615_mac_set_default_sensitivity(dev); + dev->scs_en = enable; + +out: + mutex_unlock(&dev->mt76.mutex); +} + +void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev) +{ + mt76_clear(dev, MT_WF_PHY_R0_B0_PHYMUX_5, GENMASK(22, 20)); + mt76_set(dev, MT_WF_PHY_R0_B0_PHYMUX_5, BIT(22) | BIT(20)); +} + +static void +mt7615_mac_adjust_sensitivity(struct mt7615_dev *dev, + u32 rts_err_rate, bool ofdm) +{ + int false_cca = ofdm ? dev->false_cca_ofdm : dev->false_cca_cck; + u16 def_th = ofdm ? -98 : -110; + bool update = false; + s8 *sensitivity; + int signal; + + sensitivity = ofdm ? &dev->ofdm_sensitivity : &dev->cck_sensitivity; + signal = mt76_get_min_avg_rssi(&dev->mt76); + if (!signal) { + mt7615_mac_set_default_sensitivity(dev); + return; + } + + signal = min(signal, -72); + if (false_cca > 500) { + if (rts_err_rate > MT_FRAC(40, 100)) + return; + + /* decrease coverage */ + if (*sensitivity == def_th && signal > -90) { + *sensitivity = -90; + update = true; + } else if (*sensitivity + 2 < signal) { + *sensitivity += 2; + update = true; + } + } else if ((false_cca > 0 && false_cca < 50) || + rts_err_rate > MT_FRAC(60, 100)) { + /* increase coverage */ + if (*sensitivity - 2 >= def_th) { + *sensitivity -= 2; + update = true; + } + } + + if (*sensitivity > signal) { + *sensitivity = signal; + update = true; + } + + if (update) { + u16 val; + + if (ofdm) { + /* DBDC not supported */ + val = *sensitivity * 2 + 512; + mt76_rmw(dev, MT_WF_PHY_B0_MIN_PRI_PWR, + MT_WF_PHY_B0_PD_OFDM_MASK, + MT_WF_PHY_B0_PD_OFDM(val)); + } else { + val = *sensitivity + 256; + mt76_rmw(dev, MT_WF_PHY_B0_RXTD_CCK_PD, + MT_WF_PHY_B0_PD_CCK_MASK, + MT_WF_PHY_B0_PD_CCK(val)); + mt76_rmw(dev, MT_WF_PHY_B1_RXTD_CCK_PD, + MT_WF_PHY_B1_PD_CCK_MASK, + MT_WF_PHY_B1_PD_CCK(val)); + } + dev->last_cca_adj = jiffies; + } +} + +static void +mt7615_mac_scs_check(struct mt7615_dev *dev) +{ + u32 val, rts_cnt = 0, rts_retries_cnt = 0, rts_err_rate = 0; + u32 mdrdy_cck, mdrdy_ofdm, pd_cck, pd_ofdm; + int i; + + if (!dev->scs_en) + return; + + for (i = 0; i < 4; i++) { + u32 data; + + val = mt76_rr(dev, MT_MIB_MB_SDR0(i)); + data = FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val); + if (data > rts_retries_cnt) { + rts_cnt = FIELD_GET(MT_MIB_RTS_COUNT_MASK, val); + rts_retries_cnt = data; + } + } + + val = mt76_rr(dev, MT_WF_PHY_R0_B0_PHYCTRL_STS0); + pd_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_CCK, val); + pd_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_OFDM, val); + + val = mt76_rr(dev, MT_WF_PHY_R0_B0_PHYCTRL_STS5); + mdrdy_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_CCK, val); + mdrdy_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_OFDM, val); + + dev->false_cca_ofdm = pd_ofdm - mdrdy_ofdm; + dev->false_cca_cck = pd_cck - mdrdy_cck; + mt7615_mac_cca_stats_reset(dev); + + if (rts_cnt + rts_retries_cnt) + rts_err_rate = MT_FRAC(rts_retries_cnt, + rts_cnt + rts_retries_cnt); + + /* cck */ + mt7615_mac_adjust_sensitivity(dev, rts_err_rate, false); + /* ofdm */ + mt7615_mac_adjust_sensitivity(dev, rts_err_rate, true); + + if (time_after(jiffies, dev->last_cca_adj + 10 * HZ)) + mt7615_mac_set_default_sensitivity(dev); +} + +void mt7615_update_channel(struct mt76_dev *mdev) +{ + struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); + struct mt76_channel_state *state; + u64 busy_time, tx_time, rx_time, obss_time; + + /* TODO: add DBDC support */ + 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); + + 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); + 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); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, MT7615_WATCHDOG_TIME); } + +int mt7615_dfs_stop_radar_detector(struct mt7615_dev *dev) +{ + struct cfg80211_chan_def *chandef = &dev->mt76.chandef; + int err; + + err = mt7615_mcu_rdd_cmd(dev, RDD_STOP, MT_HW_RDD0, + MT_RX_SEL0, 0); + if (err < 0) + return err; + + if (chandef->width == NL80211_CHAN_WIDTH_160 || + chandef->width == NL80211_CHAN_WIDTH_80P80) + err = mt7615_mcu_rdd_cmd(dev, RDD_STOP, MT_HW_RDD1, + MT_RX_SEL0, 0); + return err; +} + +static int mt7615_dfs_start_rdd(struct mt7615_dev *dev, int chain) +{ + int err; + + err = mt7615_mcu_rdd_cmd(dev, RDD_START, chain, MT_RX_SEL0, 0); + if (err < 0) + return err; + + return mt7615_mcu_rdd_cmd(dev, RDD_DET_MODE, chain, + MT_RX_SEL0, 1); +} + +int mt7615_dfs_start_radar_detector(struct mt7615_dev *dev) +{ + struct cfg80211_chan_def *chandef = &dev->mt76.chandef; + int err; + + /* start CAC */ + err = mt7615_mcu_rdd_cmd(dev, RDD_CAC_START, MT_HW_RDD0, + MT_RX_SEL0, 0); + if (err < 0) + return err; + + /* TODO: DBDC support */ + + err = mt7615_dfs_start_rdd(dev, MT_HW_RDD0); + if (err < 0) + return err; + + if (chandef->width == NL80211_CHAN_WIDTH_160 || + chandef->width == NL80211_CHAN_WIDTH_80P80) { + err = mt7615_dfs_start_rdd(dev, MT_HW_RDD1); + if (err < 0) + return err; + } + + return 0; +} + +int mt7615_dfs_init_radar_detector(struct mt7615_dev *dev) +{ + struct cfg80211_chan_def *chandef = &dev->mt76.chandef; + int err; + + if (dev->mt76.region == NL80211_DFS_UNSET) + return 0; + + if (test_bit(MT76_SCANNING, &dev->mt76.state)) + return 0; + + if (dev->dfs_state == chandef->chan->dfs_state) + return 0; + + dev->dfs_state = chandef->chan->dfs_state; + + if (chandef->chan->flags & IEEE80211_CHAN_RADAR) { + if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE) + return mt7615_dfs_start_radar_detector(dev); + else + return mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, MT_HW_RDD0, + MT_RX_SEL0, 0); + } else { + err = mt7615_mcu_rdd_cmd(dev, RDD_NORMAL_START, + MT_HW_RDD0, MT_RX_SEL0, 0); + if (err < 0) + return err; + + return mt7615_dfs_stop_radar_detector(dev); + } +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h index b00ce8db58e9..38695d4f92e2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h @@ -302,4 +302,32 @@ struct mt7615_tx_free { #define MT_TXS6_F1_RCPI_1 GENMASK(15, 8) #define MT_TXS6_F1_RCPI_0 GENMASK(7, 0) +enum mt7615_cipher_type { + MT_CIPHER_NONE, + MT_CIPHER_WEP40, + MT_CIPHER_TKIP, + MT_CIPHER_TKIP_NO_MIC, + MT_CIPHER_AES_CCMP, + MT_CIPHER_WEP104, + MT_CIPHER_BIP_CMAC_128, + MT_CIPHER_WEP128, + MT_CIPHER_WAPI, + MT_CIPHER_CCMP_256 = 10, + MT_CIPHER_GCMP, + MT_CIPHER_GCMP_256, +}; + +static inline struct mt7615_txp * +mt7615_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t) +{ + u8 *txwi; + + if (!t) + return NULL; + + txwi = mt76_get_txwi_ptr(dev, t); + + return (struct mt7615_txp *)(txwi + MT_TXD_SIZE); +} + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index b4d6af812c54..070b03403894 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -16,6 +16,9 @@ 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, MT7615_WATCHDOG_TIME); @@ -38,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; @@ -57,7 +61,7 @@ static int get_omac_idx(enum nl80211_iftype type, u32 mask) default: WARN_ON(1); break; - }; + } return -1; } @@ -85,9 +89,9 @@ static int mt7615_add_interface(struct ieee80211_hw *hw, } mvif->omac_idx = idx; - /* TODO: DBDC support. Use band 0 and wmm 0 for now */ + /* TODO: DBDC support. Use band 0 for now */ mvif->band_idx = 0; - mvif->wmm_idx = 0; + mvif->wmm_idx = mvif->idx % MT7615_MAX_WMM_SETS; ret = mt7615_mcu_set_dev_info(dev, vif, 1); if (ret) @@ -96,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; @@ -114,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 */ @@ -128,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) @@ -135,20 +149,32 @@ static int mt7615_set_channel(struct mt7615_dev *dev) int ret; cancel_delayed_work_sync(&dev->mt76.mac_work); + + mutex_lock(&dev->mt76.mutex); set_bit(MT76_RESET, &dev->mt76.state); + mt7615_dfs_check_channel(dev); + mt76_set_channel(&dev->mt76); ret = mt7615_mcu_set_channel(dev); if (ret) - return ret; + goto out; + ret = mt7615_dfs_init_radar_detector(dev); + mt7615_mac_cca_stats_reset(dev); + dev->mt76.survey_time = ktime_get_boottime(); + + mt7615_mac_reset_counters(dev); + +out: clear_bit(MT76_RESET, &dev->mt76.state); + mutex_unlock(&dev->mt76.mutex); mt76_txq_schedule_all(&dev->mt76); ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, MT7615_WATCHDOG_TIME); - return 0; + return ret; } static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -172,18 +198,34 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) return -EOPNOTSUPP; + /* fall back to sw encryption for unsupported ciphers */ + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; + break; + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + case WLAN_CIPHER_SUITE_SMS4: + break; + default: + return -EOPNOTSUPP; + } + if (cmd == SET_KEY) { key->hw_key_idx = wcid->idx; wcid->hw_key_idx = idx; - } else { - if (idx == wcid->hw_key_idx) - wcid->hw_key_idx = -1; - - key = NULL; + } else if (idx == wcid->hw_key_idx) { + wcid->hw_key_idx = -1; } - mt76_wcid_key_setup(&dev->mt76, wcid, key); + mt76_wcid_key_setup(&dev->mt76, wcid, + cmd == SET_KEY ? key : NULL); - return mt7615_mcu_set_wtbl_key(dev, wcid->idx, key, cmd); + return mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); } static int mt7615_config(struct ieee80211_hw *hw, u32 changed) @@ -191,14 +233,14 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed) struct mt7615_dev *dev = hw->priv; int ret = 0; - mutex_lock(&dev->mt76.mutex); - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { ieee80211_stop_queues(hw); ret = mt7615_set_channel(dev); ieee80211_wake_queues(hw); } + mutex_lock(&dev->mt76.mutex); + if (changed & IEEE80211_CONF_CHANGE_POWER) ret = mt7615_mcu_set_tx_power(dev); @@ -220,16 +262,12 @@ static int mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt7615_dev *dev = hw->priv; - static const u8 wmm_queue_map[] = { - [IEEE80211_AC_BK] = 0, - [IEEE80211_AC_BE] = 1, - [IEEE80211_AC_VI] = 2, - [IEEE80211_AC_VO] = 3, - }; - - /* TODO: hw wmm_set 1~3 */ - return mt7615_mcu_set_wmm(dev, wmm_queue_map[queue], params); + + queue += mvif->wmm_idx * MT7615_MAX_WMM_SETS; + + return mt7615_mcu_set_wmm(dev, queue, params); } static void mt7615_configure_filter(struct ieee80211_hw *hw, @@ -238,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 { \ @@ -271,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, @@ -299,6 +347,18 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&dev->mt76.mutex); } +static void +mt7615_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct mt7615_dev *dev = hw->priv; + + mutex_lock(&dev->mt76.mutex); + mt7615_mcu_set_bcn(dev, vif, true); + mutex_unlock(&dev->mt76.mutex); +} + int mt7615_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { @@ -311,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); @@ -334,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, @@ -358,7 +430,7 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, break; } msta->n_rates = i; - mt7615_mcu_set_rates(dev, msta, NULL, msta->rates); + mt7615_mac_set_rates(dev, msta, NULL, msta->rates); msta->rate_probe = false; spin_unlock_bh(&dev->mt76.lock); } @@ -410,17 +482,19 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_txq *txq = sta->txq[params->tid]; struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; u16 tid = params->tid; - u16 *ssn = ¶ms->ssn; + u16 ssn = params->ssn; struct mt76_txq *mtxq; + int ret = 0; if (!txq) return -EINVAL; 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, + mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, params->buf_size); mt7615_mcu_set_rx_ba(dev, params, 1); break; @@ -436,12 +510,11 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; - ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); mt7615_mcu_set_tx_ba(dev, params, 0); break; case IEEE80211_AMPDU_TX_START: - mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(*ssn); - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; @@ -449,25 +522,9 @@ 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; -} - -static void -mt7615_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - const u8 *mac) -{ - struct mt7615_dev *dev = hw->priv; - - set_bit(MT76_SCANNING, &dev->mt76.state); -} - -static void -mt7615_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct mt7615_dev *dev = hw->priv; - - clear_bit(MT76_SCANNING, &dev->mt76.state); + return ret; } const struct ieee80211_ops mt7615_ops = { @@ -486,8 +543,11 @@ const struct ieee80211_ops mt7615_ops = { .set_rts_threshold = mt7615_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, .sta_rate_tbl_update = mt7615_sta_rate_tbl_update, - .sw_scan_start = mt7615_sw_scan, - .sw_scan_complete = mt7615_sw_scan_complete, + .sw_scan_start = mt76_sw_scan, + .sw_scan_complete = mt76_sw_scan_complete, .release_buffered_frames = mt76_release_buffered_frames, .get_txpower = mt76_get_txpower, + .channel_switch_beacon = mt7615_channel_switch_beacon, + .get_survey = mt76_get_survey, + .get_antenna = mt76_get_antenna, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index cdad2c8dc297..f229c9ce9f65 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -75,7 +75,7 @@ static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb, txd = mcu_txd->txd; - val = FIELD_PREP(MT_TXD0_TX_BYTES, cpu_to_le16(skb->len)) | + val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) | FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_MCU) | FIELD_PREP(MT_TXD0_Q_IDX, q_idx); txd[0] = cpu_to_le32(val); @@ -113,12 +113,38 @@ static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb, } static int +mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd, + struct sk_buff *skb, int seq) +{ + struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; + int ret = 0; + + if (seq != rxd->seq) + return -EAGAIN; + + switch (cmd) { + case -MCU_CMD_PATCH_SEM_CONTROL: + skb_pull(skb, sizeof(*rxd) - 4); + ret = *skb->data; + break; + case MCU_EXT_CMD_GET_TEMP: + skb_pull(skb, sizeof(*rxd)); + ret = le32_to_cpu(*(__le32 *)skb->data); + break; + default: + break; + } + dev_kfree_skb(skb); + + return ret; +} + +static int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, int len, bool wait_resp) { struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); unsigned long expires = jiffies + 10 * HZ; - struct mt7615_mcu_rxd *rxd; struct sk_buff *skb; int ret, seq; @@ -141,16 +167,9 @@ mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, break; } - rxd = (struct mt7615_mcu_rxd *)skb->data; - if (seq != rxd->seq) - continue; - - if (cmd == -MCU_CMD_PATCH_SEM_CONTROL) { - skb_pull(skb, sizeof(*rxd) - 4); - ret = *skb->data; - } - dev_kfree_skb(skb); - break; + ret = mt7615_mcu_parse_response(dev, cmd, skb, seq); + if (ret != -EAGAIN) + break; } out: @@ -159,6 +178,62 @@ out: return ret; } +static void +mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + if (vif->csa_active) + ieee80211_csa_finish(vif); +} + +static void +mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb) +{ + struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; + + switch (rxd->ext_eid) { + case MCU_EXT_EVENT_RDD_REPORT: + ieee80211_radar_detected(dev->mt76.hw); + dev->hw_pattern++; + break; + case MCU_EXT_EVENT_CSA_NOTIFY: + ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7615_mcu_csa_finish, dev); + break; + default: + break; + } +} + +static void +mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb) +{ + struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; + + switch (rxd->eid) { + case MCU_EVENT_EXT: + mt7615_mcu_rx_ext_event(dev, skb); + break; + default: + break; + } + dev_kfree_skb(skb); +} + +void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb) +{ + struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data; + + if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT || + rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST || + rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP || + rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC || + !rxd->seq) + mt7615_mcu_rx_unsolicited_event(dev, skb); + else + mt76_mcu_rx_event(&dev->mt76, skb); +} + static int mt7615_mcu_init_download(struct mt7615_dev *dev, u32 addr, u32 len, u32 mode) { @@ -192,6 +267,7 @@ static int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data, data += cur_len; len -= cur_len; + mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); } return ret; @@ -257,9 +333,8 @@ static int mt7615_driver_own(struct mt7615_dev *dev) static int mt7615_load_patch(struct mt7615_dev *dev) { - const struct firmware *fw; const struct mt7615_patch_hdr *hdr; - const char *firmware = MT7615_ROM_PATCH; + const struct firmware *fw = NULL; int len, ret, sem; sem = mt7615_mcu_patch_sem_ctrl(dev, 1); @@ -273,9 +348,9 @@ static int mt7615_load_patch(struct mt7615_dev *dev) return -EAGAIN; } - ret = request_firmware(&fw, firmware, dev->mt76.dev); + ret = request_firmware(&fw, MT7615_ROM_PATCH, dev->mt76.dev); if (ret) - return ret; + goto out; if (!fw || !fw->data || fw->size < sizeof(*hdr)) { dev_err(dev->mt76.dev, "Invalid firmware\n"); @@ -323,7 +398,7 @@ out: return ret; } -static u32 gen_dl_mode(u8 feature_set, bool is_cr4) +static u32 mt7615_mcu_gen_dl_mode(u8 feature_set, bool is_cr4) { u32 ret = 0; @@ -337,16 +412,45 @@ static u32 gen_dl_mode(u8 feature_set, bool is_cr4) return ret; } +static int +mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev, + const struct mt7615_fw_trailer *hdr, + const u8 *data, bool is_cr4) +{ + int n_region = is_cr4 ? CR4_REGION_NUM : N9_REGION_NUM; + int err, i, offset = 0; + u32 len, addr, mode; + + for (i = 0; i < n_region; i++) { + mode = mt7615_mcu_gen_dl_mode(hdr[i].feature_set, is_cr4); + len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN; + addr = le32_to_cpu(hdr[i].addr); + + err = mt7615_mcu_init_download(dev, addr, len, mode); + if (err) { + dev_err(dev->mt76.dev, "Download request failed\n"); + return err; + } + + err = mt7615_mcu_send_firmware(dev, data + offset, len); + if (err) { + dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); + return err; + } + + offset += len; + } + + return 0; +} + static int mt7615_load_ram(struct mt7615_dev *dev) { - const struct firmware *fw; const struct mt7615_fw_trailer *hdr; - const char *n9_firmware = MT7615_FIRMWARE_N9; - const char *cr4_firmware = MT7615_FIRMWARE_CR4; - u32 n9_ilm_addr, offset; - int i, ret; + const struct firmware *fw; + int ret; - ret = request_firmware(&fw, n9_firmware, dev->mt76.dev); + ret = request_firmware(&fw, MT7615_FIRMWARE_N9, dev->mt76.dev); if (ret) return ret; @@ -362,31 +466,12 @@ static int mt7615_load_ram(struct mt7615_dev *dev) dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n", hdr->fw_ver, hdr->build_date); - n9_ilm_addr = le32_to_cpu(hdr->addr); - - for (offset = 0, i = 0; i < N9_REGION_NUM; i++) { - u32 len, addr, mode; - - len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN; - addr = le32_to_cpu(hdr[i].addr); - mode = gen_dl_mode(hdr[i].feature_set, false); - - ret = mt7615_mcu_init_download(dev, addr, len, mode); - if (ret) { - dev_err(dev->mt76.dev, "Download request failed\n"); - goto out; - } - - ret = mt7615_mcu_send_firmware(dev, fw->data + offset, len); - if (ret) { - dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); - goto out; - } - - offset += len; - } + ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, false); + if (ret) + goto out; - ret = mt7615_mcu_start_firmware(dev, n9_ilm_addr, FW_START_OVERRIDE); + ret = mt7615_mcu_start_firmware(dev, le32_to_cpu(hdr->addr), + FW_START_OVERRIDE); if (ret) { dev_err(dev->mt76.dev, "Failed to start N9 firmware\n"); goto out; @@ -394,7 +479,7 @@ static int mt7615_load_ram(struct mt7615_dev *dev) release_firmware(fw); - ret = request_firmware(&fw, cr4_firmware, dev->mt76.dev); + ret = request_firmware(&fw, MT7615_FIRMWARE_CR4, dev->mt76.dev); if (ret) return ret; @@ -410,27 +495,9 @@ static int mt7615_load_ram(struct mt7615_dev *dev) dev_info(dev->mt76.dev, "CR4 Firmware Version: %.10s, Build Time: %.15s\n", hdr->fw_ver, hdr->build_date); - for (offset = 0, i = 0; i < CR4_REGION_NUM; i++) { - u32 len, addr, mode; - - len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN; - addr = le32_to_cpu(hdr[i].addr); - mode = gen_dl_mode(hdr[i].feature_set, true); - - ret = mt7615_mcu_init_download(dev, addr, len, mode); - if (ret) { - dev_err(dev->mt76.dev, "Download request failed\n"); - goto out; - } - - ret = mt7615_mcu_send_firmware(dev, fw->data + offset, len); - if (ret) { - dev_err(dev->mt76.dev, "Failed to send firmware to device\n"); - goto out; - } - - offset += len; - } + ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, true); + if (ret) + goto out; ret = mt7615_mcu_start_firmware(dev, 0, FW_START_WORKING_PDA_CR4); if (ret) @@ -469,6 +536,8 @@ static int mt7615_load_firmware(struct mt7615_dev *dev) return -EIO; } + mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false); + dev_dbg(dev->mt76.dev, "Firmware init done\n"); return 0; @@ -573,6 +642,8 @@ int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue, #define WMM_CW_MIN_SET BIT(1) #define WMM_CW_MAX_SET BIT(2) #define WMM_TXOP_SET BIT(3) +#define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \ + WMM_CW_MAX_SET | WMM_TXOP_SET) struct req_data { u8 number; u8 rsv[3]; @@ -585,19 +656,17 @@ int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue, } __packed req = { .number = 1, .queue = queue, - .valid = WMM_AIFS_SET | WMM_TXOP_SET, + .valid = WMM_PARAM_SET, .aifs = params->aifs, + .cw_min = 5, + .cw_max = cpu_to_le16(10), .txop = cpu_to_le16(params->txop), }; - if (params->cw_min) { - req.valid |= WMM_CW_MIN_SET; - req.cw_min = params->cw_min; - } - if (params->cw_max) { - req.valid |= WMM_CW_MAX_SET; - req.cw_max = cpu_to_le16(params->cw_max); - } + if (params->cw_min) + req.cw_min = fls(params->cw_min); + if (params->cw_max) + req.cw_max = cpu_to_le16(fls(params->cw_max)); return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req, sizeof(req), true); @@ -779,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; @@ -824,78 +898,6 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev, return ret; } -static enum mt7615_cipher_type -mt7615_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) -{ - if (!key || key->keylen > 32) - return MT_CIPHER_NONE; - - memcpy(key_data, key->key, key->keylen); - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - return MT_CIPHER_WEP40; - case WLAN_CIPHER_SUITE_WEP104: - return MT_CIPHER_WEP104; - case WLAN_CIPHER_SUITE_TKIP: - /* Rx/Tx MIC keys are swapped */ - memcpy(key_data + 16, key->key + 24, 8); - memcpy(key_data + 24, key->key + 16, 8); - return MT_CIPHER_TKIP; - case WLAN_CIPHER_SUITE_CCMP: - return MT_CIPHER_AES_CCMP; - case WLAN_CIPHER_SUITE_CCMP_256: - return MT_CIPHER_CCMP_256; - case WLAN_CIPHER_SUITE_GCMP: - return MT_CIPHER_GCMP; - case WLAN_CIPHER_SUITE_GCMP_256: - return MT_CIPHER_GCMP_256; - case WLAN_CIPHER_SUITE_SMS4: - return MT_CIPHER_WAPI; - default: - return MT_CIPHER_NONE; - } -} - -int mt7615_mcu_set_wtbl_key(struct mt7615_dev *dev, int wcid, - struct ieee80211_key_conf *key, - enum set_key_cmd cmd) -{ - struct { - struct wtbl_req_hdr hdr; - struct wtbl_sec_key key; - } req = { - .hdr = { - .wlan_idx = wcid, - .operation = WTBL_SET, - .tlv_num = cpu_to_le16(1), - }, - .key = { - .tag = cpu_to_le16(WTBL_SEC_KEY), - .len = cpu_to_le16(sizeof(struct wtbl_sec_key)), - .add = cmd, - }, - }; - - if (cmd == SET_KEY) { - u8 cipher; - - cipher = mt7615_get_key_info(key, req.key.key_material); - if (cipher == MT_CIPHER_NONE) - return -EOPNOTSUPP; - - req.key.rkv = 1; - req.key.cipher_id = cipher; - req.key.key_id = key->keyidx; - req.key.key_len = key->keylen; - } else { - req.key.key_len = sizeof(req.key.key_material); - } - - return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, - &req, sizeof(req), true); -} - static int mt7615_mcu_add_wtbl_bmc(struct mt7615_dev *dev, struct mt7615_vif *mvif) @@ -1076,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; @@ -1099,6 +1104,7 @@ int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif, { struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; struct mt76_wcid *wcid = &dev->mt76.global_wcid; + struct ieee80211_mutable_offsets offs; struct req { u8 omac_idx; u8 enable; @@ -1119,13 +1125,10 @@ int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif, .enable = en, .wlan_idx = wcid->idx, .band_idx = mvif->band_idx, - /* pky_type: 0 for bcn, 1 for tim */ - .pkt_type = 0, }; struct sk_buff *skb; - u16 tim_off; - skb = ieee80211_beacon_get_tim(mt76_hw(dev), vif, &tim_off, NULL); + skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs); if (!skb) return -EINVAL; @@ -1139,8 +1142,14 @@ int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif, 0, NULL); memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len); req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len); - req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + tim_off); + req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset); + if (offs.csa_counter_offs[0]) { + u16 csa_offs; + csa_offs = MT_TXD_SIZE + offs.csa_counter_offs[0] - 4; + req.csa_ie_pos = cpu_to_le16(csa_offs); + req.csa_cnt = skb->data[offs.csa_counter_offs[0]]; + } dev_kfree_skb(skb); return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BCN_OFFLOAD, @@ -1213,9 +1222,62 @@ out: return ret; } +int mt7615_mcu_rdd_cmd(struct mt7615_dev *dev, + enum mt7615_rdd_cmd cmd, u8 index, + u8 rx_sel, u8 val) +{ + struct { + u8 ctrl; + u8 rdd_idx; + u8 rdd_rx_sel; + u8 val; + u8 rsv[4]; + } req = { + .ctrl = cmd, + .rdd_idx = index, + .rdd_rx_sel = rx_sel, + .val = val, + }; + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL, + &req, sizeof(req), true); +} + +int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev) +{ + struct { + u8 pulse_num; + u8 rsv[3]; + struct { + u32 start_time; + u16 width; + s16 power; + } pattern[32]; + } req = { + .pulse_num = dev->radar_pattern.n_pulses, + }; + u32 start_time = ktime_to_ms(ktime_get_boottime()); + int i; + + if (dev->radar_pattern.n_pulses > ARRAY_SIZE(req.pattern)) + return -EINVAL; + + /* TODO: add some noise here */ + for (i = 0; i < dev->radar_pattern.n_pulses; i++) { + req.pattern[i].width = dev->radar_pattern.width; + req.pattern[i].power = dev->radar_pattern.power; + req.pattern[i].start_time = start_time + + i * dev->radar_pattern.period; + } + + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_PATTERN, + &req, sizeof(req), false); +} + int mt7615_mcu_set_channel(struct mt7615_dev *dev) { - struct cfg80211_chan_def *chdef = &dev->mt76.chandef; + struct cfg80211_chan_def *chandef = &dev->mt76.chandef; + int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; struct { u8 control_chan; u8 center_chan; @@ -1234,17 +1296,22 @@ int mt7615_mcu_set_channel(struct mt7615_dev *dev) u8 rsv1[3]; u8 txpower_sku[53]; u8 rsv2[3]; - } req = {0}; + } req = { + .control_chan = chandef->chan->hw_value, + .center_chan = ieee80211_frequency_to_channel(freq1), + .tx_streams = (dev->mt76.chainmask >> 8) & 0xf, + .rx_streams_mask = dev->mt76.antenna_mask, + .center_chan2 = ieee80211_frequency_to_channel(freq2), + }; int ret; - req.control_chan = chdef->chan->hw_value; - req.center_chan = ieee80211_frequency_to_channel(chdef->center_freq1); - req.tx_streams = (dev->mt76.chainmask >> 8) & 0xf; - req.rx_streams_mask = dev->mt76.antenna_mask; - req.switch_reason = CH_SWITCH_NORMAL; - req.band_idx = 0; - req.center_chan2 = ieee80211_frequency_to_channel(chdef->center_freq2); - req.txpower_drop = 0; + 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; switch (dev->mt76.chandef.width) { case NL80211_CHAN_WIDTH_40: @@ -1269,6 +1336,7 @@ int mt7615_mcu_set_channel(struct mt7615_dev *dev) case NL80211_CHAN_WIDTH_20: default: req.bw = CMD_CBW_20MHZ; + break; } memset(req.txpower_sku, 0x3f, 49); @@ -1533,92 +1601,15 @@ int mt7615_mcu_set_rx_ba(struct mt7615_dev *dev, &wtbl_req, sizeof(wtbl_req), true); } -void mt7615_mcu_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta, - struct ieee80211_tx_rate *probe_rate, - struct ieee80211_tx_rate *rates) +int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index) { - int wcid = sta->wcid.idx; - u32 addr = MT_WTBL_BASE + wcid * MT_WTBL_ENTRY_SIZE; - bool stbc = false; - int n_rates = sta->n_rates; - u8 bw, bw_prev, bw_idx = 0; - u16 val[4]; - u16 probe_val; - u32 w5, w27; - int i; - - if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000)) - return; - - for (i = n_rates; i < 4; i++) - rates[i] = rates[n_rates - 1]; - - val[0] = mt7615_mac_tx_rate_val(dev, &rates[0], stbc, &bw); - bw_prev = bw; - - if (probe_rate) { - probe_val = mt7615_mac_tx_rate_val(dev, probe_rate, stbc, &bw); - if (bw) - bw_idx = 1; - else - bw_prev = 0; - } else { - probe_val = val[0]; - } - - val[1] = mt7615_mac_tx_rate_val(dev, &rates[1], stbc, &bw); - if (bw_prev) { - bw_idx = 3; - bw_prev = bw; - } - - val[2] = mt7615_mac_tx_rate_val(dev, &rates[2], stbc, &bw); - if (bw_prev) { - bw_idx = 5; - bw_prev = bw; - } - - val[3] = mt7615_mac_tx_rate_val(dev, &rates[3], stbc, &bw); - if (bw_prev) - bw_idx = 7; - - w27 = mt76_rr(dev, addr + 27 * 4); - w27 &= ~MT_WTBL_W27_CC_BW_SEL; - w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, bw); - - w5 = mt76_rr(dev, addr + 5 * 4); - w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE); - w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, bw) | - FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, bw_idx ? bw_idx - 1 : 7); - - mt76_wr(dev, MT_WTBL_RIUCR0, w5); - - mt76_wr(dev, MT_WTBL_RIUCR1, - FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) | - FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) | - FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[0])); - - mt76_wr(dev, MT_WTBL_RIUCR2, - FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[0] >> 8) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[1]) | - FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2])); - - mt76_wr(dev, MT_WTBL_RIUCR3, - FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) | - FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[2]) | - FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3])); - - mt76_wr(dev, MT_WTBL_UPDATE, - FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) | - MT_WTBL_UPDATE_RATE_UPDATE | - MT_WTBL_UPDATE_TX_COUNT_CLEAR); - - mt76_wr(dev, addr + 27 * 4, w27); - - if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET)) - mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000); + struct { + u8 action; + u8 rsv[3]; + } req = { + .action = index, + }; - sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates; - sta->wcid.tx_info |= MT_WCID_TX_INFO_SET; + return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_GET_TEMP, &req, + sizeof(req), true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h index f8b51ad25220..1fd7dffa6eef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h @@ -23,6 +23,28 @@ struct mt7615_mcu_txd { u32 reserved[5]; } __packed __aligned(4); +/* event table */ +enum { + MCU_EVENT_TARGET_ADDRESS_LEN = 0x01, + MCU_EVENT_FW_START = 0x01, + MCU_EVENT_GENERIC = 0x01, + MCU_EVENT_ACCESS_REG = 0x02, + MCU_EVENT_MT_PATCH_SEM = 0x04, + MCU_EVENT_CH_PRIVILEGE = 0x18, + MCU_EVENT_EXT = 0xed, + MCU_EVENT_RESTART_DL = 0xef, +}; + +/* ext event table */ +enum { + MCU_EXT_EVENT_PS_SYNC = 0x5, + MCU_EXT_EVENT_FW_LOG_2_HOST = 0x13, + MCU_EXT_EVENT_THERMAL_PROTECT = 0x22, + MCU_EXT_EVENT_ASSERT_DUMP = 0x23, + MCU_EXT_EVENT_RDD_REPORT = 0x3a, + MCU_EXT_EVENT_CSA_NOTIFY = 0x4f, +}; + struct mt7615_mcu_rxd { __le32 rxd[4]; @@ -76,11 +98,14 @@ enum { MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26, MCU_EXT_CMD_EDCA_UPDATE = 0x27, MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A, + MCU_EXT_CMD_GET_TEMP = 0x2c, MCU_EXT_CMD_WTBL_UPDATE = 0x32, + MCU_EXT_CMD_SET_RDD_CTRL = 0x3a, MCU_EXT_CMD_PROTECT_CTRL = 0x3e, MCU_EXT_CMD_MAC_INIT_CTRL = 0x46, MCU_EXT_CMD_BCN_OFFLOAD = 0x49, MCU_EXT_CMD_SET_RX_PATH = 0x4e, + MCU_EXT_CMD_SET_RDD_PATTERN = 0x7d, }; enum { @@ -264,34 +289,6 @@ struct wtbl_hdr_trans { u8 rsv; } __packed; -enum mt7615_cipher_type { - MT_CIPHER_NONE, - MT_CIPHER_WEP40, - MT_CIPHER_TKIP, - MT_CIPHER_TKIP_NO_MIC, - MT_CIPHER_AES_CCMP, - MT_CIPHER_WEP104, - MT_CIPHER_BIP_CMAC_128, - MT_CIPHER_WEP128, - MT_CIPHER_WAPI, - MT_CIPHER_CCMP_256 = 10, - MT_CIPHER_GCMP, - MT_CIPHER_GCMP_256, -}; - -struct wtbl_sec_key { - __le16 tag; - __le16 len; - u8 add; /* 0: add, 1: remove */ - u8 rkv; - u8 ikv; - u8 cipher_id; - u8 key_id; - u8 key_len; - u8 rsv[2]; - u8 key_material[32]; -} __packed; - enum { MT_BA_TYPE_INVALID, MT_BA_TYPE_ORIGINATOR, @@ -375,7 +372,6 @@ struct wtbl_raw { sizeof(struct wtbl_vht) + \ sizeof(struct wtbl_tx_ps) + \ sizeof(struct wtbl_hdr_trans) + \ - sizeof(struct wtbl_sec_key) + \ sizeof(struct wtbl_ba) + \ sizeof(struct wtbl_bf) + \ sizeof(struct wtbl_smps) + \ diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index f02ffcffe637..21486831172c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -10,12 +10,13 @@ #include "regs.h" #define MT7615_MAX_INTERFACES 4 +#define MT7615_MAX_WMM_SETS 4 #define MT7615_WTBL_SIZE 128 #define MT7615_WTBL_RESERVED (MT7615_WTBL_SIZE - 1) #define MT7615_WTBL_STA (MT7615_WTBL_RESERVED - \ MT7615_MAX_INTERFACES) -#define MT7615_WATCHDOG_TIME 100 /* ms */ +#define MT7615_WATCHDOG_TIME (HZ / 10) #define MT7615_RATE_RETRY 2 #define MT7615_TX_RING_SIZE 1024 @@ -25,13 +26,16 @@ #define MT7615_RX_RING_SIZE 1024 #define MT7615_RX_MCU_RING_SIZE 512 -#define MT7615_FIRMWARE_CR4 "mt7615_cr4.bin" -#define MT7615_FIRMWARE_N9 "mt7615_n9.bin" -#define MT7615_ROM_PATCH "mt7615_rom_patch.bin" +#define MT7615_FIRMWARE_CR4 "mediatek/mt7615_cr4.bin" +#define MT7615_FIRMWARE_N9 "mediatek/mt7615_n9.bin" +#define MT7615_ROM_PATCH "mediatek/mt7615_rom_patch.bin" #define MT7615_EEPROM_SIZE 1024 #define MT7615_TOKEN_SIZE 4096 +#define MT_FRAC_SCALE 12 +#define MT_FRAC(val, div) (((val) << MT_FRAC_SCALE) / (div)) + struct mt7615_vif; struct mt7615_sta; @@ -42,12 +46,24 @@ enum mt7615_hw_txq_id { MT7615_TXQ_FWDL, }; +struct mt7615_rate_set { + struct ieee80211_tx_rate probe_rate; + struct ieee80211_tx_rate rates[4]; +}; + struct mt7615_sta { struct mt76_wcid wcid; /* must be first */ struct mt7615_vif *vif; - struct ieee80211_tx_rate rates[8]; + struct list_head poll_list; + u32 airtime_ac[8]; + + struct ieee80211_tx_rate rates[4]; + + struct mt7615_rate_set rateset[2]; + u32 rate_set_tsf; + u8 rate_count; u8 n_rates; @@ -68,6 +84,27 @@ 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; + u16 width; + s16 power; + } radar_pattern; + u32 hw_pattern; + int dfs_state; + + int false_cca_ofdm, false_cca_cck; + unsigned long last_cca_adj; + u8 mac_work_count; + s8 ofdm_sensitivity; + s8 cck_sensitivity; + bool scs_en; + spinlock_t token_lock; struct idr token; }; @@ -97,6 +134,30 @@ enum { EXT_BSSID_END }; +enum { + MT_HW_RDD0, + MT_HW_RDD1, +}; + +enum { + MT_RX_SEL0, + MT_RX_SEL1, +}; + +enum mt7615_rdd_cmd { + RDD_STOP, + RDD_START, + RDD_DET_MODE, + RDD_DET_STOP, + RDD_CAC_START, + RDD_CAC_END, + RDD_NORMAL_START, + RDD_DISABLE_DFS_CAL, + RDD_PULSE_DBG, + RDD_READ_PULSE, + RDD_RESUME_BF, +}; + extern const struct ieee80211_ops mt7615_ops; extern struct pci_driver mt7615_pci_driver; @@ -115,10 +176,7 @@ int mt7615_mcu_set_dev_info(struct mt7615_dev *dev, struct ieee80211_vif *vif, bool enable); int mt7615_mcu_set_bss_info(struct mt7615_dev *dev, struct ieee80211_vif *vif, int en); -int mt7615_mcu_set_wtbl_key(struct mt7615_dev *dev, int wcid, - struct ieee80211_key_conf *key, - enum set_key_cmd cmd); -void mt7615_mcu_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta, +void mt7615_mac_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta, struct ieee80211_tx_rate *probe_rate, struct ieee80211_tx_rate *rates); int mt7615_mcu_wtbl_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif, @@ -144,6 +202,29 @@ int mt7615_mcu_set_rx_ba(struct mt7615_dev *dev, bool add); int mt7615_mcu_set_ht_cap(struct mt7615_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb); +int mt7615_mcu_rdd_cmd(struct mt7615_dev *dev, + enum mt7615_rdd_cmd cmd, u8 index, + u8 rx_sel, u8 val); +int mt7615_dfs_start_radar_detector(struct mt7615_dev *dev); +int mt7615_dfs_stop_radar_detector(struct mt7615_dev *dev); +int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev); + +static inline bool is_mt7622(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7622; +} + +static inline void mt7615_dfs_check_channel(struct mt7615_dev *dev) +{ + enum nl80211_chan_width width = dev->mt76.chandef.width; + u32 freq = dev->mt76.chandef.chan->center_freq; + struct ieee80211_hw *hw = mt76_hw(dev); + + if (hw->conf.chandef.chan->center_freq != freq || + hw->conf.chandef.width != width) + dev->dfs_state = -1; +} static inline void mt7615_irq_enable(struct mt7615_dev *dev, u32 mask) { @@ -155,9 +236,12 @@ static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask) mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0); } -u16 mt7615_mac_tx_rate_val(struct mt7615_dev *dev, - const struct ieee80211_tx_rate *rate, - bool stbc, u8 *bw); +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, @@ -165,11 +249,15 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb); void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data); void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb); +int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, + struct ieee80211_key_conf *key, + enum set_key_cmd cmd); int mt7615_mcu_set_eeprom(struct mt7615_dev *dev); int mt7615_mcu_init_mac(struct mt7615_dev *dev); int mt7615_mcu_set_rts_thresh(struct mt7615_dev *dev, u32 val); int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int enter); +int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index); int mt7615_mcu_set_tx_power(struct mt7615_dev *dev); void mt7615_mcu_exit(struct mt7615_dev *dev); @@ -193,5 +281,9 @@ void mt7615_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, void mt7615_mac_work(struct work_struct *work); void mt7615_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *txwi); +int mt76_dfs_start_rdd(struct mt7615_dev *dev, bool force); +int mt7615_dfs_init_radar_detector(struct mt7615_dev *dev); + +int mt7615_init_debugfs(struct mt7615_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c index 9e82cb53fd60..1eb1eb659c3f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c @@ -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, @@ -81,6 +84,7 @@ static int mt7615_pci_probe(struct pci_dev *pdev, .sta_add = mt7615_sta_add, .sta_assoc = mt7615_sta_assoc, .sta_remove = mt7615_sta_remove, + .update_survey = mt7615_update_channel, }; struct mt7615_dev *dev; struct mt76_dev *mdev; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index 70e5ace33cc3..61a4aa9ac6e6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -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,12 +67,51 @@ #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)) #define MT_WF_PHY_WF2_RFCTRL0 MT_WF_PHY(0x1900) #define MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN BIT(9) +#define MT_WF_PHY_R0_B0_PHYMUX_5 MT_WF_PHY(0x0614) + +#define MT_WF_PHY_R0_B0_PHYCTRL_STS0 MT_WF_PHY(0x020c) +#define MT_WF_PHYCTRL_STAT_PD_OFDM GENMASK(31, 16) +#define MT_WF_PHYCTRL_STAT_PD_CCK GENMASK(15, 0) + +#define MT_WF_PHY_R0_B0_PHYCTRL_STS5 MT_WF_PHY(0x0220) +#define MT_WF_PHYCTRL_STAT_MDRDY_OFDM GENMASK(31, 16) +#define MT_WF_PHYCTRL_STAT_MDRDY_CCK GENMASK(15, 0) + +#define MT_WF_PHY_B0_MIN_PRI_PWR MT_WF_PHY(0x229c) +#define MT_WF_PHY_B0_PD_OFDM_MASK GENMASK(28, 20) +#define MT_WF_PHY_B0_PD_OFDM(v) ((v) << 20) +#define MT_WF_PHY_B0_PD_BLK BIT(19) + +#define MT_WF_PHY_B1_MIN_PRI_PWR MT_WF_PHY(0x084) +#define MT_WF_PHY_B1_PD_OFDM_MASK GENMASK(24, 16) +#define MT_WF_PHY_B1_PD_OFDM(v) ((v) << 16) +#define MT_WF_PHY_B1_PD_BLK BIT(25) + +#define MT_WF_PHY_B0_RXTD_CCK_PD MT_WF_PHY(0x2310) +#define MT_WF_PHY_B0_PD_CCK_MASK GENMASK(8, 1) +#define MT_WF_PHY_B0_PD_CCK(v) ((v) << 1) + +#define MT_WF_PHY_B1_RXTD_CCK_PD MT_WF_PHY(0x2314) +#define MT_WF_PHY_B1_PD_CCK_MASK GENMASK(31, 24) +#define MT_WF_PHY_B1_PD_CCK(v) ((v) << 24) + #define MT_WF_CFG_BASE 0x20200 #define MT_WF_CFG(ofs) (MT_WF_CFG_BASE + (ofs)) @@ -97,12 +138,29 @@ 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) +#define MT_AGG_ACR_NO_BA_AR_RULE BIT(1) +#define MT_AGG_ACR_PKT_TIME_EN BIT(2) +#define MT_AGG_ACR_CFEND_RATE GENMASK(15, 4) +#define MT_AGG_ACR_BAR_RATE GENMASK(31, 20) + #define MT_AGG_SCR MT_WF_AGG(0x0fc) #define MT_AGG_SCR_NLNAV_MID_PTEC_DIS BIT(3) #define MT_WF_TMAC_BASE 0x21000 #define MT_WF_TMAC(ofs) (MT_WF_TMAC_BASE + (ofs)) +#define MT_TMAC_TRCR0 MT_WF_TMAC(0x09c) +#define MT_TMAC_TRCR1 MT_WF_TMAC(0x070) +#define MT_TMAC_TRCR_CCA_SEL GENMASK(31, 30) +#define MT_TMAC_TRCR_SEC_CCA_SEL GENMASK(29, 28) + #define MT_TMAC_CTCR0 MT_WF_TMAC(0x0f4) #define MT_TMAC_CTCR0_INS_DDLMT_REFTIME GENMASK(5, 0) #define MT_TMAC_CTCR0_INS_DDLMT_DENSITY GENMASK(15, 12) @@ -135,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)) @@ -142,14 +216,31 @@ #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 #define MT_WTBL_OFF_BASE 0x23400 #define MT_WTBL_OFF(n) (MT_WTBL_OFF_BASE + (n)) +#define MT_WTBL_W0_KEY_IDX GENMASK(24, 23) +#define MT_WTBL_W0_RX_KEY_VALID BIT(26) +#define MT_WTBL_W0_RX_IK_VALID BIT(27) + +#define MT_WTBL_W2_KEY_TYPE GENMASK(7, 4) + #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) @@ -157,6 +248,9 @@ #define MT_WTBL_ON_BASE 0x23000 #define MT_WTBL_ON(_n) (MT_WTBL_ON_BASE + (_n)) +#define MT_WTBL_RICR0 MT_WTBL_ON(0x010) +#define MT_WTBL_RICR1 MT_WTBL_ON(0x014) + #define MT_WTBL_RIUCR0 MT_WTBL_ON(0x020) #define MT_WTBL_RIUCR1 MT_WTBL_ON(0x024) @@ -181,8 +275,42 @@ #define MT_WTBL_W5_SHORT_GI_80 BIT(10) #define MT_WTBL_W5_SHORT_GI_160 BIT(11) #define MT_WTBL_W5_BW_CAP GENMASK(13, 12) +#define MT_WTBL_W5_MPDU_FAIL_COUNT GENMASK(25, 23) +#define MT_WTBL_W5_MPDU_OK_COUNT GENMASK(28, 26) +#define MT_WTBL_W5_RATE_IDX GENMASK(31, 29) + #define MT_WTBL_W27_CC_BW_SEL GENMASK(6, 5) +#define MT_LPON_BASE 0x24200 +#define MT_LPON(_n) (MT_LPON_BASE + (_n)) + +#define MT_LPON_T0CR MT_LPON(0x010) +#define MT_LPON_T0CR_MODE GENMASK(1, 0) + +#define MT_LPON_UTTR0 MT_LPON(0x018) +#define MT_LPON_UTTR1 MT_LPON(0x01c) + +#define MT_WF_MIB_BASE 0x24800 +#define MT_WF_MIB(ofs) (MT_WF_MIB_BASE + (ofs)) + +#define MT_MIB_M0_MISC_CR MT_WF_MIB(0x00c) +#define MT_MIB_MB_SDR0(n) MT_WF_MIB(0x100 + ((n) << 4)) +#define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16) +#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 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 #define MT_EFUSE_BASE_CTRL_EMPTY BIT(30) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig index 209d8abc49d5..7c88ed8b8f1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig @@ -10,7 +10,11 @@ config MT76x0U depends on MAC80211 depends on USB help - This adds support for MT7610U-based wireless USB dongles. + This adds support for MT7610U-based wireless USB 2.0 dongles, + which comply with IEEE 802.11ac standards and support 1x1 + 433Mbps PHY rate. + + To compile this driver as a module, choose M here. config MT76x0E tristate "MediaTek MT76x0E (PCIe) support" @@ -18,4 +22,8 @@ config MT76x0E depends on MAC80211 depends on PCI help - This adds support for MT7610/MT7630-based wireless PCIe devices. + This adds support for MT7610/MT7630-based wireless PCIe devices, + which comply with IEEE 802.11ac standards and support 1x1 + 433Mbps PHY rate. + + To compile this driver as a module, choose M here. diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 40c0d536e20d..d1405528b504 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -59,6 +59,11 @@ static void mt76x0_set_chip_cap(struct mt76x02_dev *dev) dev_dbg(dev->mt76.dev, "mask out 2GHz support\n"); } + if (is_mt7630(dev)) { + dev->mt76.cap.has_5ghz = false; + dev_dbg(dev->mt76.dev, "mask out 5GHz support\n"); + } + if (!mt76x02_field_valid(nic_conf1 & 0xff)) nic_conf1 &= 0xff00; @@ -207,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[] = { @@ -337,7 +342,11 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev) dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n", version, fae); - mt76x02_mac_setaddr(dev, dev->mt76.eeprom.data + MT_EE_MAC_ADDR); + memcpy(dev->mt76.macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR, + ETH_ALEN); + mt76_eeprom_override(&dev->mt76); + mt76x02_mac_setaddr(dev, dev->mt76.macaddr); + mt76x0_set_chip_cap(dev); mt76x0_set_freq_offset(dev); mt76x0_set_temp_offset(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c index cf7fc307322b..388b54cded1b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c @@ -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; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index d7bf7bc15e52..b2ccf50512dc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -8,46 +8,38 @@ #include <linux/etherdevice.h> #include "mt76x0.h" -static int +static void mt76x0_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef) { - int ret; - cancel_delayed_work_sync(&dev->cal_work); - dev->beacon_ops->pre_tbtt_enable(dev, false); - if (mt76_is_mmio(dev)) + mt76x02_pre_tbtt_enable(dev, false); + if (mt76_is_mmio(&dev->mt76)) tasklet_disable(&dev->dfs_pd.dfs_tasklet); mt76_set_channel(&dev->mt76); - ret = mt76x0_phy_set_channel(dev, chandef); - - /* channel cycle counters read-and-clear */ - mt76_rr(dev, MT_CH_IDLE); - mt76_rr(dev, MT_CH_BUSY); + mt76x0_phy_set_channel(dev, chandef); + 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); } - dev->beacon_ops->pre_tbtt_enable(dev, true); + mt76x02_pre_tbtt_enable(dev, true); mt76_txq_schedule_all(&dev->mt76); - - return ret; } int mt76x0_config(struct ieee80211_hw *hw, u32 changed) { struct mt76x02_dev *dev = hw->priv; - int ret = 0; mutex_lock(&dev->mt76.mutex); if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { ieee80211_stop_queues(hw); - ret = mt76x0_set_channel(dev, &hw->conf.chandef); + mt76x0_set_channel(dev, &hw->conf.chandef); ieee80211_wake_queues(hw); } @@ -69,6 +61,6 @@ int mt76x0_config(struct ieee80211_hw *hw, u32 changed) mutex_unlock(&dev->mt76.mutex); - return ret; + return 0; } EXPORT_SYMBOL_GPL(mt76x0_config); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 97e47cd2d744..6953f253a28a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -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); @@ -54,7 +53,7 @@ int mt76x0_config(struct ieee80211_hw *hw, u32 changed); /* PHY */ void mt76x0_phy_init(struct mt76x02_dev *dev); int mt76x0_phy_wait_bbp_ready(struct mt76x02_dev *dev); -int mt76x0_phy_set_channel(struct mt76x02_dev *dev, +void mt76x0_phy_set_channel(struct mt76x02_dev *dev, struct cfg80211_chan_def *chandef); void mt76x0_phy_set_txpower(struct mt76x02_dev *dev); void mt76x0_phy_calibrate(struct mt76x02_dev *dev, bool power_on); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c index 4585e1b756c2..e2974e0ae1fc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/kernel.h> @@ -80,7 +69,7 @@ static const struct ieee80211_ops mt76x0e_ops = { .sta_state = mt76_sta_state, .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, - .sw_scan_start = mt76x02_sw_scan, + .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76x02_sw_scan_complete, .ampdu_action = mt76x02_ampdu_action, .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, @@ -92,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) @@ -130,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; @@ -153,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, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c index 490c1869f2c4..038187b390ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/kernel.h> #include <linux/firmware.h> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c index 1ecfc334ae79..2ecd45f8af90 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c @@ -102,14 +102,14 @@ 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, }; WARN_ON_ONCE(!test_bit(MT76_STATE_MCU_RUNNING, - &dev->mt76.state)); + &dev->mt76.state)); return mt76_wr_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1); } else { return mt76x0_rf_csr_wr(dev, offset, val); @@ -121,13 +121,13 @@ 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, }; WARN_ON_ONCE(!test_bit(MT76_STATE_MCU_RUNNING, - &dev->mt76.state)); + &dev->mt76.state)); ret = mt76_rd_rp(dev, MT_MCU_MEMMAP_RF, &pair, 1); val = pair.value; } else { @@ -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));\ @@ -230,7 +230,8 @@ mt76x0_phy_set_band(struct mt76x02_dev *dev, enum nl80211_band band) } static void -mt76x0_phy_set_chan_rf_params(struct mt76x02_dev *dev, u8 channel, u16 rf_bw_band) +mt76x0_phy_set_chan_rf_params(struct mt76x02_dev *dev, u8 channel, + u16 rf_bw_band) { const struct mt76x0_freq_item *freq_item; u16 rf_band = rf_bw_band & 0xff00; @@ -252,9 +253,9 @@ mt76x0_phy_set_chan_rf_params(struct mt76x02_dev *dev, u8 channel, u16 rf_bw_ban rf_band = mt76x0_frequency_plan[i].band; if (b_sdm) - freq_item = &(mt76x0_sdm_frequency_plan[i]); + freq_item = &mt76x0_sdm_frequency_plan[i]; else - freq_item = &(mt76x0_frequency_plan[i]); + freq_item = &mt76x0_frequency_plan[i]; mt76x0_rf_wr(dev, MT_RF(0, 37), freq_item->pllR37); mt76x0_rf_wr(dev, MT_RF(0, 36), freq_item->pllR36); @@ -359,11 +360,12 @@ mt76x0_phy_set_chan_rf_params(struct mt76x02_dev *dev, u8 channel, u16 rf_bw_ban band = (rf_band & RF_G_BAND) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ; if (mt76x02_ext_pa_enabled(dev, band)) { - /* - MT_RF_MISC (offset: 0x0518) - [2]1'b1: enable external A band PA, 1'b0: disable external A band PA - [3]1'b1: enable external G band PA, 1'b0: disable external G band PA - */ + /* MT_RF_MISC (offset: 0x0518) + * [2]1'b1: enable external A band PA + * 1'b0: disable external A band PA + * [3]1'b1: enable external G band PA + * 1'b0: disable external G band PA + */ if (rf_band & RF_A_BAND) mt76_set(dev, MT_RF_MISC, BIT(2)); else @@ -385,7 +387,9 @@ mt76x0_phy_set_chan_rf_params(struct mt76x02_dev *dev, u8 channel, u16 rf_bw_ban mt76_wr(dev, MT_TX_ALC_CFG_1, mac_reg); } else { mt76_wr(dev, MT_TX0_RF_GAIN_ATTEN, 0x686A7800); - /* Set Atten mode = 0 For Ext A band, Disable Tx Inc dcoc Cal. */ + /* Set Atten mode = 0 + * For Ext A band, Disable Tx Inc dcoc Cal. + */ mac_reg = mt76_rr(dev, MT_TX_ALC_CFG_1); mac_reg &= 0x890400FF; mt76_wr(dev, MT_TX_ALC_CFG_1, mac_reg); @@ -490,7 +494,7 @@ mt76x0_phy_bbp_set_bw(struct mt76x02_dev *dev, enum nl80211_chan_width width) case NL80211_CHAN_WIDTH_160: case NL80211_CHAN_WIDTH_5: /* TODO error */ - return ; + return; } mt76x02_mcu_function_select(dev, BW_SETTING, bw); @@ -740,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 */ @@ -895,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); @@ -905,8 +908,8 @@ void mt76x0_phy_calibrate(struct mt76x02_dev *dev, bool power_on) } EXPORT_SYMBOL_GPL(mt76x0_phy_calibrate); -int mt76x0_phy_set_channel(struct mt76x02_dev *dev, - struct cfg80211_chan_def *chandef) +void mt76x0_phy_set_channel(struct mt76x02_dev *dev, + struct cfg80211_chan_def *chandef) { u32 ext_cca_chan[4] = { [0] = FIELD_PREP(MT_EXT_CCA_CFG_CCA0, 0) | @@ -940,7 +943,6 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, freq1 = chandef->center_freq1; channel = chandef->chan->hw_value; rf_bw_band = (channel <= 14) ? RF_G_BAND : RF_A_BAND; - dev->mt76.chandef = *chandef; switch (chandef->width) { case NL80211_CHAN_WIDTH_40: @@ -964,7 +966,7 @@ int 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 || @@ -1001,7 +1003,7 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, /* enable vco */ mt76x0_rf_set(dev, MT_RF(0, 4), BIT(7)); if (scan) - return 0; + return; mt76x02_init_agc_gain(dev); mt76x0_phy_calibrate(dev, false); @@ -1009,8 +1011,6 @@ int mt76x0_phy_set_channel(struct mt76x02_dev *dev, ieee80211_queue_delayed_work(dev->mt76.hw, &dev->cal_work, MT_CALIBRATE_INTERVAL); - - return 0; } static void mt76x0_phy_temp_sensor(struct mt76x02_dev *dev) @@ -1074,7 +1074,7 @@ mt76x0_phy_update_channel_gain(struct mt76x02_dev *dev) dev->cal.avg_rssi_all = -75; low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) + - (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev)); + (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev)); gain_change = dev->cal.low_gain < 0 || (dev->cal.low_gain & 2) ^ (low_gain & 2); @@ -1122,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 @@ -1169,7 +1169,8 @@ static void mt76x0_phy_rf_init(struct mt76x02_dev *dev) if (item->bw_band == RF_BW_20) mt76x0_rf_wr(dev, item->rf_bank_reg, item->value); - else if (((RF_G_BAND | RF_BW_20) & item->bw_band) == (RF_G_BAND | RF_BW_20)) + else if (((RF_G_BAND | RF_BW_20) & item->bw_band) == + (RF_G_BAND | RF_BW_20)) mt76x0_rf_wr(dev, item->rf_bank_reg, item->value); } @@ -1181,10 +1182,9 @@ static void mt76x0_phy_rf_init(struct mt76x02_dev *dev) } } - /* - Frequency calibration - E1: B0.R22<6:0>: xo_cxo<6:0> - E2: B0.R21<0>: xo_cxo<0>, B0.R22<7:0>: xo_cxo<8:1> + /* Frequency calibration + * E1: B0.R22<6:0>: xo_cxo<6:0> + * E2: B0.R21<0>: xo_cxo<0>, B0.R22<7:0>: xo_cxo<8:1> */ mt76x0_rf_wr(dev, MT_RF(0, 22), min_t(u8, dev->cal.rx.freq_offset, 0xbf)); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.h b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.h index b4b2ca747699..441d6559d4fd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.h @@ -6,8 +6,8 @@ #ifndef _MT76X0_PHY_H_ #define _MT76X0_PHY_H_ -#define RF_G_BAND 0x0100 -#define RF_A_BAND 0x0200 +#define RF_G_BAND 0x0100 +#define RF_A_BAND 0x0200 #define RF_A_BAND_LB 0x0400 #define RF_A_BAND_MB 0x0800 #define RF_A_BAND_HB 0x1000 @@ -18,9 +18,9 @@ #define RF_BW_10 4 #define RF_BW_80 8 -#define MT_RF(bank, reg) ((bank) << 16 | (reg)) -#define MT_RF_BANK(offset) (offset >> 16) -#define MT_RF_REG(offset) (offset & 0xff) +#define MT_RF(bank, reg) ((bank) << 16 | (reg)) +#define MT_RF_BANK(offset) ((offset) >> 16) +#define MT_RF_REG(offset) ((offset) & 0xff) #define MT_RF_VCO_BP_CLOSE_LOOP BIT(3) #define MT_RF_VCO_BP_CLOSE_LOOP_MASK GENMASK(3, 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c index 627ed1fc7b15..65ba9fc6ea0b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c @@ -32,10 +32,13 @@ static struct usb_device_id mt76x0_device_table[] = { { USB_DEVICE(0x20f4, 0x806b) }, /* TRENDnet TEW-806UBH */ { USB_DEVICE(0x7392, 0xc711) }, /* Devolo Wifi ac Stick */ { USB_DEVICE(0x0df6, 0x0079) }, /* Sitecom Europe B.V. ac Stick */ - { USB_DEVICE(0x2357, 0x0105), - .driver_info = 1, }, /* TP-LINK Archer T1U */ - { USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7630, 0xff, 0x2, 0xff)}, /* MT7630U */ - { USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7650, 0xff, 0x2, 0xff)}, /* MT7650U */ + { USB_DEVICE(0x2357, 0x0123) }, /* TP-LINK T2UHP */ + /* TP-LINK Archer T1U */ + { USB_DEVICE(0x2357, 0x0105), .driver_info = 1, }, + /* MT7630U */ + { USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7630, 0xff, 0x2, 0xff)}, + /* MT7650U */ + { USB_DEVICE_AND_INTERFACE_INFO(0x0E8D, 0x7650, 0xff, 0x2, 0xff)}, { 0, } }; @@ -100,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; @@ -125,22 +128,24 @@ static const struct ieee80211_ops mt76x0u_ops = { .sta_state = mt76_sta_state, .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, - .sw_scan_start = mt76x02_sw_scan, + .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76x02_sw_scan_complete, .ampdu_action = mt76x02_ampdu_action, .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .set_rts_threshold = mt76x02_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, .get_txpower = mt76_get_txpower, + .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) +static int mt76x0u_init_hardware(struct mt76x02_dev *dev, bool reset) { int err; - mt76x0_chip_onoff(dev, true, true); + mt76x0_chip_onoff(dev, true, reset); if (!mt76x02_wait_for_mac(&dev->mt76)) return -ETIMEDOUT; @@ -173,7 +178,7 @@ static int mt76x0u_register_device(struct mt76x02_dev *dev) if (err < 0) goto out_err; - err = mt76x0u_init_hardware(dev); + err = mt76x0u_init_hardware(dev, true); if (err < 0) goto out_err; @@ -200,6 +205,9 @@ 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, .tx_status_data = mt76x02_tx_status_data, @@ -214,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; @@ -236,7 +244,7 @@ static int mt76x0u_probe(struct usb_interface *usb_intf, if (ret) goto err; - /* Disable the HW, otherwise MCU fail to initalize on hot reboot */ + /* Disable the HW, otherwise MCU fail to initialize on hot reboot */ mt76x0_chip_onoff(dev, false, false); if (!mt76x02_wait_for_mac(mdev)) { @@ -266,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; @@ -274,9 +283,9 @@ err: static void mt76x0_disconnect(struct usb_interface *usb_intf) { struct mt76x02_dev *dev = usb_get_intfdata(usb_intf); - bool initalized = test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); + bool initialized = test_bit(MT76_STATE_INITIALIZED, &dev->mt76.state); - if (!initalized) + if (!initialized) return; ieee80211_unregister_hw(dev->mt76.hw); @@ -285,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); } @@ -309,7 +319,7 @@ static int __maybe_unused mt76x0_resume(struct usb_interface *usb_intf) if (ret < 0) goto err; - ret = mt76x0u_init_hardware(dev); + ret = mt76x0u_init_hardware(dev, false); if (ret) goto err; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c index 4a282761ca58..888a930a5e08 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb_mcu.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/kernel.h> #include <linux/firmware.h> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index f7fd53a1738a..0ca0bbfe8769 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x02_H @@ -71,10 +60,15 @@ struct mt76x02_calibration { struct mt76x02_beacon_ops { unsigned int nslots; unsigned int slot_size; - void (*pre_tbtt_enable) (struct mt76x02_dev *, bool); - void (*beacon_enable) (struct mt76x02_dev *, bool); + void (*pre_tbtt_enable)(struct mt76x02_dev *dev, bool en); + void (*beacon_enable)(struct mt76x02_dev *dev, bool en); }; +#define mt76x02_beacon_enable(dev, enable) \ + (dev)->beacon_ops->beacon_enable(dev, enable) +#define mt76x02_pre_tbtt_enable(dev, enable) \ + (dev)->beacon_ops->pre_tbtt_enable(dev, enable) + struct mt76x02_dev { struct mt76_dev mt76; /* must be first */ @@ -87,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; @@ -98,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; @@ -137,8 +130,8 @@ extern struct ieee80211_rate mt76x02_rates[12]; void mt76x02_init_device(struct mt76x02_dev *dev); void mt76x02_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, u64 multicast); + unsigned int changed_flags, + unsigned int *total_flags, u64 multicast); int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); void mt76x02_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, @@ -147,20 +140,20 @@ void mt76x02_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev); int mt76x02_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_vif *vif); void mt76x02_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); + struct ieee80211_vif *vif); int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params); + struct ieee80211_ampdu_params *params); int mt76x02_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 ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); + u16 queue, const struct ieee80211_tx_queue_params *params); void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta); + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); s8 mt76x02_tx_get_max_txpwr_adj(struct mt76x02_dev *dev, const struct ieee80211_tx_rate *rate); s8 mt76x02_tx_get_txpwr_adj(struct mt76x02_dev *dev, s8 txpwr, @@ -183,8 +176,6 @@ int mt76x02_tx_prepare_skb(struct mt76_dev *mdev, void *txwi, enum mt76_txq_id qid, struct mt76_wcid *wcid, struct ieee80211_sta *sta, struct mt76_tx_info *tx_info); -void mt76x02_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - const u8 *mac); void mt76x02_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void mt76x02_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); @@ -197,6 +188,7 @@ struct beacon_bc_data { struct sk_buff_head q; struct sk_buff *tail[8]; }; + void mt76x02_init_beacon_config(struct mt76x02_dev *dev); void mt76x02e_init_beacon_config(struct mt76x02_dev *dev); void mt76x02_resync_beacon_timer(struct mt76x02_dev *dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c index d61c686e08de..4209209ac940 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_beacon.c @@ -1,19 +1,8 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76x02.h" @@ -88,10 +77,7 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) { if (vif_idx == i) { force_update = !!dev->beacons[i] ^ !!skb; - - if (dev->beacons[i]) - dev_kfree_skb(dev->beacons[i]); - + dev_kfree_skb(dev->beacons[i]); dev->beacons[i] = skb; __mt76x02_mac_set_beacon(dev, bcn_idx, skb); } else if (force_update && dev->beacons[i]) { @@ -115,53 +101,41 @@ int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, } EXPORT_SYMBOL_GPL(mt76x02_mac_set_beacon); -static void -__mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx, - bool val, struct sk_buff *skb) -{ - u8 old_mask = dev->mt76.beacon_mask; - bool en; - u32 reg; - - if (val) { - dev->mt76.beacon_mask |= BIT(vif_idx); - if (skb) - mt76x02_mac_set_beacon(dev, vif_idx, skb); - } else { - dev->mt76.beacon_mask &= ~BIT(vif_idx); - mt76x02_mac_set_beacon(dev, vif_idx, NULL); - } - - if (!!old_mask == !!dev->mt76.beacon_mask) - return; - - en = dev->mt76.beacon_mask; - - reg = MT_BEACON_TIME_CFG_BEACON_TX | - MT_BEACON_TIME_CFG_TBTT_EN | - MT_BEACON_TIME_CFG_TIMER_EN; - mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en); - - dev->beacon_ops->beacon_enable(dev, en); -} - void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, - struct ieee80211_vif *vif, bool val) + struct ieee80211_vif *vif, bool enable) { - u8 vif_idx = ((struct mt76x02_vif *)vif->drv_priv)->idx; - struct sk_buff *skb = NULL; - - dev->beacon_ops->pre_tbtt_enable(dev, false); + struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; + u8 old_mask = dev->mt76.beacon_mask; - if (mt76_is_usb(dev)) - skb = ieee80211_beacon_get(mt76_hw(dev), vif); + mt76x02_pre_tbtt_enable(dev, false); if (!dev->mt76.beacon_mask) dev->tbtt_count = 0; - __mt76x02_mac_set_beacon_enable(dev, vif_idx, val, skb); + if (enable) { + dev->mt76.beacon_mask |= BIT(mvif->idx); + } else { + dev->mt76.beacon_mask &= ~BIT(mvif->idx); + mt76x02_mac_set_beacon(dev, mvif->idx, NULL); + } - dev->beacon_ops->pre_tbtt_enable(dev, true); + if (!!old_mask == !!dev->mt76.beacon_mask) + goto out; + + if (dev->mt76.beacon_mask) + mt76_set(dev, MT_BEACON_TIME_CFG, + MT_BEACON_TIME_CFG_BEACON_TX | + MT_BEACON_TIME_CFG_TBTT_EN | + MT_BEACON_TIME_CFG_TIMER_EN); + else + mt76_clear(dev, MT_BEACON_TIME_CFG, + MT_BEACON_TIME_CFG_BEACON_TX | + MT_BEACON_TIME_CFG_TBTT_EN | + MT_BEACON_TIME_CFG_TIMER_EN); + mt76x02_beacon_enable(dev, !!dev->mt76.beacon_mask); + +out: + mt76x02_pre_tbtt_enable(dev, true); } void @@ -237,7 +211,8 @@ mt76x02_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif) } void -mt76x02_enqueue_buffered_bc(struct mt76x02_dev *dev, struct beacon_bc_data *data, +mt76x02_enqueue_buffered_bc(struct mt76x02_dev *dev, + struct beacon_bc_data *data, int max_nframes) { int i, nframes; @@ -281,4 +256,3 @@ void mt76x02_init_beacon_config(struct mt76x02_dev *dev) } EXPORT_SYMBOL_GPL(mt76x02_init_beacon_config); - diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c index 1b1e424ccbb2..68b40d63a46d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/debugfs.h> @@ -30,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++) @@ -154,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c index 50e9b310e496..5dec33ed8527 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76x02.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h index 0408613b45a4..491010a32247 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x02_DFS_H diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h index 6394010a565f..4aff4f8e87b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x02_DMA_H diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c index 07f0496d828a..c54c50fd639a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <asm/unaligned.h> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h index 0ba536de3d6e..99941a4700f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x02_EEPROM_H diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 82bafb5ac326..4460548f346a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -1,23 +1,33 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #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) { @@ -92,7 +102,6 @@ void mt76x02_mac_wcid_sync_pn(struct mt76x02_dev *dev, u8 idx, atomic64_set(&key->tx_pn, pn); } - int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx, struct ieee80211_key_conf *key) { @@ -267,7 +276,7 @@ bool mt76x02_mac_load_tx_status(struct mt76x02_dev *dev, static int mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, - enum nl80211_band band) + enum nl80211_band band) { u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); @@ -343,7 +352,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, ieee80211_has_protected(hdr->frame_control)) { wcid = NULL; ieee80211_get_tx_rates(info->control.vif, sta, skb, - info->control.rates, 1); + info->control.rates, 1); } if (wcid) @@ -353,6 +362,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, if (wcid && wcid->sw_iv && key) { u64 pn = atomic64_inc_return(&key->tx_pn); + ccmp_pn[0] = pn; ccmp_pn[1] = pn >> 8; ccmp_pn[2] = 0; @@ -445,8 +455,8 @@ mt76x02_tx_rate_fallback(struct ieee80211_tx_rate *rates, int idx, int phy) case MT_PHY_TYPE_HT: /* MCS 8 falls back to MCS 0 */ if (rates[0].idx == 8) { - rates[1].idx = 0; - break; + rates[1].idx = 0; + break; } /* fall through */ default: @@ -473,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); @@ -527,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; @@ -560,26 +580,26 @@ 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; stat_val = stat->rate; - stat_val |= ((u32) stat->retry) << 16; + stat_val |= ((u32)stat->retry) << 16; stat_cache = msta->status.rate; - stat_cache |= ((u32) msta->status.retry) << 16; + stat_cache |= ((u32)msta->status.retry) << 16; if (*update == 0 && stat_val == stat_cache && 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); @@ -587,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(); } @@ -718,7 +761,7 @@ mt76x02_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain) int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, void *rxi) { - struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76x02_rxwi *rxwi = rxi; struct mt76x02_sta *sta; u32 rxinfo = le32_to_cpu(rxwi->rxinfo); @@ -779,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; @@ -959,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); @@ -1105,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) @@ -1127,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h index cb39da79527a..7d946aa77182 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h @@ -1,18 +1,7 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76X02_MAC_H @@ -34,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 */ @@ -46,6 +40,7 @@ struct mt76x02_sta { struct mt76x02_tx_status status; int n_frames; + struct ewma_pktlen pktlen; }; #define MT_RXINFO_BA BIT(0) @@ -172,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); @@ -203,11 +199,12 @@ 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); void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, - struct ieee80211_vif *vif, bool val); + struct ieee80211_vif *vif, bool enable); void mt76x02_edcca_init(struct mt76x02_dev *dev); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c index 6501b853b65c..6274b6a24b07 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/kernel.h> @@ -65,7 +54,7 @@ int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data, break; } - rxfce = (u32 *) skb->cb; + rxfce = (u32 *)skb->cb; if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce)) check_seq = true; @@ -86,11 +75,11 @@ int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func, u32 val) { struct { - __le32 id; - __le32 value; + __le32 id; + __le32 value; } __packed __aligned(4) msg = { - .id = cpu_to_le32(func), - .value = cpu_to_le32(val), + .id = cpu_to_le32(func), + .value = cpu_to_le32(val), }; bool wait = false; @@ -111,7 +100,8 @@ int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on) .level = cpu_to_le32(0), }; - return mt76_mcu_send_msg(dev, CMD_POWER_SAVING_OP, &msg, sizeof(msg), false); + return mt76_mcu_send_msg(dev, CMD_POWER_SAVING_OP, &msg, sizeof(msg), + false); } EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state); @@ -124,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) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h index a7b0d3e5df1d..c81a9655c4c9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x02_MCU_H diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index 467b28379870..4e2371c926d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/kernel.h> @@ -97,7 +86,8 @@ void mt76x02e_init_beacon_config(struct mt76x02_dev *dev) dev->beacon_ops = &beacon_ops; /* Fire a pre-TBTT interrupt 8 ms before TBTT */ - mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, 8 << 4); + mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_PRE_TBTT, + 8 << 4); mt76_rmw_field(dev, MT_INT_TIMER_CFG, MT_INT_TIMER_CFG_GP_TIMER, MT_DFS_GP_INTERVAL); mt76_wr(dev, MT_INT_TIMER_EN, 0); @@ -201,7 +191,7 @@ int mt76x02_dma_init(struct mt76x02_dev *dev) return -ENOMEM; tasklet_init(&dev->mt76.tx_tasklet, mt76x02_tx_tasklet, - (unsigned long) dev); + (unsigned long)dev); tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet, (unsigned long)dev); @@ -353,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, @@ -395,12 +386,12 @@ static void mt76x02_key_sync(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76_wcid *wcid; if (!sta) - return; + return; - wcid = (struct mt76_wcid *) sta->drv_priv; + wcid = (struct mt76_wcid *)sta->drv_priv; if (wcid->hw_key_idx != key->keyidx || wcid->sw_iv) - return; + return; mt76x02_mac_wcid_sync_pn(dev, wcid->idx, key); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c index a54b63a96eae..d7334267b530 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/kernel.h> @@ -183,7 +172,8 @@ bool mt76x02_phy_adjust_vga_gain(struct mt76x02_dev *dev) bool ret = false; u32 false_cca; - false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, mt76_rr(dev, MT_RX_STAT_1)); + false_cca = FIELD_GET(MT_RX_STAT_1_CCA_ERRORS, + mt76_rr(dev, MT_RX_STAT_1)); dev->cal.false_cca = false_cca; if (false_cca > 800 && dev->cal.agc_gain_adjust < limit) { dev->cal.agc_gain_adjust += 2; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h index d2971db06f13..fc2e41006a0d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_phy.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x02_PHY_H diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h index ea7833964ec0..21c0f351fa09 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_regs.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76X02_REGS_H @@ -19,8 +8,8 @@ #define MT_ASIC_VERSION 0x0000 -#define MT76XX_REV_E3 0x22 -#define MT76XX_REV_E4 0x33 +#define MT76XX_REV_E3 0x22 +#define MT76XX_REV_E4 0x33 #define MT_CMB_CTRL 0x0020 #define MT_CMB_CTRL_XTAL_RDY BIT(22) @@ -120,7 +109,7 @@ #define MT_INT_RX_DONE(_n) BIT(_n) #define MT_INT_RX_DONE_ALL GENMASK(1, 0) #define MT_INT_TX_DONE_ALL GENMASK(13, 4) -#define MT_INT_TX_DONE(_n) BIT(_n + 4) +#define MT_INT_TX_DONE(_n) BIT((_n) + 4) #define MT_INT_RX_COHERENT BIT(16) #define MT_INT_TX_COHERENT BIT(17) #define MT_INT_ANY_COHERENT BIT(18) @@ -149,21 +138,21 @@ #define MT_WPDMA_DELAY_INT_CFG 0x0210 -#define MT_WMM_AIFSN 0x0214 +#define MT_WMM_AIFSN 0x0214 #define MT_WMM_AIFSN_MASK GENMASK(3, 0) #define MT_WMM_AIFSN_SHIFT(_n) ((_n) * 4) -#define MT_WMM_CWMIN 0x0218 +#define MT_WMM_CWMIN 0x0218 #define MT_WMM_CWMIN_MASK GENMASK(3, 0) #define MT_WMM_CWMIN_SHIFT(_n) ((_n) * 4) -#define MT_WMM_CWMAX 0x021c +#define MT_WMM_CWMAX 0x021c #define MT_WMM_CWMAX_MASK GENMASK(3, 0) #define MT_WMM_CWMAX_SHIFT(_n) ((_n) * 4) #define MT_WMM_TXOP_BASE 0x0220 #define MT_WMM_TXOP(_n) (MT_WMM_TXOP_BASE + (((_n) / 2) << 2)) -#define MT_WMM_TXOP_SHIFT(_n) ((_n & 1) * 16) +#define MT_WMM_TXOP_SHIFT(_n) (((_n) & 1) * 16) #define MT_WMM_TXOP_MASK GENMASK(15, 0) #define MT_WMM_CTRL 0x0230 /* MT76x0 */ @@ -607,7 +596,7 @@ #define MT_TX_AGG_CNT(_id) ((_id) < 8 ? \ MT_TX_AGG_CNT_BASE0 + ((_id) << 2) : \ - MT_TX_AGG_CNT_BASE1 + ((_id - 8) << 2)) + MT_TX_AGG_CNT_BASE1 + (((_id) - 8) << 2)) #define MT_TX_STAT_FIFO_EXT 0x1798 #define MT_TX_STAT_FIFO_EXT_RETRY GENMASK(7, 0) @@ -680,17 +669,17 @@ #define MT_SKEY_BASE_0 0xac00 #define MT_SKEY_BASE_1 0xb400 -#define MT_SKEY_0(_bss, _idx) (MT_SKEY_BASE_0 + (4 * (_bss) + _idx) * 32) -#define MT_SKEY_1(_bss, _idx) (MT_SKEY_BASE_1 + (4 * ((_bss) & 7) + _idx) * 32) -#define MT_SKEY(_bss, _idx) ((_bss & 8) ? MT_SKEY_1(_bss, _idx) : MT_SKEY_0(_bss, _idx)) +#define MT_SKEY_0(_bss, _idx) (MT_SKEY_BASE_0 + (4 * (_bss) + (_idx)) * 32) +#define MT_SKEY_1(_bss, _idx) (MT_SKEY_BASE_1 + (4 * ((_bss) & 7) + (_idx)) * 32) +#define MT_SKEY(_bss, _idx) (((_bss) & 8) ? MT_SKEY_1(_bss, _idx) : MT_SKEY_0(_bss, _idx)) #define MT_SKEY_MODE_BASE_0 0xb000 #define MT_SKEY_MODE_BASE_1 0xb3f0 -#define MT_SKEY_MODE_0(_bss) (MT_SKEY_MODE_BASE_0 + ((_bss / 2) << 2)) +#define MT_SKEY_MODE_0(_bss) (MT_SKEY_MODE_BASE_0 + (((_bss) / 2) << 2)) #define MT_SKEY_MODE_1(_bss) (MT_SKEY_MODE_BASE_1 + ((((_bss) & 7) / 2) << 2)) -#define MT_SKEY_MODE(_bss) ((_bss & 8) ? MT_SKEY_MODE_1(_bss) : MT_SKEY_MODE_0(_bss)) +#define MT_SKEY_MODE(_bss) (((_bss) & 8) ? MT_SKEY_MODE_1(_bss) : MT_SKEY_MODE_0(_bss)) #define MT_SKEY_MODE_MASK GENMASK(3, 0) -#define MT_SKEY_MODE_SHIFT(_bss, _idx) (4 * ((_idx) + 4 * (_bss & 1))) +#define MT_SKEY_MODE_SHIFT(_bss, _idx) (4 * ((_idx) + 4 * ((_bss) & 1))) #define MT_BEACON_BASE 0xc000 diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.c b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.c index 5b42d2c87937..a812c3a1e258 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h index 713f12d3c8de..61ecaf0fe065 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_trace.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if !defined(__MT76x02_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) @@ -25,7 +14,8 @@ #define MAXNAME 32 #define DEV_ENTRY __array(char, wiphy_name, 32) -#define DEV_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) +#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ + wiphy_name(mt76_hw(dev)->wiphy), MAXNAME) #define DEV_PR_FMT "%s" #define DEV_PR_ARG __entry->wiphy_name diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c index 04118f08debc..13825f642087 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_txrx.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/kernel.h> @@ -169,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; @@ -182,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h index 7b53f9e57f29..a57dcc8820aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x02_USB_H @@ -19,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, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c index e4332d5a5757..d03d3c8e296c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76x02_usb.h" @@ -34,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; @@ -94,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; @@ -108,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index 0cb8751321a1..a993cd7e9948 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index ad5323447ed4..0960fc56b672 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/module.h> @@ -21,14 +10,14 @@ #define CCK_RATE(_idx, _rate) { \ .bitrate = _rate, \ .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ - .hw_value = (MT_PHY_TYPE_CCK << 8) | _idx, \ - .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + _idx), \ + .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + (_idx)), \ } #define OFDM_RATE(_idx, _rate) { \ .bitrate = _rate, \ - .hw_value = (MT_PHY_TYPE_OFDM << 8) | _idx, \ - .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | _idx, \ + .hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ + .hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \ } struct ieee80211_rate mt76x02_rates[] = { @@ -61,6 +50,20 @@ static const struct ieee80211_iface_limit mt76x02_if_limits[] = { }, }; +static const struct ieee80211_iface_limit mt76x02u_if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC) + }, { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION) | +#ifdef CONFIG_MAC80211_MESH + BIT(NL80211_IFTYPE_MESH_POINT) | +#endif + BIT(NL80211_IFTYPE_AP) + }, +}; + static const struct ieee80211_iface_combination mt76x02_if_comb[] = { { .limits = mt76x02_if_limits, @@ -75,6 +78,16 @@ static const struct ieee80211_iface_combination mt76x02_if_comb[] = { } }; +static const struct ieee80211_iface_combination mt76x02u_if_comb[] = { + { + .limits = mt76x02u_if_limits, + .n_limits = ARRAY_SIZE(mt76x02u_if_limits), + .max_interfaces = 2, + .num_different_channels = 1, + .beacon_int_infra_match = true, + } +}; + static void mt76x02_led_set_config(struct mt76_dev *mdev, u8 delay_on, u8 delay_off) @@ -140,17 +153,11 @@ 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; + wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02u_if_comb); } else { INIT_DELAYED_WORK(&dev->wdt_work, mt76x02_wdt_work); @@ -175,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; @@ -249,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); @@ -281,7 +288,7 @@ mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, mvif->idx = idx; mvif->group_wcid.idx = MT_VIF_WCID(idx); mvif->group_wcid.hw_key_idx = -1; - mtxq = (struct mt76_txq *) vif->txq->drv_priv; + mtxq = (struct mt76_txq *)vif->txq->drv_priv; mtxq->wcid = &mvif->group_wcid; mt76_txq_init(&dev->mt76, vif->txq); @@ -345,21 +352,23 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action = params->action; struct ieee80211_sta *sta = params->sta; struct mt76x02_dev *dev = hw->priv; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; struct ieee80211_txq *txq = sta->txq[params->tid]; u16 tid = params->tid; - u16 *ssn = ¶ms->ssn; + u16 ssn = params->ssn; struct mt76_txq *mtxq; + int ret = 0; if (!txq) return -EINVAL; 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, params->buf_size); + ssn, params->buf_size); mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); break; case IEEE80211_AMPDU_RX_STOP: @@ -375,19 +384,19 @@ int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; - ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn); break; case IEEE80211_AMPDU_TX_START: - mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(*ssn); - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; break; case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } + mutex_unlock(&dev->mt76.mutex); - return 0; + return ret; } EXPORT_SYMBOL_GPL(mt76x02_ampdu_action); @@ -429,12 +438,12 @@ 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; - msta = sta ? (struct mt76x02_sta *) sta->drv_priv : NULL; + msta = sta ? (struct mt76x02_sta *)sta->drv_priv : NULL; wcid = msta ? &msta->wcid : &mvif->group_wcid; if (cmd == SET_KEY) { @@ -558,11 +567,11 @@ int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val) EXPORT_SYMBOL_GPL(mt76x02_set_rts_threshold); void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) { struct mt76x02_dev *dev = hw->priv; - struct mt76x02_sta *msta = (struct mt76x02_sta *) sta->drv_priv; + struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates); struct ieee80211_tx_rate rate = {}; @@ -588,15 +597,6 @@ void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len) } EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad); -void mt76x02_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - const u8 *mac) -{ - struct mt76x02_dev *dev = hw->priv; - - set_bit(MT76_SCANNING, &dev->mt76.state); -} -EXPORT_SYMBOL_GPL(mt76x02_sw_scan); - void mt76x02_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -619,7 +619,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig index 1f69908f8373..5fd4973e32df 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig @@ -8,8 +8,12 @@ config MT76x2E select MT76x2_COMMON depends on MAC80211 depends on PCI - ---help--- - This adds support for MT7612/MT7602/MT7662-based wireless PCIe devices. + help + This adds support for MT7612/MT7602/MT7662-based wireless PCIe + devices, which comply with IEEE 802.11ac standards and support + 2SS to 866Mbit/s PHY rate. + + To compile this driver as a module, choose M here. config MT76x2U tristate "MediaTek MT76x2U (USB) support" @@ -18,4 +22,8 @@ config MT76x2U depends on MAC80211 depends on USB help - This adds support for MT7612U-based wireless USB dongles. + This adds support for MT7612U-based wireless USB 3.0 dongles, + which comply with IEEE 802.11ac standards and support 2SS to + 866Mbit/s PHY rate. + + To compile this driver as a module, choose M here. diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c index 6f6998561d9d..9f91556c7f38 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/module.h> @@ -33,7 +22,7 @@ mt76x2_eeprom_get_macaddr(struct mt76x02_dev *dev) static bool mt76x2_has_cal_free_data(struct mt76x02_dev *dev, u8 *efuse) { - u16 *efuse_w = (u16 *) efuse; + u16 *efuse_w = (u16 *)efuse; if (efuse_w[MT_EE_NIC_CONF_0] != 0) return false; @@ -372,7 +361,8 @@ mt76x2_get_power_info_2g(struct mt76x02_dev *dev, t->chain[chain].tssi_slope = data[0]; t->chain[chain].tssi_offset = data[1]; t->chain[chain].target_power = data[2]; - t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); + t->chain[chain].delta = + mt76x02_sign_extend_optional(data[delta_idx], 7); val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_TSSI_OFF_TXPOWER); t->target_power = val >> 8; @@ -381,7 +371,7 @@ mt76x2_get_power_info_2g(struct mt76x02_dev *dev, static void mt76x2_get_power_info_5g(struct mt76x02_dev *dev, struct mt76x2_tx_power_info *t, - struct ieee80211_channel *chan, + struct ieee80211_channel *chan, int chain, int offset) { int channel = chan->hw_value; @@ -423,7 +413,8 @@ mt76x2_get_power_info_5g(struct mt76x02_dev *dev, t->chain[chain].tssi_slope = data[0]; t->chain[chain].tssi_offset = data[1]; t->chain[chain].target_power = data[2]; - t->chain[chain].delta = mt76x02_sign_extend_optional(data[delta_idx], 7); + t->chain[chain].delta = + mt76x02_sign_extend_optional(data[delta_idx], 7); val = mt76x02_eeprom_get(dev, MT_EE_RF_2G_RX_HIGH_GAIN); t->target_power = val & 0xff; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h index 9e735524d367..4dcf6518cb0d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x2_EEPROM_H diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c index 97c3543eed8a..79e583eb066b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/init.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76x2.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c index e99d4c9bd428..e08740ca3d0c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76x2.h" diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h index 42ff221d7706..d5c3d26b94c1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mac.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x2_MAC_H @@ -23,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) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c index cd3e082f486c..76d8cd37d4de 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/kernel.h> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h index 40ef43926c06..41fd66563e82 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x2_MCU_H @@ -71,7 +60,8 @@ struct mt76x2_tssi_comp { u8 offset1; } __packed __aligned(4); -int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev, struct mt76x2_tssi_comp *tssi_data); +int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev, + struct mt76x2_tssi_comp *tssi_data); int mt76x2_mcu_init_gain(struct mt76x02_dev *dev, u8 channel, u32 gain, bool force); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h index d7abe3d73bad..41680c420cda 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x2_H diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h index 76cb1f84eff5..f9d37c6cf1f0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mt76x2u.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __MT76x2U_H @@ -35,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, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c index e84d5c5911ea..53ca0cedf026 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/kernel.h> @@ -32,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, @@ -92,6 +83,8 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* RG_SSUSB_CDR_BR_PE1D = 0x3 */ mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3); + mt76_pci_disable_aspm(pdev); + return 0; error: diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c index 71aea2832644..33fcec9179b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c @@ -1,23 +1,13 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/delay.h> #include "mt76x2.h" #include "eeprom.h" #include "mcu.h" +#include "../mt76x02_mac.h" static void mt76x2_mac_pbf_init(struct mt76x02_dev *dev) @@ -143,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) { @@ -275,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) @@ -336,4 +299,3 @@ fail: return ret; } - diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index 3a1467326f4d..cfe8905ce73f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -1,20 +1,10 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76x2.h" +#include "../mt76x02_mac.h" static int mt76x2_start(struct ieee80211_hw *hw) @@ -22,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; @@ -65,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); @@ -151,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, @@ -176,7 +147,7 @@ const struct ieee80211_ops mt76x2_ops = { .sta_state = mt76_sta_state, .set_key = mt76x02_set_key, .conf_tx = mt76x02_conf_tx, - .sw_scan_start = mt76x02_sw_scan, + .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76x02_sw_scan_complete, .flush = mt76x2_flush, .ampdu_action = mt76x02_ampdu_action, @@ -188,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, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c index 605dc66ae83b..ca6f968411ac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/kernel.h> @@ -66,7 +55,7 @@ mt76pci_load_rom_patch(struct mt76x02_dev *dev) mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ROM_PATCH_OFFSET); - cur = (__le32 *) (fw->data + sizeof(*hdr)); + cur = (__le32 *)(fw->data + sizeof(*hdr)); len = fw->size - sizeof(*hdr); mt76_wr_copy(dev, MT_MCU_ROM_PATCH_ADDR, cur, len); @@ -121,7 +110,7 @@ mt76pci_load_firmware(struct mt76x02_dev *dev) dev_info(dev->mt76.dev, "Build: %x\n", val); dev_info(dev->mt76.dev, "Build Time: %.16s\n", hdr->build_time); - cur = (__le32 *) (fw->data + sizeof(*hdr)); + cur = (__le32 *)(fw->data + sizeof(*hdr)); len = le32_to_cpu(hdr->ilm_len); mt76_wr(dev, MT_MCU_PCIE_REMAP_BASE4, MT_MCU_ILM_OFFSET); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c index 2edf1bd0c18c..23f35bf8d47b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_phy.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/delay.h> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c index cdedf95ca4f5..edbab4fa7f6e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/phy.c @@ -1,18 +1,7 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76x2.h" @@ -25,7 +14,8 @@ mt76x2_adjust_high_lna_gain(struct mt76x02_dev *dev, int reg, s8 offset) { s8 gain; - gain = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, mt76_rr(dev, MT_BBP(AGC, reg))); + gain = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, + mt76_rr(dev, MT_BBP(AGC, reg))); gain -= offset / 2; mt76_rmw_field(dev, MT_BBP(AGC, reg), MT_BBP_AGC_LNA_HIGH_GAIN, gain); } @@ -295,7 +285,7 @@ void mt76x2_phy_update_channel_gain(struct mt76x02_dev *dev) dev->cal.avg_rssi_all = -75; low_gain = (dev->cal.avg_rssi_all > mt76x02_get_rssi_gain_thresh(dev)) + - (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev)); + (dev->cal.avg_rssi_all > mt76x02_get_low_rssi_gain_thresh(dev)); gain_change = dev->cal.low_gain < 0 || (dev->cal.low_gain & 2) ^ (low_gain & 2); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c index 7a994a783510..b64ad816cc25 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/kernel.h> @@ -36,6 +25,9 @@ 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, .tx_status_data = mt76x02_tx_status_data, @@ -49,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; @@ -81,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); @@ -96,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); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c index 94f52f98019b..2910068f4e79 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_init.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/delay.h> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c index 3b82345756ea..59cbe826188a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mac.c @@ -1,32 +1,11 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #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; @@ -113,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; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index e4dfc3bea3c5..9e97204841f5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -1,27 +1,17 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #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,7 +38,7 @@ mt76x2u_set_channel(struct mt76x02_dev *dev, int err; cancel_delayed_work_sync(&dev->cal_work); - dev->beacon_ops->pre_tbtt_enable(dev, false); + mt76x02_pre_tbtt_enable(dev, false); mutex_lock(&dev->mt76.mutex); set_bit(MT76_RESET, &dev->mt76.state); @@ -59,12 +49,13 @@ mt76x2u_set_channel(struct mt76x02_dev *dev, err = mt76x2u_phy_set_channel(dev, chandef); + mt76x02_mac_cc_reset(dev); mt76x2_mac_resume(dev); clear_bit(MT76_RESET, &dev->mt76.state); mutex_unlock(&dev->mt76.mutex); - dev->beacon_ops->pre_tbtt_enable(dev, true); + mt76x02_pre_tbtt_enable(dev, true); mt76_txq_schedule_all(&dev->mt76); return err; @@ -121,10 +112,12 @@ const struct ieee80211_ops mt76x2u_ops = { .bss_info_changed = mt76x02_bss_info_changed, .configure_filter = mt76x02_configure_filter, .conf_tx = mt76x02_conf_tx, - .sw_scan_start = mt76x02_sw_scan, + .sw_scan_start = mt76_sw_scan, .sw_scan_complete = mt76x02_sw_scan_complete, .sta_rate_tbl_update = mt76x02_sta_rate_tbl_update, .get_txpower = mt76_get_txpower, + .get_survey = mt76_get_survey, .set_tim = mt76_set_tim, .release_buffered_frames = mt76_release_buffered_frames, + .get_antenna = mt76_get_antenna, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c index 152d41fe9ff5..dd22d8af0901 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_mcu.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/firmware.h> diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c index dfd54f9b0e97..b1381f9df992 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_phy.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76x2u.h" diff --git a/drivers/net/wireless/mediatek/mt76/pci.c b/drivers/net/wireless/mediatek/mt76/pci.c new file mode 100644 index 000000000000..04c5a692bc85 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/pci.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (C) 2019 Lorenzo Bianconi <lorenzo@kernel.org> + */ + +#include <linux/pci.h> + +void mt76_pci_disable_aspm(struct pci_dev *pdev) +{ + struct pci_dev *parent = pdev->bus->self; + u16 aspm_conf, parent_aspm_conf = 0; + + pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &aspm_conf); + aspm_conf &= PCI_EXP_LNKCTL_ASPMC; + if (parent) { + pcie_capability_read_word(parent, PCI_EXP_LNKCTL, + &parent_aspm_conf); + parent_aspm_conf &= PCI_EXP_LNKCTL_ASPMC; + } + + if (!aspm_conf && (!parent || !parent_aspm_conf)) { + /* aspm already disabled */ + return; + } + + dev_info(&pdev->dev, "disabling ASPM %s %s\n", + (aspm_conf & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "", + (aspm_conf & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : ""); + + if (IS_ENABLED(CONFIG_PCIEASPM)) { + int err; + + err = pci_disable_link_state(pdev, aspm_conf); + if (!err) + return; + } + + /* both device and parent should have the same ASPM setting. + * disable ASPM in downstream component first and then upstream. + */ + pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_conf); + if (parent) + pcie_capability_clear_word(parent, PCI_EXP_LNKCTL, + aspm_conf); +} +EXPORT_SYMBOL_GPL(mt76_pci_disable_aspm); diff --git a/drivers/net/wireless/mediatek/mt76/trace.c b/drivers/net/wireless/mediatek/mt76/trace.c index ea4ab8729ae4..ed3df3c8b4b3 100644 --- a/drivers/net/wireless/mediatek/mt76/trace.c +++ b/drivers/net/wireless/mediatek/mt76/trace.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/net/wireless/mediatek/mt76/trace.h b/drivers/net/wireless/mediatek/mt76/trace.h index ea30895933c5..0b3e635da868 100644 --- a/drivers/net/wireless/mediatek/mt76/trace.h +++ b/drivers/net/wireless/mediatek/mt76/trace.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if !defined(__MT76_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) @@ -24,10 +13,11 @@ #define TRACE_SYSTEM mt76 #define MAXNAME 32 -#define DEV_ENTRY __array(char, wiphy_name, 32) -#define DEV_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(dev->hw->wiphy), MAXNAME) -#define DEV_PR_FMT "%s" -#define DEV_PR_ARG __entry->wiphy_name +#define DEV_ENTRY __array(char, wiphy_name, 32) +#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ + wiphy_name(dev->hw->wiphy), MAXNAME) +#define DEV_PR_FMT "%s" +#define DEV_PR_ARG __entry->wiphy_name #define REG_ENTRY __field(u32, reg) __field(u32, val) #define REG_ASSIGN __entry->reg = reg; __entry->val = val diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 5397827668b9..7ee91d946882 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "mt76.h" @@ -97,7 +86,7 @@ mt76_txq_get_qid(struct ieee80211_txq *txq) static void mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (!ieee80211_is_data_qos(hdr->frame_control) || !ieee80211_is_data_present(hdr->frame_control)) @@ -217,8 +206,8 @@ mt76_tx_status_skb_get(struct mt76_dev *dev, struct mt76_wcid *wcid, int pktid, if (cb->pktid == pktid) return skb; - if (pktid >= 0 && - !time_after(jiffies, cb->jiffies + MT_TX_STATUS_SKB_TIMEOUT)) + if (pktid >= 0 && !time_after(jiffies, cb->jiffies + + MT_TX_STATUS_SKB_TIMEOUT)) continue; __mt76_tx_status_skb_done(dev, skb, MT_TX_CB_TXS_FAILED | @@ -260,7 +249,7 @@ mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct mt76_queue *q; int qid = skb_get_queue_mapping(skb); @@ -280,7 +269,7 @@ mt76_tx(struct mt76_dev *dev, struct ieee80211_sta *sta, tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; txq = sta->txq[tid]; - mtxq = (struct mt76_txq *) txq->drv_priv; + mtxq = (struct mt76_txq *)txq->drv_priv; if (mtxq->aggr) mt76_check_agg_ssn(mtxq, skb); @@ -328,7 +317,7 @@ static void mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta, struct sk_buff *skb, bool last) { - struct mt76_wcid *wcid = (struct mt76_wcid *) sta->drv_priv; + struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE; @@ -354,7 +343,7 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta, spin_lock_bh(&hwq->lock); for (i = 0; tids && nframes; i++, tids >>= 1) { struct ieee80211_txq *txq = sta->txq[i]; - struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; + struct mt76_txq *mtxq = (struct mt76_txq *)txq->drv_priv; struct sk_buff *skb; if (!(tids & 1)) @@ -389,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); @@ -403,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)) @@ -438,15 +423,12 @@ mt76_txq_send_burst(struct mt76_dev *dev, struct mt76_sw_queue *sq, if (probe) break; - if (test_bit(MT76_OFFCHANNEL, &dev->state) || - test_bit(MT76_RESET, &dev->state)) + if (test_bit(MT76_RESET, &dev->state)) 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; @@ -493,13 +475,10 @@ 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; - if (test_bit(MT76_OFFCHANNEL, &dev->state) || - test_bit(MT76_RESET, &dev->state)) { + if (test_bit(MT76_RESET, &dev->state)) { ret = -EBUSY; break; } @@ -526,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); @@ -568,6 +546,13 @@ void mt76_txq_schedule_all(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76_txq_schedule_all); +void mt76_tx_tasklet(unsigned long data) +{ + struct mt76_dev *dev = (struct mt76_dev *)data; + + mt76_txq_schedule_all(dev); +} + void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta, bool send_bar) { @@ -610,7 +595,7 @@ void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq) if (!txq) return; - mtxq = (struct mt76_txq *) txq->drv_priv; + mtxq = (struct mt76_txq *)txq->drv_priv; while ((skb = skb_dequeue(&mtxq->retry_q)) != NULL) ieee80211_free_txskb(dev->hw, skb); @@ -619,7 +604,7 @@ EXPORT_SYMBOL_GPL(mt76_txq_remove); void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq) { - struct mt76_txq *mtxq = (struct mt76_txq *) txq->drv_priv; + struct mt76_txq *mtxq = (struct mt76_txq *)txq->drv_priv; skb_queue_head_init(&mtxq->retry_q); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index fb87ce7fbdf6..d6d47081e281 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/module.h> @@ -26,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++) { @@ -71,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; @@ -95,9 +85,9 @@ static u32 __mt76u_rr(struct mt76_dev *dev, u32 addr) ret = __mt76u_vendor_request(dev, req, USB_DIR_IN | USB_TYPE_VENDOR, - 0, offset, usb->data, sizeof(__le32)); + 0, offset, &usb->reg_val, sizeof(__le32)); if (ret == sizeof(__le32)) - data = get_unaligned_le32(usb->data); + data = le32_to_cpu(usb->reg_val); trace_usb_reg_rr(dev, addr, data); return data; @@ -114,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; @@ -131,10 +120,10 @@ static void __mt76u_wr(struct mt76_dev *dev, u32 addr, u32 val) } offset = addr & ~MT_VEND_TYPE_MASK; - put_unaligned_le32(val, usb->data); + usb->reg_val = cpu_to_le32(val); __mt76u_vendor_request(dev, req, USB_DIR_OUT | USB_TYPE_VENDOR, 0, - offset, usb->data, sizeof(__le32)); + offset, &usb->reg_val, sizeof(__le32)); trace_usb_reg_wr(dev, addr, val); } @@ -164,12 +153,12 @@ static void mt76u_copy(struct mt76_dev *dev, u32 offset, int i, ret; mutex_lock(&usb->usb_ctrl_mtx); - for (i = 0; i < (len / 4); i++) { - put_unaligned_le32(val[i], usb->data); + for (i = 0; i < DIV_ROUND_UP(len, 4); i++) { + put_unaligned(val[i], (u32 *)usb->data); ret = __mt76u_vendor_request(dev, MT_VEND_MULTI_WRITE, USB_DIR_OUT | USB_TYPE_VENDOR, 0, offset + i * 4, usb->data, - sizeof(__le32)); + sizeof(u32)); if (ret < 0) break; } @@ -246,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 || @@ -309,7 +299,7 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76_queue *q, struct urb *urb, } urb->num_sgs = max_t(int, i, urb->num_sgs); - urb->transfer_buffer_length = urb->num_sgs * q->buf_size, + urb->transfer_buffer_length = urb->num_sgs * q->buf_size; sg_init_marker(urb->sg, urb->num_sgs); return i ? : -ENOMEM; @@ -320,14 +310,13 @@ mt76u_refill_rx(struct mt76_dev *dev, struct urb *urb, int nsgs, gfp_t gfp) { struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; - if (dev->usb.sg_en) { + if (dev->usb.sg_en) return mt76u_fill_rx_sg(dev, q, urb, nsgs, gfp); - } else { - urb->transfer_buffer_length = q->buf_size; - urb->transfer_buffer = page_frag_alloc(&q->rx_page, - q->buf_size, gfp); - return urb->transfer_buffer ? 0 : -ENOMEM; - } + + urb->transfer_buffer_length = q->buf_size; + urb->transfer_buffer = page_frag_alloc(&q->rx_page, q->buf_size, gfp); + + return urb->transfer_buffer ? 0 : -ENOMEM; } static int @@ -382,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) @@ -707,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); } @@ -723,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) { @@ -736,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); } @@ -763,13 +749,14 @@ mt76u_tx_setup_buffers(struct mt76_dev *dev, struct sk_buff *skb, if (!dev->usb.sg_en) { urb->transfer_buffer = skb->data; return 0; - } else { - sg_init_table(urb->sg, MT_TX_SG_MAX_SIZE); - urb->num_sgs = skb_to_sgvec(skb, urb->sg, 0, skb->len); - if (urb->num_sgs == 0) - return -ENOMEM; - return urb->num_sgs; } + + sg_init_table(urb->sg, MT_TX_SG_MAX_SIZE); + urb->num_sgs = skb_to_sgvec(skb, urb->sg, 0, skb->len); + if (!urb->num_sgs) + return -ENOMEM; + + return urb->num_sgs; } static int @@ -885,7 +872,8 @@ void mt76u_stop_tx(struct mt76_dev *dev) struct mt76_queue *q; int i, j, ret; - ret = wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), HZ/5); + ret = wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(dev), + HZ / 5); if (!ret) { dev_err(dev->dev, "timed out waiting for pending tx\n"); @@ -916,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); @@ -957,29 +945,45 @@ int mt76u_init(struct mt76_dev *dev, .rr = mt76u_rr, .wr = mt76u_wr, .rmw = mt76u_rmw, - .copy = mt76u_copy, + .write_copy = mt76u_copy, .wr_rp = mt76u_wr_rp, .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"); diff --git a/drivers/net/wireless/mediatek/mt76/usb_trace.c b/drivers/net/wireless/mediatek/mt76/usb_trace.c index 7e1f540f0b7a..9942bdd6177b 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_trace.c +++ b/drivers/net/wireless/mediatek/mt76/usb_trace.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/net/wireless/mediatek/mt76/usb_trace.h b/drivers/net/wireless/mediatek/mt76/usb_trace.h index b56c32343eb1..f5ab3215af80 100644 --- a/drivers/net/wireless/mediatek/mt76/usb_trace.h +++ b/drivers/net/wireless/mediatek/mt76/usb_trace.h @@ -1,17 +1,6 @@ +/* SPDX-License-Identifier: ISC */ /* * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if !defined(__MT76_USB_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) @@ -24,10 +13,11 @@ #define TRACE_SYSTEM mt76_usb #define MAXNAME 32 -#define DEV_ENTRY __array(char, wiphy_name, 32) -#define DEV_ASSIGN strlcpy(__entry->wiphy_name, wiphy_name(dev->hw->wiphy), MAXNAME) -#define DEV_PR_FMT "%s " -#define DEV_PR_ARG __entry->wiphy_name +#define DEV_ENTRY __array(char, wiphy_name, 32) +#define DEV_ASSIGN strlcpy(__entry->wiphy_name, \ + wiphy_name(dev->hw->wiphy), MAXNAME) +#define DEV_PR_FMT "%s " +#define DEV_PR_ARG __entry->wiphy_name #define REG_ENTRY __field(u32, reg) __field(u32, val) #define REG_ASSIGN __entry->reg = reg; __entry->val = val @@ -65,7 +55,7 @@ DECLARE_EVENT_CLASS(urb_transfer, TP_PROTO(struct mt76_dev *dev, struct urb *u), TP_ARGS(dev, u), TP_STRUCT__entry( - DEV_ENTRY __field(unsigned, pipe) __field(u32, len) + DEV_ENTRY __field(unsigned int, pipe) __field(u32, len) ), TP_fast_assign( DEV_ASSIGN; diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c index 69270c1a9091..23d1e1da78b2 100644 --- a/drivers/net/wireless/mediatek/mt76/util.c +++ b/drivers/net/wireless/mediatek/mt76/util.c @@ -1,17 +1,6 @@ +// SPDX-License-Identifier: ISC /* * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/wireless/mediatek/mt76/util.h index 9f8d59269a9e..fe3479c8e561 100644 --- a/drivers/net/wireless/mediatek/mt76/util.h +++ b/drivers/net/wireless/mediatek/mt76/util.h @@ -12,7 +12,7 @@ #include <linux/bitfield.h> #define MT76_INCR(_var, _size) \ - _var = (((_var) + 1) % _size) + (_var = (((_var) + 1) % (_size))) int mt76_wcid_alloc(unsigned long *mask, int size); @@ -25,7 +25,7 @@ mt76_wcid_free(unsigned long *mask, int idx) static inline void mt76_skb_set_moredata(struct sk_buff *skb, bool enable) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; if (enable) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); diff --git a/drivers/net/wireless/mediatek/mt7601u/debugfs.c b/drivers/net/wireless/mediatek/mt7601u/debugfs.c index 5e549831370c..300242bce799 100644 --- a/drivers/net/wireless/mediatek/mt7601u/debugfs.c +++ b/drivers/net/wireless/mediatek/mt7601u/debugfs.c @@ -27,7 +27,7 @@ mt76_reg_get(void *data, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n"); static int mt7601u_ampdu_stat_read(struct seq_file *file, void *data) diff --git a/drivers/net/wireless/mediatek/mt7601u/init.c b/drivers/net/wireless/mediatek/mt7601u/init.c index 9bfac9f1d47f..cada48800928 100644 --- a/drivers/net/wireless/mediatek/mt7601u/init.c +++ b/drivers/net/wireless/mediatek/mt7601u/init.c @@ -557,6 +557,9 @@ mt76_init_sband_2g(struct mt7601u_dev *dev) { dev->sband_2g = devm_kzalloc(dev->dev, sizeof(*dev->sband_2g), GFP_KERNEL); + if (!dev->sband_2g) + return -ENOMEM; + dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = dev->sband_2g; WARN_ON(dev->ee->reg.start - 1 + dev->ee->reg.num > diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c index 89a7b1234ffb..671d8897ae76 100644 --- a/drivers/net/wireless/mediatek/mt7601u/main.c +++ b/drivers/net/wireless/mediatek/mt7601u/main.c @@ -351,7 +351,7 @@ mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta = params->sta; enum ieee80211_ampdu_mlme_action action = params->action; u16 tid = params->tid; - u16 *ssn = ¶ms->ssn; + u16 ssn = params->ssn; struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv; WARN_ON(msta->wcid.idx > GROUP_WCID(0)); @@ -371,9 +371,8 @@ mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: break; case IEEE80211_AMPDU_TX_START: - msta->agg_ssn[tid] = *ssn << 4; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - break; + msta->agg_ssn[tid] = ssn << 4; + return IEEE80211_AMPDU_TX_START_IMMEDIATE; case IEEE80211_AMPDU_TX_STOP_CONT: ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; diff --git a/drivers/net/wireless/mediatek/mt7601u/phy.c b/drivers/net/wireless/mediatek/mt7601u/phy.c index 06f5702ab4bd..d863ab4a66c9 100644 --- a/drivers/net/wireless/mediatek/mt7601u/phy.c +++ b/drivers/net/wireless/mediatek/mt7601u/phy.c @@ -213,7 +213,7 @@ int mt7601u_wait_bbp_ready(struct mt7601u_dev *dev) do { val = mt7601u_bbp_rr(dev, MT_BBP_REG_VERSION); - if (val && ~val) + if (val && val != 0xff) break; } while (--i); |