summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/mediatek/mt76
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-12-16 00:22:29 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2020-12-16 00:22:29 +0300
commitd635a69dd4981cc51f90293f5f64268620ed1565 (patch)
tree5e0a758b402ea7d624c25c3a343545dd29e80f31 /drivers/net/wireless/mediatek/mt76
parentac73e3dc8acd0a3be292755db30388c3580f5674 (diff)
parentefd5a1584537698220578227e6467638307c2a0b (diff)
downloadlinux-d635a69dd4981cc51f90293f5f64268620ed1565.tar.xz
Merge tag 'net-next-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from Jakub Kicinski: "Core: - support "prefer busy polling" NAPI operation mode, where we defer softirq for some time expecting applications to periodically busy poll - AF_XDP: improve efficiency by more batching and hindering the adjacency cache prefetcher - af_packet: make packet_fanout.arr size configurable up to 64K - tcp: optimize TCP zero copy receive in presence of partial or unaligned reads making zero copy a performance win for much smaller messages - XDP: add bulk APIs for returning / freeing frames - sched: support fragmenting IP packets as they come out of conntrack - net: allow virtual netdevs to forward UDP L4 and fraglist GSO skbs BPF: - BPF switch from crude rlimit-based to memcg-based memory accounting - BPF type format information for kernel modules and related tracing enhancements - BPF implement task local storage for BPF LSM - allow the FENTRY/FEXIT/RAW_TP tracing programs to use bpf_sk_storage Protocols: - mptcp: improve multiple xmit streams support, memory accounting and many smaller improvements - TLS: support CHACHA20-POLY1305 cipher - seg6: add support for SRv6 End.DT4/DT6 behavior - sctp: Implement RFC 6951: UDP Encapsulation of SCTP - ppp_generic: add ability to bridge channels directly - bridge: Connectivity Fault Management (CFM) support as is defined in IEEE 802.1Q section 12.14. Drivers: - mlx5: make use of the new auxiliary bus to organize the driver internals - mlx5: more accurate port TX timestamping support - mlxsw: - improve the efficiency of offloaded next hop updates by using the new nexthop object API - support blackhole nexthops - support IEEE 802.1ad (Q-in-Q) bridging - rtw88: major bluetooth co-existance improvements - iwlwifi: support new 6 GHz frequency band - ath11k: Fast Initial Link Setup (FILS) - mt7915: dual band concurrent (DBDC) support - net: ipa: add basic support for IPA v4.5 Refactor: - a few pieces of in_interrupt() cleanup work from Sebastian Andrzej Siewior - phy: add support for shared interrupts; get rid of multiple driver APIs and have the drivers write a full IRQ handler, slight growth of driver code should be compensated by the simpler API which also allows shared IRQs - add common code for handling netdev per-cpu counters - move TX packet re-allocation from Ethernet switch tag drivers to a central place - improve efficiency and rename nla_strlcpy - number of W=1 warning cleanups as we now catch those in a patchwork build bot Old code removal: - wan: delete the DLCI / SDLA drivers - wimax: move to staging - wifi: remove old WDS wifi bridging support" * tag 'net-next-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1922 commits) net: hns3: fix expression that is currently always true net: fix proc_fs init handling in af_packet and tls nfc: pn533: convert comma to semicolon af_vsock: Assign the vsock transport considering the vsock address flags af_vsock: Set VMADDR_FLAG_TO_HOST flag on the receive path vsock_addr: Check for supported flag values vm_sockets: Add VMADDR_FLAG_TO_HOST vsock flag vm_sockets: Add flags field in the vsock address data structure net: Disable NETIF_F_HW_TLS_TX when HW_CSUM is disabled tcp: Add logic to check for SYN w/ data in tcp_simple_retransmit net: mscc: ocelot: install MAC addresses in .ndo_set_rx_mode from process context nfc: s3fwrn5: Release the nfc firmware net: vxget: clean up sparse warnings mlxsw: spectrum_router: Use eXtended mezzanine to offload IPv4 router mlxsw: spectrum: Set KVH XLT cache mode for Spectrum2/3 mlxsw: spectrum_router_xm: Introduce basic XM cache flushing mlxsw: reg: Add Router LPM Cache Enable Register mlxsw: reg: Add Router LPM Cache ML Delete Register mlxsw: spectrum_router_xm: Implement L-value tracking for M-index mlxsw: reg: Add XM Router M Table Register ...
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76')
-rw-r--r--drivers/net/wireless/mediatek/mt76/debugfs.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.c37
-rw-r--r--drivers/net/wireless/mediatek/mt76/eeprom.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mac80211.c149
-rw-r--r--drivers/net/wireless/mediatek/mt76/mcu.c80
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h121
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/beacon.c30
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/dma.c61
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/init.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mac.c9
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/main.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mcu.c131
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/pci.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c139
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/dma.c55
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c22
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/init.c23
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.c199
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/main.c122
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.c544
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.h17
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mmio.c9
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h92
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c9
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/regs.h11
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/sdio.c71
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c42
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c142
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/testmode.c28
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/usb.c9
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c16
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c89
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/init.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/pci.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/phy.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/usb.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mac.c16
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c55
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c76
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_util.c13
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c18
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/Makefile2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c47
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/dma.c76
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c64
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/init.c435
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.c539
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.h16
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/main.c133
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.c734
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.h54
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h64
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/pci.c24
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/regs.h52
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/testmode.c377
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/testmode.h40
-rw-r--r--drivers/net/wireless/mediatek/mt76/sdio.c196
-rw-r--r--drivers/net/wireless/mediatek/mt76/testmode.c41
-rw-r--r--drivers/net/wireless/mediatek/mt76/testmode.h18
-rw-r--r--drivers/net/wireless/mediatek/mt76/tx.c60
-rw-r--r--drivers/net/wireless/mediatek/mt76/usb.c89
76 files changed, 3446 insertions, 2156 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c
index 52f583cb1418..d4a6b8108971 100644
--- a/drivers/net/wireless/mediatek/mt76/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/debugfs.c
@@ -30,8 +30,8 @@ int mt76_queues_read(struct seq_file *s, void *data)
struct mt76_dev *dev = dev_get_drvdata(s->private);
int i;
- for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) {
- struct mt76_queue *q = dev->q_tx[i];
+ for (i = 0; i < ARRAY_SIZE(dev->phy.q_tx); i++) {
+ struct mt76_queue *q = dev->phy.q_tx[i];
if (!q)
continue;
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 214fc95b8a33..73eeb00d5aa6 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -72,9 +72,11 @@ mt76_free_pending_txwi(struct mt76_dev *dev)
{
struct mt76_txwi_cache *t;
+ local_bh_disable();
while ((t = __mt76_get_txwi(dev)) != NULL)
dma_unmap_single(dev->dev, t->dma_addr, dev->drv->txwi_size,
DMA_TO_DEVICE);
+ local_bh_enable();
}
static int
@@ -86,6 +88,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
int i;
spin_lock_init(&q->lock);
+ spin_lock_init(&q->cleanup_lock);
q->regs = dev->mmio.regs + ring_base + idx * MT_RING_SIZE;
q->ndesc = n_desc;
@@ -215,16 +218,15 @@ mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q)
}
static void
-mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
+mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush)
{
- struct mt76_queue *q = dev->q_tx[qid];
struct mt76_queue_entry entry;
- bool wake = false;
int last;
if (!q)
return;
+ spin_lock_bh(&q->cleanup_lock);
if (flush)
last = -1;
else
@@ -237,13 +239,13 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
if (entry.txwi) {
if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE))
mt76_put_txwi(dev, entry.txwi);
- wake = !flush;
}
if (!flush && q->tail == last)
last = readl(&q->regs->dma_idx);
}
+ spin_unlock_bh(&q->cleanup_lock);
if (flush) {
spin_lock_bh(&q->lock);
@@ -252,16 +254,8 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
spin_unlock_bh(&q->lock);
}
- wake = wake && q->stopped &&
- qid < IEEE80211_NUM_ACS && q->queued < q->ndesc - 8;
- if (wake)
- q->stopped = false;
-
if (!q->queued)
wake_up(&dev->tx_wait);
-
- if (wake)
- ieee80211_wake_queue(dev->hw, qid);
}
static void *
@@ -312,10 +306,9 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
}
static int
-mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid,
+mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, u32 tx_info)
{
- struct mt76_queue *q = dev->q_tx[qid];
struct mt76_queue_buf buf;
dma_addr_t addr;
@@ -343,11 +336,10 @@ error:
}
static int
-mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
+mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta)
{
- struct mt76_queue *q = dev->q_tx[qid];
struct mt76_tx_info tx_info = {
.skb = skb,
};
@@ -397,7 +389,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
dma_sync_single_for_cpu(dev->dev, t->dma_addr, dev->drv->txwi_size,
DMA_TO_DEVICE);
- ret = dev->drv->tx_prepare_skb(dev, txwi, qid, wcid, sta, &tx_info);
+ ret = dev->drv->tx_prepare_skb(dev, txwi, q->qid, wcid, sta, &tx_info);
dma_sync_single_for_device(dev->dev, t->dma_addr, dev->drv->txwi_size,
DMA_TO_DEVICE);
if (ret < 0)
@@ -661,8 +653,15 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
mt76_worker_disable(&dev->tx_worker);
netif_napi_del(&dev->tx_napi);
- for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++)
- mt76_dma_tx_cleanup(dev, i, true);
+
+ for (i = 0; i < ARRAY_SIZE(dev->phy.q_tx); i++) {
+ mt76_dma_tx_cleanup(dev, dev->phy.q_tx[i], true);
+ if (dev->phy2)
+ mt76_dma_tx_cleanup(dev, dev->phy2->q_tx[i], true);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(dev->q_mcu); i++)
+ mt76_dma_tx_cleanup(dev, dev->q_mcu[i], true);
mt76_for_each_q_rx(dev, i) {
netif_napi_del(&dev->napi[i]);
diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
index 3044e0069991..90278aeb6721 100644
--- a/drivers/net/wireless/mediatek/mt76/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
@@ -88,8 +88,10 @@ out_put_node:
}
void
-mt76_eeprom_override(struct mt76_dev *dev)
+mt76_eeprom_override(struct mt76_phy *phy)
{
+ struct mt76_dev *dev = phy->dev;
+
#ifdef CONFIG_OF
struct device_node *np = dev->dev->of_node;
const u8 *mac = NULL;
@@ -97,14 +99,14 @@ mt76_eeprom_override(struct mt76_dev *dev)
if (np)
mac = of_get_mac_address(np);
if (!IS_ERR_OR_NULL(mac))
- ether_addr_copy(dev->macaddr, mac);
+ ether_addr_copy(phy->macaddr, mac);
#endif
- if (!is_valid_ether_addr(dev->macaddr)) {
- eth_random_addr(dev->macaddr);
+ if (!is_valid_ether_addr(phy->macaddr)) {
+ eth_random_addr(phy->macaddr);
dev_info(dev->dev,
"Invalid MAC address, using random address %pM\n",
- dev->macaddr);
+ phy->macaddr);
}
}
EXPORT_SYMBOL_GPL(mt76_eeprom_override);
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 4befe7f937a9..a840396f2c74 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -159,21 +159,22 @@ static void mt76_init_stream_cap(struct mt76_phy *phy,
void mt76_set_stream_caps(struct mt76_phy *phy, bool vht)
{
- if (phy->dev->cap.has_2ghz)
+ if (phy->cap.has_2ghz)
mt76_init_stream_cap(phy, &phy->sband_2g.sband, false);
- if (phy->dev->cap.has_5ghz)
+ if (phy->cap.has_5ghz)
mt76_init_stream_cap(phy, &phy->sband_5g.sband, vht);
}
EXPORT_SYMBOL_GPL(mt76_set_stream_caps);
static int
-mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
+mt76_init_sband(struct mt76_phy *phy, struct mt76_sband *msband,
const struct ieee80211_channel *chan, int n_chan,
struct ieee80211_rate *rates, int n_rates, bool vht)
{
struct ieee80211_supported_band *sband = &msband->sband;
- struct ieee80211_sta_ht_cap *ht_cap;
struct ieee80211_sta_vht_cap *vht_cap;
+ struct ieee80211_sta_ht_cap *ht_cap;
+ struct mt76_dev *dev = phy->dev;
void *chanlist;
int size;
@@ -203,7 +204,7 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
- mt76_init_stream_cap(&dev->phy, sband, vht);
+ mt76_init_stream_cap(phy, sband, vht);
if (!vht)
return 0;
@@ -221,27 +222,25 @@ mt76_init_sband(struct mt76_dev *dev, struct mt76_sband *msband,
}
static int
-mt76_init_sband_2g(struct mt76_dev *dev, struct ieee80211_rate *rates,
+mt76_init_sband_2g(struct mt76_phy *phy, struct ieee80211_rate *rates,
int n_rates)
{
- dev->hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->phy.sband_2g.sband;
+ phy->hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
- return mt76_init_sband(dev, &dev->phy.sband_2g,
- mt76_channels_2ghz,
- ARRAY_SIZE(mt76_channels_2ghz),
- rates, n_rates, false);
+ return mt76_init_sband(phy, &phy->sband_2g, mt76_channels_2ghz,
+ ARRAY_SIZE(mt76_channels_2ghz), rates,
+ n_rates, false);
}
static int
-mt76_init_sband_5g(struct mt76_dev *dev, struct ieee80211_rate *rates,
+mt76_init_sband_5g(struct mt76_phy *phy, struct ieee80211_rate *rates,
int n_rates, bool vht)
{
- dev->hw->wiphy->bands[NL80211_BAND_5GHZ] = &dev->phy.sband_5g.sband;
+ phy->hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
- return mt76_init_sband(dev, &dev->phy.sband_5g,
- mt76_channels_5ghz,
- ARRAY_SIZE(mt76_channels_5ghz),
- rates, n_rates, vht);
+ return mt76_init_sband(phy, &phy->sband_5g, mt76_channels_5ghz,
+ ARRAY_SIZE(mt76_channels_5ghz), rates,
+ n_rates, vht);
}
static void
@@ -274,12 +273,13 @@ mt76_check_sband(struct mt76_phy *phy, struct mt76_sband *msband,
}
static void
-mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
+mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
{
+ struct mt76_dev *dev = phy->dev;
struct wiphy *wiphy = hw->wiphy;
SET_IEEE80211_DEV(hw, dev->dev);
- SET_IEEE80211_PERM_ADDR(hw, dev->macaddr);
+ SET_IEEE80211_PERM_ADDR(hw, phy->macaddr);
wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
@@ -305,6 +305,7 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
+ ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
ieee80211_hw_set(hw, TX_AMSDU);
@@ -314,7 +315,6 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
ieee80211_hw_set(hw, MFP_CAPABLE);
ieee80211_hw_set(hw, AP_LINK_PS);
ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);
- ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
wiphy->interface_modes =
@@ -333,65 +333,57 @@ mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
const struct ieee80211_ops *ops)
{
struct ieee80211_hw *hw;
+ unsigned int phy_size;
struct mt76_phy *phy;
- unsigned int phy_size, chan_size;
- unsigned int size_2g, size_5g;
- void *priv;
phy_size = ALIGN(sizeof(*phy), 8);
- chan_size = sizeof(dev->phy.sband_2g.chan[0]);
- size_2g = ALIGN(ARRAY_SIZE(mt76_channels_2ghz) * chan_size, 8);
- size_5g = ALIGN(ARRAY_SIZE(mt76_channels_5ghz) * chan_size, 8);
-
- size += phy_size + size_2g + size_5g;
- hw = ieee80211_alloc_hw(size, ops);
+ hw = ieee80211_alloc_hw(size + phy_size, ops);
if (!hw)
return NULL;
phy = hw->priv;
phy->dev = dev;
phy->hw = hw;
+ phy->priv = hw->priv + phy_size;
- mt76_phy_init(dev, hw);
-
- priv = hw->priv + phy_size;
+ return phy;
+}
+EXPORT_SYMBOL_GPL(mt76_alloc_phy);
- phy->sband_2g = dev->phy.sband_2g;
- phy->sband_2g.chan = priv;
- priv += size_2g;
+int mt76_register_phy(struct mt76_phy *phy, bool vht,
+ struct ieee80211_rate *rates, int n_rates)
+{
+ int ret;
- phy->sband_5g = dev->phy.sband_5g;
- phy->sband_5g.chan = priv;
- priv += size_5g;
+ mt76_phy_init(phy, phy->hw);
- phy->priv = priv;
+ if (phy->cap.has_2ghz) {
+ ret = mt76_init_sband_2g(phy, rates, n_rates);
+ if (ret)
+ return ret;
+ }
- hw->wiphy->bands[NL80211_BAND_2GHZ] = &phy->sband_2g.sband;
- hw->wiphy->bands[NL80211_BAND_5GHZ] = &phy->sband_5g.sband;
+ if (phy->cap.has_5ghz) {
+ ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
+ if (ret)
+ return ret;
+ }
+ wiphy_read_of_freq_limits(phy->hw->wiphy);
mt76_check_sband(phy, &phy->sband_2g, NL80211_BAND_2GHZ);
mt76_check_sband(phy, &phy->sband_5g, NL80211_BAND_5GHZ);
- return phy;
-}
-EXPORT_SYMBOL_GPL(mt76_alloc_phy);
-
-int
-mt76_register_phy(struct mt76_phy *phy)
-{
- int ret;
-
ret = ieee80211_register_hw(phy->hw);
if (ret)
return ret;
phy->dev->phy2 = phy;
+
return 0;
}
EXPORT_SYMBOL_GPL(mt76_register_phy);
-void
-mt76_unregister_phy(struct mt76_phy *phy)
+void mt76_unregister_phy(struct mt76_phy *phy)
{
struct mt76_dev *dev = phy->dev;
@@ -459,16 +451,16 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
int ret;
dev_set_drvdata(dev->dev, dev);
- mt76_phy_init(dev, hw);
+ mt76_phy_init(phy, hw);
- if (dev->cap.has_2ghz) {
- ret = mt76_init_sband_2g(dev, rates, n_rates);
+ if (phy->cap.has_2ghz) {
+ ret = mt76_init_sband_2g(phy, rates, n_rates);
if (ret)
return ret;
}
- if (dev->cap.has_5ghz) {
- ret = mt76_init_sband_5g(dev, rates + 4, n_rates - 4, vht);
+ if (phy->cap.has_5ghz) {
+ ret = mt76_init_sband_5g(phy, rates + 4, n_rates - 4, vht);
if (ret)
return ret;
}
@@ -539,14 +531,11 @@ EXPORT_SYMBOL_GPL(mt76_rx);
bool mt76_has_tx_pending(struct mt76_phy *phy)
{
- struct mt76_dev *dev = phy->dev;
struct mt76_queue *q;
- int i, offset;
-
- offset = __MT_TXQ_MAX * (phy != &dev->phy);
+ int i;
for (i = 0; i < __MT_TXQ_MAX; i++) {
- q = dev->q_tx[offset + i];
+ q = phy->q_tx[i];
if (q && q->queued)
return true;
}
@@ -842,7 +831,7 @@ mt76_airtime_check(struct mt76_dev *dev, struct sk_buff *skb)
return;
if (!wcid || !wcid->sta) {
- if (!ether_addr_equal(hdr->addr1, dev->macaddr))
+ if (!ether_addr_equal(hdr->addr1, dev->phy.macaddr))
return;
wcid = NULL;
@@ -932,7 +921,8 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
{
struct ieee80211_sta *sta;
struct ieee80211_hw *hw;
- struct sk_buff *skb;
+ struct sk_buff *skb, *tmp;
+ LIST_HEAD(list);
spin_lock(&dev->rx_lock);
while ((skb = __skb_dequeue(frames)) != NULL) {
@@ -942,9 +932,19 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
}
mt76_rx_convert(dev, skb, &hw, &sta);
- ieee80211_rx_napi(hw, sta, skb, napi);
+ ieee80211_rx_list(hw, sta, skb, &list);
}
spin_unlock(&dev->rx_lock);
+
+ if (!napi) {
+ netif_receive_skb_list(&list);
+ return;
+ }
+
+ list_for_each_entry_safe(skb, tmp, &list, list) {
+ skb_list_del_init(skb);
+ napi_gro_receive(napi, skb);
+ }
}
void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
@@ -1202,3 +1202,22 @@ int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
return 0;
}
EXPORT_SYMBOL_GPL(mt76_get_antenna);
+
+struct mt76_queue *
+mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
+ int ring_base)
+{
+ struct mt76_queue *hwq;
+ int err;
+
+ hwq = devm_kzalloc(dev->dev, sizeof(*hwq), GFP_KERNEL);
+ if (!hwq)
+ return ERR_PTR(-ENOMEM);
+
+ err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
+ if (err < 0)
+ return ERR_PTR(err);
+
+ return hwq;
+}
+EXPORT_SYMBOL_GPL(mt76_init_queue);
diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c
index ade61a5334c6..d3a5e2c4f12a 100644
--- a/drivers/net/wireless/mediatek/mt76/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mcu.c
@@ -50,3 +50,83 @@ void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb)
wake_up(&dev->mcu.wait);
}
EXPORT_SYMBOL_GPL(mt76_mcu_rx_event);
+
+int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data,
+ int len, bool wait_resp, struct sk_buff **ret_skb)
+{
+ struct sk_buff *skb;
+
+ if (dev->mcu_ops->mcu_send_msg)
+ return dev->mcu_ops->mcu_send_msg(dev, cmd, data, len, wait_resp);
+
+ skb = mt76_mcu_msg_alloc(dev, data, len);
+ if (!skb)
+ return -ENOMEM;
+
+ return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, ret_skb);
+}
+EXPORT_SYMBOL_GPL(mt76_mcu_send_and_get_msg);
+
+int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
+ int cmd, bool wait_resp,
+ struct sk_buff **ret_skb)
+{
+ unsigned long expires;
+ int ret, seq;
+
+ if (ret_skb)
+ *ret_skb = NULL;
+
+ mutex_lock(&dev->mcu.mutex);
+
+ ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq);
+ if (ret < 0)
+ goto out;
+
+ if (!wait_resp) {
+ ret = 0;
+ goto out;
+ }
+
+ expires = jiffies + dev->mcu.timeout;
+
+ do {
+ skb = mt76_mcu_get_response(dev, expires);
+ ret = dev->mcu_ops->mcu_parse_response(dev, cmd, skb, seq);
+ if (!ret && ret_skb)
+ *ret_skb = skb;
+ else
+ dev_kfree_skb(skb);
+ } while (ret == -EAGAIN);
+
+out:
+ mutex_unlock(&dev->mcu.mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt76_mcu_skb_send_and_get_msg);
+
+int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
+ int len)
+{
+ int err, cur_len;
+
+ while (len > 0) {
+ cur_len = min_t(int, 4096 - dev->mcu_ops->headroom, len);
+
+ err = mt76_mcu_send_msg(dev, cmd, data, cur_len, false);
+ if (err)
+ return err;
+
+ data += cur_len;
+ len -= cur_len;
+
+ if (dev->queue_ops->tx_cleanup)
+ dev->queue_ops->tx_cleanup(dev,
+ dev->q_mcu[MT_MCUQ_FWDL],
+ false);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76_mcu_send_firmware);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index a5be66de1cff..3e496a188bf0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -64,18 +64,23 @@ enum mt76_txq_id {
MT_TXQ_BE = IEEE80211_AC_BE,
MT_TXQ_BK = IEEE80211_AC_BK,
MT_TXQ_PSD,
- MT_TXQ_MCU,
- MT_TXQ_MCU_WA,
MT_TXQ_BEACON,
MT_TXQ_CAB,
- MT_TXQ_FWDL,
__MT_TXQ_MAX
};
+enum mt76_mcuq_id {
+ MT_MCUQ_WM,
+ MT_MCUQ_WA,
+ MT_MCUQ_FWDL,
+ __MT_MCUQ_MAX
+};
+
enum mt76_rxq_id {
MT_RXQ_MAIN,
MT_RXQ_MCU,
MT_RXQ_MCU_WA,
+ MT_RXQ_EXT,
__MT_RXQ_MAX
};
@@ -121,6 +126,7 @@ struct mt76_queue {
struct mt76_queue_regs __iomem *regs;
spinlock_t lock;
+ spinlock_t cleanup_lock;
struct mt76_queue_entry *entry;
struct mt76_desc *desc;
@@ -131,9 +137,11 @@ struct mt76_queue {
int queued;
int buf_size;
bool stopped;
+ bool blocked;
u8 buf_offset;
u8 hw_idx;
+ u8 qid;
dma_addr_t desc_dma;
struct sk_buff *rx_head;
@@ -147,7 +155,9 @@ struct mt76_mcu_ops {
int (*mcu_send_msg)(struct mt76_dev *dev, int cmd, const void *data,
int len, bool wait_resp);
int (*mcu_skb_send_msg)(struct mt76_dev *dev, struct sk_buff *skb,
- int cmd, bool wait_resp);
+ int cmd, int *seq);
+ int (*mcu_parse_response)(struct mt76_dev *dev, int cmd,
+ struct sk_buff *skb, int seq);
u32 (*mcu_rr)(struct mt76_dev *dev, u32 offset);
void (*mcu_wr)(struct mt76_dev *dev, u32 offset, u32 val);
int (*mcu_wr_rp)(struct mt76_dev *dev, u32 base,
@@ -164,11 +174,11 @@ struct mt76_queue_ops {
int idx, int n_desc, int bufsize,
u32 ring_base);
- int (*tx_queue_skb)(struct mt76_dev *dev, enum mt76_txq_id qid,
+ int (*tx_queue_skb)(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta);
- int (*tx_queue_skb_raw)(struct mt76_dev *dev, enum mt76_txq_id qid,
+ int (*tx_queue_skb_raw)(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, u32 tx_info);
void *(*dequeue)(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
@@ -176,7 +186,7 @@ struct mt76_queue_ops {
void (*rx_reset)(struct mt76_dev *dev, enum mt76_rxq_id qid);
- void (*tx_cleanup)(struct mt76_dev *dev, enum mt76_txq_id qid,
+ void (*tx_cleanup)(struct mt76_dev *dev, struct mt76_queue *q,
bool flush);
void (*kick)(struct mt76_dev *dev, struct mt76_queue *q);
@@ -185,6 +195,7 @@ struct mt76_queue_ops {
enum mt76_wcid_flags {
MT_WCID_FLAG_CHECK_PS,
MT_WCID_FLAG_PS,
+ MT_WCID_FLAG_4ADDR,
};
#define MT76_N_WCIDS 288
@@ -411,6 +422,7 @@ enum mt76u_out_ep {
struct mt76_mcu {
struct mutex mutex;
u32 msg_seq;
+ int timeout;
struct sk_buff_head res_q;
wait_queue_head_t wait;
@@ -426,7 +438,9 @@ struct mt76_usb {
u8 *data;
u16 data_len;
- struct tasklet_struct rx_tasklet;
+ struct mt76_worker status_worker;
+ struct mt76_worker rx_worker;
+
struct work_struct stat_work;
u8 out_ep[__MT_EP_OUT_MAX];
@@ -445,25 +459,18 @@ struct mt76_usb {
#define MT76S_XMIT_BUF_SZ (16 * PAGE_SIZE)
struct mt76_sdio {
- struct workqueue_struct *txrx_wq;
- struct {
- struct work_struct xmit_work;
- struct work_struct status_work;
- } tx;
- struct {
- struct work_struct recv_work;
- struct work_struct net_work;
- } rx;
+ struct mt76_worker txrx_worker;
+ struct mt76_worker status_worker;
+ struct mt76_worker net_worker;
struct work_struct stat_work;
- u8 *xmit_buf[MT_TXQ_MCU_WA];
+ u8 *xmit_buf[IEEE80211_NUM_ACS + 2];
struct sdio_func *func;
void *intr_data;
struct {
- struct mutex lock;
int pse_data_quota;
int ple_data_quota;
int pse_mcu_quota;
@@ -528,6 +535,8 @@ struct mt76_testmode_data {
u8 tx_rate_nss;
u8 tx_rate_sgi;
u8 tx_rate_ldpc;
+ u8 tx_rate_stbc;
+ u8 tx_ltf;
u8 tx_antenna_mask;
@@ -555,15 +564,20 @@ struct mt76_phy {
unsigned long state;
+ struct mt76_queue *q_tx[__MT_TXQ_MAX];
+
struct cfg80211_chan_def chandef;
struct ieee80211_channel *main_chan;
struct mt76_channel_state *chan_state;
ktime_t survey_time;
+ struct mt76_hw_cap cap;
struct mt76_sband sband_2g;
struct mt76_sband sband_5g;
+ u8 macaddr[ETH_ALEN];
+
u32 vif_mask;
int txpower_cur;
@@ -601,7 +615,7 @@ struct mt76_dev {
struct sk_buff_head rx_skb[__MT_RXQ_MAX];
struct list_head txwi_cache;
- struct mt76_queue *q_tx[2 * __MT_TXQ_MAX];
+ struct mt76_queue *q_mcu[__MT_MCUQ_MAX];
struct mt76_queue q_rx[__MT_RXQ_MAX];
const struct mt76_queue_ops *queue_ops;
int tx_dma_idx[4];
@@ -619,7 +633,6 @@ struct mt76_dev {
struct mt76_wcid global_wcid;
struct mt76_wcid __rcu *wcid[MT76_N_WCIDS];
- u8 macaddr[ETH_ALEN];
u32 rev;
u32 aggr_stats[32];
@@ -630,7 +643,6 @@ struct mt76_dev {
struct debugfs_blob_wrapper eeprom;
struct debugfs_blob_wrapper otp;
- struct mt76_hw_cap cap;
struct mt76_rate_power rate_power;
@@ -690,10 +702,7 @@ enum mt76_phy_type {
#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__)
-#define mt76_mcu_send_msg(dev, ...) (dev)->mt76.mcu_ops->mcu_send_msg(&((dev)->mt76), __VA_ARGS__)
-#define __mt76_mcu_send_msg(dev, ...) (dev)->mcu_ops->mcu_send_msg((dev), __VA_ARGS__)
-#define __mt76_mcu_skb_send_msg(dev, ...) (dev)->mcu_ops->mcu_skb_send_msg((dev), __VA_ARGS__)
#define mt76_mcu_restart(dev, ...) (dev)->mt76.mcu_ops->mcu_restart(&((dev)->mt76))
#define __mt76_mcu_restart(dev, ...) (dev)->mcu_ops->mcu_restart((dev))
@@ -752,7 +761,7 @@ static inline u16 mt76_rev(struct mt76_dev *dev)
#define mt76_tx_queue_skb_raw(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb_raw(&((dev)->mt76), __VA_ARGS__)
#define mt76_tx_queue_skb(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb(&((dev)->mt76), __VA_ARGS__)
#define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__)
-#define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__)
+#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__)
#define mt76_for_each_q_rx(dev, i) \
@@ -770,7 +779,8 @@ void mt76_unregister_phy(struct mt76_phy *phy);
struct mt76_phy *mt76_alloc_phy(struct mt76_dev *dev, unsigned int size,
const struct ieee80211_ops *ops);
-int mt76_register_phy(struct mt76_phy *phy);
+int mt76_register_phy(struct mt76_phy *phy, bool vht,
+ struct ieee80211_rate *rates, int n_rates);
struct dentry *mt76_register_debugfs(struct mt76_dev *dev);
int mt76_queues_read(struct seq_file *s, void *data);
@@ -778,7 +788,40 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
s8 *val, int len);
int mt76_eeprom_init(struct mt76_dev *dev, int len);
-void mt76_eeprom_override(struct mt76_dev *dev);
+void mt76_eeprom_override(struct mt76_phy *phy);
+
+struct mt76_queue *
+mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
+ int ring_base);
+static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx,
+ int n_desc, int ring_base)
+{
+ struct mt76_queue *q;
+
+ q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base);
+ if (IS_ERR(q))
+ return PTR_ERR(q);
+
+ q->qid = qid;
+ phy->q_tx[qid] = q;
+
+ return 0;
+}
+
+static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx,
+ int n_desc, int ring_base)
+{
+ struct mt76_queue *q;
+
+ q = mt76_init_queue(dev, qid, idx, n_desc, ring_base);
+ if (IS_ERR(q))
+ return PTR_ERR(q);
+
+ q->qid = __MT_TXQ_MAX + qid;
+ dev->q_mcu[qid] = q;
+
+ return 0;
+}
static inline struct mt76_phy *
mt76_dev_phy(struct mt76_dev *dev, bool phy_ext)
@@ -901,7 +944,7 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb);
void mt76_tx(struct mt76_phy *dev, struct ieee80211_sta *sta,
struct mt76_wcid *wcid, struct sk_buff *skb);
void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
-void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
+void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta,
bool send_bar);
void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb);
void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid);
@@ -1064,7 +1107,6 @@ void mt76u_queues_deinit(struct mt76_dev *dev);
int mt76s_init(struct mt76_dev *dev, struct sdio_func *func,
const struct mt76_bus_ops *bus_ops);
int mt76s_alloc_queues(struct mt76_dev *dev);
-void mt76s_stop_txrx(struct mt76_dev *dev);
void mt76s_deinit(struct mt76_dev *dev);
struct sk_buff *
@@ -1073,6 +1115,25 @@ mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
void mt76_mcu_rx_event(struct mt76_dev *dev, struct sk_buff *skb);
struct sk_buff *mt76_mcu_get_response(struct mt76_dev *dev,
unsigned long expires);
+int mt76_mcu_send_and_get_msg(struct mt76_dev *dev, int cmd, const void *data,
+ int len, bool wait_resp, struct sk_buff **ret);
+int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
+ int cmd, bool wait_resp, struct sk_buff **ret);
+int mt76_mcu_send_firmware(struct mt76_dev *dev, int cmd, const void *data,
+ int len);
+static inline int
+mt76_mcu_send_msg(struct mt76_dev *dev, int cmd, const void *data, int len,
+ bool wait_resp)
+{
+ return mt76_mcu_send_and_get_msg(dev, cmd, data, len, wait_resp, NULL);
+}
+
+static inline int
+mt76_mcu_skb_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd,
+ bool wait_resp)
+{
+ return mt76_mcu_skb_send_and_get_msg(dev, skb, cmd, wait_resp, NULL);
+}
void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, u32 clear, u32 set);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c
index d728c5e43783..5d4522f440b7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c
@@ -13,23 +13,25 @@ static void
mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
struct mt7603_dev *dev = (struct mt7603_dev *)priv;
+ struct mt76_dev *mdev = &dev->mt76;
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
struct sk_buff *skb = NULL;
- if (!(dev->mt76.beacon_mask & BIT(mvif->idx)))
+ if (!(mdev->beacon_mask & BIT(mvif->idx)))
return;
skb = ieee80211_beacon_get(mt76_hw(dev), vif);
if (!skb)
return;
- mt76_tx_queue_skb(dev, MT_TXQ_BEACON, skb, &mvif->sta.wcid, NULL);
+ mt76_tx_queue_skb(dev, dev->mphy.q_tx[MT_TXQ_BEACON], skb,
+ &mvif->sta.wcid, NULL);
spin_lock_bh(&dev->ps_lock);
mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY |
FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, mvif->sta.wcid.idx) |
FIELD_PREP(MT_DMA_FQCR0_TARGET_QID,
- dev->mt76.q_tx[MT_TXQ_CAB]->hw_idx) |
+ dev->mphy.q_tx[MT_TXQ_CAB]->hw_idx) |
FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, 3) |
FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, 8));
@@ -64,9 +66,10 @@ mt7603_add_buffered_bc(void *priv, u8 *mac, struct ieee80211_vif *vif)
data->count[mvif->idx]++;
}
-void mt7603_pre_tbtt_tasklet(unsigned long arg)
+void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t)
{
- struct mt7603_dev *dev = (struct mt7603_dev *)arg;
+ struct mt7603_dev *dev = from_tasklet(dev, t, mt76.pre_tbtt_tasklet);
+ struct mt76_dev *mdev = &dev->mt76;
struct mt76_queue *q;
struct beacon_bc_data data = {};
struct sk_buff *skb;
@@ -78,7 +81,7 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
data.dev = dev;
__skb_queue_head_init(&data.q);
- q = dev->mt76.q_tx[MT_TXQ_BEACON];
+ q = dev->mphy.q_tx[MT_TXQ_BEACON];
spin_lock_bh(&q->lock);
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
@@ -89,13 +92,13 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
/* Flush all previous CAB queue packets */
mt76_wr(dev, MT_WF_ARB_CAB_FLUSH, GENMASK(30, 16) | BIT(0));
- mt76_queue_tx_cleanup(dev, MT_TXQ_CAB, false);
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_CAB], false);
- mt76_csa_check(&dev->mt76);
- if (dev->mt76.csa_complete)
+ mt76_csa_check(mdev);
+ if (mdev->csa_complete)
goto out;
- q = dev->mt76.q_tx[MT_TXQ_CAB];
+ q = dev->mphy.q_tx[MT_TXQ_CAB];
do {
nframes = skb_queue_len(&data.q);
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
@@ -120,7 +123,7 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
struct ieee80211_vif *vif = info->control.vif;
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
- mt76_tx_queue_skb(dev, MT_TXQ_CAB, skb, &mvif->sta.wcid, NULL);
+ mt76_tx_queue_skb(dev, q, skb, &mvif->sta.wcid, NULL);
}
mt76_queue_kick(dev, q);
spin_unlock_bh(&q->lock);
@@ -135,9 +138,8 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
((1 << (MT7603_MAX_INTERFACES - 1)) - 1)));
out:
- mt76_queue_tx_cleanup(dev, MT_TXQ_BEACON, false);
- if (dev->mt76.q_tx[MT_TXQ_BEACON]->queued >
- hweight8(dev->mt76.beacon_mask))
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BEACON], false);
+ if (dev->mphy.q_tx[MT_TXQ_BEACON]->queued > hweight8(mdev->beacon_mask))
dev->beacon_check++;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
index d60d00f6f6a0..0086f18cb79a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
@@ -4,27 +4,6 @@
#include "mac.h"
#include "../dma.h"
-static int
-mt7603_init_tx_queue(struct mt7603_dev *dev, int qid, int idx, int n_desc)
-{
- struct mt76_queue *hwq;
- int err;
-
- hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
- if (!hwq)
- return -ENOMEM;
-
- err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE);
- if (err < 0)
- return err;
-
- dev->mt76.q_tx[qid] = hwq;
-
- mt7603_irq_enable(dev, MT_INT_TX_DONE(idx));
-
- return 0;
-}
-
static void
mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb)
{
@@ -152,14 +131,16 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget)
dev = container_of(napi, struct mt7603_dev, mt76.tx_napi);
dev->tx_dma_check = 0;
- for (i = MT_TXQ_MCU; i >= 0; i--)
- mt76_queue_tx_cleanup(dev, i, false);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
+ for (i = MT_TXQ_PSD; i >= 0; i--)
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false);
if (napi_complete_done(napi, 0))
mt7603_irq_enable(dev, MT_INT_TX_DONE_ALL);
- for (i = MT_TXQ_MCU; i >= 0; i--)
- mt76_queue_tx_cleanup(dev, i, false);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
+ for (i = MT_TXQ_PSD; i >= 0; i--)
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false);
mt7603_mac_sta_poll(dev);
@@ -191,32 +172,42 @@ int mt7603_dma_init(struct mt7603_dev *dev)
mt7603_pse_client_reset(dev);
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
- ret = mt7603_init_tx_queue(dev, i, wmm_queue_map[i],
- MT7603_TX_RING_SIZE);
+ ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i],
+ MT7603_TX_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
}
- ret = mt7603_init_tx_queue(dev, MT_TXQ_PSD,
- MT_TX_HW_QUEUE_MGMT, MT7603_PSD_RING_SIZE);
+ ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT,
+ MT7603_PSD_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
- ret = mt7603_init_tx_queue(dev, MT_TXQ_MCU,
- MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
+ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT_TX_HW_QUEUE_MCU,
+ MT_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
- ret = mt7603_init_tx_queue(dev, MT_TXQ_BEACON,
- MT_TX_HW_QUEUE_BCN, MT_MCU_RING_SIZE);
+ ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_BEACON, MT_TX_HW_QUEUE_BCN,
+ MT_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
- ret = mt7603_init_tx_queue(dev, MT_TXQ_CAB,
- MT_TX_HW_QUEUE_BMC, MT_MCU_RING_SIZE);
+ ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_CAB, MT_TX_HW_QUEUE_BMC,
+ MT_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
+ mt7603_irq_enable(dev,
+ MT_INT_TX_DONE(IEEE80211_AC_VO) |
+ MT_INT_TX_DONE(IEEE80211_AC_VI) |
+ MT_INT_TX_DONE(IEEE80211_AC_BE) |
+ MT_INT_TX_DONE(IEEE80211_AC_BK) |
+ MT_INT_TX_DONE(MT_TX_HW_QUEUE_MGMT) |
+ MT_INT_TX_DONE(MT_TX_HW_QUEUE_MCU) |
+ MT_INT_TX_DONE(MT_TX_HW_QUEUE_BCN) |
+ MT_INT_TX_DONE(MT_TX_HW_QUEUE_BMC));
+
ret = mt7603_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
MT7603_MCU_RX_RING_SIZE, MT_RX_BUF_SIZE);
if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c
index 01f1e0da5ee1..d951cb81df83 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c
@@ -141,6 +141,7 @@ static int mt7603_check_eeprom(struct mt76_dev *dev)
switch (val) {
case 0x7628:
case 0x7603:
+ case 0x7600:
return 0;
default:
return -EINVAL;
@@ -170,8 +171,8 @@ int mt7603_eeprom_init(struct mt7603_dev *dev)
}
eeprom = (u8 *)dev->mt76.eeprom.data;
- dev->mt76.cap.has_2ghz = true;
- memcpy(dev->mt76.macaddr, eeprom + MT_EE_MAC_ADDR, ETH_ALEN);
+ dev->mphy.cap.has_2ghz = true;
+ memcpy(dev->mphy.macaddr, eeprom + MT_EE_MAC_ADDR, ETH_ALEN);
/* Check for 1SS devices */
dev->mphy.antenna_mask = 3;
@@ -180,7 +181,7 @@ int mt7603_eeprom_init(struct mt7603_dev *dev)
is_mt7688(dev))
dev->mphy.antenna_mask = 1;
- mt76_eeprom_override(&dev->mt76);
+ mt76_eeprom_override(&dev->mphy);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
index c4848fafd270..b14e08046e20 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
@@ -533,8 +533,7 @@ int mt7603_register_device(struct mt7603_dev *dev)
spin_lock_init(&dev->ps_lock);
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7603_mac_work);
- tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt7603_pre_tbtt_tasklet,
- (unsigned long)dev);
+ tasklet_setup(&dev->mt76.pre_tbtt_tasklet, mt7603_pre_tbtt_tasklet);
dev->slottime = 9;
dev->sensitivity_limit = 28;
@@ -557,6 +556,7 @@ int mt7603_register_device(struct mt7603_dev *dev)
ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
/* init led callbacks */
if (IS_ENABLED(CONFIG_MT76_LEDS)) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
index f665a1c95eed..55095e66f2ef 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
@@ -445,7 +445,7 @@ void mt7603_mac_sta_poll(struct mt7603_dev *dev)
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];
+ struct mt76_queue *q = dev->mphy.q_tx[i];
u8 qidx = q->hw_idx;
u8 tid = ac_to_tid[i];
u32 txtime = airtime[qidx];
@@ -896,7 +896,7 @@ mt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
struct ieee80211_vif *vif = info->control.vif;
- struct mt76_queue *q = dev->mt76.q_tx[qid];
+ struct mt76_queue *q = dev->mphy.q_tx[qid];
struct mt7603_vif *mvif;
int wlan_idx;
int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
@@ -1434,8 +1434,9 @@ static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev)
mt7603_pse_client_reset(dev);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], true);
for (i = 0; i < __MT_TXQ_MAX; i++)
- mt76_queue_tx_cleanup(dev, i, true);
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
mt76_for_each_q_rx(&dev->mt76, i) {
mt76_queue_rx_reset(dev, i);
@@ -1514,7 +1515,7 @@ static bool mt7603_tx_hang(struct mt7603_dev *dev)
int i;
for (i = 0; i < 4; i++) {
- q = dev->mt76.q_tx[i];
+ q = dev->mphy.q_tx[i];
if (!q->queued)
continue;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
index c9226dceb510..6d47b57cbc39 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
@@ -380,9 +380,11 @@ mt7603_ps_tx_list(struct mt7603_dev *dev, struct sk_buff_head *list)
{
struct sk_buff *skb;
- while ((skb = __skb_dequeue(list)) != NULL)
- mt76_tx_queue_skb_raw(dev, skb_get_queue_mapping(skb),
- skb, 0);
+ while ((skb = __skb_dequeue(list)) != NULL) {
+ int qid = skb_get_queue_mapping(skb);
+
+ mt76_tx_queue_skb_raw(dev, dev->mphy.q_tx[qid], skb, 0);
+ }
}
void
@@ -392,7 +394,7 @@ mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps)
struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv;
struct sk_buff_head list;
- mt76_stop_tx_queues(&dev->mt76, sta, true);
+ mt76_stop_tx_queues(&dev->mphy, sta, true);
mt7603_wtbl_set_ps(dev, msta, ps);
if (ps)
return;
@@ -512,7 +514,7 @@ mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
u16 cw_max = (1 << 10) - 1;
u32 val;
- queue = dev->mt76.q_tx[queue]->hw_idx;
+ queue = dev->mphy.q_tx[queue]->hw_idx;
if (params->cw_min)
cw_min = params->cw_min;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
index a47a3a644ecc..96b6c8916730 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
@@ -14,14 +14,38 @@ struct mt7603_fw_trailer {
} __packed;
static int
-__mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb,
- int cmd, int *wait_seq)
+mt7603_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ struct sk_buff *skb, int seq)
{
+ struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
+ struct mt7603_mcu_rxd *rxd;
+
+ if (!skb) {
+ dev_err(mdev->dev,
+ "MCU message %d (seq %d) timed out\n",
+ cmd, seq);
+ dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
+ return -ETIMEDOUT;
+ }
+
+ rxd = (struct mt7603_mcu_rxd *)skb->data;
+ if (seq != rxd->seq)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int
+mt7603_mcu_skb_send_msg(struct mt76_dev *mdev, struct sk_buff *skb,
+ int cmd, int *wait_seq)
+{
+ struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
int hdrlen = dev->mcu_running ? sizeof(struct mt7603_mcu_txd) : 12;
- struct mt76_dev *mdev = &dev->mt76;
struct mt7603_mcu_txd *txd;
u8 seq;
+ mdev->mcu.timeout = 3 * HZ;
+
seq = ++mdev->mcu.msg_seq & 0xf;
if (!seq)
seq = ++mdev->mcu.msg_seq & 0xf;
@@ -49,56 +73,7 @@ __mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb,
if (wait_seq)
*wait_seq = seq;
- return mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0);
-}
-
-static int
-mt7603_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
- int len, bool wait_resp)
-{
- struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
- unsigned long expires = jiffies + 3 * HZ;
- struct mt7603_mcu_rxd *rxd;
- struct sk_buff *skb;
- int ret, seq;
-
- skb = mt76_mcu_msg_alloc(mdev, data, len);
- if (!skb)
- return -ENOMEM;
-
- mutex_lock(&mdev->mcu.mutex);
-
- ret = __mt7603_mcu_msg_send(dev, skb, cmd, &seq);
- if (ret)
- goto out;
-
- while (wait_resp) {
- bool check_seq = false;
-
- skb = mt76_mcu_get_response(&dev->mt76, expires);
- if (!skb) {
- dev_err(mdev->dev,
- "MCU message %d (seq %d) timed out\n",
- cmd, seq);
- dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
- ret = -ETIMEDOUT;
- break;
- }
-
- rxd = (struct mt7603_mcu_rxd *)skb->data;
- if (seq == rxd->seq)
- check_seq = true;
-
- dev_kfree_skb(skb);
-
- if (check_seq)
- break;
- }
-
-out:
- mutex_unlock(&mdev->mcu.mutex);
-
- return ret;
+ return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0);
}
static int
@@ -114,29 +89,8 @@ mt7603_mcu_init_download(struct mt7603_dev *dev, u32 addr, u32 len)
.mode = cpu_to_le32(BIT(31)),
};
- return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
- &req, sizeof(req), true);
-}
-
-static int
-mt7603_mcu_send_firmware(struct mt7603_dev *dev, const void *data, int len)
-{
- int cur_len, ret = 0;
-
- while (len > 0) {
- cur_len = min_t(int, 4096 - sizeof(struct mt7603_mcu_txd),
- len);
-
- ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER,
- data, cur_len, false);
- if (ret)
- break;
-
- data += cur_len;
- len -= cur_len;
- }
-
- return ret;
+ return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
+ &req, sizeof(req), true);
}
static int
@@ -150,15 +104,14 @@ mt7603_mcu_start_firmware(struct mt7603_dev *dev, u32 addr)
.addr = cpu_to_le32(addr),
};
- return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req,
+ sizeof(req), true);
}
static int
mt7603_mcu_restart(struct mt76_dev *dev)
{
- return __mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ,
- NULL, 0, true);
+ return mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL, 0, true);
}
static int mt7603_load_firmware(struct mt7603_dev *dev)
@@ -226,7 +179,8 @@ static int mt7603_load_firmware(struct mt7603_dev *dev)
goto out;
}
- ret = mt7603_mcu_send_firmware(dev, fw->data, dl_len);
+ ret = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER,
+ fw->data, dl_len);
if (ret) {
dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
goto out;
@@ -266,7 +220,8 @@ int mt7603_mcu_init(struct mt7603_dev *dev)
{
static const struct mt76_mcu_ops mt7603_mcu_ops = {
.headroom = sizeof(struct mt7603_mcu_txd),
- .mcu_send_msg = mt7603_mcu_msg_send,
+ .mcu_skb_send_msg = mt7603_mcu_skb_send_msg,
+ .mcu_parse_response = mt7603_mcu_parse_response,
.mcu_restart = mt7603_mcu_restart,
};
@@ -377,8 +332,8 @@ int mt7603_mcu_set_eeprom(struct mt7603_dev *dev)
data[i].val = eep[req_fields[i]];
}
- ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
- req, len, true);
+ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
+ req, len, true);
kfree(req);
return ret;
@@ -424,8 +379,8 @@ static int mt7603_mcu_set_tx_power(struct mt7603_dev *dev)
memcpy(req.temp_comp_power, eep + MT_EE_STEP_NUM_NEG_6_7,
sizeof(req.temp_comp_power));
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_TX_POWER_CTRL,
+ &req, sizeof(req), true);
}
int mt7603_mcu_set_channel(struct mt7603_dev *dev)
@@ -470,8 +425,8 @@ int mt7603_mcu_set_channel(struct mt7603_dev *dev)
for (i = 0; i < ARRAY_SIZE(req.txpower); i++)
req.txpower[i] = tx_power;
- ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH,
- &req, sizeof(req), true);
+ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_CHANNEL_SWITCH, &req,
+ sizeof(req), true);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
index 2a6e4332ad06..6e0a92a28b1c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
@@ -256,7 +256,7 @@ void mt7603_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
void mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
-void mt7603_pre_tbtt_tasklet(unsigned long arg);
+void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t);
void mt7603_update_channel(struct mt76_dev *mdev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/pci.c b/drivers/net/wireless/mediatek/mt76/mt7603/pci.c
index a5845da3547a..06fa28f645f2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/pci.c
@@ -57,7 +57,8 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
error:
- ieee80211_free_hw(mt76_hw(dev));
+ mt76_free_device(&dev->mt76);
+
return ret;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
index 00ba550fc48f..4d5e3f8b2a62 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
@@ -55,11 +55,26 @@ static int
mt7615_pm_set(void *data, u64 val)
{
struct mt7615_dev *dev = data;
+ int ret = 0;
if (!mt7615_wait_for_mcu_init(dev))
return 0;
- return mt7615_pm_set_enable(dev, val);
+ if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76))
+ return -EOPNOTSUPP;
+
+ mt7615_mutex_acquire(dev);
+
+ if (dev->phy.n_beacon_vif) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ dev->pm.enable = val;
+out:
+ mt7615_mutex_release(dev);
+
+ return ret;
}
static int
@@ -172,7 +187,7 @@ mt7615_reset_test_set(void *data, u64 val)
skb_put(skb, 1);
mt7615_mutex_acquire(dev);
- mt76_tx_queue_skb_raw(dev, 0, skb, 0);
+ mt76_tx_queue_skb_raw(dev, dev->mphy.q_tx[0], skb, 0);
mt7615_mutex_release(dev);
return 0;
@@ -317,21 +332,18 @@ static int
mt7615_queues_read(struct seq_file *s, void *data)
{
struct mt7615_dev *dev = dev_get_drvdata(s->private);
- static const struct {
+ struct {
+ struct mt76_queue *q;
char *queue;
- int id;
} queue_map[] = {
- { "PDMA0", MT_TXQ_BE },
- { "MCUQ", MT_TXQ_MCU },
- { "MCUFWQ", MT_TXQ_FWDL },
+ { dev->mphy.q_tx[MT_TXQ_BE], "PDMA0" },
+ { dev->mt76.q_mcu[MT_MCUQ_WM], "MCUQ" },
+ { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" },
};
int i;
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
- struct mt76_queue *q = dev->mt76.q_tx[queue_map[i].id];
-
- if (!q)
- continue;
+ struct mt76_queue *q = queue_map[i].q;
seq_printf(s,
"%s: queued=%d head=%d tail=%d\n",
@@ -365,6 +377,107 @@ mt7615_rf_reg_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_reg, mt7615_rf_reg_get, mt7615_rf_reg_set,
"0x%08llx\n");
+static ssize_t
+mt7615_ext_mac_addr_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct mt7615_dev *dev = file->private_data;
+ char buf[32 * ((ETH_ALEN * 3) + 4) + 1];
+ u8 addr[ETH_ALEN];
+ int ofs = 0;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ if (!(dev->muar_mask & BIT(i)))
+ continue;
+
+ mt76_wr(dev, MT_WF_RMAC_MAR1,
+ FIELD_PREP(MT_WF_RMAC_MAR1_IDX, i * 2) |
+ MT_WF_RMAC_MAR1_START);
+ put_unaligned_le32(mt76_rr(dev, MT_WF_RMAC_MAR0), addr);
+ put_unaligned_le16((mt76_rr(dev, MT_WF_RMAC_MAR1) &
+ MT_WF_RMAC_MAR1_ADDR), addr + 4);
+ ofs += snprintf(buf + ofs, sizeof(buf) - ofs, "%d=%pM\n", i, addr);
+ }
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, ofs);
+}
+
+static ssize_t
+mt7615_ext_mac_addr_write(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct mt7615_dev *dev = file->private_data;
+ unsigned long idx = 0;
+ u8 addr[ETH_ALEN];
+ char buf[32];
+ char *p;
+
+ if (count > sizeof(buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, userbuf, count))
+ return -EFAULT;
+
+ buf[sizeof(buf) - 1] = '\0';
+
+ p = strchr(buf, '=');
+ if (p) {
+ *p = 0;
+ p++;
+
+ if (kstrtoul(buf, 0, &idx) || idx > 31)
+ return -EINVAL;
+ } else {
+ idx = 0;
+ p = buf;
+ }
+
+ if (!mac_pton(p, addr))
+ return -EINVAL;
+
+ if (is_valid_ether_addr(addr)) {
+ dev->muar_mask |= BIT(idx);
+ } else {
+ memset(addr, 0, sizeof(addr));
+ dev->muar_mask &= ~BIT(idx);
+ }
+
+ mt76_rmw_field(dev, MT_WF_RMAC_MORE(0), MT_WF_RMAC_MORE_MUAR_MODE, 1);
+ mt76_wr(dev, MT_WF_RMAC_MAR0, get_unaligned_le32(addr));
+ mt76_wr(dev, MT_WF_RMAC_MAR1,
+ get_unaligned_le16(addr + 4) |
+ FIELD_PREP(MT_WF_RMAC_MAR1_IDX, idx * 2) |
+ MT_WF_RMAC_MAR1_START |
+ MT_WF_RMAC_MAR1_WRITE);
+
+ mt76_rmw_field(dev, MT_WF_RMAC_MORE(0), MT_WF_RMAC_MORE_MUAR_MODE, !!dev->muar_mask);
+
+ return count;
+}
+
+static const struct file_operations fops_ext_mac_addr = {
+ .open = simple_open,
+ .llseek = generic_file_llseek,
+ .read = mt7615_ext_mac_addr_read,
+ .write = mt7615_ext_mac_addr_write,
+ .owner = THIS_MODULE,
+};
+
+static int
+mt7663s_sched_quota_read(struct seq_file *s, void *data)
+{
+ struct mt7615_dev *dev = dev_get_drvdata(s->private);
+ struct mt76_sdio *sdio = &dev->mt76.sdio;
+
+ seq_printf(s, "pse_data_quota\t%d\n", sdio->sched.pse_data_quota);
+ seq_printf(s, "ple_data_quota\t%d\n", sdio->sched.ple_data_quota);
+ seq_printf(s, "pse_mcu_quota\t%d\n", sdio->sched.pse_mcu_quota);
+ seq_printf(s, "sched_deficit\t%d\n", sdio->sched.deficit);
+
+ return 0;
+}
+
int mt7615_init_debugfs(struct mt7615_dev *dev)
{
struct dentry *dir;
@@ -406,11 +519,15 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
&fops_reset_test);
debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir,
mt7615_read_temperature);
+ debugfs_create_file("ext_mac_addr", 0600, dir, dev, &fops_ext_mac_addr);
debugfs_create_u32("rf_wfidx", 0600, dir, &dev->debugfs_rf_wf);
debugfs_create_u32("rf_regidx", 0600, dir, &dev->debugfs_rf_reg);
debugfs_create_file_unsafe("rf_regval", 0600, dir, dev,
&fops_rf_reg);
+ if (mt76_is_sdio(&dev->mt76))
+ debugfs_create_devm_seqfile(dev->mt76.dev, "sched-quota", dir,
+ mt7663s_sched_quota_read);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
index bf8ae14121db..25e3069cf2b1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -12,25 +12,6 @@
#include "mac.h"
static int
-mt7615_init_tx_queue(struct mt7615_dev *dev, int qid, int idx, int n_desc)
-{
- struct mt76_queue *hwq;
- int err;
-
- hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
- if (!hwq)
- return -ENOMEM;
-
- err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE);
- if (err < 0)
- return err;
-
- dev->mt76.q_tx[qid] = hwq;
-
- return 0;
-}
-
-static int
mt7622_init_tx_queues_multi(struct mt7615_dev *dev)
{
static const u8 wmm_queue_map[] = {
@@ -43,20 +24,21 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev)
int i;
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
- ret = mt7615_init_tx_queue(dev, i, wmm_queue_map[i],
- MT7615_TX_RING_SIZE / 2);
+ ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i],
+ MT7615_TX_RING_SIZE / 2,
+ MT_TX_RING_BASE);
if (ret)
return ret;
}
- ret = mt7615_init_tx_queue(dev, MT_TXQ_PSD,
- MT7622_TXQ_MGMT, MT7615_TX_MGMT_RING_SIZE);
+ ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT7622_TXQ_MGMT,
+ MT7615_TX_MGMT_RING_SIZE,
+ MT_TX_RING_BASE);
if (ret)
return ret;
- ret = mt7615_init_tx_queue(dev, MT_TXQ_MCU,
- MT7622_TXQ_MCU, MT7615_TX_MCU_RING_SIZE);
- return ret;
+ return mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7622_TXQ_MCU,
+ MT7615_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
}
static int
@@ -64,25 +46,24 @@ mt7615_init_tx_queues(struct mt7615_dev *dev)
{
int ret, i;
- ret = mt7615_init_tx_queue(dev, MT_TXQ_FWDL,
- MT7615_TXQ_FWDL,
- MT7615_TX_FWDL_RING_SIZE);
+ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7615_TXQ_FWDL,
+ MT7615_TX_FWDL_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
if (!is_mt7615(&dev->mt76))
return mt7622_init_tx_queues_multi(dev);
- ret = mt7615_init_tx_queue(dev, 0, 0, MT7615_TX_RING_SIZE);
+ ret = mt76_init_tx_queue(&dev->mphy, 0, 0, MT7615_TX_RING_SIZE,
+ MT_TX_RING_BASE);
if (ret)
return ret;
- for (i = 1; i < MT_TXQ_MCU; i++)
- dev->mt76.q_tx[i] = dev->mt76.q_tx[0];
+ for (i = 1; i <= MT_TXQ_PSD ; i++)
+ dev->mphy.q_tx[i] = dev->mphy.q_tx[0];
- ret = mt7615_init_tx_queue(dev, MT_TXQ_MCU, MT7615_TXQ_MCU,
- MT7615_TX_MCU_RING_SIZE);
- return 0;
+ return mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7615_TXQ_MCU,
+ MT7615_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
}
static int mt7615_poll_tx(struct napi_struct *napi, int budget)
@@ -91,7 +72,7 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget)
dev = container_of(napi, struct mt7615_dev, mt76.tx_napi);
- mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
if (napi_complete_done(napi, 0))
mt7615_irq_enable(dev, mt7615_tx_mcu_int_mask(dev));
@@ -202,7 +183,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)
int ret;
/* Increase buffer size to receive large VHT MPDUs */
- if (dev->mt76.cap.has_5ghz)
+ if (dev->mphy.cap.has_5ghz)
rx_buf_size *= 2;
mt76_dma_attach(&dev->mt76);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
index f4756bb946c3..3232ebd5eda6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
@@ -99,20 +99,20 @@ mt7615_eeprom_parse_hw_band_cap(struct mt7615_dev *dev)
if (is_mt7663(&dev->mt76)) {
/* dual band */
- dev->mt76.cap.has_2ghz = true;
- dev->mt76.cap.has_5ghz = true;
+ dev->mphy.cap.has_2ghz = true;
+ dev->mphy.cap.has_5ghz = true;
return;
}
if (is_mt7622(&dev->mt76)) {
/* 2GHz only */
- dev->mt76.cap.has_2ghz = true;
+ dev->mphy.cap.has_2ghz = true;
return;
}
if (is_mt7611(&dev->mt76)) {
/* 5GHz only */
- dev->mt76.cap.has_5ghz = true;
+ dev->mphy.cap.has_5ghz = true;
return;
}
@@ -120,17 +120,17 @@ mt7615_eeprom_parse_hw_band_cap(struct mt7615_dev *dev)
eeprom[MT_EE_WIFI_CONF]);
switch (val) {
case MT_EE_5GHZ:
- dev->mt76.cap.has_5ghz = true;
+ dev->mphy.cap.has_5ghz = true;
break;
case MT_EE_2GHZ:
- dev->mt76.cap.has_2ghz = true;
+ dev->mphy.cap.has_2ghz = true;
break;
case MT_EE_DBDC:
dev->dbdc_support = true;
- /* fall through */
+ fallthrough;
default:
- dev->mt76.cap.has_2ghz = true;
- dev->mt76.cap.has_5ghz = true;
+ dev->mphy.cap.has_2ghz = true;
+ dev->mphy.cap.has_5ghz = true;
break;
}
}
@@ -342,10 +342,10 @@ int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr)
}
mt7615_eeprom_parse_hw_cap(dev);
- memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
+ memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
ETH_ALEN);
- mt76_eeprom_override(&dev->mt76);
+ mt76_eeprom_override(&dev->mphy);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index e194259c84e9..a73b76e57c7f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -221,7 +221,7 @@ static const struct ieee80211_iface_combination if_comb_radar[] = {
{
.limits = if_limits,
.n_limits = ARRAY_SIZE(if_limits),
- .max_interfaces = 4,
+ .max_interfaces = MT7615_MAX_INTERFACES,
.num_different_channels = 1,
.beacon_int_infra_match = true,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
@@ -237,7 +237,7 @@ static const struct ieee80211_iface_combination if_comb[] = {
{
.limits = if_limits,
.n_limits = ARRAY_SIZE(if_limits),
- .max_interfaces = 4,
+ .max_interfaces = MT7615_MAX_INTERFACES,
.num_different_channels = 1,
.beacon_int_infra_match = true,
}
@@ -385,7 +385,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
{
struct mt7615_phy *phy = mt7615_ext_phy(dev);
struct mt76_phy *mphy;
- int ret;
+ int i, ret;
if (!is_mt7615(&dev->mt76))
return -EOPNOTSUPP;
@@ -422,14 +422,21 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
* Make the secondary PHY MAC address local without overlapping with
* the usual MAC address allocation scheme on multiple virtual interfaces
*/
- mphy->hw->wiphy->perm_addr[0] |= 2;
- mphy->hw->wiphy->perm_addr[0] ^= BIT(7);
+ memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
+ ETH_ALEN);
+ mphy->macaddr[0] |= 2;
+ mphy->macaddr[0] ^= BIT(7);
+ mt76_eeprom_override(mphy);
/* second phy can only handle 5 GHz */
- mphy->sband_2g.sband.n_channels = 0;
- mphy->hw->wiphy->bands[NL80211_BAND_2GHZ] = NULL;
+ mphy->cap.has_5ghz = true;
- ret = mt76_register_phy(mphy);
+ /* mt7615 second phy shares the same hw queues with the primary one */
+ for (i = 0; i <= MT_TXQ_PSD ; i++)
+ mphy->q_tx[i] = dev->mphy.q_tx[i];
+
+ ret = mt76_register_phy(mphy, true, mt7615_rates,
+ ARRAY_SIZE(mt7615_rates));
if (ret)
ieee80211_free_hw(mphy->hw);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index 8dc645e398fd..0f360be0b885 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -215,8 +215,8 @@ static void mt7615_mac_fill_tm_rx(struct mt7615_dev *dev, __le32 *rxv)
dev->test.last_rcpi[1] = FIELD_GET(MT_RXV4_RCPI1, rxv4);
dev->test.last_rcpi[2] = FIELD_GET(MT_RXV4_RCPI2, rxv4);
dev->test.last_rcpi[3] = FIELD_GET(MT_RXV4_RCPI3, rxv4);
- dev->test.last_ib_rssi = FIELD_GET(MT_RXV3_IB_RSSI, rxv3);
- dev->test.last_wb_rssi = FIELD_GET(MT_RXV3_WB_RSSI, rxv3);
+ dev->test.last_ib_rssi[0] = FIELD_GET(MT_RXV3_IB_RSSI, rxv3);
+ dev->test.last_wb_rssi[0] = FIELD_GET(MT_RXV3_WB_RSSI, rxv3);
#endif
}
@@ -915,22 +915,20 @@ mt7615_mac_queue_rate_update(struct mt7615_phy *phy, struct mt7615_sta *sta,
struct ieee80211_tx_rate *rates)
{
struct mt7615_dev *dev = phy->dev;
- struct mt7615_wtbl_desc *wd;
+ struct mt7615_wtbl_rate_desc *wrd;
- if (work_pending(&dev->wtbl_work))
+ if (work_pending(&dev->rate_work))
return -EBUSY;
- wd = kzalloc(sizeof(*wd), GFP_ATOMIC);
- if (!wd)
+ wrd = kzalloc(sizeof(*wrd), GFP_ATOMIC);
+ if (!wrd)
return -ENOMEM;
- wd->type = MT7615_WTBL_RATE_DESC;
- wd->sta = sta;
-
+ wrd->sta = sta;
mt7615_mac_update_rate_desc(phy, sta, probe_rate, rates,
- &wd->rate);
- list_add_tail(&wd->node, &dev->wd_head);
- queue_work(dev->mt76.wq, &dev->wtbl_work);
+ &wrd->rate);
+ list_add_tail(&wrd->node, &dev->wrd_head);
+ queue_work(dev->mt76.wq, &dev->rate_work);
return 0;
}
@@ -1030,31 +1028,33 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
}
EXPORT_SYMBOL_GPL(mt7615_mac_set_rates);
-int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev,
- struct mt76_wcid *wcid,
- u8 *key, u8 keylen,
- enum mt7615_cipher_type cipher,
- enum set_key_cmd cmd)
+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(dev, wcid->idx) + 30 * 4;
u8 data[32] = {};
- if (keylen > sizeof(data))
+ 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 + 24, 8);
- memcpy(data + 24, key + 16, 8);
+ memcpy(data, key->key, 16);
+ memcpy(data + 16, key->key + 24, 8);
+ memcpy(data + 24, key->key + 16, 8);
+ } else {
+ 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);
}
- 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, keylen);
- else if (cipher == MT_CIPHER_BIP_CMAC_128)
- memcpy(data + 16, key, 16);
} else {
if (wcid->cipher & ~BIT(cipher)) {
if (cipher != MT_CIPHER_BIP_CMAC_128)
@@ -1068,12 +1068,11 @@ int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_key);
-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)
+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(dev, wcid->idx), w0, w1;
@@ -1105,12 +1104,11 @@ int mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_pk);
-void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev,
- struct mt76_wcid *wcid,
- enum mt7615_cipher_type cipher,
- enum set_key_cmd cmd)
+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(dev, wcid->idx);
@@ -1128,12 +1126,11 @@ void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev,
mt76_clear(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE);
}
}
-EXPORT_SYMBOL_GPL(mt7615_mac_wtbl_update_cipher);
-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_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;
@@ -1142,25 +1139,32 @@ int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
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->key, key->keylen,
- cipher, cmd);
+ err = mt7615_mac_wtbl_update_key(dev, wcid, key, cipher, cmd);
if (err < 0)
- goto out;
+ return err;
- err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx,
- cmd);
+ err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx, cmd);
if (err < 0)
- goto out;
+ return err;
if (cmd == SET_KEY)
wcid->cipher |= BIT(cipher);
else
wcid->cipher &= ~BIT(cipher);
-out:
+ return 0;
+}
+
+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 err;
+
+ spin_lock_bh(&dev->mt76.lock);
+ err = __mt7615_mac_wtbl_set_key(dev, wcid, key, cmd);
spin_unlock_bh(&dev->mt76.lock);
return err;
@@ -1431,12 +1435,12 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
struct mt7615_tx_free *free = (struct mt7615_tx_free *)skb->data;
u8 i, count;
- mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
if (is_mt7615(&dev->mt76)) {
- mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
} else {
for (i = 0; i < IEEE80211_NUM_ACS; i++)
- mt76_queue_tx_cleanup(dev, i, false);
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false);
}
count = FIELD_GET(MT_TX_FREE_MSDU_ID_CNT, le16_to_cpu(free->ctrl));
@@ -1969,49 +1973,6 @@ out:
queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
}
-static void
-mt7615_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
-{
- struct mt7615_phy *phy = priv;
- struct mt7615_dev *dev = phy->dev;
- bool ext_phy = phy != &dev->phy;
-
- if (mt7615_mcu_set_bss_pm(dev, vif, dev->pm.enable))
- return;
-
- if (dev->pm.enable) {
- vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
- mt76_set(dev, MT_WF_RFCR(ext_phy),
- MT_WF_RFCR_DROP_OTHER_BEACON);
- } else {
- vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
- mt76_clear(dev, MT_WF_RFCR(ext_phy),
- MT_WF_RFCR_DROP_OTHER_BEACON);
- }
-}
-
-int mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable)
-{
- struct mt76_phy *mphy = dev->phy.mt76;
-
- if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76))
- return -EOPNOTSUPP;
-
- mt7615_mutex_acquire(dev);
-
- if (dev->pm.enable == enable)
- goto out;
-
- dev->pm.enable = enable;
- ieee80211_iterate_active_interfaces(mphy->hw,
- IEEE80211_IFACE_ITER_RESUME_ALL,
- mt7615_pm_interface_iter, mphy->priv);
-out:
- mt7615_mutex_release(dev);
-
- return 0;
-}
-
void mt7615_mac_work(struct work_struct *work)
{
struct mt7615_phy *phy;
@@ -2083,8 +2044,9 @@ void mt7615_dma_reset(struct mt7615_dev *dev)
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
usleep_range(1000, 2000);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], true);
for (i = 0; i < __MT_TXQ_MAX; i++)
- mt76_queue_tx_cleanup(dev, i, true);
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
mt76_for_each_q_rx(&dev->mt76, i) {
mt76_queue_rx_reset(dev, i);
@@ -2314,3 +2276,46 @@ stop:
mt7615_dfs_stop_radar_detector(phy);
return 0;
}
+
+int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy,
+ struct ieee80211_vif *vif,
+ bool enable)
+{
+ struct mt7615_dev *dev = phy->dev;
+ bool ext_phy = phy != &dev->phy;
+ int err;
+
+ if (!mt7615_firmware_offload(dev))
+ return -EOPNOTSUPP;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_MONITOR:
+ return 0;
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
+ if (enable)
+ phy->n_beacon_vif++;
+ else
+ phy->n_beacon_vif--;
+ fallthrough;
+ default:
+ break;
+ }
+
+ err = mt7615_mcu_set_bss_pm(dev, vif, !phy->n_beacon_vif);
+ if (err)
+ return err;
+
+ if (phy->n_beacon_vif) {
+ vif->driver_flags &= ~IEEE80211_VIF_BEACON_FILTER;
+ mt76_clear(dev, MT_WF_RFCR(ext_phy),
+ MT_WF_RFCR_DROP_OTHER_BEACON);
+ } else {
+ vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+ mt76_set(dev, MT_WF_RFCR(ext_phy),
+ MT_WF_RFCR_DROP_OTHER_BEACON);
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 3186b7b2ca48..56dd0b4e4460 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -115,29 +115,50 @@ static void mt7615_stop(struct ieee80211_hw *hw)
mt7615_mutex_release(dev);
}
-static int get_omac_idx(enum nl80211_iftype type, u32 mask)
+static inline int get_free_idx(u32 mask, u8 start, u8 end)
+{
+ return ffs(~mask & GENMASK(end, start));
+}
+
+static int get_omac_idx(enum nl80211_iftype type, u64 mask)
{
int i;
switch (type) {
- case NL80211_IFTYPE_MONITOR:
- case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
- /* ap use hw bssid 0 and ext bssid */
+ case NL80211_IFTYPE_STATION:
+ /* prefer hw bssid slot 1-3 */
+ i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3);
+ if (i)
+ return i - 1;
+
+ if (type != NL80211_IFTYPE_STATION)
+ break;
+
+ /* next, try to find a free repeater entry for the sta */
+ i = get_free_idx(mask >> REPEATER_BSSID_START, 0,
+ REPEATER_BSSID_MAX - REPEATER_BSSID_START);
+ if (i)
+ return i + 32 - 1;
+
+ i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
+ if (i)
+ return i - 1;
+
if (~mask & BIT(HW_BSSID_0))
return HW_BSSID_0;
- for (i = EXT_BSSID_1; i < EXT_BSSID_END; i++)
- if (~mask & BIT(i))
- return i;
-
break;
- case NL80211_IFTYPE_STATION:
- /* sta use hw bssid other than 0 */
- for (i = HW_BSSID_1; i < HW_BSSID_MAX; i++)
- if (~mask & BIT(i))
- return i;
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_AP:
+ /* ap uses hw bssid 0 and ext bssid */
+ if (~mask & BIT(HW_BSSID_0))
+ return HW_BSSID_0;
+
+ i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
+ if (i)
+ return i - 1;
break;
default:
@@ -187,8 +208,8 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
mvif->wmm_idx = mvif->idx % MT7615_MAX_WMM_SETS;
dev->mphy.vif_mask |= BIT(mvif->idx);
- dev->omac_mask |= BIT(mvif->omac_idx);
- phy->omac_mask |= BIT(mvif->omac_idx);
+ dev->omac_mask |= BIT_ULL(mvif->omac_idx);
+ phy->omac_mask |= BIT_ULL(mvif->omac_idx);
mt7615_mcu_set_dbdc(dev);
@@ -211,15 +232,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
if (ret)
goto out;
- if (dev->pm.enable) {
- ret = mt7615_mcu_set_bss_pm(dev, vif, true);
- if (ret)
- goto out;
-
- vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
- mt76_set(dev, MT_WF_RFCR(ext_phy),
- MT_WF_RFCR_DROP_OTHER_BEACON);
- }
+ mt7615_mac_set_beacon_filter(phy, vif, true);
out:
mt7615_mutex_release(dev);
@@ -245,20 +258,14 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
mt7615_free_pending_tx_skbs(dev, msta);
- if (dev->pm.enable) {
- bool ext_phy = phy != &dev->phy;
-
- mt7615_mcu_set_bss_pm(dev, vif, false);
- mt76_clear(dev, MT_WF_RFCR(ext_phy),
- MT_WF_RFCR_DROP_OTHER_BEACON);
- }
+ mt7615_mac_set_beacon_filter(phy, vif, false);
mt7615_mcu_add_dev_info(dev, vif, false);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
dev->mphy.vif_mask &= ~BIT(mvif->idx);
- dev->omac_mask &= ~BIT(mvif->omac_idx);
- phy->omac_mask &= ~BIT(mvif->omac_idx);
+ dev->omac_mask &= ~BIT_ULL(mvif->omac_idx);
+ phy->omac_mask &= ~BIT_ULL(mvif->omac_idx);
mt7615_mutex_release(dev);
@@ -334,39 +341,6 @@ out:
return ret;
}
-static int
-mt7615_queue_key_update(struct mt7615_dev *dev, enum set_key_cmd cmd,
- struct mt7615_sta *msta,
- struct ieee80211_key_conf *key)
-{
- struct mt7615_wtbl_desc *wd;
-
- wd = kzalloc(sizeof(*wd), GFP_KERNEL);
- if (!wd)
- return -ENOMEM;
-
- wd->type = MT7615_WTBL_KEY_DESC;
- wd->sta = msta;
-
- wd->key.key = kmemdup(key->key, key->keylen, GFP_KERNEL);
- if (!wd->key.key) {
- kfree(wd);
- return -ENOMEM;
- }
- wd->key.cipher = key->cipher;
- wd->key.keyidx = key->keyidx;
- wd->key.keylen = key->keylen;
- wd->key.cmd = cmd;
-
- spin_lock_bh(&dev->mt76.lock);
- list_add_tail(&wd->node, &dev->wd_head);
- spin_unlock_bh(&dev->mt76.lock);
-
- queue_work(dev->mt76.wq, &dev->wtbl_work);
-
- return 0;
-}
-
static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
@@ -393,8 +367,6 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
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:
@@ -402,6 +374,8 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
case WLAN_CIPHER_SUITE_GCMP_256:
case WLAN_CIPHER_SUITE_SMS4:
break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
default:
return -EOPNOTSUPP;
}
@@ -420,7 +394,7 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (mt76_is_mmio(&dev->mt76))
err = mt7615_mac_wtbl_set_key(dev, wcid, key, cmd);
else
- err = mt7615_queue_key_update(dev, cmd, msta, key);
+ err = __mt7615_mac_wtbl_set_key(dev, wcid, key, cmd);
mt7615_mutex_release(dev);
@@ -511,7 +485,6 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw,
} while (0)
phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS |
- MT_WF_RFCR_DROP_OTHER_BEACON |
MT_WF_RFCR_DROP_FRAME_REPORT |
MT_WF_RFCR_DROP_PROBEREQ |
MT_WF_RFCR_DROP_MCAST_FILTERED |
@@ -522,6 +495,9 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw,
MT_WF_RFCR_DROP_UNWANTED_CTL |
MT_WF_RFCR_DROP_STBC_MULTI);
+ if (phy->n_beacon_vif || !mt7615_firmware_offload(dev))
+ phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_BEACON;
+
MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM |
MT_WF_RFCR_DROP_A3_MAC |
MT_WF_RFCR_DROP_A3_BSSID);
@@ -1127,7 +1103,6 @@ static int mt7615_suspend(struct ieee80211_hw *hw,
{
struct mt7615_dev *dev = mt7615_hw_dev(hw);
struct mt7615_phy *phy = mt7615_hw_phy(hw);
- bool ext_phy = phy != &dev->phy;
int err = 0;
cancel_delayed_work_sync(&dev->pm.ps_work);
@@ -1139,8 +1114,6 @@ static int mt7615_suspend(struct ieee80211_hw *hw,
cancel_delayed_work_sync(&phy->scan_work);
cancel_delayed_work_sync(&phy->mac_work);
- mt76_set(dev, MT_WF_RFCR(ext_phy), MT_WF_RFCR_DROP_OTHER_BEACON);
-
set_bit(MT76_STATE_SUSPEND, &phy->mt76->state);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
@@ -1158,7 +1131,7 @@ static int mt7615_resume(struct ieee80211_hw *hw)
{
struct mt7615_dev *dev = mt7615_hw_dev(hw);
struct mt7615_phy *phy = mt7615_hw_phy(hw);
- bool running, ext_phy = phy != &dev->phy;
+ bool running;
mt7615_mutex_acquire(dev);
@@ -1182,7 +1155,6 @@ static int mt7615_resume(struct ieee80211_hw *hw)
ieee80211_queue_delayed_work(hw, &phy->mac_work,
MT7615_WATCHDOG_TIME);
- mt76_clear(dev, MT_WF_RFCR(ext_phy), MT_WF_RFCR_DROP_OTHER_BEACON);
mt7615_mutex_release(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 31b40fb83f6c..a44b7766dec6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -94,6 +94,9 @@ void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb,
__le32 *txd;
u32 val;
+ /* TODO: make dynamic based on msg type */
+ dev->mt76.mcu.timeout = 20 * HZ;
+
seq = ++dev->mt76.mcu.msg_seq & 0xf;
if (!seq)
seq = ++dev->mt76.mcu.msg_seq & 0xf;
@@ -165,32 +168,22 @@ void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(mt7615_mcu_fill_msg);
-static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
- int cmd, int *wait_seq)
+int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ struct sk_buff *skb, int seq)
{
- enum mt76_txq_id qid;
-
- mt7615_mcu_fill_msg(dev, skb, cmd, wait_seq);
- if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
- qid = MT_TXQ_MCU;
- else
- qid = MT_TXQ_FWDL;
-
- return mt76_tx_queue_skb_raw(dev, qid, skb, 0);
-}
-
-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;
+ struct mt7615_mcu_rxd *rxd;
int ret = 0;
- if (seq != rxd->seq) {
- ret = -EAGAIN;
- goto out;
+ if (!skb) {
+ dev_err(mdev->dev, "Message %ld (seq %d) timeout\n",
+ cmd & MCU_CMD_MASK, seq);
+ return -ETIMEDOUT;
}
+ rxd = (struct mt7615_mcu_rxd *)skb->data;
+ if (seq != rxd->seq)
+ return -EAGAIN;
+
switch (cmd) {
case MCU_CMD_PATCH_SEM_CONTROL:
skb_pull(skb, sizeof(*rxd) - 4);
@@ -228,69 +221,26 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd,
default:
break;
}
-out:
- dev_kfree_skb(skb);
-
- return ret;
-}
-
-int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq)
-{
- unsigned long expires = jiffies + 20 * HZ;
- struct sk_buff *skb;
- int ret = 0;
-
- while (true) {
- skb = mt76_mcu_get_response(&dev->mt76, expires);
- if (!skb) {
- dev_err(dev->mt76.dev, "Message %ld (seq %d) timeout\n",
- cmd & MCU_CMD_MASK, seq);
- return -ETIMEDOUT;
- }
-
- ret = mt7615_mcu_parse_response(dev, cmd, skb, seq);
- if (ret != -EAGAIN)
- break;
- }
return ret;
}
-EXPORT_SYMBOL_GPL(mt7615_mcu_wait_response);
+EXPORT_SYMBOL_GPL(mt7615_mcu_parse_response);
static int
mt7615_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
- int cmd, bool wait_resp)
+ int cmd, int *seq)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
- int ret, seq;
-
- mutex_lock(&mdev->mcu.mutex);
-
- ret = __mt7615_mcu_msg_send(dev, skb, cmd, &seq);
- if (ret)
- goto out;
-
- if (wait_resp)
- ret = mt7615_mcu_wait_response(dev, cmd, seq);
-
-out:
- mutex_unlock(&mdev->mcu.mutex);
-
- return ret;
-}
-
-int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
- int len, bool wait_resp)
-{
- struct sk_buff *skb;
+ enum mt76_txq_id qid;
- skb = mt76_mcu_msg_alloc(mdev, data, len);
- if (!skb)
- return -ENOMEM;
+ mt7615_mcu_fill_msg(dev, skb, cmd, seq);
+ if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
+ qid = MT_MCUQ_WM;
+ else
+ qid = MT_MCUQ_FWDL;
- return __mt76_mcu_skb_send_msg(mdev, skb, cmd, wait_resp);
+ return mt76_tx_queue_skb_raw(dev, dev->mt76.q_mcu[qid], skb, 0);
}
-EXPORT_SYMBOL_GPL(mt7615_mcu_msg_send);
u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg)
{
@@ -303,9 +253,9 @@ u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg)
.address = cpu_to_le32(reg),
};
- return __mt76_mcu_send_msg(&dev->mt76,
- MCU_EXT_CMD_RF_REG_ACCESS | MCU_QUERY_PREFIX,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76,
+ MCU_EXT_CMD_RF_REG_ACCESS | MCU_QUERY_PREFIX,
+ &req, sizeof(req), true);
}
int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val)
@@ -320,8 +270,8 @@ int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val)
.data = cpu_to_le32(val),
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RF_REG_ACCESS, &req,
- sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RF_REG_ACCESS, &req,
+ sizeof(req), false);
}
static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)
@@ -645,8 +595,44 @@ static int mt7615_mcu_init_download(struct mt7615_dev *dev, u32 addr,
.mode = cpu_to_le32(mode),
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_TARGET_ADDRESS_LEN_REQ,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_TARGET_ADDRESS_LEN_REQ,
+ &req, sizeof(req), true);
+}
+
+static int
+mt7615_mcu_muar_config(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+ bool bssid, bool enable)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ u32 idx = mvif->omac_idx - REPEATER_BSSID_START;
+ u32 mask = dev->omac_mask >> 32 & ~BIT(idx);
+ const u8 *addr = vif->addr;
+ struct {
+ u8 mode;
+ u8 force_clear;
+ u8 clear_bitmap[8];
+ u8 entry_count;
+ u8 write;
+
+ u8 index;
+ u8 bssid;
+ u8 addr[ETH_ALEN];
+ } __packed req = {
+ .mode = !!mask || enable,
+ .entry_count = 1,
+ .write = 1,
+
+ .index = idx * 2 + bssid,
+ };
+
+ if (bssid)
+ addr = vif->bss_conf.bssid;
+
+ if (enable)
+ ether_addr_copy(req.addr, addr);
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MUAR_UPDATE, &req,
+ sizeof(req), true);
}
static int
@@ -684,9 +670,12 @@ mt7615_mcu_add_dev(struct mt7615_dev *dev, struct ieee80211_vif *vif,
},
};
+ if (mvif->omac_idx >= REPEATER_BSSID_START)
+ return mt7615_mcu_muar_config(dev, vif, false, enable);
+
memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE,
- &data, sizeof(data), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE,
+ &data, sizeof(data), true);
}
static int
@@ -750,8 +739,8 @@ mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev,
}
dev_kfree_skb(skb);
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BCN_OFFLOAD,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BCN_OFFLOAD, &req,
+ sizeof(req), true);
}
static int
@@ -781,8 +770,8 @@ mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
.band_idx = band,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL, &req,
+ sizeof(req), true);
}
static struct sk_buff *
@@ -1266,6 +1255,9 @@ mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
struct mt7615_dev *dev = phy->dev;
struct sk_buff *skb;
+ if (mvif->omac_idx >= REPEATER_BSSID_START)
+ mt7615_mcu_muar_config(dev, vif, true, enable);
+
skb = mt7615_mcu_alloc_sta_req(dev, mvif, NULL);
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -1275,11 +1267,12 @@ mt7615_mcu_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
mt7615_mcu_bss_basic_tlv(skb, vif, sta, enable);
- if (enable && mvif->omac_idx > EXT_BSSID_START)
+ if (enable && mvif->omac_idx >= EXT_BSSID_START &&
+ mvif->omac_idx < REPEATER_BSSID_START)
mt7615_mcu_bss_ext_tlv(skb, mvif);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_BSS_INFO_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_BSS_INFO_UPDATE, true);
}
static int
@@ -1299,8 +1292,8 @@ mt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev,
mt7615_mcu_wtbl_ba_tlv(skb, params, enable, true, NULL, wtbl_hdr);
- err = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_WTBL_UPDATE, true);
+ err = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE,
+ true);
if (err < 0)
return err;
@@ -1310,8 +1303,8 @@ mt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev,
mt7615_mcu_sta_ba_tlv(skb, params, enable, true);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
}
static int
@@ -1331,8 +1324,8 @@ mt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev,
mt7615_mcu_sta_ba_tlv(skb, params, enable, false);
- err = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
if (err < 0 || !enable)
return err;
@@ -1343,8 +1336,8 @@ mt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev,
mt7615_mcu_wtbl_ba_tlv(skb, params, enable, false, NULL, wtbl_hdr);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_WTBL_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE,
+ true);
}
static int
@@ -1383,7 +1376,7 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif,
cmd = enable ? MCU_EXT_CMD_WTBL_UPDATE : MCU_EXT_CMD_STA_REC_UPDATE;
skb = enable ? wskb : sskb;
- err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
+ err = mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
if (err < 0) {
skb = enable ? sskb : wskb;
dev_kfree_skb(skb);
@@ -1394,7 +1387,7 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif,
cmd = enable ? MCU_EXT_CMD_STA_REC_UPDATE : MCU_EXT_CMD_WTBL_UPDATE;
skb = enable ? sskb : wskb;
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
}
static const struct mt7615_mcu_ops wtbl_update_ops = {
@@ -1432,8 +1425,8 @@ mt7615_mcu_sta_ba(struct mt7615_dev *dev,
&skb);
mt7615_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
}
static int
@@ -1484,7 +1477,7 @@ mt7615_mcu_add_sta_cmd(struct mt7615_dev *dev, struct ieee80211_vif *vif,
mt7615_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr);
}
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
}
static int
@@ -1586,7 +1579,7 @@ mt7615_mcu_uni_add_dev(struct mt7615_dev *dev,
data = enable ? (void *)&dev_req : (void *)&basic_req;
len = enable ? sizeof(dev_req) : sizeof(basic_req);
- err = __mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true);
+ err = mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true);
if (err < 0)
return err;
@@ -1594,7 +1587,7 @@ mt7615_mcu_uni_add_dev(struct mt7615_dev *dev,
data = enable ? (void *)&basic_req : (void *)&dev_req;
len = enable ? sizeof(basic_req) : sizeof(dev_req);
- return __mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true);
+ return mt76_mcu_send_msg(&dev->mt76, cmd, data, len, true);
}
static int
@@ -1708,8 +1701,8 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
basic_req.basic.sta_idx = cpu_to_le16(mvif->sta.wcid.idx);
basic_req.basic.conn_state = !enable;
- err = __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
- &basic_req, sizeof(basic_req), true);
+ err = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
+ &basic_req, sizeof(basic_req), true);
if (err < 0)
return err;
@@ -1744,8 +1737,8 @@ mt7615_mcu_uni_add_bss(struct mt7615_phy *phy, struct ieee80211_vif *vif,
else if (rlm_req.rlm.control_channel > rlm_req.rlm.center_chan)
rlm_req.rlm.sco = 3; /* SCB */
- return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
- &rlm_req, sizeof(rlm_req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
+ &rlm_req, sizeof(rlm_req), true);
}
static int
@@ -1816,8 +1809,8 @@ mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev,
}
dev_kfree_skb(skb);
- return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
+ &req, sizeof(req), true);
}
static int
@@ -1846,8 +1839,8 @@ mt7615_mcu_uni_tx_ba(struct mt7615_dev *dev,
mt7615_mcu_wtbl_ba_tlv(skb, params, enable, true, sta_wtbl,
wtbl_hdr);
- err = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_UNI_CMD_STA_REC_UPDATE, true);
+ err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_UNI_CMD_STA_REC_UPDATE, true);
if (err < 0)
return err;
@@ -1857,8 +1850,8 @@ mt7615_mcu_uni_tx_ba(struct mt7615_dev *dev,
mt7615_mcu_sta_ba_tlv(skb, params, enable, true);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_UNI_CMD_STA_REC_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_UNI_CMD_STA_REC_UPDATE, true);
}
static int
@@ -1879,8 +1872,8 @@ mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev,
mt7615_mcu_sta_ba_tlv(skb, params, enable, false);
- err = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_UNI_CMD_STA_REC_UPDATE, true);
+ err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_UNI_CMD_STA_REC_UPDATE, true);
if (err < 0 || !enable)
return err;
@@ -1898,8 +1891,8 @@ mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev,
mt7615_mcu_wtbl_ba_tlv(skb, params, enable, false, sta_wtbl,
wtbl_hdr);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_UNI_CMD_STA_REC_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_UNI_CMD_STA_REC_UPDATE, true);
}
static int
@@ -1922,29 +1915,6 @@ static const struct mt7615_mcu_ops uni_update_ops = {
.set_fw_ctrl = mt7615_mcu_fw_pmctrl,
};
-static int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data,
- int len)
-{
- int ret = 0, cur_len;
-
- while (len > 0) {
- cur_len = min_t(int, 4096 - dev->mt76.mcu_ops->headroom, len);
-
- ret = __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FW_SCATTER,
- data, cur_len, false);
- if (ret)
- break;
-
- data += cur_len;
- len -= cur_len;
-
- if (mt76_is_mmio(&dev->mt76))
- mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false);
- }
-
- return ret;
-}
-
static int mt7615_mcu_start_firmware(struct mt7615_dev *dev, u32 addr,
u32 option)
{
@@ -1956,14 +1926,13 @@ static int mt7615_mcu_start_firmware(struct mt7615_dev *dev, u32 addr,
.addr = cpu_to_le32(addr),
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FW_START_REQ,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FW_START_REQ, &req,
+ sizeof(req), true);
}
int mt7615_mcu_restart(struct mt76_dev *dev)
{
- return __mt76_mcu_send_msg(dev, MCU_CMD_RESTART_DL_REQ, NULL,
- 0, true);
+ return mt76_mcu_send_msg(dev, MCU_CMD_RESTART_DL_REQ, NULL, 0, true);
}
EXPORT_SYMBOL_GPL(mt7615_mcu_restart);
@@ -1975,8 +1944,8 @@ static int mt7615_mcu_patch_sem_ctrl(struct mt7615_dev *dev, bool get)
.op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE),
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_SEM_CONTROL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_SEM_CONTROL, &req,
+ sizeof(req), true);
}
static int mt7615_mcu_start_patch(struct mt7615_dev *dev)
@@ -1988,8 +1957,8 @@ static int mt7615_mcu_start_patch(struct mt7615_dev *dev)
.check_crc = 0,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_FINISH_REQ,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_FINISH_REQ, &req,
+ sizeof(req), true);
}
static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)
@@ -2032,7 +2001,8 @@ static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)
goto out;
}
- ret = mt7615_mcu_send_firmware(dev, fw->data + sizeof(*hdr), len);
+ ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER,
+ fw->data + sizeof(*hdr), len);
if (ret) {
dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
goto out;
@@ -2092,7 +2062,8 @@ mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev,
return err;
}
- err = mt7615_mcu_send_firmware(dev, data + offset, len);
+ err = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER,
+ data + offset, len);
if (err) {
dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
return err;
@@ -2285,8 +2256,8 @@ int mt7615_mcu_fw_log_2_host(struct mt7615_dev *dev, u8 ctrl)
.ctrl_val = ctrl
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_LOG_2_HOST,
- &data, sizeof(data), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_LOG_2_HOST, &data,
+ sizeof(data), true);
}
static int mt7663_load_n9(struct mt7615_dev *dev, const char *name)
@@ -2333,7 +2304,8 @@ static int mt7663_load_n9(struct mt7615_dev *dev, const char *name)
goto out;
}
- ret = mt7615_mcu_send_firmware(dev, fw->data + offset, len);
+ ret = mt76_mcu_send_firmware(&dev->mt76, MCU_CMD_FW_SCATTER,
+ fw->data + offset, len);
if (ret) {
dev_err(dev->mt76.dev, "Failed to send firmware\n");
goto out;
@@ -2467,7 +2439,7 @@ int mt7615_mcu_init(struct mt7615_dev *dev)
static const struct mt76_mcu_ops mt7615_mcu_ops = {
.headroom = sizeof(struct mt7615_mcu_txd),
.mcu_skb_send_msg = mt7615_mcu_send_message,
- .mcu_send_msg = mt7615_mcu_msg_send,
+ .mcu_parse_response = mt7615_mcu_parse_response,
.mcu_restart = mt7615_mcu_restart,
};
int ret;
@@ -2492,7 +2464,7 @@ int mt7615_mcu_init(struct mt7615_dev *dev)
if (ret)
return ret;
- mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
dev_dbg(dev->mt76.dev, "Firmware init done\n");
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
mt7615_mcu_fw_log_2_host(dev, 0);
@@ -2547,8 +2519,8 @@ int mt7615_mcu_set_eeprom(struct mt7615_dev *dev)
skb_put_data(skb, &req_hdr, sizeof(req_hdr));
skb_put_data(skb, eep + offset, eep_len);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_EFUSE_BUFFER_MODE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_EFUSE_BUFFER_MODE, true);
}
EXPORT_SYMBOL_GPL(mt7615_mcu_set_eeprom);
@@ -2563,8 +2535,8 @@ int mt7615_mcu_set_mac_enable(struct mt7615_dev *dev, int band, bool enable)
.band = band,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL, &req,
+ sizeof(req), true);
}
int mt7615_mcu_set_rts_thresh(struct mt7615_phy *phy, u32 val)
@@ -2583,8 +2555,8 @@ int mt7615_mcu_set_rts_thresh(struct mt7615_phy *phy, u32 val)
.pkt_thresh = cpu_to_le32(0x2),
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL, &req,
+ sizeof(req), true);
}
int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
@@ -2620,8 +2592,8 @@ int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
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);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req,
+ sizeof(req), true);
}
int mt7615_mcu_set_dbdc(struct mt7615_dev *dev)
@@ -2654,13 +2626,13 @@ int mt7615_mcu_set_dbdc(struct mt7615_dev *dev)
} while (0)
for (i = 0; i < 4; i++) {
- bool band = !!(ext_phy->omac_mask & BIT(i));
+ bool band = !!(ext_phy->omac_mask & BIT_ULL(i));
ADD_DBDC_ENTRY(DBDC_TYPE_BSS, i, band);
}
for (i = 0; i < 14; i++) {
- bool band = !!(ext_phy->omac_mask & BIT(0x11 + i));
+ bool band = !!(ext_phy->omac_mask & BIT_ULL(0x11 + i));
ADD_DBDC_ENTRY(DBDC_TYPE_MBSS, i, band);
}
@@ -2679,8 +2651,8 @@ int mt7615_mcu_set_dbdc(struct mt7615_dev *dev)
ADD_DBDC_ENTRY(DBDC_TYPE_MGMT, 1, 1);
out:
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DBDC_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DBDC_CTRL, &req,
+ sizeof(req), true);
}
int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev)
@@ -2689,8 +2661,8 @@ int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev)
.operation = WTBL_RESET_ALL,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE, &req,
+ sizeof(req), true);
}
EXPORT_SYMBOL_GPL(mt7615_mcu_del_wtbl_all);
@@ -2711,56 +2683,98 @@ int mt7615_mcu_rdd_cmd(struct mt7615_dev *dev,
.val = val,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL, &req,
+ sizeof(req), true);
}
int mt7615_mcu_set_fcc5_lpn(struct mt7615_dev *dev, int val)
{
struct {
- u16 tag;
- u16 min_lpn;
+ __le16 tag;
+ __le16 min_lpn;
} req = {
- .tag = 0x1,
- .min_lpn = val,
+ .tag = cpu_to_le16(0x1),
+ .min_lpn = cpu_to_le16(val),
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, &req,
+ sizeof(req), true);
}
int mt7615_mcu_set_pulse_th(struct mt7615_dev *dev,
const struct mt7615_dfs_pulse *pulse)
{
struct {
- u16 tag;
- struct mt7615_dfs_pulse pulse;
+ __le16 tag;
+ __le32 max_width; /* us */
+ __le32 max_pwr; /* dbm */
+ __le32 min_pwr; /* dbm */
+ __le32 min_stgr_pri; /* us */
+ __le32 max_stgr_pri; /* us */
+ __le32 min_cr_pri; /* us */
+ __le32 max_cr_pri; /* us */
} req = {
- .tag = 0x3,
+ .tag = cpu_to_le16(0x3),
+#define __req_field(field) .field = cpu_to_le32(pulse->field)
+ __req_field(max_width),
+ __req_field(max_pwr),
+ __req_field(min_pwr),
+ __req_field(min_stgr_pri),
+ __req_field(max_stgr_pri),
+ __req_field(min_cr_pri),
+ __req_field(max_cr_pri),
+#undef __req_field
};
- memcpy(&req.pulse, pulse, sizeof(*pulse));
-
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, &req,
+ sizeof(req), true);
}
int mt7615_mcu_set_radar_th(struct mt7615_dev *dev, int index,
const struct mt7615_dfs_pattern *pattern)
{
struct {
- u16 tag;
- u16 radar_type;
- struct mt7615_dfs_pattern pattern;
+ __le16 tag;
+ __le16 radar_type;
+ u8 enb;
+ u8 stgr;
+ u8 min_crpn;
+ u8 max_crpn;
+ u8 min_crpr;
+ u8 min_pw;
+ u8 max_pw;
+ __le32 min_pri;
+ __le32 max_pri;
+ u8 min_crbn;
+ u8 max_crbn;
+ u8 min_stgpn;
+ u8 max_stgpn;
+ u8 min_stgpr;
} req = {
- .tag = 0x2,
- .radar_type = index,
+ .tag = cpu_to_le16(0x2),
+ .radar_type = cpu_to_le16(index),
+#define __req_field_u8(field) .field = pattern->field
+#define __req_field_u32(field) .field = cpu_to_le32(pattern->field)
+ __req_field_u8(enb),
+ __req_field_u8(stgr),
+ __req_field_u8(min_crpn),
+ __req_field_u8(max_crpn),
+ __req_field_u8(min_crpr),
+ __req_field_u8(min_pw),
+ __req_field_u8(max_pw),
+ __req_field_u32(min_pri),
+ __req_field_u32(max_pri),
+ __req_field_u8(min_crbn),
+ __req_field_u8(max_crbn),
+ __req_field_u8(min_stgpn),
+ __req_field_u8(max_stgpn),
+ __req_field_u8(min_stgpr),
+#undef __req_field_u8
+#undef __req_field_u32
};
- memcpy(&req.pattern, pattern, sizeof(*pattern));
-
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, &req,
+ sizeof(req), true);
}
int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev)
@@ -2769,9 +2783,9 @@ int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev)
u8 pulse_num;
u8 rsv[3];
struct {
- u32 start_time;
- u16 width;
- s16 power;
+ __le32 start_time;
+ __le16 width;
+ __le16 power;
} pattern[32];
} req = {
.pulse_num = dev->radar_pattern.n_pulses,
@@ -2784,14 +2798,15 @@ int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev)
/* 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;
+ u32 ts = start_time + i * dev->radar_pattern.period;
+
+ req.pattern[i].width = cpu_to_le16(dev->radar_pattern.width);
+ req.pattern[i].power = cpu_to_le16(dev->radar_pattern.power);
+ req.pattern[i].start_time = cpu_to_le32(ts);
}
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_PATTERN,
- &req, sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_PATTERN,
+ &req, sizeof(req), false);
}
static void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku)
@@ -2885,7 +2900,7 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)
else
mt7615_mcu_set_txpower_sku(phy, req.txpower_sku);
- return __mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
}
int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index)
@@ -2897,8 +2912,8 @@ int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index)
.action = index,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_GET_TEMP, &req,
- sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_GET_TEMP, &req,
+ sizeof(req), true);
}
int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode,
@@ -2918,8 +2933,8 @@ int mt7615_mcu_set_test_param(struct mt7615_dev *dev, u8 param, bool test_mode,
.value = cpu_to_le32(val),
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req,
- sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req,
+ sizeof(req), false);
}
int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable)
@@ -2936,8 +2951,9 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable)
.sku_enable = enable,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, &req,
- sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76,
+ MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, &req,
+ sizeof(req), true);
}
int mt7615_mcu_set_vif_ps(struct mt7615_dev *dev, struct ieee80211_vif *vif)
@@ -2957,8 +2973,8 @@ int mt7615_mcu_set_vif_ps(struct mt7615_dev *dev, struct ieee80211_vif *vif)
if (vif->type != NL80211_IFTYPE_STATION)
return -ENOTSUPP;
- return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_PS_PROFILE,
- &req, sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_PS_PROFILE, &req,
+ sizeof(req), false);
}
int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy)
@@ -3018,8 +3034,8 @@ int mt7615_mcu_set_channel_domain(struct mt7615_phy *phy)
skb_put_data(skb, &channel, sizeof(channel));
}
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_CMD_SET_CHAN_DOMAIN, false);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_SET_CHAN_DOMAIN,
+ false);
}
#define MT7615_SCAN_CHANNEL_TIME 60
@@ -3101,8 +3117,8 @@ int mt7615_mcu_hw_scan(struct mt7615_phy *phy, struct ieee80211_vif *vif,
req->scan_func = 1;
}
- err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_START_HW_SCAN,
- false);
+ err = mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_START_HW_SCAN,
+ false);
if (err < 0)
clear_bit(MT76_HW_SCANNING, &phy->mt76->state);
@@ -3130,8 +3146,8 @@ int mt7615_mcu_cancel_hw_scan(struct mt7615_phy *phy,
ieee80211_scan_completed(phy->mt76->hw, &info);
}
- return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_CANCEL_HW_SCAN, &req,
- sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_CANCEL_HW_SCAN, &req,
+ sizeof(req), false);
}
int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy,
@@ -3202,8 +3218,8 @@ int mt7615_mcu_sched_scan_req(struct mt7615_phy *phy,
memcpy(skb_put(skb, sreq->ie_len), sreq->ie, sreq->ie_len);
}
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_CMD_SCHED_SCAN_REQ, false);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_CMD_SCHED_SCAN_REQ,
+ false);
}
int mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy,
@@ -3226,8 +3242,8 @@ int mt7615_mcu_sched_scan_enable(struct mt7615_phy *phy,
else
clear_bit(MT76_HW_SCHED_SCANNING, &phy->mt76->state);
- return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SCHED_SCAN_ENABLE,
- &req, sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SCHED_SCAN_ENABLE, &req,
+ sizeof(req), false);
}
static int mt7615_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
@@ -3366,8 +3382,8 @@ again:
out:
req.center_freq = cpu_to_le16(center_freq);
- ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RXDCOC_CAL, &req,
- sizeof(req), true);
+ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RXDCOC_CAL, &req,
+ sizeof(req), true);
if ((chandef->width == NL80211_CHAN_WIDTH_80P80 ||
chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) {
@@ -3487,8 +3503,8 @@ again:
out:
req.center_freq = cpu_to_le16(center_freq);
- ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXDPD_CAL, &req,
- sizeof(req), true);
+ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXDPD_CAL, &req,
+ sizeof(req), true);
if ((chandef->width == NL80211_CHAN_WIDTH_80P80 ||
chandef->width == NL80211_CHAN_WIDTH_160) && !req.is_freq2) {
@@ -3528,17 +3544,16 @@ int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,
};
int err;
- if (vif->type != NL80211_IFTYPE_STATION ||
- !mt7615_firmware_offload(dev))
- return -ENOTSUPP;
+ if (vif->type != NL80211_IFTYPE_STATION)
+ return 0;
- err = __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT,
- &req_hdr, sizeof(req_hdr), false);
+ err = mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_ABORT, &req_hdr,
+ sizeof(req_hdr), false);
if (err < 0 || !enable)
return err;
- return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED,
- &req, sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_BSS_CONNECTED, &req,
+ sizeof(req), false);
}
#ifdef CONFIG_PM
@@ -3569,9 +3584,11 @@ int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend)
req.hdr.hif_type = 2;
else if (mt76_is_usb(&dev->mt76))
req.hdr.hif_type = 1;
+ else if (mt76_is_sdio(&dev->mt76))
+ req.hdr.hif_type = 0;
- return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_HIF_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_HIF_CTRL, &req,
+ sizeof(req), true);
}
EXPORT_SYMBOL_GPL(mt7615_mcu_set_hif_suspend);
@@ -3587,6 +3604,7 @@ mt7615_mcu_set_wow_ctrl(struct mt7615_phy *phy, struct ieee80211_vif *vif,
u8 pad[3];
} __packed hdr;
struct mt7615_wow_ctrl_tlv wow_ctrl_tlv;
+ struct mt7615_wow_gpio_param_tlv gpio_tlv;
} req = {
.hdr = {
.bss_idx = mvif->idx,
@@ -3596,6 +3614,11 @@ mt7615_mcu_set_wow_ctrl(struct mt7615_phy *phy, struct ieee80211_vif *vif,
.len = cpu_to_le16(sizeof(struct mt7615_wow_ctrl_tlv)),
.cmd = suspend ? 1 : 2,
},
+ .gpio_tlv = {
+ .tag = cpu_to_le16(UNI_SUSPEND_WOW_GPIO_PARAM),
+ .len = cpu_to_le16(sizeof(struct mt7615_wow_gpio_param_tlv)),
+ .gpio_pin = 0xff, /* follow fw about GPIO pin */
+ },
};
if (wowlan->magic_pkt)
@@ -3609,12 +3632,14 @@ mt7615_mcu_set_wow_ctrl(struct mt7615_phy *phy, struct ieee80211_vif *vif,
}
if (mt76_is_mmio(&dev->mt76))
- req.wow_ctrl_tlv.wakeup_hif = 2;
+ req.wow_ctrl_tlv.wakeup_hif = WOW_PCIE;
else if (mt76_is_usb(&dev->mt76))
- req.wow_ctrl_tlv.wakeup_hif = 1;
+ req.wow_ctrl_tlv.wakeup_hif = WOW_USB;
+ else if (mt76_is_sdio(&dev->mt76))
+ req.wow_ctrl_tlv.wakeup_hif = WOW_GPIO;
- return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND, &req,
+ sizeof(req), true);
}
static int
@@ -3649,8 +3674,8 @@ mt7615_mcu_set_wow_pattern(struct mt7615_dev *dev,
memcpy(ptlv->pattern, pattern->pattern, pattern->pattern_len);
memcpy(ptlv->mask, pattern->mask, pattern->pattern_len / 8);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_UNI_CMD_SUSPEND, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_SUSPEND,
+ true);
}
static int
@@ -3678,8 +3703,8 @@ mt7615_mcu_set_suspend_mode(struct mt7615_dev *dev,
},
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_SUSPEND, &req,
+ sizeof(req), true);
}
static int
@@ -3705,8 +3730,8 @@ mt7615_mcu_set_gtk_rekey(struct mt7615_dev *dev,
},
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD, &req,
+ sizeof(req), true);
}
static int
@@ -3731,8 +3756,8 @@ mt7615_mcu_set_arp_filter(struct mt7615_dev *dev, struct ieee80211_vif *vif,
},
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_OFFLOAD, &req,
+ sizeof(req), true);
}
void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac,
@@ -3744,8 +3769,6 @@ void mt7615_mcu_set_suspend_iter(void *priv, u8 *mac,
struct cfg80211_wowlan *wowlan = hw->wiphy->wowlan_config;
int i;
- mt7615_mcu_set_bss_pm(phy->dev, vif, suspend);
-
mt7615_mcu_set_gtk_rekey(phy->dev, vif, suspend);
mt7615_mcu_set_arp_filter(phy->dev, vif, suspend);
@@ -3822,8 +3845,8 @@ int mt7615_mcu_update_gtk_rekey(struct ieee80211_hw *hw,
memcpy(gtk_tlv->kck, key->kck, NL80211_KCK_LEN);
memcpy(gtk_tlv->replay_ctr, key->replay_ctr, NL80211_REPLAY_CTR_LEN);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_UNI_CMD_OFFLOAD, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_OFFLOAD,
+ true);
}
#endif /* CONFIG_PM */
@@ -3843,8 +3866,8 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
phy->roc_grant = false;
- return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_ROC, &req,
- sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_ROC, &req,
+ sizeof(req), false);
}
int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw,
@@ -3890,8 +3913,8 @@ int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw,
memcpy(addr, &info->arp_addr_list[i], sizeof(__be32));
}
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_UNI_CMD_OFFLOAD, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_OFFLOAD,
+ true);
}
int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
@@ -3912,8 +3935,8 @@ int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
if (!mt7615_firmware_offload(dev))
return -ENOTSUPP;
- return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_P2P_OPPPS,
- &req, sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_CMD_SET_P2P_OPPPS, &req,
+ sizeof(req), false);
}
u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset)
@@ -3925,8 +3948,8 @@ u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset)
.addr = cpu_to_le32(offset),
};
- return __mt76_mcu_send_msg(dev, MCU_CMD_REG_READ,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(dev, MCU_CMD_REG_READ, &req, sizeof(req),
+ true);
}
EXPORT_SYMBOL_GPL(mt7615_mcu_reg_rr);
@@ -3940,7 +3963,6 @@ void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val)
.val = cpu_to_le32(val),
};
- __mt76_mcu_send_msg(dev, MCU_CMD_REG_WRITE,
- &req, sizeof(req), false);
+ mt76_mcu_send_msg(dev, MCU_CMD_REG_WRITE, &req, sizeof(req), false);
}
EXPORT_SYMBOL_GPL(mt7615_mcu_reg_wr);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
index 7b856e9eee1e..6ef5670211d1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
@@ -275,6 +275,7 @@ enum {
MCU_EXT_CMD_PROTECT_CTRL = 0x3e,
MCU_EXT_CMD_DBDC_CTRL = 0x45,
MCU_EXT_CMD_MAC_INIT_CTRL = 0x46,
+ MCU_EXT_CMD_MUAR_UPDATE = 0x48,
MCU_EXT_CMD_BCN_OFFLOAD = 0x49,
MCU_EXT_CMD_SET_RX_PATH = 0x4e,
MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58,
@@ -477,6 +478,12 @@ struct mt7615_bss_qos_tlv {
u8 pad[3];
} __packed;
+enum {
+ WOW_USB = 1,
+ WOW_PCIE = 2,
+ WOW_GPIO = 3,
+};
+
struct mt7615_wow_ctrl_tlv {
__le16 tag;
__le16 len;
@@ -501,6 +508,16 @@ struct mt7615_wow_ctrl_tlv {
u8 rsv[4];
} __packed;
+struct mt7615_wow_gpio_param_tlv {
+ __le16 tag;
+ __le16 len;
+ u8 gpio_pin;
+ u8 trigger_lvl;
+ u8 pad[2];
+ __le32 gpio_interval;
+ u8 rsv[4];
+} __packed;
+
#define MT7615_WOW_MASK_MAX_LEN 16
#define MT7615_WOW_PATTEN_MAX_LEN 128
struct mt7615_wow_pattern_tlv {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
index 6de492a4cf02..a7f92fa0488f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
@@ -98,9 +98,9 @@ static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
return IRQ_HANDLED;
}
-static void mt7615_irq_tasklet(unsigned long data)
+static void mt7615_irq_tasklet(struct tasklet_struct *t)
{
- struct mt7615_dev *dev = (struct mt7615_dev *)data;
+ struct mt7615_dev *dev = from_tasklet(dev, t, irq_tasklet);
u32 intr, mask = 0, tx_mcu_mask = mt7615_tx_mcu_int_mask(dev);
mt76_wr(dev, MT_INT_MASK_CSR, 0);
@@ -203,7 +203,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
dev = container_of(mdev, struct mt7615_dev, mt76);
mt76_mmio_init(&dev->mt76, mem_base);
- tasklet_init(&dev->irq_tasklet, mt7615_irq_tasklet, (unsigned long)dev);
+ tasklet_setup(&dev->irq_tasklet, mt7615_irq_tasklet);
dev->reg_map = map;
dev->ops = ops;
@@ -240,7 +240,8 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
return 0;
error:
- ieee80211_free_hw(mt76_hw(dev));
+ mt76_free_device(&dev->mt76);
+
return ret;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 6a9f9187f76a..99b8abdbb08f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -11,7 +11,7 @@
#include "../mt76.h"
#include "regs.h"
-#define MT7615_MAX_INTERFACES 4
+#define MT7615_MAX_INTERFACES 16
#define MT7615_MAX_WMM_SETS 4
#define MT7663_WTBL_SIZE 32
#define MT7615_WTBL_SIZE 128
@@ -106,29 +106,11 @@ struct mt7615_rate_desc {
u8 bw;
};
-enum mt7615_wtbl_desc_type {
- MT7615_WTBL_RATE_DESC,
- MT7615_WTBL_KEY_DESC
-};
-
-struct mt7615_key_desc {
- enum set_key_cmd cmd;
- u32 cipher;
- s8 keyidx;
- u8 keylen;
- u8 *key;
-};
-
-struct mt7615_wtbl_desc {
+struct mt7615_wtbl_rate_desc {
struct list_head node;
- enum mt7615_wtbl_desc_type type;
+ struct mt7615_rate_desc rate;
struct mt7615_sta *sta;
-
- union {
- struct mt7615_rate_desc rate;
- struct mt7615_key_desc key;
- };
};
struct mt7615_sta {
@@ -175,8 +157,10 @@ struct mt7615_phy {
struct ieee80211_vif *monitor_vif;
+ u8 n_beacon_vif;
+
u32 rxfilter;
- u32 omac_mask;
+ u64 omac_mask;
u16 noise;
@@ -254,7 +238,7 @@ struct mt7615_dev {
struct tasklet_struct irq_tasklet;
struct mt7615_phy phy;
- u32 omac_mask;
+ u64 omac_mask;
u16 chainmask;
@@ -289,20 +273,22 @@ struct mt7615_dev {
u8 fw_ver;
- struct work_struct wtbl_work;
- struct list_head wd_head;
+ struct work_struct rate_work;
+ struct list_head wrd_head;
u32 debugfs_rf_wf;
u32 debugfs_rf_reg;
+ u32 muar_mask;
+
#ifdef CONFIG_NL80211_TESTMODE
struct {
u32 *reg_backup;
s16 last_freq_offset;
u8 last_rcpi[4];
- s8 last_ib_rssi;
- s8 last_wb_rssi;
+ s8 last_ib_rssi[4];
+ s8 last_wb_rssi[4];
} test;
#endif
@@ -344,24 +330,13 @@ enum {
HW_BSSID_1,
HW_BSSID_2,
HW_BSSID_3,
- HW_BSSID_MAX,
+ HW_BSSID_MAX = HW_BSSID_3,
EXT_BSSID_START = 0x10,
EXT_BSSID_1,
- EXT_BSSID_2,
- EXT_BSSID_3,
- EXT_BSSID_4,
- EXT_BSSID_5,
- EXT_BSSID_6,
- EXT_BSSID_7,
- EXT_BSSID_8,
- EXT_BSSID_9,
- EXT_BSSID_10,
- EXT_BSSID_11,
- EXT_BSSID_12,
- EXT_BSSID_13,
- EXT_BSSID_14,
- EXT_BSSID_15,
- EXT_BSSID_END
+ EXT_BSSID_15 = 0x1f,
+ EXT_BSSID_MAX = EXT_BSSID_15,
+ REPEATER_BSSID_START = 0x20,
+ REPEATER_BSSID_MAX = 0x3f,
};
enum {
@@ -452,7 +427,6 @@ bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev);
void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
struct ieee80211_tx_rate *probe_rate,
struct ieee80211_tx_rate *rates);
-int mt7615_pm_set_enable(struct mt7615_dev *dev, bool enable);
void mt7615_pm_wake_work(struct work_struct *work);
int mt7615_pm_wake(struct mt7615_dev *dev);
void mt7615_pm_power_save_sched(struct mt7615_dev *dev);
@@ -542,7 +516,7 @@ static inline u8 mt7615_lmac_mapping(struct mt7615_dev *dev, u8 ac)
static inline u32 mt7615_tx_mcu_int_mask(struct mt7615_dev *dev)
{
- return MT_INT_TX_DONE(dev->mt76.q_tx[MT_TXQ_MCU]->hw_idx);
+ return MT_INT_TX_DONE(dev->mt76.q_mcu[MT_MCUQ_WM]->hw_idx);
}
void mt7615_dma_reset(struct mt7615_dev *dev);
@@ -568,28 +542,18 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
struct ieee80211_sta *sta, int pid,
struct ieee80211_key_conf *key, bool beacon);
void mt7615_mac_set_timing(struct mt7615_phy *phy);
+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_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd);
-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);
-void mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev,
- struct mt76_wcid *wcid,
- enum mt7615_cipher_type cipher,
- enum set_key_cmd cmd);
-int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev,
- struct mt76_wcid *wcid,
- u8 *key, u8 keylen,
- enum mt7615_cipher_type cipher,
- enum set_key_cmd cmd);
void mt7615_mac_reset_work(struct work_struct *work);
u32 mt7615_mac_get_sta_tid_sn(struct mt7615_dev *dev, int wcid, u8 tid);
-int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq);
-int mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
- int len, bool wait_resp);
+int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ struct sk_buff *skb, int seq);
u32 mt7615_rf_rr(struct mt7615_dev *dev, u32 wf, u32 reg);
int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val);
int mt7615_mcu_set_dbdc(struct mt7615_dev *dev);
@@ -651,6 +615,9 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
int mt7615_init_debugfs(struct mt7615_dev *dev);
int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq);
+int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy,
+ struct ieee80211_vif *vif,
+ bool enable);
int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,
bool enable);
int mt7615_mcu_set_hif_suspend(struct mt7615_dev *dev, bool suspend);
@@ -674,14 +641,13 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update);
void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
struct mt76_queue_entry *e);
-void mt7663_usb_sdio_wtbl_work(struct work_struct *work);
int mt7663_usb_sdio_register_device(struct mt7615_dev *dev);
int mt7663u_mcu_init(struct mt7615_dev *dev);
/* sdio */
u32 mt7663s_read_pcr(struct mt7615_dev *dev);
int mt7663s_mcu_init(struct mt7615_dev *dev);
-void mt7663s_tx_work(struct work_struct *work);
+void mt7663s_txrx_worker(struct mt76_worker *w);
void mt7663s_rx_work(struct work_struct *work);
void mt7663s_sdio_irq(struct sdio_func *func);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
index 06a0f8f7bc89..27fcb1374685 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
@@ -16,8 +16,15 @@ static void mt7615_init_work(struct work_struct *work)
{
struct mt7615_dev *dev = container_of(work, struct mt7615_dev,
mcu_work);
+ int i, ret;
- if (mt7615_mcu_init(dev))
+ ret = mt7615_mcu_init(dev);
+ for (i = 0; (ret == -EAGAIN) && (i < 10); i++) {
+ msleep(200);
+ ret = mt7615_mcu_init(dev);
+ }
+
+ if (ret)
return;
mt7615_mcu_set_eeprom(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
index 61623f480806..6e5db015b32c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
@@ -333,6 +333,9 @@ enum mt7615_reg_base {
#define MT_WF_RFCR_DROP_NDPA BIT(20)
#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21)
+#define MT_WF_RMAC_MORE(_band) MT_WF_RMAC((_band) ? 0x124 : 0x024)
+#define MT_WF_RMAC_MORE_MUAR_MODE GENMASK(31, 30)
+
#define MT_WF_RFCR1(_band) MT_WF_RMAC((_band) ? 0x104 : 0x004)
#define MT_WF_RFCR1_DROP_ACK BIT(4)
#define MT_WF_RFCR1_DROP_BF_POLL BIT(5)
@@ -342,6 +345,14 @@ enum mt7615_reg_base {
#define MT_CHFREQ(_band) MT_WF_RMAC((_band) ? 0x130 : 0x030)
+#define MT_WF_RMAC_MAR0 MT_WF_RMAC(0x025c)
+#define MT_WF_RMAC_MAR1 MT_WF_RMAC(0x0260)
+#define MT_WF_RMAC_MAR1_ADDR GENMASK(15, 0)
+#define MT_WF_RMAC_MAR1_START BIT(16)
+#define MT_WF_RMAC_MAR1_WRITE BIT(17)
+#define MT_WF_RMAC_MAR1_IDX GENMASK(29, 24)
+#define MT_WF_RMAC_MAR1_GROUP GENMASK(31, 30)
+
#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)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
index 874c929d8552..347975eaba86 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
@@ -294,30 +294,6 @@ release:
return ret;
}
-static int mt7663s_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
- struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
- struct mt76_sdio *sdio = &mdev->sdio;
- u32 pse, ple;
- int err;
-
- err = mt7615_mac_sta_add(mdev, vif, sta);
- if (err < 0)
- return err;
-
- /* init sched data quota */
- pse = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA);
- ple = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA);
-
- mutex_lock(&sdio->sched.lock);
- sdio->sched.pse_data_quota = pse;
- sdio->sched.ple_data_quota = ple;
- mutex_unlock(&sdio->sched.lock);
-
- return 0;
-}
-
static int mt7663s_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
@@ -329,7 +305,7 @@ static int mt7663s_probe(struct sdio_func *func,
.tx_status_data = mt7663_usb_sdio_tx_status_data,
.rx_skb = mt7615_queue_rx_skb,
.sta_ps = mt7615_sta_ps,
- .sta_add = mt7663s_sta_add,
+ .sta_add = mt7615_mac_sta_add,
.sta_remove = mt7615_mac_sta_remove,
.update_survey = mt7615_update_channel,
};
@@ -366,14 +342,11 @@ static int mt7663s_probe(struct sdio_func *func,
ret = mt76s_init(mdev, func, &mt7663s_ops);
if (ret < 0)
- goto err_free;
-
- INIT_WORK(&mdev->sdio.tx.xmit_work, mt7663s_tx_work);
- INIT_WORK(&mdev->sdio.rx.recv_work, mt7663s_rx_work);
+ goto error;
ret = mt7663s_hw_init(dev, func);
if (ret)
- goto err_deinit;
+ goto error;
mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
(mt76_rr(dev, MT_HW_REV) & 0xff);
@@ -384,7 +357,7 @@ static int mt7663s_probe(struct sdio_func *func,
GFP_KERNEL);
if (!mdev->sdio.intr_data) {
ret = -ENOMEM;
- goto err_deinit;
+ goto error;
}
for (i = 0; i < ARRAY_SIZE(mdev->sdio.xmit_buf); i++) {
@@ -393,23 +366,29 @@ static int mt7663s_probe(struct sdio_func *func,
GFP_KERNEL);
if (!mdev->sdio.xmit_buf[i]) {
ret = -ENOMEM;
- goto err_deinit;
+ goto error;
}
}
ret = mt76s_alloc_queues(&dev->mt76);
if (ret)
- goto err_deinit;
+ goto error;
+
+ ret = mt76_worker_setup(mt76_hw(dev), &mdev->sdio.txrx_worker,
+ mt7663s_txrx_worker, "sdio-txrx");
+ if (ret)
+ goto error;
+
+ sched_set_fifo_low(mdev->sdio.txrx_worker.task);
ret = mt7663_usb_sdio_register_device(dev);
if (ret)
- goto err_deinit;
+ goto error;
return 0;
-err_deinit:
+error:
mt76s_deinit(&dev->mt76);
-err_free:
mt76_free_device(&dev->mt76);
return ret;
@@ -432,6 +411,7 @@ static int mt7663s_suspend(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct mt7615_dev *mdev = sdio_get_drvdata(func);
+ int err;
if (!test_bit(MT76_STATE_SUSPEND, &mdev->mphy.state) &&
mt7615_firmware_offload(mdev)) {
@@ -444,9 +424,20 @@ static int mt7663s_suspend(struct device *dev)
sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
- mt76s_stop_txrx(&mdev->mt76);
+ err = mt7615_mcu_set_fw_ctrl(mdev);
+ if (err)
+ return err;
- return mt7615_mcu_set_fw_ctrl(mdev);
+ mt76_worker_disable(&mdev->mt76.sdio.txrx_worker);
+ mt76_worker_disable(&mdev->mt76.sdio.status_worker);
+ mt76_worker_disable(&mdev->mt76.sdio.net_worker);
+
+ cancel_work_sync(&mdev->mt76.sdio.stat_work);
+ clear_bit(MT76_READING_STATS, &mdev->mphy.state);
+
+ mt76_tx_status_check(&mdev->mt76, NULL, true);
+
+ return 0;
}
static int mt7663s_resume(struct device *dev)
@@ -455,6 +446,10 @@ static int mt7663s_resume(struct device *dev)
struct mt7615_dev *mdev = sdio_get_drvdata(func);
int err;
+ mt76_worker_enable(&mdev->mt76.sdio.txrx_worker);
+ mt76_worker_enable(&mdev->mt76.sdio.status_worker);
+ mt76_worker_enable(&mdev->mt76.sdio.net_worker);
+
err = mt7615_mcu_set_drv_ctrl(mdev);
if (err)
return err;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
index 38670c00380c..17fe4187d1de 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
@@ -19,46 +19,34 @@
static int mt7663s_mcu_init_sched(struct mt7615_dev *dev)
{
struct mt76_sdio *sdio = &dev->mt76.sdio;
- u32 pse0, ple, pse1, txdwcnt;
-
- pse0 = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA);
- pse1 = mt76_get_field(dev, MT_PSE_PG_HIF1_GROUP, MT_HIF1_MIN_QUOTA);
- ple = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP, MT_HIF0_MIN_QUOTA);
+ u32 txdwcnt;
+
+ sdio->sched.pse_data_quota = mt76_get_field(dev, MT_PSE_PG_HIF0_GROUP,
+ MT_HIF0_MIN_QUOTA);
+ sdio->sched.pse_mcu_quota = mt76_get_field(dev, MT_PSE_PG_HIF1_GROUP,
+ MT_HIF1_MIN_QUOTA);
+ sdio->sched.ple_data_quota = mt76_get_field(dev, MT_PLE_PG_HIF0_GROUP,
+ MT_HIF0_MIN_QUOTA);
txdwcnt = mt76_get_field(dev, MT_PP_TXDWCNT,
MT_PP_TXDWCNT_TX1_ADD_DW_CNT);
-
- mutex_lock(&sdio->sched.lock);
-
- sdio->sched.pse_data_quota = pse0;
- sdio->sched.ple_data_quota = ple;
- sdio->sched.pse_mcu_quota = pse1;
sdio->sched.deficit = txdwcnt << 2;
- mutex_unlock(&sdio->sched.lock);
-
return 0;
}
static int
mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
- int cmd, bool wait_resp)
+ int cmd, int *seq)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
- int ret, seq;
-
- mutex_lock(&mdev->mcu.mutex);
+ int ret;
- mt7615_mcu_fill_msg(dev, skb, cmd, &seq);
- ret = mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, 0);
+ mt7615_mcu_fill_msg(dev, skb, cmd, seq);
+ ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, 0);
if (ret)
- goto out;
-
- mt76_queue_kick(dev, mdev->q_tx[MT_TXQ_MCU]);
- if (wait_resp)
- ret = mt7615_mcu_wait_response(dev, cmd, seq);
+ return ret;
-out:
- mutex_unlock(&mdev->mcu.mutex);
+ mt76_queue_kick(dev, mdev->q_mcu[MT_MCUQ_WM]);
return ret;
}
@@ -127,7 +115,7 @@ int mt7663s_mcu_init(struct mt7615_dev *dev)
.headroom = sizeof(struct mt7615_mcu_txd),
.tailroom = MT_USB_TAIL_SIZE,
.mcu_skb_send_msg = mt7663s_mcu_send_message,
- .mcu_send_msg = mt7615_mcu_msg_send,
+ .mcu_parse_response = mt7615_mcu_parse_response,
.mcu_restart = mt7615_mcu_restart,
.mcu_rr = mt7615_mcu_reg_rr,
.mcu_wr = mt7615_mcu_reg_wr,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
index 2486cda3243b..13d77f8fca86 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
@@ -46,11 +46,9 @@ static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota)
return 0;
- mutex_lock(&sdio->sched.lock);
sdio->sched.pse_mcu_quota += pse_mcu_quota;
sdio->sched.pse_data_quota += pse_data_quota;
sdio->sched.ple_data_quota += ple_data_quota;
- mutex_unlock(&sdio->sched.lock);
return pse_data_quota + ple_data_quota + pse_mcu_quota;
}
@@ -105,10 +103,7 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
buf = page_address(page);
- sdio_claim_host(sdio->func);
err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len);
- sdio_release_host(sdio->func);
-
if (err < 0) {
dev_err(dev->dev, "sdio read data failed:%d\n", err);
__free_pages(page, order);
@@ -138,19 +133,52 @@ static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
return i;
}
-static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
- int buf_sz, int *pse_size, int *ple_size)
+static int mt7663s_rx_handler(struct mt76_dev *dev)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+ struct mt76s_intr *intr = sdio->intr_data;
+ int nframes = 0, ret;
+
+ ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
+ if (ret < 0)
+ return ret;
+
+ trace_dev_irq(dev, intr->isr, 0);
+
+ if (intr->isr & WHIER_RX0_DONE_INT_EN) {
+ ret = mt7663s_rx_run_queue(dev, 0, intr);
+ if (ret > 0) {
+ mt76_worker_schedule(&sdio->net_worker);
+ nframes += ret;
+ }
+ }
+
+ if (intr->isr & WHIER_RX1_DONE_INT_EN) {
+ ret = mt7663s_rx_run_queue(dev, 1, intr);
+ if (ret > 0) {
+ mt76_worker_schedule(&sdio->net_worker);
+ nframes += ret;
+ }
+ }
+
+ nframes += !!mt7663s_refill_sched_quota(dev, intr->tx.wtqcr);
+
+ return nframes;
+}
+
+static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, bool mcu, int buf_sz,
+ int *pse_size, int *ple_size)
{
int pse_sz;
pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
- if (qid == MT_TXQ_MCU) {
+ if (mcu) {
if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz)
return -EBUSY;
} else {
if (sdio->sched.pse_data_quota < *pse_size + pse_sz ||
- sdio->sched.ple_data_quota < *ple_size)
+ sdio->sched.ple_data_quota < *ple_size + 1)
return -EBUSY;
*ple_size = *ple_size + 1;
@@ -160,17 +188,15 @@ static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
return 0;
}
-static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
+static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, bool mcu,
int pse_size, int ple_size)
{
- mutex_lock(&sdio->sched.lock);
- if (qid == MT_TXQ_MCU) {
+ if (mcu) {
sdio->sched.pse_mcu_quota -= pse_size;
} else {
sdio->sched.pse_data_quota -= pse_size;
sdio->sched.ple_data_quota -= ple_size;
}
- mutex_unlock(&sdio->sched.lock);
}
static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
@@ -181,22 +207,20 @@ static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
if (len > sdio->func->cur_blksize)
len = roundup(len, sdio->func->cur_blksize);
- sdio_claim_host(sdio->func);
err = sdio_writesb(sdio->func, MCR_WTDR1, data, len);
- sdio_release_host(sdio->func);
-
if (err)
dev_err(dev->dev, "sdio write failed: %d\n", err);
return err;
}
-static int mt7663s_tx_run_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
+static int mt7663s_tx_run_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
- int err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0;
- struct mt76_queue *q = dev->q_tx[qid];
+ int qid, err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0;
+ bool mcu = q == dev->q_mcu[MT_MCUQ_WM];
struct mt76_sdio *sdio = &dev->sdio;
+ qid = mcu ? ARRAY_SIZE(sdio->xmit_buf) - 1 : q->qid;
while (q->first != q->head) {
struct mt76_queue_entry *e = &q->entry[q->first];
struct sk_buff *iter;
@@ -214,7 +238,7 @@ static int mt7663s_tx_run_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
if (len + e->skb->len + 4 > MT76S_XMIT_BUF_SZ)
break;
- if (mt7663s_tx_pick_quota(sdio, qid, e->buf_sz, &pse_sz,
+ if (mt7663s_tx_pick_quota(sdio, mcu, e->buf_sz, &pse_sz,
&ple_sz))
break;
@@ -240,78 +264,44 @@ next:
if (err)
return err;
}
- mt7663s_tx_update_quota(sdio, qid, pse_sz, ple_sz);
+ mt7663s_tx_update_quota(sdio, mcu, pse_sz, ple_sz);
- return nframes;
-}
-
-void mt7663s_tx_work(struct work_struct *work)
-{
- struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
- tx.xmit_work);
- struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
- int i, nframes = 0;
+ mt76_worker_schedule(&sdio->status_worker);
- for (i = 0; i < MT_TXQ_MCU_WA; i++) {
- int ret;
-
- ret = mt7663s_tx_run_queue(dev, i);
- if (ret < 0)
- break;
-
- nframes += ret;
- }
- if (nframes)
- queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
-
- queue_work(sdio->txrx_wq, &sdio->tx.status_work);
+ return nframes;
}
-void mt7663s_rx_work(struct work_struct *work)
+void mt7663s_txrx_worker(struct mt76_worker *w)
{
- struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
- rx.recv_work);
+ struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
+ txrx_worker);
struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
- struct mt76s_intr *intr = sdio->intr_data;
- int nframes = 0, ret;
+ int i, nframes, ret;
/* disable interrupt */
sdio_claim_host(sdio->func);
sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
- ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
- sdio_release_host(sdio->func);
-
- if (ret < 0)
- goto out;
- trace_dev_irq(dev, intr->isr, 0);
+ do {
+ nframes = 0;
- if (intr->isr & WHIER_RX0_DONE_INT_EN) {
- ret = mt7663s_rx_run_queue(dev, 0, intr);
- if (ret > 0) {
- queue_work(sdio->txrx_wq, &sdio->rx.net_work);
- nframes += ret;
+ /* tx */
+ for (i = 0; i <= MT_TXQ_PSD; i++) {
+ ret = mt7663s_tx_run_queue(dev, dev->phy.q_tx[i]);
+ if (ret > 0)
+ nframes += ret;
}
- }
-
- if (intr->isr & WHIER_RX1_DONE_INT_EN) {
- ret = mt7663s_rx_run_queue(dev, 1, intr);
- if (ret > 0) {
- queue_work(sdio->txrx_wq, &sdio->rx.net_work);
+ ret = mt7663s_tx_run_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
+ if (ret > 0)
nframes += ret;
- }
- }
- if (mt7663s_refill_sched_quota(dev, intr->tx.wtqcr))
- queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
+ /* rx */
+ ret = mt7663s_rx_handler(dev);
+ if (ret > 0)
+ nframes += ret;
+ } while (nframes > 0);
- if (nframes) {
- queue_work(sdio->txrx_wq, &sdio->rx.recv_work);
- return;
- }
-out:
/* enable interrupt */
- sdio_claim_host(sdio->func);
sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
sdio_release_host(sdio->func);
}
@@ -324,5 +314,5 @@ void mt7663s_sdio_irq(struct sdio_func *func)
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
return;
- queue_work(sdio->txrx_wq, &sdio->rx.recv_work);
+ mt76_worker_schedule(&sdio->txrx_worker);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c
index e4dc62314bae..8fc97a52411a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c
@@ -90,8 +90,8 @@ mt7615_tm_set_tx_power(struct mt7615_phy *phy)
data[ret - MT_EE_NIC_CONF_0] = tx_power[i];
}
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_SET_TX_POWER_CTRL, false);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_SET_TX_POWER_CTRL, false);
}
static void
@@ -335,9 +335,7 @@ mt7615_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg)
if (!rx)
return -ENOMEM;
- if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, dev->test.last_freq_offset) ||
- nla_put_s32(msg, MT76_TM_RX_ATTR_IB_RSSI, dev->test.last_ib_rssi) ||
- nla_put_s32(msg, MT76_TM_RX_ATTR_WB_RSSI, dev->test.last_wb_rssi))
+ if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, dev->test.last_freq_offset))
return -ENOMEM;
rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI);
@@ -350,6 +348,26 @@ mt7615_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg)
nla_nest_end(msg, rssi);
+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_IB_RSSI);
+ if (!rssi)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(dev->test.last_ib_rssi); i++)
+ if (nla_put_s8(msg, i, dev->test.last_ib_rssi[i]))
+ return -ENOMEM;
+
+ nla_nest_end(msg, rssi);
+
+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_WB_RSSI);
+ if (!rssi)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(dev->test.last_wb_rssi); i++)
+ if (nla_put_s8(msg, i, dev->test.last_wb_rssi[i]))
+ return -ENOMEM;
+
+ nla_nest_end(msg, rssi);
+
nla_nest_end(msg, rx);
return 0;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
index f0ad83af9e00..a60cfa345521 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
@@ -126,21 +126,20 @@ static int mt7663u_probe(struct usb_interface *usb_intf,
alloc_queues:
ret = mt76u_alloc_mcu_queue(&dev->mt76);
if (ret)
- goto error_free_q;
+ goto error;
ret = mt76u_alloc_queues(&dev->mt76);
if (ret)
- goto error_free_q;
+ goto error;
ret = mt7663_usb_sdio_register_device(dev);
if (ret)
- goto error_free_q;
+ goto error;
return 0;
-error_free_q:
- mt76u_queues_deinit(&dev->mt76);
error:
+ mt76u_queues_deinit(&dev->mt76);
usb_set_intfdata(usb_intf, NULL);
usb_put_dev(interface_to_usbdev(usb_intf));
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c
index 4d8be366af31..c55698f9c49a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c
@@ -15,14 +15,12 @@
static int
mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
- int cmd, bool wait_resp)
+ int cmd, int *seq)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
- int ret, seq, ep, len, pad;
+ int ret, ep, len, pad;
- mutex_lock(&mdev->mcu.mutex);
-
- mt7615_mcu_fill_msg(dev, skb, cmd, &seq);
+ mt7615_mcu_fill_msg(dev, skb, cmd, seq);
if (cmd != MCU_CMD_FW_SCATTER)
ep = MT_EP_OUT_INBAND_CMD;
else
@@ -37,14 +35,8 @@ mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
ret = mt76u_bulk_msg(&dev->mt76, skb->data, skb->len, NULL,
1000, ep);
- if (ret < 0)
- goto out;
-
- if (wait_resp)
- ret = mt7615_mcu_wait_response(dev, cmd, seq);
out:
- mutex_unlock(&mdev->mcu.mutex);
dev_kfree_skb(skb);
return ret;
@@ -56,7 +48,7 @@ int mt7663u_mcu_init(struct mt7615_dev *dev)
.headroom = MT_USB_HDR_SIZE + sizeof(struct mt7615_mcu_txd),
.tailroom = MT_USB_TAIL_SIZE,
.mcu_skb_send_msg = mt7663u_mcu_send_message,
- .mcu_send_msg = mt7615_mcu_msg_send,
+ .mcu_parse_response = mt7615_mcu_parse_response,
.mcu_restart = mt7615_mcu_restart,
};
int ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
index 3b29a6d3dc64..203256862dfd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
@@ -61,12 +61,11 @@ mt7663_usb_sdio_write_txwi(struct mt7615_dev *dev, struct mt76_wcid *wcid,
skb_push(skb, MT_USB_TXD_SIZE);
}
-static int
-mt7663_usb_sdio_set_rates(struct mt7615_dev *dev,
- struct mt7615_wtbl_desc *wd)
+static int mt7663_usb_sdio_set_rates(struct mt7615_dev *dev,
+ struct mt7615_wtbl_rate_desc *wrd)
{
- struct mt7615_rate_desc *rate = &wd->rate;
- struct mt7615_sta *sta = wd->sta;
+ struct mt7615_rate_desc *rate = &wrd->rate;
+ struct mt7615_sta *sta = wrd->sta;
u32 w5, w27, addr, val;
lockdep_assert_held(&dev->mt76.mutex);
@@ -132,86 +131,30 @@ mt7663_usb_sdio_set_rates(struct mt7615_dev *dev,
return 0;
}
-static int
-mt7663_usb_sdio_set_key(struct mt7615_dev *dev,
- struct mt7615_wtbl_desc *wd)
+static void mt7663_usb_sdio_rate_work(struct work_struct *work)
{
- struct mt7615_key_desc *key = &wd->key;
- struct mt7615_sta *sta = wd->sta;
- enum mt7615_cipher_type cipher;
- struct mt76_wcid *wcid;
- int err;
-
- lockdep_assert_held(&dev->mt76.mutex);
-
- if (!sta) {
- err = -EINVAL;
- goto out;
- }
-
- cipher = mt7615_mac_get_cipher(key->cipher);
- if (cipher == MT_CIPHER_NONE) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- wcid = &wd->sta->wcid;
-
- mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, key->cmd);
- err = mt7615_mac_wtbl_update_key(dev, wcid, key->key, key->keylen,
- cipher, key->cmd);
- if (err < 0)
- goto out;
-
- err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx,
- key->cmd);
- if (err < 0)
- goto out;
-
- if (key->cmd == SET_KEY)
- wcid->cipher |= BIT(cipher);
- else
- wcid->cipher &= ~BIT(cipher);
-out:
- kfree(key->key);
-
- return err;
-}
-
-void mt7663_usb_sdio_wtbl_work(struct work_struct *work)
-{
- struct mt7615_wtbl_desc *wd, *wd_next;
- struct list_head wd_list;
+ struct mt7615_wtbl_rate_desc *wrd, *wrd_next;
+ struct list_head wrd_list;
struct mt7615_dev *dev;
dev = (struct mt7615_dev *)container_of(work, struct mt7615_dev,
- wtbl_work);
+ rate_work);
- INIT_LIST_HEAD(&wd_list);
+ INIT_LIST_HEAD(&wrd_list);
spin_lock_bh(&dev->mt76.lock);
- list_splice_init(&dev->wd_head, &wd_list);
+ list_splice_init(&dev->wrd_head, &wrd_list);
spin_unlock_bh(&dev->mt76.lock);
- list_for_each_entry_safe(wd, wd_next, &wd_list, node) {
- list_del(&wd->node);
+ list_for_each_entry_safe(wrd, wrd_next, &wrd_list, node) {
+ list_del(&wrd->node);
mt7615_mutex_acquire(dev);
-
- switch (wd->type) {
- case MT7615_WTBL_RATE_DESC:
- mt7663_usb_sdio_set_rates(dev, wd);
- break;
- case MT7615_WTBL_KEY_DESC:
- mt7663_usb_sdio_set_key(dev, wd);
- break;
- }
-
+ mt7663_usb_sdio_set_rates(dev, wrd);
mt7615_mutex_release(dev);
- kfree(wd);
+ kfree(wrd);
}
}
-EXPORT_SYMBOL_GPL(mt7663_usb_sdio_wtbl_work);
bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update)
{
@@ -357,8 +300,8 @@ int mt7663_usb_sdio_register_device(struct mt7615_dev *dev)
struct ieee80211_hw *hw = mt76_hw(dev);
int err;
- INIT_WORK(&dev->wtbl_work, mt7663_usb_sdio_wtbl_work);
- INIT_LIST_HEAD(&dev->wd_head);
+ INIT_WORK(&dev->rate_work, mt7663_usb_sdio_rate_work);
+ INIT_LIST_HEAD(&dev->wrd_head);
mt7615_init_device(dev);
err = mt7663_usb_sdio_init_hardware(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
index 9087607b621e..dd66fd12a2e6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c
@@ -52,15 +52,15 @@ static void mt76x0_set_chip_cap(struct mt76x02_dev *dev)
mt76x02_eeprom_parse_hw_cap(dev);
dev_dbg(dev->mt76.dev, "2GHz %d 5GHz %d\n",
- dev->mt76.cap.has_2ghz, dev->mt76.cap.has_5ghz);
+ dev->mphy.cap.has_2ghz, dev->mphy.cap.has_5ghz);
if (dev->no_2ghz) {
- dev->mt76.cap.has_2ghz = false;
+ dev->mphy.cap.has_2ghz = false;
dev_dbg(dev->mt76.dev, "mask out 2GHz support\n");
}
if (is_mt7630(dev)) {
- dev->mt76.cap.has_5ghz = false;
+ dev->mphy.cap.has_5ghz = false;
dev_dbg(dev->mt76.dev, "mask out 5GHz support\n");
}
@@ -342,10 +342,10 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev)
dev_info(dev->mt76.dev, "EEPROM ver:%02hhx fae:%02hhx\n",
version, fae);
- memcpy(dev->mt76.macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
+ memcpy(dev->mphy.macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
ETH_ALEN);
- mt76_eeprom_override(&dev->mt76);
- mt76x02_mac_setaddr(dev, dev->mt76.macaddr);
+ mt76_eeprom_override(&dev->mphy);
+ mt76x02_mac_setaddr(dev, dev->mphy.macaddr);
mt76x0_set_chip_cap(dev);
mt76x0_set_freq_offset(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
index d78866bf41ba..0bac39bf3b66 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
@@ -245,7 +245,7 @@ int mt76x0_register_device(struct mt76x02_dev *dev)
if (ret)
return ret;
- if (dev->mt76.cap.has_5ghz) {
+ if (dev->mphy.cap.has_5ghz) {
struct ieee80211_supported_band *sband;
sband = &dev->mphy.sband_5g.sband;
@@ -253,7 +253,7 @@ int mt76x0_register_device(struct mt76x02_dev *dev)
mt76x0_init_txpower(dev, sband);
}
- if (dev->mt76.cap.has_2ghz)
+ if (dev->mphy.cap.has_2ghz)
mt76x0_init_txpower(dev, &dev->mphy.sband_2g.sband);
mt76x02_init_debugfs(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
index dda11c704aba..b87d8e136cb9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
@@ -194,7 +194,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
error:
- ieee80211_free_hw(mt76_hw(dev));
+ mt76_free_device(&dev->mt76);
+
return ret;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c
index 007c762c6db1..f0962507f72f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci_mcu.c
@@ -117,6 +117,7 @@ int mt76x0e_mcu_init(struct mt76x02_dev *dev)
{
static const struct mt76_mcu_ops mt76x0e_mcu_ops = {
.mcu_send_msg = mt76x02_mcu_msg_send,
+ .mcu_parse_response = mt76x02_mcu_parse_response,
};
int err;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
index 3de33aadf794..e91c314cdfac 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
@@ -447,11 +447,11 @@ static void mt76x0_phy_ant_select(struct mt76x02_dev *dev)
else
coex3 |= BIT(4);
coex3 |= BIT(3);
- if (dev->mt76.cap.has_2ghz)
+ if (dev->mphy.cap.has_2ghz)
wlan |= BIT(6);
} else {
/* sigle antenna mode */
- if (dev->mt76.cap.has_5ghz) {
+ if (dev->mphy.cap.has_5ghz) {
coex3 |= BIT(3) | BIT(4);
} else {
wlan |= BIT(6);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
index ce6b286a8152..b12cb17cb43d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
@@ -277,6 +277,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_queues_deinit(&dev->mt76);
mt76_free_device(&dev->mt76);
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
index b29cd39dc176..a601350531cd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
@@ -609,10 +609,11 @@ static void mt76x02_dfs_check_event_window(struct mt76x02_dev *dev)
}
}
-static void mt76x02_dfs_tasklet(unsigned long arg)
+static void mt76x02_dfs_tasklet(struct tasklet_struct *t)
{
- struct mt76x02_dev *dev = (struct mt76x02_dev *)arg;
- struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
+ struct mt76x02_dfs_pattern_detector *dfs_pd = from_tasklet(dfs_pd, t,
+ dfs_tasklet);
+ struct mt76x02_dev *dev = container_of(dfs_pd, typeof(*dev), dfs_pd);
u32 engine_mask;
int i;
@@ -860,8 +861,7 @@ void mt76x02_dfs_init_detector(struct mt76x02_dev *dev)
INIT_LIST_HEAD(&dfs_pd->seq_pool);
dev->mt76.region = NL80211_DFS_UNSET;
dfs_pd->last_sw_check = jiffies;
- tasklet_init(&dfs_pd->dfs_tasklet, mt76x02_dfs_tasklet,
- (unsigned long)dev);
+ tasklet_setup(&dfs_pd->dfs_tasklet, mt76x02_dfs_tasklet);
}
static void
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c
index c54c50fd639a..0acabba2d1a5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_eeprom.c
@@ -75,14 +75,14 @@ void mt76x02_eeprom_parse_hw_cap(struct mt76x02_dev *dev)
switch (FIELD_GET(MT_EE_NIC_CONF_0_BOARD_TYPE, val)) {
case BOARD_TYPE_5GHZ:
- dev->mt76.cap.has_5ghz = true;
+ dev->mphy.cap.has_5ghz = true;
break;
case BOARD_TYPE_2GHZ:
- dev->mt76.cap.has_2ghz = true;
+ dev->mphy.cap.has_2ghz = true;
break;
default:
- dev->mt76.cap.has_2ghz = true;
- dev->mt76.cap.has_5ghz = true;
+ dev->mphy.cap.has_2ghz = true;
+ dev->mphy.cap.has_5ghz = true;
break;
}
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index da6d3f51f6d4..16b40a73fd1f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -727,24 +727,24 @@ void mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr)
static const u8 null_addr[ETH_ALEN] = {};
int i;
- ether_addr_copy(dev->mt76.macaddr, addr);
+ ether_addr_copy(dev->mphy.macaddr, addr);
- if (!is_valid_ether_addr(dev->mt76.macaddr)) {
- eth_random_addr(dev->mt76.macaddr);
+ if (!is_valid_ether_addr(dev->mphy.macaddr)) {
+ eth_random_addr(dev->mphy.macaddr);
dev_info(dev->mt76.dev,
"Invalid MAC address, using random address %pM\n",
- dev->mt76.macaddr);
+ dev->mphy.macaddr);
}
- mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mt76.macaddr));
+ mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mphy.macaddr));
mt76_wr(dev, MT_MAC_ADDR_DW1,
- get_unaligned_le16(dev->mt76.macaddr + 4) |
+ get_unaligned_le16(dev->mphy.macaddr + 4) |
FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff));
mt76_wr(dev, MT_MAC_BSSID_DW0,
- get_unaligned_le32(dev->mt76.macaddr));
+ get_unaligned_le32(dev->mphy.macaddr));
mt76_wr(dev, MT_MAC_BSSID_DW1,
- get_unaligned_le16(dev->mt76.macaddr + 4) |
+ get_unaligned_le16(dev->mphy.macaddr + 4) |
FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 APs + 8 STAs */
MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT);
/* enable 7 additional beacon slots and control them with bypass mask */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c
index 267058086a90..4aa5c36afeaf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c
@@ -10,6 +10,28 @@
#include "mt76x02_mcu.h"
+int mt76x02_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ struct sk_buff *skb, int seq)
+{
+ struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
+ u32 *rxfce;
+
+ if (!skb) {
+ dev_err(mdev->dev,
+ "MCU message %d (seq %d) timed out\n", cmd,
+ seq);
+ dev->mcu_timeout = 1;
+ return -ETIMEDOUT;
+ }
+
+ rxfce = (u32 *)skb->cb;
+ if (seq != FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce))
+ return -EAGAIN;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt76x02_mcu_parse_response);
+
int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
int len, bool wait_resp)
{
@@ -39,31 +61,15 @@ int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
FIELD_PREP(MT_MCU_MSG_PORT, CPU_TX_PORT) |
FIELD_PREP(MT_MCU_MSG_LEN, skb->len);
- ret = mt76_tx_queue_skb_raw(dev, MT_TXQ_MCU, skb, tx_info);
+ ret = mt76_tx_queue_skb_raw(dev, mdev->q_mcu[MT_MCUQ_WM], skb, tx_info);
if (ret)
goto out;
while (wait_resp) {
- u32 *rxfce;
- bool check_seq = false;
-
skb = mt76_mcu_get_response(&dev->mt76, expires);
- if (!skb) {
- dev_err(mdev->dev,
- "MCU message %d (seq %d) timed out\n", cmd,
- seq);
- ret = -ETIMEDOUT;
- dev->mcu_timeout = 1;
- break;
- }
-
- rxfce = (u32 *)skb->cb;
-
- if (seq == FIELD_GET(MT_RX_FCE_INFO_CMD_SEQ, *rxfce))
- check_seq = true;
-
+ ret = mt76x02_mcu_parse_response(mdev, cmd, skb, seq);
dev_kfree_skb(skb);
- if (check_seq)
+ if (ret != -EAGAIN)
break;
}
@@ -89,7 +95,8 @@ int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func,
if (func != Q_SELECT)
wait = true;
- return mt76_mcu_send_msg(dev, CMD_FUN_SET_OP, &msg, sizeof(msg), wait);
+ return mt76_mcu_send_msg(&dev->mt76, CMD_FUN_SET_OP, &msg,
+ sizeof(msg), wait);
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_function_select);
@@ -103,8 +110,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->mt76, CMD_POWER_SAVING_OP, &msg,
+ sizeof(msg), false);
}
EXPORT_SYMBOL_GPL(mt76x02_mcu_set_radio_state);
@@ -123,8 +130,8 @@ int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param)
if (is_mt76x2e)
mt76_rmw(dev, MT_MCU_COM_REG0, BIT(31), 0);
- ret = mt76_mcu_send_msg(dev, CMD_CALIBRATION_OP, &msg, sizeof(msg),
- true);
+ ret = mt76_mcu_send_msg(&dev->mt76, CMD_CALIBRATION_OP, &msg,
+ sizeof(msg), true);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h
index 5fba1266c648..e187ed52968e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.h
@@ -89,6 +89,8 @@ int mt76x02_mcu_cleanup(struct mt76x02_dev *dev);
int mt76x02_mcu_calibrate(struct mt76x02_dev *dev, int type, u32 param);
int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
int len, bool wait_resp);
+int mt76x02_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ struct sk_buff *skb, int seq);
int mt76x02_mcu_function_select(struct mt76x02_dev *dev, enum mcu_function func,
u32 val);
int mt76x02_mcu_set_radio_state(struct mt76x02_dev *dev, bool on);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index cf68731bd094..e7e87311d355 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -11,10 +11,11 @@
#include "mt76x02_mcu.h"
#include "trace.h"
-static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
+static void mt76x02_pre_tbtt_tasklet(struct tasklet_struct *t)
{
- struct mt76x02_dev *dev = (struct mt76x02_dev *)arg;
- struct mt76_queue *q = dev->mt76.q_tx[MT_TXQ_PSD];
+ struct mt76x02_dev *dev = from_tasklet(dev, t, mt76.pre_tbtt_tasklet);
+ struct mt76_dev *mdev = &dev->mt76;
+ struct mt76_queue *q = dev->mphy.q_tx[MT_TXQ_PSD];
struct beacon_bc_data data = {};
struct sk_buff *skb;
int i;
@@ -35,9 +36,9 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
mt76_wr(dev, MT_BCN_BYPASS_MASK,
0xff00 | ~(0xff00 >> dev->beacon_data_count));
- mt76_csa_check(&dev->mt76);
+ mt76_csa_check(mdev);
- if (dev->mt76.csa_complete)
+ if (mdev->csa_complete)
return;
mt76x02_enqueue_buffered_bc(dev, &data, 8);
@@ -58,8 +59,7 @@ static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
struct ieee80211_vif *vif = info->control.vif;
struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
- mt76_tx_queue_skb(dev, MT_TXQ_PSD, skb, &mvif->group_wcid,
- NULL);
+ mt76_tx_queue_skb(dev, q, skb, &mvif->group_wcid, NULL);
}
spin_unlock_bh(&q->lock);
}
@@ -104,27 +104,6 @@ void mt76x02e_init_beacon_config(struct mt76x02_dev *dev)
EXPORT_SYMBOL_GPL(mt76x02e_init_beacon_config);
static int
-mt76x02_init_tx_queue(struct mt76x02_dev *dev, int qid, int idx, int n_desc)
-{
- struct mt76_queue *hwq;
- int err;
-
- hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
- if (!hwq)
- return -ENOMEM;
-
- err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE);
- if (err < 0)
- return err;
-
- dev->mt76.q_tx[qid] = hwq;
-
- mt76x02_irq_enable(dev, MT_INT_TX_DONE(idx));
-
- return 0;
-}
-
-static int
mt76x02_init_rx_queue(struct mt76x02_dev *dev, struct mt76_queue *q,
int idx, int n_desc, int bufsize)
{
@@ -169,14 +148,16 @@ static int mt76x02_poll_tx(struct napi_struct *napi, int budget)
mt76x02_mac_poll_tx_status(dev, false);
- for (i = MT_TXQ_MCU; i >= 0; i--)
- mt76_queue_tx_cleanup(dev, i, false);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
+ for (i = MT_TXQ_PSD; i >= 0; i--)
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false);
if (napi_complete_done(napi, 0))
mt76x02_irq_enable(dev, MT_INT_TX_DONE_ALL);
- for (i = MT_TXQ_MCU; i >= 0; i--)
- mt76_queue_tx_cleanup(dev, i, false);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
+ for (i = MT_TXQ_PSD; i >= 0; i--)
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], false);
mt76_worker_schedule(&dev->mt76.tx_worker);
@@ -198,8 +179,7 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
return -ENOMEM;
dev->mt76.tx_worker.fn = mt76x02_tx_worker;
- tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet,
- (unsigned long)dev);
+ tasklet_setup(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet);
spin_lock_init(&dev->txstatus_fifo_lock);
kfifo_init(&dev->txstatus_fifo, status_fifo, fifo_size);
@@ -209,22 +189,31 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- ret = mt76x02_init_tx_queue(dev, i, mt76_ac_to_hwq(i),
- MT76x02_TX_RING_SIZE);
+ ret = mt76_init_tx_queue(&dev->mphy, i, mt76_ac_to_hwq(i),
+ MT76x02_TX_RING_SIZE,
+ MT_TX_RING_BASE);
if (ret)
return ret;
}
- ret = mt76x02_init_tx_queue(dev, MT_TXQ_PSD,
- MT_TX_HW_QUEUE_MGMT, MT76x02_PSD_RING_SIZE);
+ ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT,
+ MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
- ret = mt76x02_init_tx_queue(dev, MT_TXQ_MCU,
- MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
+ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT_TX_HW_QUEUE_MCU,
+ MT_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
+ mt76x02_irq_enable(dev,
+ MT_INT_TX_DONE(IEEE80211_AC_VO) |
+ MT_INT_TX_DONE(IEEE80211_AC_VI) |
+ MT_INT_TX_DONE(IEEE80211_AC_BE) |
+ MT_INT_TX_DONE(IEEE80211_AC_BK) |
+ MT_INT_TX_DONE(MT_TX_HW_QUEUE_MGMT) |
+ MT_INT_TX_DONE(MT_TX_HW_QUEUE_MCU));
+
ret = mt76x02_init_rx_queue(dev, &dev->mt76.q_rx[MT_RXQ_MCU], 1,
MT_MCU_RING_SIZE, MT_RX_BUF_SIZE);
if (ret)
@@ -292,7 +281,7 @@ irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance)
if (dev->mt76.csa_complete)
mt76_csa_finish(&dev->mt76);
else
- mt76_queue_kick(dev, dev->mt76.q_tx[MT_TXQ_PSD]);
+ mt76_queue_kick(dev, dev->mphy.q_tx[MT_TXQ_PSD]);
}
if (intr & MT_INT_TX_STAT)
@@ -357,7 +346,7 @@ static bool mt76x02_tx_hang(struct mt76x02_dev *dev)
int i;
for (i = 0; i < 4; i++) {
- q = dev->mt76.q_tx[i];
+ q = dev->mphy.q_tx[i];
if (!q->queued)
continue;
@@ -475,8 +464,9 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
if (restart)
mt76_mcu_restart(dev);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], true);
for (i = 0; i < __MT_TXQ_MAX; i++)
- mt76_queue_tx_cleanup(dev, i, true);
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
mt76_for_each_q_rx(&dev->mt76, i) {
mt76_queue_rx_reset(dev, i);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index 2c2f56112b57..efd70ddc2fd1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -67,7 +67,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
struct mt76_tx_info *tx_info)
{
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
- int pid, len = tx_info->skb->len, ep = q2ep(mdev->q_tx[qid]->hw_idx);
+ int pid, len = tx_info->skb->len, ep = q2ep(dev->mphy.q_tx[qid]->hw_idx);
struct mt76x02_txwi *txwi;
bool ampdu = IEEE80211_SKB_CB(tx_info->skb)->flags & IEEE80211_TX_CTL_AMPDU;
enum mt76_qsel qsel;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c
index e43d13d7c988..2953df7d8388 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c
@@ -297,6 +297,7 @@ void mt76x02u_init_mcu(struct mt76_dev *dev)
.headroom = MT_CMD_HDR_LEN,
.tailroom = 8,
.mcu_send_msg = mt76x02u_mcu_send_msg,
+ .mcu_parse_response = mt76x02_mcu_parse_response,
.mcu_wr_rp = mt76x02u_mcu_wr_rp,
.mcu_rd_rp = mt76x02u_mcu_rd_rp,
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index 11b769af2f8f..7ac20d3c16d7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -186,6 +186,7 @@ void mt76x02_init_device(struct mt76x02_dev *dev)
ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES);
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
+ ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
dev->mt76.global_wcid.idx = 255;
dev->mt76.global_wcid.hw_key_idx = -1;
@@ -304,12 +305,12 @@ mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
/* Allow to change address in HW if we create first interface. */
if (!dev->mphy.vif_mask &&
- (((vif->addr[0] ^ dev->mt76.macaddr[0]) & ~GENMASK(4, 1)) ||
- memcmp(vif->addr + 1, dev->mt76.macaddr + 1, ETH_ALEN - 1)))
+ (((vif->addr[0] ^ dev->mphy.macaddr[0]) & ~GENMASK(4, 1)) ||
+ memcmp(vif->addr + 1, dev->mphy.macaddr + 1, ETH_ALEN - 1)))
mt76x02_mac_setaddr(dev, vif->addr);
if (vif->addr[0] & BIT(1))
- idx = 1 + (((dev->mt76.macaddr[0] ^ vif->addr[0]) >> 2) & 7);
+ idx = 1 + (((dev->mphy.macaddr[0] ^ vif->addr[0]) >> 2) & 7);
/*
* Client mode typically only has one configurable BSSID register,
@@ -487,7 +488,7 @@ int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u8 cw_min = 5, cw_max = 10, qid;
u32 val;
- qid = dev->mt76.q_tx[queue]->hw_idx;
+ qid = dev->mphy.q_tx[queue]->hw_idx;
if (params->cw_min)
cw_min = fls(params->cw_min);
@@ -621,7 +622,7 @@ void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta,
struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv;
int idx = msta->wcid.idx;
- mt76_stop_tx_queues(&dev->mt76, sta, true);
+ mt76_stop_tx_queues(&dev->mphy, sta, true);
if (mt76_is_mmio(mdev))
mt76x02_mac_wcid_set_drop(dev, idx, ps);
}
@@ -677,7 +678,7 @@ void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev)
for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) {
u8 *addr = dev->macaddr_list[i].addr;
- memcpy(addr, dev->mt76.macaddr, ETH_ALEN);
+ memcpy(addr, dev->mphy.macaddr, ETH_ALEN);
if (!i)
continue;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c
index 410ffce3baff..c57e05a5c65e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c
@@ -16,7 +16,7 @@ mt76x2_eeprom_get_macaddr(struct mt76x02_dev *dev)
{
void *src = dev->mt76.eeprom.data + MT_EE_MAC_ADDR;
- memcpy(dev->mt76.macaddr, src, ETH_ALEN);
+ memcpy(dev->mphy.macaddr, src, ETH_ALEN);
return 0;
}
@@ -502,8 +502,8 @@ int mt76x2_eeprom_init(struct mt76x02_dev *dev)
mt76x02_eeprom_parse_hw_cap(dev);
mt76x2_eeprom_get_macaddr(dev);
- mt76_eeprom_override(&dev->mt76);
- dev->mt76.macaddr[0] &= ~BIT(1);
+ mt76_eeprom_override(&dev->mphy);
+ dev->mphy.macaddr[0] &= ~BIT(1);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c
index 9635c04ce032..3c2738903d7d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/mcu.c
@@ -33,13 +33,14 @@ int mt76x2_mcu_set_channel(struct mt76x02_dev *dev, u8 channel, u8 bw,
};
/* first set the channel without the extension channel info */
- mt76_mcu_send_msg(dev, CMD_SWITCH_CHANNEL_OP, &msg, sizeof(msg), true);
+ mt76_mcu_send_msg(&dev->mt76, CMD_SWITCH_CHANNEL_OP, &msg,
+ sizeof(msg), true);
usleep_range(5000, 10000);
msg.ext_chan = 0xe0 + bw_index;
- return mt76_mcu_send_msg(dev, CMD_SWITCH_CHANNEL_OP, &msg, sizeof(msg),
- true);
+ return mt76_mcu_send_msg(&dev->mt76, CMD_SWITCH_CHANNEL_OP, &msg,
+ sizeof(msg), true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_set_channel);
@@ -66,7 +67,8 @@ int mt76x2_mcu_load_cr(struct mt76x02_dev *dev, u8 type, u8 temp_level,
msg.cfg = cpu_to_le32(val);
/* first set the channel without the extension channel info */
- return mt76_mcu_send_msg(dev, CMD_LOAD_CR, &msg, sizeof(msg), true);
+ return mt76_mcu_send_msg(&dev->mt76, CMD_LOAD_CR, &msg, sizeof(msg),
+ true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_load_cr);
@@ -84,8 +86,8 @@ int mt76x2_mcu_init_gain(struct mt76x02_dev *dev, u8 channel, u32 gain,
if (force)
msg.channel |= cpu_to_le32(BIT(31));
- return mt76_mcu_send_msg(dev, CMD_INIT_GAIN_OP, &msg, sizeof(msg),
- true);
+ return mt76_mcu_send_msg(&dev->mt76, CMD_INIT_GAIN_OP, &msg,
+ sizeof(msg), true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_init_gain);
@@ -100,7 +102,7 @@ int mt76x2_mcu_tssi_comp(struct mt76x02_dev *dev,
.data = *tssi_data,
};
- return mt76_mcu_send_msg(dev, CMD_CALIBRATION_OP, &msg, sizeof(msg),
- true);
+ return mt76_mcu_send_msg(&dev->mt76, CMD_CALIBRATION_OP, &msg,
+ sizeof(msg), true);
}
EXPORT_SYMBOL_GPL(mt76x2_mcu_tssi_comp);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
index 4d50dad29ddf..ecaf85b483ac 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
@@ -90,7 +90,8 @@ mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
error:
- ieee80211_free_hw(mt76_hw(dev));
+ mt76_free_device(&dev->mt76);
+
return ret;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
index 48a3ebc9892a..620484390418 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
@@ -69,7 +69,7 @@ mt76x2_fixup_xtal(struct mt76x02_dev *dev)
int mt76x2_mac_reset(struct mt76x02_dev *dev, bool hard)
{
- const u8 *macaddr = dev->mt76.macaddr;
+ const u8 *macaddr = dev->mphy.macaddr;
u32 val;
int i, k;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c
index ca6f968411ac..e5b6282d1a6c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_mcu.c
@@ -179,6 +179,7 @@ int mt76x2_mcu_init(struct mt76x02_dev *dev)
static const struct mt76_mcu_ops mt76x2_mcu_ops = {
.mcu_restart = mt76pci_mcu_restart,
.mcu_send_msg = mt76x02_mcu_msg_send,
+ .mcu_parse_response = mt76x02_mcu_parse_response,
};
int ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
index 4e003c7b62cf..2575369e44e2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
@@ -75,6 +75,7 @@ static int mt76x2u_probe(struct usb_interface *intf,
return 0;
err:
+ mt76u_queues_deinit(&dev->mt76);
mt76_free_device(&dev->mt76);
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile
index 57fe726cc38b..cc2054dffa98 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/Makefile
@@ -4,3 +4,5 @@ obj-$(CONFIG_MT7915E) += mt7915e.o
mt7915e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
debugfs.o
+
+mt7915e-$(CONFIG_NL80211_TESTMODE) += testmode.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
index 1049927faf24..7d810fbf2862 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
@@ -48,32 +48,6 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
mt7915_radar_trigger, "%lld\n");
static int
-mt7915_dbdc_set(void *data, u64 val)
-{
- struct mt7915_dev *dev = data;
-
- if (val)
- mt7915_register_ext_phy(dev);
- else
- mt7915_unregister_ext_phy(dev);
-
- return 0;
-}
-
-static int
-mt7915_dbdc_get(void *data, u64 *val)
-{
- struct mt7915_dev *dev = data;
-
- *val = !!mt7915_ext_phy(dev);
-
- return 0;
-}
-
-DEFINE_DEBUGFS_ATTRIBUTE(fops_dbdc, mt7915_dbdc_get,
- mt7915_dbdc_set, "%lld\n");
-
-static int
mt7915_fw_debug_set(void *data, u64 val)
{
struct mt7915_dev *dev = data;
@@ -233,6 +207,7 @@ static const struct file_operations fops_tx_stats = {
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
+ .owner = THIS_MODULE,
};
static int mt7915_read_temperature(struct seq_file *s, void *data)
@@ -279,19 +254,23 @@ static int
mt7915_queues_read(struct seq_file *s, void *data)
{
struct mt7915_dev *dev = dev_get_drvdata(s->private);
- static const struct {
+ struct mt76_phy *mphy_ext = dev->mt76.phy2;
+ struct mt76_queue *ext_q = mphy_ext ? mphy_ext->q_tx[MT_TXQ_BE] : NULL;
+ struct {
+ struct mt76_queue *q;
char *queue;
- int id;
} queue_map[] = {
- { "WFDMA0", MT_TXQ_BE },
- { "MCUWM", MT_TXQ_MCU },
- { "MCUWA", MT_TXQ_MCU_WA },
- { "MCUFWQ", MT_TXQ_FWDL },
+ { dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" },
+ { ext_q, "WFDMA1" },
+ { dev->mphy.q_tx[MT_TXQ_BE], "WFDMA0" },
+ { dev->mt76.q_mcu[MT_MCUQ_WM], "MCUWM" },
+ { dev->mt76.q_mcu[MT_MCUQ_WA], "MCUWA" },
+ { dev->mt76.q_mcu[MT_MCUQ_FWDL], "MCUFWQ" },
};
int i;
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
- struct mt76_queue *q = dev->mt76.q_tx[queue_map[i].id];
+ struct mt76_queue *q = queue_map[i].q;
if (!q)
continue;
@@ -375,7 +354,6 @@ int mt7915_init_debugfs(struct mt7915_dev *dev)
debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
mt7915_queues_acq);
debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats);
- debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc);
debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern);
/* test knobs */
@@ -460,6 +438,7 @@ static const struct file_operations fops_sta_stats = {
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
+ .owner = THIS_MODULE,
};
void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
index cfa12c4c671f..8c1f9c77b14f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
@@ -5,42 +5,16 @@
#include "../dma.h"
#include "mac.h"
-static int
-mt7915_init_tx_queues(struct mt7915_dev *dev, int n_desc)
+int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc)
{
- struct mt76_queue *hwq;
- int err, i;
+ int i, err;
- hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
- if (!hwq)
- return -ENOMEM;
-
- err = mt76_queue_alloc(dev, hwq, MT7915_TXQ_BAND0, n_desc, 0,
- MT_TX_RING_BASE);
- if (err < 0)
- return err;
-
- for (i = 0; i < MT_TXQ_MCU; i++)
- dev->mt76.q_tx[i] = hwq;
-
- return 0;
-}
-
-static int
-mt7915_init_mcu_queue(struct mt7915_dev *dev, int qid, int idx, int n_desc)
-{
- struct mt76_queue *hwq;
- int err;
-
- hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
- if (!hwq)
- return -ENOMEM;
-
- err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE);
+ err = mt76_init_tx_queue(phy->mt76, 0, idx, n_desc, MT_TX_RING_BASE);
if (err < 0)
return err;
- dev->mt76.q_tx[qid] = hwq;
+ for (i = 0; i <= MT_TXQ_PSD; i++)
+ phy->mt76->q_tx[i] = phy->mt76->q_tx[0];
return 0;
}
@@ -61,6 +35,11 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
case PKT_TYPE_RX_EVENT:
mt7915_mcu_rx_event(dev, skb);
break;
+#ifdef CONFIG_NL80211_TESTMODE
+ case PKT_TYPE_TXRXV:
+ mt7915_mac_fill_rx_vector(dev, skb);
+ break;
+#endif
case PKT_TYPE_NORMAL:
if (!mt7915_mac_fill_rx(dev, skb)) {
mt76_rx(&dev->mt76, q, skb);
@@ -76,8 +55,8 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
static void
mt7915_tx_cleanup(struct mt7915_dev *dev)
{
- mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false);
- mt76_queue_tx_cleanup(dev, MT_TXQ_MCU_WA, false);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], false);
}
static int mt7915_poll_tx(struct napi_struct *napi, int budget)
@@ -257,25 +236,26 @@ int mt7915_dma_init(struct mt7915_dev *dev)
mt76_wr(dev, MT_WFDMA1_PRI_DLY_INT_CFG0, 0);
/* init tx queue */
- ret = mt7915_init_tx_queues(dev, MT7915_TX_RING_SIZE);
+ ret = mt7915_init_tx_queues(&dev->phy, MT7915_TXQ_BAND0,
+ MT7915_TX_RING_SIZE);
if (ret)
return ret;
/* command to WM */
- ret = mt7915_init_mcu_queue(dev, MT_TXQ_MCU, MT7915_TXQ_MCU_WM,
- MT7915_TX_MCU_RING_SIZE);
+ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7915_TXQ_MCU_WM,
+ MT7915_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
/* command to WA */
- ret = mt7915_init_mcu_queue(dev, MT_TXQ_MCU_WA, MT7915_TXQ_MCU_WA,
- MT7915_TX_MCU_RING_SIZE);
+ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WA, MT7915_TXQ_MCU_WA,
+ MT7915_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
/* firmware download */
- ret = mt7915_init_mcu_queue(dev, MT_TXQ_FWDL, MT7915_TXQ_FWDL,
- MT7915_TX_FWDL_RING_SIZE);
+ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7915_TXQ_FWDL,
+ MT7915_TX_FWDL_RING_SIZE, MT_TX_RING_BASE);
if (ret)
return ret;
@@ -293,13 +273,21 @@ int mt7915_dma_init(struct mt7915_dev *dev)
if (ret)
return ret;
- /* rx data */
- ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0,
- MT7915_RX_RING_SIZE, rx_buf_size,
- MT_RX_DATA_RING_BASE);
+ /* rx data queue */
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
+ MT7915_RXQ_BAND0, MT7915_RX_RING_SIZE,
+ rx_buf_size, MT_RX_DATA_RING_BASE);
if (ret)
return ret;
+ if (dev->dbdc_support) {
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_EXT],
+ MT7915_RXQ_BAND1, MT7915_RX_RING_SIZE,
+ rx_buf_size, MT_RX_DATA_RING_BASE);
+ if (ret)
+ return ret;
+ }
+
ret = mt76_init_queues(dev);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
index 7deba7ebd68a..7a2be3f61398 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
@@ -4,16 +4,11 @@
#include "mt7915.h"
#include "eeprom.h"
-static inline bool mt7915_efuse_valid(u8 val)
-{
- return !(val == 0xff);
-}
-
-u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset)
+static u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset)
{
u8 *data = dev->mt76.eeprom.data;
- if (!mt7915_efuse_valid(data[offset]))
+ if (data[offset] == 0xff)
mt7915_mcu_get_eeprom(dev, offset);
return data[offset];
@@ -34,10 +29,10 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev)
static int mt7915_check_eeprom(struct mt7915_dev *dev)
{
- u16 val;
u8 *eeprom = dev->mt76.eeprom.data;
+ u16 val;
- mt7915_eeprom_read(dev, 0);
+ mt7915_eeprom_read(dev, MT_EE_CHIP_ID);
val = get_unaligned_le16(eeprom);
switch (val) {
@@ -48,35 +43,50 @@ static int mt7915_check_eeprom(struct mt7915_dev *dev)
}
}
-static void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev)
+void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy)
{
- u8 *eeprom = dev->mt76.eeprom.data;
- u8 tx_mask, max_nss = 4;
- u32 val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF);
+ struct mt7915_dev *dev = phy->dev;
+ bool ext_phy = phy != &dev->phy;
+ u32 val;
+ val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF + ext_phy);
val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val);
switch (val) {
case MT_EE_5GHZ:
- dev->mt76.cap.has_5ghz = true;
+ phy->mt76->cap.has_5ghz = true;
break;
case MT_EE_2GHZ:
- dev->mt76.cap.has_2ghz = true;
+ phy->mt76->cap.has_2ghz = true;
break;
default:
- dev->mt76.cap.has_2ghz = true;
- dev->mt76.cap.has_5ghz = true;
+ phy->mt76->cap.has_2ghz = true;
+ phy->mt76->cap.has_5ghz = true;
break;
}
+}
+
+static void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev)
+{
+ u8 nss, tx_mask[2] = {}, *eeprom = dev->mt76.eeprom.data;
+
+ mt7915_eeprom_parse_band_config(&dev->phy);
/* read tx mask from eeprom */
- tx_mask = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK,
- eeprom[MT_EE_WIFI_CONF]);
- if (!tx_mask || tx_mask > max_nss)
- tx_mask = max_nss;
-
- dev->chainmask = BIT(tx_mask) - 1;
- dev->mphy.antenna_mask = dev->chainmask;
- dev->phy.chainmask = dev->chainmask;
+ tx_mask[0] = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK,
+ eeprom[MT_EE_WIFI_CONF]);
+ if (dev->dbdc_support)
+ tx_mask[1] = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK,
+ eeprom[MT_EE_WIFI_CONF + 1]);
+
+ nss = tx_mask[0] + tx_mask[1];
+ if (!nss || nss > 4) {
+ tx_mask[0] = 4;
+ nss = 4;
+ }
+
+ dev->chainmask = BIT(nss) - 1;
+ dev->mphy.antenna_mask = BIT(tx_mask[0]) - 1;
+ dev->phy.chainmask = dev->mphy.antenna_mask;
}
int mt7915_eeprom_init(struct mt7915_dev *dev)
@@ -92,10 +102,10 @@ int mt7915_eeprom_init(struct mt7915_dev *dev)
return ret;
mt7915_eeprom_parse_hw_cap(dev);
- memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
+ memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
ETH_ALEN);
- mt76_eeprom_override(&dev->mt76);
+ mt76_eeprom_override(&dev->mphy);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
index 4e31d6ab4fa6..6712032b40df 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
@@ -15,6 +15,7 @@ enum mt7915_eeprom_field {
MT_EE_CHIP_ID = 0x000,
MT_EE_VERSION = 0x002,
MT_EE_MAC_ADDR = 0x004,
+ MT_EE_MAC_ADDR2 = 0x00a,
MT_EE_DDIE_FT_VERSION = 0x050,
MT_EE_WIFI_CONF = 0x190,
MT_EE_TX0_POWER_2G = 0x2fc,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index 0232b66acb4f..ed4635bd151a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -6,6 +6,113 @@
#include "mac.h"
#include "eeprom.h"
+#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) | (4 + (_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), \
+}
+
+static struct ieee80211_rate mt7915_rates[] = {
+ CCK_RATE(0, 10),
+ CCK_RATE(1, 20),
+ CCK_RATE(2, 55),
+ CCK_RATE(3, 110),
+ OFDM_RATE(11, 60),
+ OFDM_RATE(15, 90),
+ OFDM_RATE(10, 120),
+ OFDM_RATE(14, 180),
+ OFDM_RATE(9, 240),
+ OFDM_RATE(13, 360),
+ OFDM_RATE(8, 480),
+ OFDM_RATE(12, 540),
+};
+
+static const struct ieee80211_iface_limit if_limits[] = {
+ {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_ADHOC)
+ }, {
+ .max = 16,
+ .types = BIT(NL80211_IFTYPE_AP) |
+#ifdef CONFIG_MAC80211_MESH
+ BIT(NL80211_IFTYPE_MESH_POINT)
+#endif
+ }, {
+ .max = MT7915_MAX_INTERFACES,
+ .types = BIT(NL80211_IFTYPE_STATION)
+ }
+};
+
+static const struct ieee80211_iface_combination if_comb[] = {
+ {
+ .limits = if_limits,
+ .n_limits = ARRAY_SIZE(if_limits),
+ .max_interfaces = MT7915_MAX_INTERFACES,
+ .num_different_channels = 1,
+ .beacon_int_infra_match = true,
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160) |
+ BIT(NL80211_CHAN_WIDTH_80P80),
+ }
+};
+
+static void
+mt7915_regd_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
+ struct mt76_phy *mphy = hw->priv;
+ struct mt7915_phy *phy = mphy->priv;
+ struct cfg80211_chan_def *chandef = &mphy->chandef;
+
+ dev->mt76.region = request->dfs_region;
+
+ if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
+ return;
+
+ mt7915_dfs_init_radar_detector(phy);
+}
+
+static void
+mt7915_init_wiphy(struct ieee80211_hw *hw)
+{
+ struct mt7915_phy *phy = mt7915_hw_phy(hw);
+ struct wiphy *wiphy = hw->wiphy;
+
+ hw->queues = 4;
+ hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
+ hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
+
+ phy->slottime = 9;
+
+ hw->sta_data_size = sizeof(struct mt7915_sta);
+ hw->vif_data_size = sizeof(struct mt7915_vif);
+
+ wiphy->iface_combinations = if_comb;
+ wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+ wiphy->reg_notifier = mt7915_regd_notifier;
+ wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
+
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
+
+ ieee80211_hw_set(hw, HAS_RATE_CONTROL);
+ ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+
+ hw->max_tx_fragments = 4;
+}
+
static void
mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
{
@@ -35,25 +142,26 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
+
+ mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536);
+ /* disable rx rate report by default due to hw issues */
+ mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
}
static void mt7915_mac_init(struct mt7915_dev *dev)
{
int i;
- mt76_rmw_field(dev, MT_DMA_DCR0, MT_DMA_DCR0_MAX_RX_LEN, 1536);
mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536);
- /* enable rx rate report */
- mt76_set(dev, MT_DMA_DCR0, MT_DMA_DCR0_RXD_G5_EN);
/* disable hardware de-agg */
mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
for (i = 0; i < MT7915_WTBL_SIZE; i++)
mt7915_mac_wtbl_update(dev, i,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+ for (i = 0; i < 2; i++)
+ mt7915_mac_init_band(dev, i);
- mt7915_mac_init_band(dev, 0);
- mt7915_mac_init_band(dev, 1);
mt7915_mcu_set_rts_thresh(&dev->phy, 0x92b);
}
@@ -108,6 +216,60 @@ static void mt7915_init_txpower(struct mt7915_dev *dev)
mt7915_eeprom_init_sku(dev);
}
+static int mt7915_register_ext_phy(struct mt7915_dev *dev)
+{
+ struct mt7915_phy *phy = mt7915_ext_phy(dev);
+ struct mt76_phy *mphy;
+ int ret;
+
+ if (!dev->dbdc_support)
+ return 0;
+
+ if (phy)
+ return 0;
+
+ mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops);
+ if (!mphy)
+ return -ENOMEM;
+
+ phy = mphy->priv;
+ phy->dev = dev;
+ phy->mt76 = mphy;
+ phy->chainmask = dev->chainmask & ~dev->phy.chainmask;
+ mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1;
+ mt7915_init_wiphy(mphy->hw);
+
+ INIT_LIST_HEAD(&phy->stats_list);
+ INIT_DELAYED_WORK(&phy->mac_work, mt7915_mac_work);
+
+ mt7915_eeprom_parse_band_config(phy);
+ mt7915_set_stream_vht_txbf_caps(phy);
+ mt7915_set_stream_he_caps(phy);
+
+ memcpy(mphy->macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR2,
+ ETH_ALEN);
+ mt76_eeprom_override(mphy);
+
+ /* The second interface does not get any packets unless it has a vif */
+ ieee80211_hw_set(mphy->hw, WANT_MONITOR_VIF);
+
+ ret = mt7915_init_tx_queues(phy, MT7915_TXQ_BAND1,
+ MT7915_TX_RING_SIZE);
+ if (ret)
+ goto error;
+
+ ret = mt76_register_phy(mphy, true, mt7915_rates,
+ ARRAY_SIZE(mt7915_rates));
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ ieee80211_free_hw(mphy->hw);
+ return ret;
+}
+
static void mt7915_init_work(struct work_struct *work)
{
struct mt7915_dev *dev = container_of(work, struct mt7915_dev,
@@ -117,6 +279,7 @@ static void mt7915_init_work(struct work_struct *work)
mt7915_mac_init(dev);
mt7915_init_txpower(dev);
mt7915_txbf_init(dev);
+ mt7915_register_ext_phy(dev);
}
static int mt7915_init_hardware(struct mt7915_dev *dev)
@@ -129,6 +292,8 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
spin_lock_init(&dev->token_lock);
idr_init(&dev->token);
+ dev->dbdc_support = !!(mt7915_l1_rr(dev, MT_HW_BOUND) & BIT(5));
+
ret = mt7915_dma_init(dev);
if (ret)
return ret;
@@ -162,109 +327,6 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
return 0;
}
-#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) | (4 + (_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), \
-}
-
-static struct ieee80211_rate mt7915_rates[] = {
- CCK_RATE(0, 10),
- CCK_RATE(1, 20),
- CCK_RATE(2, 55),
- CCK_RATE(3, 110),
- OFDM_RATE(11, 60),
- OFDM_RATE(15, 90),
- OFDM_RATE(10, 120),
- OFDM_RATE(14, 180),
- OFDM_RATE(9, 240),
- OFDM_RATE(13, 360),
- OFDM_RATE(8, 480),
- OFDM_RATE(12, 540),
-};
-
-static const struct ieee80211_iface_limit if_limits[] = {
- {
- .max = 1,
- .types = BIT(NL80211_IFTYPE_ADHOC)
- }, {
- .max = MT7915_MAX_INTERFACES,
- .types = BIT(NL80211_IFTYPE_AP) |
-#ifdef CONFIG_MAC80211_MESH
- BIT(NL80211_IFTYPE_MESH_POINT) |
-#endif
- BIT(NL80211_IFTYPE_STATION)
- }
-};
-
-static const struct ieee80211_iface_combination if_comb[] = {
- {
- .limits = if_limits,
- .n_limits = ARRAY_SIZE(if_limits),
- .max_interfaces = 4,
- .num_different_channels = 1,
- .beacon_int_infra_match = true,
- .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
- BIT(NL80211_CHAN_WIDTH_20) |
- BIT(NL80211_CHAN_WIDTH_40) |
- BIT(NL80211_CHAN_WIDTH_80) |
- BIT(NL80211_CHAN_WIDTH_160) |
- BIT(NL80211_CHAN_WIDTH_80P80),
- }
-};
-
-static void
-mt7915_regd_notifier(struct wiphy *wiphy,
- struct regulatory_request *request)
-{
- struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
- struct mt7915_dev *dev = mt7915_hw_dev(hw);
- struct mt76_phy *mphy = hw->priv;
- struct mt7915_phy *phy = mphy->priv;
- struct cfg80211_chan_def *chandef = &mphy->chandef;
-
- dev->mt76.region = request->dfs_region;
-
- if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
- return;
-
- mt7915_dfs_init_radar_detector(phy);
-}
-
-static void
-mt7915_init_wiphy(struct ieee80211_hw *hw)
-{
- struct mt7915_phy *phy = mt7915_hw_phy(hw);
- struct wiphy *wiphy = hw->wiphy;
-
- hw->queues = 4;
- hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
- hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
-
- phy->slottime = 9;
-
- hw->sta_data_size = sizeof(struct mt7915_sta);
- hw->vif_data_size = sizeof(struct mt7915_vif);
-
- wiphy->iface_combinations = if_comb;
- wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
- wiphy->reg_notifier = mt7915_regd_notifier;
- wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
-
- wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
-
- ieee80211_hw_set(hw, HAS_RATE_CONTROL);
-
- hw->max_tx_fragments = 4;
-}
-
void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy)
{
int nss = hweight8(phy->chainmask);
@@ -342,7 +404,7 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap,
elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
/* num_snd_dim */
- c = (nss - 1) | (max_t(int, mcs->tx_mcs_160, 1) << 3);
+ c = (nss - 1) | (max_t(int, le16_to_cpu(mcs->tx_mcs_160), 1) << 3);
elem->phy_cap_info[5] |= c;
c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB |
@@ -354,35 +416,24 @@ mt7915_set_stream_he_txbf_caps(struct ieee80211_sta_he_cap *he_cap,
}
static void
-mt7915_gen_ppe_thresh(u8 *he_ppet)
+mt7915_gen_ppe_thresh(u8 *he_ppet, int nss)
{
- int ru, nss, max_nss = 1, max_ru = 3;
- u8 bit = 7, ru_bit_mask = 0x7;
+ u8 i, ppet_bits, ppet_size, ru_bit_mask = 0x7; /* HE80 */
u8 ppet16_ppet8_ru3_ru0[] = {0x1c, 0xc7, 0x71};
- he_ppet[0] = max_nss & IEEE80211_PPE_THRES_NSS_MASK;
- he_ppet[0] |= (ru_bit_mask <<
- IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS) &
- IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK;
-
- for (nss = 0; nss <= max_nss; nss++) {
- for (ru = 0; ru < max_ru; ru++) {
- u8 val;
- int i;
-
- if (!(ru_bit_mask & BIT(ru)))
- continue;
-
- val = (ppet16_ppet8_ru3_ru0[nss] >> (ru * 6)) &
- 0x3f;
- val = ((val >> 3) & 0x7) | ((val & 0x7) << 3);
- for (i = 5; i >= 0; i--) {
- he_ppet[bit / 8] |=
- ((val >> i) & 0x1) << ((bit % 8));
- bit++;
- }
- }
- }
+ he_ppet[0] = FIELD_PREP(IEEE80211_PPE_THRES_NSS_MASK, nss - 1) |
+ FIELD_PREP(IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK,
+ ru_bit_mask);
+
+ ppet_bits = IEEE80211_PPE_THRES_INFO_PPET_SIZE *
+ nss * hweight8(ru_bit_mask) * 2;
+ ppet_size = DIV_ROUND_UP(ppet_bits, 8);
+
+ for (i = 0; i < ppet_size - 1; i++)
+ he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3];
+
+ he_ppet[i + 1] = ppet16_ppet8_ru3_ru0[i % 3] &
+ (0xff >> (8 - (ppet_bits - 1) % 8));
}
static int
@@ -513,7 +564,7 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
if (he_cap_elem->phy_cap_info[6] &
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
- mt7915_gen_ppe_thresh(he_cap->ppe_thres);
+ mt7915_gen_ppe_thresh(he_cap->ppe_thres, nss);
} else {
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_NOMIMAL_PKT_PADDING_16US;
@@ -528,10 +579,9 @@ void mt7915_set_stream_he_caps(struct mt7915_phy *phy)
{
struct ieee80211_sband_iftype_data *data;
struct ieee80211_supported_band *band;
- struct mt76_dev *mdev = &phy->dev->mt76;
int n;
- if (mdev->cap.has_2ghz) {
+ if (phy->mt76->cap.has_2ghz) {
data = phy->iftype[NL80211_BAND_2GHZ];
n = mt7915_init_he_caps(phy, NL80211_BAND_2GHZ, data);
@@ -540,7 +590,7 @@ void mt7915_set_stream_he_caps(struct mt7915_phy *phy)
band->n_iftype_data = n;
}
- if (mdev->cap.has_5ghz) {
+ if (phy->mt76->cap.has_5ghz) {
data = phy->iftype[NL80211_BAND_5GHZ];
n = mt7915_init_he_caps(phy, NL80211_BAND_5GHZ, data);
@@ -550,95 +600,7 @@ void mt7915_set_stream_he_caps(struct mt7915_phy *phy)
}
}
-static void
-mt7915_cap_dbdc_enable(struct mt7915_dev *dev)
-{
- dev->mphy.sband_5g.sband.vht_cap.cap &=
- ~(IEEE80211_VHT_CAP_SHORT_GI_160 |
- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
-
- if (dev->chainmask == 0xf)
- dev->mphy.antenna_mask = dev->chainmask >> 2;
- else
- dev->mphy.antenna_mask = dev->chainmask >> 1;
-
- dev->phy.chainmask = dev->mphy.antenna_mask;
- dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask;
- dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask;
-
- mt76_set_stream_caps(&dev->mphy, true);
- mt7915_set_stream_vht_txbf_caps(&dev->phy);
- mt7915_set_stream_he_caps(&dev->phy);
-}
-
-static void
-mt7915_cap_dbdc_disable(struct mt7915_dev *dev)
-{
- dev->mphy.sband_5g.sband.vht_cap.cap |=
- IEEE80211_VHT_CAP_SHORT_GI_160 |
- IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
-
- dev->mphy.antenna_mask = dev->chainmask;
- dev->phy.chainmask = dev->chainmask;
- dev->mphy.hw->wiphy->available_antennas_rx = dev->chainmask;
- dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask;
-
- mt76_set_stream_caps(&dev->mphy, true);
- mt7915_set_stream_vht_txbf_caps(&dev->phy);
- mt7915_set_stream_he_caps(&dev->phy);
-}
-
-int mt7915_register_ext_phy(struct mt7915_dev *dev)
-{
- struct mt7915_phy *phy = mt7915_ext_phy(dev);
- struct mt76_phy *mphy;
- int ret;
- bool bound;
-
- /* TODO: enble DBDC */
- bound = mt7915_l1_rr(dev, MT_HW_BOUND) & BIT(5);
- if (!bound)
- return -EINVAL;
-
- if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
- return -EINVAL;
-
- if (phy)
- return 0;
-
- mt7915_cap_dbdc_enable(dev);
- mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops);
- if (!mphy)
- return -ENOMEM;
-
- phy = mphy->priv;
- phy->dev = dev;
- phy->mt76 = mphy;
- phy->chainmask = dev->chainmask & ~dev->phy.chainmask;
- mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1;
- mt7915_init_wiphy(mphy->hw);
-
- INIT_LIST_HEAD(&phy->stats_list);
- INIT_DELAYED_WORK(&phy->mac_work, mt7915_mac_work);
-
- /*
- * Make the secondary PHY MAC address local without overlapping with
- * the usual MAC address allocation scheme on multiple virtual interfaces
- */
- mphy->hw->wiphy->perm_addr[0] |= 2;
- mphy->hw->wiphy->perm_addr[0] ^= BIT(7);
-
- /* The second interface does not get any packets unless it has a vif */
- ieee80211_hw_set(mphy->hw, WANT_MONITOR_VIF);
-
- ret = mt76_register_phy(mphy);
- if (ret)
- ieee80211_free_hw(mphy->hw);
-
- return ret;
-}
-
-void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
+static void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
{
struct mt7915_phy *phy = mt7915_ext_phy(dev);
struct mt76_phy *mphy = dev->mt76.phy2;
@@ -646,7 +608,6 @@ void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
if (!phy)
return;
- mt7915_cap_dbdc_disable(dev);
mt76_unregister_phy(mphy);
ieee80211_free_hw(mphy->hw);
}
@@ -683,9 +644,22 @@ int mt7915_register_device(struct mt7915_dev *dev)
dev->mphy.sband_5g.sband.vht_cap.cap |=
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
- mt7915_cap_dbdc_disable(dev);
+ if (!dev->dbdc_support)
+ dev->mphy.sband_5g.sband.vht_cap.cap |=
+ IEEE80211_VHT_CAP_SHORT_GI_160 |
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask;
+ dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask;
+
+ mt76_set_stream_caps(&dev->mphy, true);
+ mt7915_set_stream_vht_txbf_caps(&dev->phy);
+ mt7915_set_stream_he_caps(&dev->phy);
dev->phy.dfs_state = -1;
+#ifdef CONFIG_NL80211_TESTMODE
+ dev->mt76.test_ops = &mt7915_testmode_ops;
+#endif
+
ret = mt76_register_device(&dev->mt76, true, mt7915_rates,
ARRAY_SIZE(mt7915_rates));
if (ret)
@@ -716,6 +690,7 @@ void mt7915_unregister_device(struct mt7915_dev *dev)
ieee80211_free_txskb(hw, txwi->skb);
}
mt76_put_txwi(&dev->mt76, txwi);
+ dev->token_count--;
}
spin_unlock_bh(&dev->token_lock);
idr_destroy(&dev->token);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 6f159d99a596..f504eeb221f9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -562,21 +562,271 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
return 0;
}
+#ifdef CONFIG_NL80211_TESTMODE
+void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb)
+{
+ __le32 *rxd = (__le32 *)skb->data;
+ __le32 *rxv = rxd + 4;
+ u32 rcpi, ib_rssi, wb_rssi, v20, v21;
+ s32 foe;
+ u8 snr;
+ int i;
+
+ rcpi = le32_to_cpu(rxv[6]);
+ ib_rssi = le32_to_cpu(rxv[7]);
+ wb_rssi = le32_to_cpu(rxv[8]) >> 5;
+
+ for (i = 0; i < 4; i++, rcpi >>= 8, ib_rssi >>= 8, wb_rssi >>= 9) {
+ if (i == 3)
+ wb_rssi = le32_to_cpu(rxv[9]);
+
+ dev->test.last_rcpi[i] = rcpi & 0xff;
+ dev->test.last_ib_rssi[i] = ib_rssi & 0xff;
+ dev->test.last_wb_rssi[i] = wb_rssi & 0xff;
+ }
+
+ v20 = le32_to_cpu(rxv[20]);
+ v21 = le32_to_cpu(rxv[21]);
+
+ foe = FIELD_GET(MT_CRXV_FOE_LO, v20) |
+ (FIELD_GET(MT_CRXV_FOE_HI, v21) << MT_CRXV_FOE_SHIFT);
+
+ snr = FIELD_GET(MT_CRXV_SNR, v20) - 16;
+
+ dev->test.last_freq_offset = foe;
+ dev->test.last_snr = snr;
+
+ dev_kfree_skb(skb);
+}
+#endif
+
+static void
+mt7915_mac_write_txwi_tm(struct mt7915_dev *dev, struct mt76_phy *mphy,
+ __le32 *txwi, struct sk_buff *skb)
+{
+#ifdef CONFIG_NL80211_TESTMODE
+ struct mt76_testmode_data *td = &dev->mt76.test;
+ u8 rate_idx = td->tx_rate_idx;
+ u8 nss = td->tx_rate_nss;
+ u8 bw, mode;
+ u16 rateval = 0;
+ u32 val;
+
+ if (skb != dev->mt76.test.tx_skb)
+ return;
+
+ switch (td->tx_rate_mode) {
+ case MT76_TM_TX_MODE_CCK:
+ mode = MT_PHY_TYPE_CCK;
+ break;
+ case MT76_TM_TX_MODE_HT:
+ nss = 1 + (rate_idx >> 3);
+ mode = MT_PHY_TYPE_HT;
+ break;
+ case MT76_TM_TX_MODE_VHT:
+ mode = MT_PHY_TYPE_VHT;
+ break;
+ case MT76_TM_TX_MODE_HE_SU:
+ mode = MT_PHY_TYPE_HE_SU;
+ break;
+ case MT76_TM_TX_MODE_HE_EXT_SU:
+ mode = MT_PHY_TYPE_HE_EXT_SU;
+ break;
+ case MT76_TM_TX_MODE_HE_TB:
+ mode = MT_PHY_TYPE_HE_TB;
+ break;
+ case MT76_TM_TX_MODE_HE_MU:
+ mode = MT_PHY_TYPE_HE_MU;
+ break;
+ case MT76_TM_TX_MODE_OFDM:
+ default:
+ mode = MT_PHY_TYPE_OFDM;
+ break;
+ }
+
+ switch (mphy->chandef.width) {
+ case NL80211_CHAN_WIDTH_40:
+ bw = 1;
+ break;
+ case NL80211_CHAN_WIDTH_80:
+ bw = 2;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ case NL80211_CHAN_WIDTH_160:
+ bw = 3;
+ break;
+ default:
+ bw = 0;
+ break;
+ }
+
+ if (td->tx_rate_stbc && nss == 1) {
+ nss++;
+ rateval |= MT_TX_RATE_STBC;
+ }
+
+ rateval |= FIELD_PREP(MT_TX_RATE_IDX, rate_idx) |
+ FIELD_PREP(MT_TX_RATE_MODE, mode) |
+ FIELD_PREP(MT_TX_RATE_NSS, nss - 1);
+
+ txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE);
+
+ le32p_replace_bits(&txwi[3], 1, MT_TXD3_REM_TX_COUNT);
+ if (td->tx_rate_mode < MT76_TM_TX_MODE_HT)
+ txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
+
+ val = MT_TXD6_FIXED_BW |
+ FIELD_PREP(MT_TXD6_BW, bw) |
+ FIELD_PREP(MT_TXD6_TX_RATE, rateval) |
+ FIELD_PREP(MT_TXD6_SGI, td->tx_rate_sgi);
+
+ /* for HE_SU/HE_EXT_SU PPDU
+ * - 1x, 2x, 4x LTF + 0.8us GI
+ * - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI
+ * for HE_MU PPDU
+ * - 2x, 4x LTF + 0.8us GI
+ * - 2x LTF + 1.6us GI, 4x LTF + 3.2us GI
+ * for HE_TB PPDU
+ * - 1x, 2x LTF + 1.6us GI
+ * - 4x LTF + 3.2us GI
+ */
+ if (mode >= MT_PHY_TYPE_HE_SU)
+ val |= FIELD_PREP(MT_TXD6_HELTF, td->tx_ltf);
+
+ if (td->tx_rate_ldpc)
+ val |= MT_TXD6_LDPC;
+
+ txwi[6] |= cpu_to_le32(val);
+ txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX,
+ dev->test.spe_idx));
+#endif
+}
+
+static void
+mt7915_mac_write_txwi_8023(struct mt7915_dev *dev, __le32 *txwi,
+ struct sk_buff *skb, struct mt76_wcid *wcid)
+{
+
+ u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+ u8 fc_type, fc_stype;
+ bool wmm = false;
+ u32 val;
+
+ if (wcid->sta) {
+ struct ieee80211_sta *sta;
+
+ sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
+ wmm = sta->wme;
+ }
+
+ val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3) |
+ FIELD_PREP(MT_TXD1_TID, tid);
+
+ if (be16_to_cpu(skb->protocol) >= ETH_P_802_3_MIN)
+ val |= MT_TXD1_ETH_802_3;
+
+ txwi[1] |= cpu_to_le32(val);
+
+ fc_type = IEEE80211_FTYPE_DATA >> 2;
+ fc_stype = wmm ? IEEE80211_STYPE_QOS_DATA >> 4 : 0;
+
+ val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+ FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
+
+ txwi[2] |= cpu_to_le32(val);
+
+ val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
+ FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
+ txwi[7] |= cpu_to_le32(val);
+}
+
+static void
+mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi,
+ struct sk_buff *skb, struct ieee80211_key_conf *key)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ bool multicast = is_multicast_ether_addr(hdr->addr1);
+ u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+ __le16 fc = hdr->frame_control;
+ u8 fc_type, fc_stype;
+ u32 val;
+
+ if (ieee80211_is_action(fc) &&
+ mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+ mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
+ u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+
+ txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA);
+ tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK;
+ } else if (ieee80211_is_back_req(hdr->frame_control)) {
+ struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr;
+ u16 control = le16_to_cpu(bar->control);
+
+ tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control);
+ }
+
+ val = FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
+ FIELD_PREP(MT_TXD1_HDR_INFO,
+ ieee80211_get_hdrlen_from_skb(skb) / 2) |
+ FIELD_PREP(MT_TXD1_TID, tid);
+ txwi[1] |= cpu_to_le32(val);
+
+ fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
+ fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
+
+ val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
+ FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |
+ FIELD_PREP(MT_TXD2_MULTICAST, multicast);
+
+ if (key && multicast && ieee80211_is_robust_mgmt_frame(skb) &&
+ key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+ val |= MT_TXD2_BIP;
+ txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+ }
+
+ if (!ieee80211_is_data(fc) || multicast)
+ val |= MT_TXD2_FIX_RATE;
+
+ txwi[2] |= cpu_to_le32(val);
+
+ if (ieee80211_is_beacon(fc)) {
+ txwi[3] &= ~cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
+ txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
+ }
+
+ if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+ u16 seqno = le16_to_cpu(hdr->seq_ctrl);
+
+ if (ieee80211_is_back_req(hdr->frame_control)) {
+ struct ieee80211_bar *bar;
+
+ bar = (struct ieee80211_bar *)skb->data;
+ seqno = le16_to_cpu(bar->start_seq_num);
+ }
+
+ val = MT_TXD3_SN_VALID |
+ FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
+ txwi[3] |= cpu_to_le32(val);
+ }
+
+ val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
+ FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
+ txwi[7] |= cpu_to_le32(val);
+}
+
void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, bool beacon)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
- bool multicast = is_multicast_ether_addr(hdr->addr1);
struct ieee80211_vif *vif = info->control.vif;
struct mt76_phy *mphy = &dev->mphy;
bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY;
- u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
- __le16 fc = hdr->frame_control;
- u16 tx_count = 15, seqno = 0;
- u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+ u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
+ bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+ u16 tx_count = 15;
u32 val;
if (vif) {
@@ -589,13 +839,6 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
if (ext_phy && dev->mt76.phy2)
mphy = dev->mt76.phy2;
- fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
- fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
-
- txwi[4] = 0;
- txwi[5] = 0;
- txwi[6] = 0;
-
if (beacon) {
p_fmt = MT_TX_TYPE_FW;
q_idx = MT_LMAC_BCN0;
@@ -608,20 +851,6 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
mt7915_lmac_mapping(dev, skb_get_queue_mapping(skb));
}
- if (ieee80211_is_action(fc) &&
- mgmt->u.action.category == WLAN_CATEGORY_BACK &&
- mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
- u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
-
- txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA);
- tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK;
- } else if (ieee80211_is_back_req(hdr->frame_control)) {
- struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr;
- u16 control = le16_to_cpu(bar->control);
-
- tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control);
- }
-
val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
@@ -629,10 +858,6 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
val = MT_TXD1_LONG_FORMAT |
FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) |
- FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
- FIELD_PREP(MT_TXD1_HDR_INFO,
- ieee80211_get_hdrlen_from_skb(skb) / 2) |
- FIELD_PREP(MT_TXD1_TID, tid) |
FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
if (ext_phy && q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)
@@ -640,27 +865,31 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
txwi[1] = cpu_to_le32(val);
- val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
- FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |
- 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);
+ txwi[2] = 0;
+
+ val = MT_TXD3_SW_POWER_MGMT |
+ FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
+ if (key)
+ val |= MT_TXD3_PROTECT_FRAME;
+ if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+ val |= MT_TXD3_NO_ACK;
- if (!ieee80211_is_data(fc) || multicast) {
+ txwi[3] = cpu_to_le32(val);
+ txwi[4] = 0;
+ txwi[5] = 0;
+ txwi[6] = 0;
+ txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0;
+
+ if (is_8023)
+ mt7915_mac_write_txwi_8023(dev, txwi, skb, wcid);
+ else
+ mt7915_mac_write_txwi_80211(dev, txwi, skb, key);
+
+ if (txwi[2] & cpu_to_le32(MT_TXD2_FIX_RATE)) {
u16 rate;
/* hardware won't add HTC for mgmt/ctrl frame */
- txwi[2] |= cpu_to_le32(MT_TXD2_FIX_RATE | MT_TXD2_HTC_VLD);
+ txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD);
if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
rate = MT7915_5G_RATE_DEFAULT;
@@ -673,35 +902,28 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
}
- if (!ieee80211_is_beacon(fc))
- txwi[3] |= cpu_to_le32(MT_TXD3_SW_POWER_MGMT);
- else
- tx_count = 0x1f;
-
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK);
-
- val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
- FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
- if (wcid->amsdu)
- val |= MT_TXD7_HW_AMSDU;
- txwi[7] = cpu_to_le32(val);
-
- val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
- if (info->flags & IEEE80211_TX_CTL_INJECTED) {
- seqno = le16_to_cpu(hdr->seq_ctrl);
+ if (mt76_testmode_enabled(&dev->mt76))
+ mt7915_mac_write_txwi_tm(dev, mphy, txwi, skb);
+}
- if (ieee80211_is_back_req(hdr->frame_control)) {
- struct ieee80211_bar *bar;
+static void
+mt7915_set_tx_blocked(struct mt7915_dev *dev, bool blocked)
+{
+ struct mt76_phy *mphy = &dev->mphy, *mphy2 = dev->mt76.phy2;
+ struct mt76_queue *q, *q2 = NULL;
- bar = (struct ieee80211_bar *)skb->data;
- seqno = le16_to_cpu(bar->start_seq_num);
- }
+ q = mphy->q_tx[0];
+ if (blocked == q->blocked)
+ return;
- val |= MT_TXD3_SN_VALID |
- FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
+ q->blocked = blocked;
+ if (mphy2) {
+ q2 = mphy2->q_tx[0];
+ q2->blocked = blocked;
}
- txwi[3] |= cpu_to_le32(val);
+
+ if (!blocked)
+ mt76_worker_schedule(&dev->mt76.tx_worker);
}
int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
@@ -723,11 +945,11 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (!wcid)
wcid = &dev->mt76.global_wcid;
- cb->wcid = wcid->idx;
-
mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
false);
+ cb->wcid = wcid->idx;
+
txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE);
for (i = 0; i < nbuf; i++) {
txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
@@ -740,12 +962,13 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
tx_info->buf[1].skip_unmap = true;
tx_info->nbuf = MT_CT_DMA_BUF_NUM;
- txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD);
+ txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD | MT_CT_INFO_FROM_HOST);
if (!key)
txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
- if (ieee80211_is_mgmt(hdr->frame_control))
+ if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
+ ieee80211_is_mgmt(hdr->frame_control))
txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
if (vif) {
@@ -759,12 +982,21 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
spin_lock_bh(&dev->token_lock);
id = idr_alloc(&dev->token, t, 0, MT7915_TOKEN_SIZE, GFP_ATOMIC);
+ if (id >= 0)
+ dev->token_count++;
+
+ if (dev->token_count >= MT7915_TOKEN_SIZE - MT7915_TOKEN_FREE_THR)
+ mt7915_set_tx_blocked(dev, true);
spin_unlock_bh(&dev->token_lock);
+
if (id < 0)
return id;
txp->token = cpu_to_le16(id);
- txp->rept_wds_wcid = 0xff;
+ if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
+ txp->rept_wds_wcid = cpu_to_le16(wcid->idx);
+ else
+ txp->rept_wds_wcid = cpu_to_le16(0x3ff);
tx_info->skb = DMA_DUMMY_DATA;
return 0;
@@ -795,17 +1027,19 @@ mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
ieee80211_start_tx_ba_session(sta, tid, 0);
}
-static inline void
-mt7915_tx_status(struct ieee80211_sta *sta, struct ieee80211_hw *hw,
- struct ieee80211_tx_info *info, struct sk_buff *skb)
+static void
+mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb,
+ struct ieee80211_sta *sta, u8 stat,
+ struct list_head *free_list)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_status status = {
.sta = sta,
.info = info,
+ .skb = skb,
+ .free_list = free_list,
};
-
- if (skb)
- status.skb = skb;
+ struct ieee80211_hw *hw;
if (sta) {
struct mt7915_sta *msta;
@@ -814,18 +1048,19 @@ mt7915_tx_status(struct ieee80211_sta *sta, struct ieee80211_hw *hw,
status.rate = &msta->stats.tx_rate;
}
- /* use status_ext to report HE rate */
- ieee80211_tx_status_ext(hw, &status);
-}
+ hw = mt76_tx_status_get_hw(mdev, skb);
-static void
-mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb,
- struct ieee80211_sta *sta, u8 stat)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_hw *hw;
+#ifdef CONFIG_NL80211_TESTMODE
+ if (skb == mdev->test.tx_skb) {
+ struct mt7915_phy *phy = mt7915_hw_phy(hw);
+ struct ieee80211_vif *vif = phy->monitor_vif;
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
- hw = mt76_tx_status_get_hw(mdev, skb);
+ mt76_tx_complete_skb(mdev, mvif->sta.wcid.idx, skb);
+
+ return;
+ }
+#endif
if (info->flags & IEEE80211_TX_CTL_AMPDU)
info->flags |= IEEE80211_TX_STAT_AMPDU;
@@ -837,16 +1072,7 @@ mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb,
info->flags |= IEEE80211_TX_STAT_ACK;
info->status.tx_time = 0;
-
- if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) {
- mt7915_tx_status(sta, hw, info, skb);
- return;
- }
-
- if (sta || !(info->flags & IEEE80211_TX_CTL_NO_ACK))
- mt7915_tx_status(sta, hw, info, NULL);
-
- ieee80211_free_txskb(hw, skb);
+ ieee80211_tx_status_ext(hw, &status);
}
void mt7915_txp_skb_unmap(struct mt76_dev *dev,
@@ -865,13 +1091,21 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
{
struct mt7915_tx_free *free = (struct mt7915_tx_free *)skb->data;
struct mt76_dev *mdev = &dev->mt76;
+ struct mt76_phy *mphy_ext = mdev->phy2;
struct mt76_txwi_cache *txwi;
struct ieee80211_sta *sta = NULL;
+ LIST_HEAD(free_list);
+ struct sk_buff *tmp;
u8 i, count;
+ bool wake = false;
/* clean DMA queues and unmap buffers first */
- mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
- mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_PSD], false);
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BE], false);
+ if (mphy_ext) {
+ mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_PSD], false);
+ mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[MT_TXQ_BE], false);
+ }
/*
* TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE,
@@ -908,6 +1142,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
if (list_empty(&msta->poll_list))
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
+ continue;
}
msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
@@ -915,6 +1150,11 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
spin_lock_bh(&dev->token_lock);
txwi = idr_remove(&dev->token, msdu);
+ if (txwi)
+ dev->token_count--;
+ if (dev->token_count < MT7915_TOKEN_SIZE - MT7915_TOKEN_FREE_THR &&
+ dev->mphy.q_tx[0]->blocked)
+ wake = true;
spin_unlock_bh(&dev->token_lock);
if (!txwi)
@@ -937,16 +1177,29 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
}
- mt7915_tx_complete_status(mdev, txwi->skb, sta, stat);
+ mt7915_tx_complete_status(mdev, txwi->skb, sta, stat, &free_list);
txwi->skb = NULL;
}
mt76_put_txwi(mdev, txwi);
}
- dev_kfree_skb(skb);
mt7915_mac_sta_poll(dev);
+
+ if (wake) {
+ spin_lock_bh(&dev->token_lock);
+ mt7915_set_tx_blocked(dev, false);
+ spin_unlock_bh(&dev->token_lock);
+ }
+
mt76_worker_schedule(&dev->mt76.tx_worker);
+
+ napi_consume_skb(skb, 1);
+
+ list_for_each_entry_safe(skb, tmp, &free_list, list) {
+ skb_list_del_init(skb);
+ napi_consume_skb(skb, 1);
+ }
}
void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
@@ -979,7 +1232,8 @@ void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
wcid = rcu_dereference(dev->mt76.wcid[cb->wcid]);
- mt7915_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0);
+ mt7915_tx_complete_status(mdev, e->skb, wcid_to_sta(wcid), 0,
+ NULL);
}
}
@@ -1081,17 +1335,48 @@ void mt7915_mac_set_timing(struct mt7915_phy *phy)
MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
}
-/*
- * TODO: mib counters are read-clear and there're many HE functionalities need
- * such info, hence firmware prepares a task to read the fields out to a shared
- * structure. User should switch to use event format to avoid race condition.
- */
+void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy)
+{
+ mt7915_l2_set(dev, MT_WF_PHY_RXTD12(ext_phy),
+ MT_WF_PHY_RXTD12_IRPI_SW_CLR_ONLY |
+ MT_WF_PHY_RXTD12_IRPI_SW_CLR);
+
+ mt7915_l2_set(dev, MT_WF_PHY_RX_CTRL1(ext_phy),
+ FIELD_PREP(MT_WF_PHY_RX_CTRL1_IPI_EN, 0x5));
+}
+
+static u8
+mt7915_phy_get_nf(struct mt7915_phy *phy, int idx)
+{
+ static const u8 nf_power[] = { 92, 89, 86, 83, 80, 75, 70, 65, 60, 55, 52 };
+ struct mt7915_dev *dev = phy->dev;
+ u32 val, sum = 0, n = 0;
+ int nss, i;
+
+ for (nss = 0; nss < hweight8(phy->chainmask); nss++) {
+ u32 reg = MT_WF_IRPI(nss + (idx << dev->dbdc_support));
+
+ for (i = 0; i < ARRAY_SIZE(nf_power); i++, reg += 4) {
+ val = mt7915_l2_rr(dev, reg);
+ sum += val * nf_power[i];
+ n += val;
+ }
+ }
+
+ if (!n)
+ return 0;
+
+ return sum / n;
+}
+
static void
mt7915_phy_update_channel(struct mt76_phy *mphy, int idx)
{
struct mt7915_dev *dev = container_of(mphy->dev, struct mt7915_dev, mt76);
+ struct mt7915_phy *phy = (struct mt7915_phy *)mphy->priv;
struct mt76_channel_state *state;
u64 busy_time, tx_time, rx_time, obss_time;
+ int nf;
busy_time = mt76_get_field(dev, MT_MIB_SDR9(idx),
MT_MIB_SDR9_BUSY_MASK);
@@ -1102,12 +1387,18 @@ mt7915_phy_update_channel(struct mt76_phy *mphy, int idx)
obss_time = mt76_get_field(dev, MT_WF_RMAC_MIB_AIRTIME14(idx),
MT_MIB_OBSSTIME_MASK);
- /* TODO: state->noise */
+ nf = mt7915_phy_get_nf(phy, idx);
+ if (!phy->noise)
+ phy->noise = nf << 4;
+ else if (nf)
+ phy->noise += nf - (phy->noise >> 4);
+
state = mphy->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;
+ state->noise = -(phy->noise >> 4);
}
void mt7915_update_channel(struct mt76_dev *mdev)
@@ -1162,8 +1453,10 @@ mt7915_update_beacons(struct mt7915_dev *dev)
}
static void
-mt7915_dma_reset(struct mt7915_dev *dev)
+mt7915_dma_reset(struct mt7915_phy *phy)
{
+ struct mt7915_dev *dev = phy->dev;
+ struct mt76_phy *mphy_ext = dev->mt76.phy2;
int i;
mt76_clear(dev, MT_WFDMA0_GLO_CFG,
@@ -1172,8 +1465,12 @@ mt7915_dma_reset(struct mt7915_dev *dev)
MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN);
usleep_range(1000, 2000);
- for (i = 0; i < __MT_TXQ_MAX; i++)
- mt76_queue_tx_cleanup(dev, i, true);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WA], true);
+ for (i = 0; i < __MT_TXQ_MAX; i++) {
+ mt76_queue_tx_cleanup(dev, phy->mt76->q_tx[i], true);
+ if (mphy_ext)
+ mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true);
+ }
mt76_for_each_q_rx(&dev->mt76, i) {
mt76_queue_rx_reset(dev, i);
@@ -1229,7 +1526,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
- mt7915_dma_reset(dev);
+ mt7915_dma_reset(&dev->phy);
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
mt7915_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
@@ -1329,7 +1626,7 @@ mt7915_mac_sta_stats_work(struct mt7915_phy *phy)
spin_unlock_bh(&dev->sta_poll_lock);
/* use MT_TX_FREE_RATE to report Tx rate for further devices */
- mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO, msta->wcid.idx);
+ mt7915_mcu_get_tx_rate(dev, RATE_CTRL_RU_INFO, msta->wcid.idx);
spin_lock_bh(&dev->sta_poll_lock);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
index c8bb5ea96c60..d420392b952d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.h
@@ -128,6 +128,11 @@ enum rx_pkt_type {
#define MT_CRXV_HE_BEAM_CHNG BIT(13)
#define MT_CRXV_HE_DOPPLER BIT(16)
+#define MT_CRXV_SNR GENMASK(18, 13)
+#define MT_CRXV_FOE_LO GENMASK(31, 19)
+#define MT_CRXV_FOE_HI GENMASK(6, 0)
+#define MT_CRXV_FOE_SHIFT 13
+
enum tx_header_format {
MT_HDR_FORMAT_802_3,
MT_HDR_FORMAT_CMD,
@@ -160,6 +165,7 @@ enum tx_mcu_port_q_idx {
#define MT_CT_INFO_MGMT_FRAME BIT(2)
#define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3)
#define MT_CT_INFO_HSR2_TX BIT(4)
+#define MT_CT_INFO_FROM_HOST BIT(7)
#define MT_TXD_SIZE (8 * 4)
@@ -176,6 +182,7 @@ enum tx_mcu_port_q_idx {
#define MT_TXD1_HDR_PAD GENMASK(19, 18)
#define MT_TXD1_HDR_FORMAT GENMASK(17, 16)
#define MT_TXD1_HDR_INFO GENMASK(15, 11)
+#define MT_TXD1_ETH_802_3 BIT(15)
#define MT_TXD1_VTA BIT(10)
#define MT_TXD1_WLAN_IDX GENMASK(9, 0)
@@ -229,7 +236,7 @@ enum tx_mcu_port_q_idx {
#define MT_TXD6_ANT_ID GENMASK(7, 4)
#define MT_TXD6_DYN_BW BIT(3)
#define MT_TXD6_FIXED_BW BIT(2)
-#define MT_TXD6_BW GENMASK(2, 0)
+#define MT_TXD6_BW GENMASK(1, 0)
#define MT_TXD7_TXD_LEN GENMASK(31, 30)
#define MT_TXD7_UDP_TCP_SUM BIT(29)
@@ -246,7 +253,9 @@ enum tx_mcu_port_q_idx {
#define MT_TX_RATE_STBC BIT(13)
#define MT_TX_RATE_NSS GENMASK(12, 10)
#define MT_TX_RATE_MODE GENMASK(9, 6)
-#define MT_TX_RATE_IDX GENMASK(5, 0)
+#define MT_TX_RATE_SU_EXT_TONE BIT(5)
+#define MT_TX_RATE_DCM BIT(4)
+#define MT_TX_RATE_IDX GENMASK(3, 0)
#define MT_TXP_MAX_BUF_NUM 6
@@ -254,8 +263,7 @@ struct mt7915_txp {
__le16 flags;
__le16 token;
u8 bss_idx;
- u8 rept_wds_wcid;
- u8 rsv;
+ __le16 rept_wds_wcid;
u8 nbuf;
__le32 buf[MT_TXP_MAX_BUF_NUM];
__le16 len[MT_TXP_MAX_BUF_NUM];
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index c48158392057..0c82aa2ef219 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -34,21 +34,24 @@ static int mt7915_start(struct ieee80211_hw *hw)
mt7915_mcu_set_pm(dev, 0, 0);
mt7915_mcu_set_mac(dev, 0, true, false);
mt7915_mcu_set_scs(dev, 0, true);
+ mt7915_mac_enable_nf(dev, 0);
}
if (phy != &dev->phy) {
mt7915_mcu_set_pm(dev, 1, 0);
mt7915_mcu_set_mac(dev, 1, true, false);
mt7915_mcu_set_scs(dev, 1, true);
+ mt7915_mac_enable_nf(dev, 1);
}
- mt7915_mcu_set_sku_en(phy, true);
+ mt7915_mcu_set_sku_en(phy, !mt76_testmode_enabled(&dev->mt76));
mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH);
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
- ieee80211_queue_delayed_work(hw, &phy->mac_work,
- MT7915_WATCHDOG_TIME);
+ if (!mt76_testmode_enabled(&dev->mt76))
+ ieee80211_queue_delayed_work(hw, &phy->mac_work,
+ MT7915_WATCHDOG_TIME);
if (!running)
mt7915_mac_reset_counters(phy);
@@ -67,6 +70,8 @@ static void mt7915_stop(struct ieee80211_hw *hw)
mutex_lock(&dev->mt76.mutex);
+ mt76_testmode_reset(&dev->mt76, true);
+
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
if (phy != &dev->phy) {
@@ -82,28 +87,51 @@ static void mt7915_stop(struct ieee80211_hw *hw)
mutex_unlock(&dev->mt76.mutex);
}
-static int get_omac_idx(enum nl80211_iftype type, u32 mask)
+static inline int get_free_idx(u32 mask, u8 start, u8 end)
+{
+ return ffs(~mask & GENMASK(end, start));
+}
+
+static int get_omac_idx(enum nl80211_iftype type, u64 mask)
{
int i;
switch (type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+ /* prefer hw bssid slot 1-3 */
+ i = get_free_idx(mask, HW_BSSID_1, HW_BSSID_3);
+ if (i)
+ return i - 1;
+
+ if (type != NL80211_IFTYPE_STATION)
+ break;
+
+ /* next, try to find a free repeater entry for the sta */
+ i = get_free_idx(mask >> REPEATER_BSSID_START, 0,
+ REPEATER_BSSID_MAX - REPEATER_BSSID_START);
+ if (i)
+ return i + 32 - 1;
+
+ i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
+ if (i)
+ return i - 1;
+
+ if (~mask & BIT(HW_BSSID_0))
+ return HW_BSSID_0;
+
+ break;
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP:
/* ap uses hw bssid 0 and ext bssid */
if (~mask & BIT(HW_BSSID_0))
return HW_BSSID_0;
- for (i = EXT_BSSID_1; i < EXT_BSSID_END; i++)
- if (~mask & BIT(i))
- return i;
- break;
- case NL80211_IFTYPE_MESH_POINT:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_STATION:
- /* station uses hw bssid other than 0 */
- for (i = HW_BSSID_1; i < HW_BSSID_MAX; i++)
- if (~mask & BIT(i))
- return i;
+ i = get_free_idx(mask, EXT_BSSID_1, EXT_BSSID_MAX);
+ if (i)
+ return i - 1;
+
break;
default:
WARN_ON(1);
@@ -125,6 +153,12 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
mutex_lock(&dev->mt76.mutex);
+ mt76_testmode_reset(&dev->mt76, true);
+
+ if (vif->type == NL80211_IFTYPE_MONITOR &&
+ is_zero_ether_addr(vif->addr))
+ phy->monitor_vif = vif;
+
mvif->idx = ffs(~phy->mt76->vif_mask) - 1;
if (mvif->idx >= MT7915_MAX_INTERFACES) {
ret = -ENOSPC;
@@ -146,12 +180,12 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
else
mvif->wmm_idx = mvif->idx % MT7915_MAX_WMM_SETS;
- ret = mt7915_mcu_add_dev_info(dev, vif, true);
+ ret = mt7915_mcu_add_dev_info(phy, vif, true);
if (ret)
goto out;
phy->mt76->vif_mask |= BIT(mvif->idx);
- phy->omac_mask |= BIT(mvif->omac_idx);
+ phy->omac_mask |= BIT_ULL(mvif->omac_idx);
idx = MT7915_WTBL_RESERVED - mvif->idx;
@@ -171,6 +205,11 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
mtxq->wcid = &mvif->sta.wcid;
}
+ if (vif->type != NL80211_IFTYPE_AP &&
+ (!mvif->omac_idx || mvif->omac_idx > 3))
+ vif->offload_flags = 0;
+ vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
+
out:
mutex_unlock(&dev->mt76.mutex);
@@ -188,13 +227,20 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw,
/* TODO: disable beacon for the bss */
- mt7915_mcu_add_dev_info(dev, vif, false);
+ mutex_lock(&dev->mt76.mutex);
+ mt76_testmode_reset(&dev->mt76, true);
+ mutex_unlock(&dev->mt76.mutex);
+
+ if (vif == phy->monitor_vif)
+ phy->monitor_vif = NULL;
+
+ mt7915_mcu_add_dev_info(phy, vif, false);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
mutex_lock(&dev->mt76.mutex);
phy->mt76->vif_mask &= ~BIT(mvif->idx);
- phy->omac_mask &= ~BIT(mvif->omac_idx);
+ phy->omac_mask &= ~BIT_ULL(mvif->omac_idx);
mutex_unlock(&dev->mt76.mutex);
spin_lock_bh(&dev->sta_poll_lock);
@@ -222,7 +268,7 @@ static void mt7915_init_dfs_state(struct mt7915_phy *phy)
phy->dfs_state = -1;
}
-static int mt7915_set_channel(struct mt7915_phy *phy)
+int mt7915_set_channel(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
int ret;
@@ -251,8 +297,10 @@ out:
mutex_unlock(&dev->mt76.mutex);
mt76_txq_schedule_all(phy->mt76);
- ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work,
- MT7915_WATCHDOG_TIME);
+
+ if (!mt76_testmode_enabled(&dev->mt76))
+ ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work,
+ MT7915_WATCHDOG_TIME);
return ret;
}
@@ -283,8 +331,6 @@ static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
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:
@@ -292,6 +338,8 @@ static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
case WLAN_CIPHER_SUITE_GCMP_256:
case WLAN_CIPHER_SUITE_SMS4:
break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
default:
return -EOPNOTSUPP;
}
@@ -316,6 +364,13 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
int ret;
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+#ifdef CONFIG_NL80211_TESTMODE
+ if (dev->mt76.test.state != MT76_TM_STATE_OFF) {
+ mutex_lock(&dev->mt76.mutex);
+ mt76_testmode_reset(&dev->mt76, false);
+ mutex_unlock(&dev->mt76.mutex);
+ }
+#endif
ieee80211_stop_queues(hw);
ret = mt7915_set_channel(phy);
if (ret)
@@ -332,11 +387,16 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&dev->mt76.mutex);
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
- if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
+ bool enabled = !!(hw->conf.flags & IEEE80211_CONF_MONITOR);
+
+ if (!enabled)
phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC;
else
phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC;
+ mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN,
+ enabled);
+ mt76_testmode_reset(&dev->mt76, true);
mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter);
}
@@ -764,9 +824,13 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
struct station_info *sinfo)
{
+ struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
struct mt7915_sta_stats *stats = &msta->stats;
+ if (mt7915_mcu_get_rx_rate(phy, vif, sta, &sinfo->rxrate) == 0)
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
+
if (!stats->tx_rate.legacy && !stats->tx_rate.flags)
return;
@@ -802,6 +866,22 @@ mt7915_sta_rc_update(struct ieee80211_hw *hw,
ieee80211_queue_work(hw, &dev->rc_work);
}
+static void mt7915_sta_set_4addr(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ bool enabled)
+{
+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+
+ if (enabled)
+ set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
+ else
+ clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
+
+ mt7915_mcu_sta_update_hdr_trans(dev, vif, sta);
+}
+
const struct ieee80211_ops mt7915_ops = {
.tx = mt7915_tx,
.start = mt7915_start,
@@ -833,6 +913,9 @@ const struct ieee80211_ops mt7915_ops = {
.set_antenna = mt7915_set_antenna,
.set_coverage_class = mt7915_set_coverage_class,
.sta_statistics = mt7915_sta_statistics,
+ .sta_set_4addr = mt7915_sta_set_4addr,
+ CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
+ CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
#ifdef CONFIG_MAC80211_DEBUGFS
.sta_add_debugfs = mt7915_sta_add_debugfs,
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index a3ccc1785661..5fdd1a6d32ee 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -215,32 +215,71 @@ mt7915_mcu_get_sta_nss(u16 mcs_map)
return nss - 1;
}
-static int __mt7915_mcu_msg_send(struct mt7915_dev *dev, struct sk_buff *skb,
- int cmd, int *wait_seq)
+static int
+mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ struct sk_buff *skb, int seq)
{
+ struct mt7915_mcu_rxd *rxd;
+ int ret = 0;
+
+ if (!skb) {
+ dev_err(mdev->dev, "Message %d (seq %d) timeout\n",
+ cmd, seq);
+ return -ETIMEDOUT;
+ }
+
+ rxd = (struct mt7915_mcu_rxd *)skb->data;
+ 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_THERMAL_CTRL:
+ skb_pull(skb, sizeof(*rxd) + 4);
+ ret = le32_to_cpu(*(__le32 *)skb->data);
+ break;
+ default:
+ skb_pull(skb, sizeof(struct mt7915_mcu_rxd));
+ break;
+ }
+
+ return ret;
+}
+
+static int
+mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
+ int cmd, int *wait_seq)
+{
+ struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
struct mt7915_mcu_txd *mcu_txd;
u8 seq, pkt_fmt, qidx;
enum mt76_txq_id txq;
__le32 *txd;
u32 val;
+ /* TODO: make dynamic based on msg type */
+ mdev->mcu.timeout = 20 * HZ;
+
seq = ++dev->mt76.mcu.msg_seq & 0xf;
if (!seq)
seq = ++dev->mt76.mcu.msg_seq & 0xf;
if (cmd == -MCU_CMD_FW_SCATTER) {
- txq = MT_TXQ_FWDL;
+ txq = MT_MCUQ_FWDL;
goto exit;
}
mcu_txd = (struct mt7915_mcu_txd *)skb_push(skb, sizeof(*mcu_txd));
if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state)) {
- txq = MT_TXQ_MCU_WA;
+ txq = MT_MCUQ_WA;
qidx = MT_TX_MCU_PORT_RX_Q0;
pkt_fmt = MT_TX_TYPE_CMD;
} else {
- txq = MT_TXQ_MCU;
+ txq = MT_MCUQ_WM;
qidx = MT_TX_MCU_PORT_RX_Q0;
pkt_fmt = MT_TX_TYPE_CMD;
}
@@ -276,7 +315,10 @@ static int __mt7915_mcu_msg_send(struct mt7915_dev *dev, struct sk_buff *skb,
mcu_txd->set_query = MCU_Q_SET;
}
- mcu_txd->s2d_index = MCU_S2D_H2N;
+ if (cmd == MCU_EXT_CMD_MWDS_SUPPORT)
+ mcu_txd->s2d_index = MCU_S2D_H2C;
+ else
+ mcu_txd->s2d_index = MCU_S2D_H2N;
WARN_ON(cmd == MCU_EXT_CMD_EFUSE_ACCESS &&
mcu_txd->set_query != MCU_Q_QUERY);
@@ -284,116 +326,7 @@ exit:
if (wait_seq)
*wait_seq = seq;
- return mt76_tx_queue_skb_raw(dev, txq, skb, 0);
-}
-
-static int
-mt7915_mcu_parse_eeprom(struct mt7915_dev *dev, struct sk_buff *skb)
-{
- struct mt7915_mcu_eeprom_info *res;
- u8 *buf;
-
- if (!skb)
- return -EINVAL;
-
- skb_pull(skb, sizeof(struct mt7915_mcu_rxd));
-
- res = (struct mt7915_mcu_eeprom_info *)skb->data;
- buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr);
- memcpy(buf, res->data, 16);
-
- return 0;
-}
-
-static int
-mt7915_mcu_parse_response(struct mt7915_dev *dev, int cmd,
- struct sk_buff *skb, int seq)
-{
- struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data;
- int ret = 0;
-
- if (seq != rxd->seq) {
- ret = -EAGAIN;
- goto out;
- }
-
- switch (cmd) {
- case -MCU_CMD_PATCH_SEM_CONTROL:
- skb_pull(skb, sizeof(*rxd) - 4);
- ret = *skb->data;
- break;
- case MCU_EXT_CMD_THERMAL_CTRL:
- skb_pull(skb, sizeof(*rxd) + 4);
- ret = le32_to_cpu(*(__le32 *)skb->data);
- break;
- case MCU_EXT_CMD_EFUSE_ACCESS:
- ret = mt7915_mcu_parse_eeprom(dev, skb);
- break;
- default:
- break;
- }
-out:
- dev_kfree_skb(skb);
-
- return ret;
-}
-
-static int
-mt7915_mcu_wait_response(struct mt7915_dev *dev, int cmd, int seq)
-{
- unsigned long expires = jiffies + 20 * HZ;
- struct sk_buff *skb;
- int ret = 0;
-
- while (true) {
- skb = mt76_mcu_get_response(&dev->mt76, expires);
- if (!skb) {
- dev_err(dev->mt76.dev, "Message %d (seq %d) timeout\n",
- cmd, seq);
- return -ETIMEDOUT;
- }
-
- ret = mt7915_mcu_parse_response(dev, cmd, skb, seq);
- if (ret != -EAGAIN)
- break;
- }
-
- return ret;
-}
-
-static int
-mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
- int cmd, bool wait_resp)
-{
- struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
- int ret, seq;
-
- mutex_lock(&mdev->mcu.mutex);
-
- ret = __mt7915_mcu_msg_send(dev, skb, cmd, &seq);
- if (ret)
- goto out;
-
- if (wait_resp)
- ret = mt7915_mcu_wait_response(dev, cmd, seq);
-
-out:
- mutex_unlock(&mdev->mcu.mutex);
-
- return ret;
-}
-
-static int
-mt7915_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
- int len, bool wait_resp)
-{
- struct sk_buff *skb;
-
- skb = mt76_mcu_msg_alloc(mdev, data, len);
- if (!skb)
- return -ENOMEM;
-
- return __mt76_mcu_skb_send_msg(mdev, skb, cmd, wait_resp);
+ return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[txq], skb, 0);
}
static void
@@ -419,8 +352,8 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
}
static void
-mt7915_mcu_tx_rate_cal(struct mt76_phy *mphy, struct mt7915_mcu_ra_info *ra,
- struct rate_info *rate, u16 r)
+mt7915_mcu_tx_rate_parse(struct mt76_phy *mphy, struct mt7915_mcu_ra_info *ra,
+ struct rate_info *rate, u16 r)
{
struct ieee80211_supported_band *sband;
u16 ru_idx = le16_to_cpu(ra->ru_idx);
@@ -532,11 +465,11 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb)
mphy = dev->mt76.phy2;
/* current rate */
- mt7915_mcu_tx_rate_cal(mphy, ra, &rate, curr);
+ mt7915_mcu_tx_rate_parse(mphy, ra, &rate, curr);
stats->tx_rate = rate;
/* probing rate */
- mt7915_mcu_tx_rate_cal(mphy, ra, &prob_rate, probe);
+ mt7915_mcu_tx_rate_parse(mphy, ra, &prob_rate, probe);
stats->prob_rate = prob_rate;
if (attempts) {
@@ -1005,18 +938,42 @@ mt7915_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7915_phy *phy)
}
}
-static void
-mt7915_mcu_bss_sync_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
+static int
+mt7915_mcu_muar_config(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+ bool bssid, bool enable)
{
- struct bss_info_sync_mode *sync;
- struct tlv *tlv;
+ struct mt7915_dev *dev = phy->dev;
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ u32 idx = mvif->omac_idx - REPEATER_BSSID_START;
+ u32 mask = phy->omac_mask >> 32 & ~BIT(idx);
+ const u8 *addr = vif->addr;
+ struct {
+ u8 mode;
+ u8 force_clear;
+ u8 clear_bitmap[8];
+ u8 entry_count;
+ u8 write;
+ u8 band;
- tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_SYNC_MODE, sizeof(*sync));
+ u8 index;
+ u8 bssid;
+ u8 addr[ETH_ALEN];
+ } __packed req = {
+ .mode = !!mask || enable,
+ .entry_count = 1,
+ .write = 1,
+ .band = phy != &dev->phy,
+ .index = idx * 2 + bssid,
+ };
- sync = (struct bss_info_sync_mode *)tlv;
- sync->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
- sync->dtim_period = vif->bss_conf.dtim_period;
- sync->enable = true;
+ if (bssid)
+ addr = vif->bss_conf.bssid;
+
+ if (enable)
+ ether_addr_copy(req.addr, addr);
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MUAR_UPDATE, &req,
+ sizeof(req), true);
}
int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
@@ -1025,6 +982,9 @@ int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct sk_buff *skb;
+ if (mvif->omac_idx >= REPEATER_BSSID_START)
+ mt7915_mcu_muar_config(phy, vif, true, enable);
+
skb = mt7915_mcu_alloc_sta_req(phy->dev, mvif, NULL,
MT7915_BSS_UPDATE_MAX_SIZE);
if (IS_ERR(skb))
@@ -1045,14 +1005,13 @@ int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
if (vif->bss_conf.he_support)
mt7915_mcu_bss_he_tlv(skb, vif, phy);
- if (mvif->omac_idx > HW_BSSID_MAX)
+ if (mvif->omac_idx >= EXT_BSSID_START &&
+ mvif->omac_idx < REPEATER_BSSID_START)
mt7915_mcu_bss_ext_tlv(skb, mvif);
- else
- mt7915_mcu_bss_sync_tlv(skb, vif);
}
- return __mt76_mcu_skb_send_msg(&phy->dev->mt76, skb,
- MCU_EXT_CMD_BSS_INFO_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&phy->dev->mt76, skb,
+ MCU_EXT_CMD_BSS_INFO_UPDATE, true);
}
/** starec & wtbl **/
@@ -1133,8 +1092,8 @@ int mt7915_mcu_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif,
if (ret)
return ret;
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
}
static void
@@ -1213,8 +1172,8 @@ mt7915_mcu_sta_ba(struct mt7915_dev *dev,
&skb);
mt7915_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr);
- ret = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
if (ret)
return ret;
@@ -1225,8 +1184,8 @@ mt7915_mcu_sta_ba(struct mt7915_dev *dev,
mt7915_mcu_sta_ba_tlv(skb, params, enable, tx);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
}
int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
@@ -1508,9 +1467,7 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
muru = (struct sta_rec_muru *)tlv;
muru->cfg.ofdma_dl_en = true;
- muru->cfg.ofdma_ul_en = true;
muru->cfg.mimo_dl_en = true;
- muru->cfg.mimo_ul_en = true;
muru->ofdma_dl.punc_pream_rx =
HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
@@ -1563,8 +1520,8 @@ mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif,
/* starec muru */
mt7915_mcu_sta_muru_tlv(skb, sta);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
}
static void
@@ -1662,7 +1619,7 @@ mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht),
wtbl_tlv, sta_wtbl);
ht = (struct wtbl_ht *)tlv;
- ht->ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING;
+ ht->ldpc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING);
ht->af = sta->ht_cap.ampdu_factor;
ht->mm = sta->ht_cap.ampdu_density;
ht->ht = true;
@@ -1676,7 +1633,7 @@ mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht),
wtbl_tlv, sta_wtbl);
vht = (struct wtbl_vht *)tlv;
- vht->ldpc = sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC,
+ vht->ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
vht->vht = true;
af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
@@ -1688,6 +1645,53 @@ mt7915_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
mt7915_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_tlv);
}
+static void
+mt7915_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ void *sta_wtbl, void *wtbl_tlv)
+{
+ struct mt7915_sta *msta;
+ struct wtbl_hdr_trans *htr = NULL;
+ struct tlv *tlv;
+
+ tlv = mt7915_mcu_add_nested_tlv(skb, WTBL_HDR_TRANS, sizeof(*htr),
+ wtbl_tlv, sta_wtbl);
+ htr = (struct wtbl_hdr_trans *)tlv;
+ htr->no_rx_trans = true;
+ if (vif->type == NL80211_IFTYPE_STATION)
+ htr->to_ds = true;
+ else
+ htr->from_ds = true;
+
+ if (!sta)
+ return;
+
+ msta = (struct mt7915_sta *)sta->drv_priv;
+ if (test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags)) {
+ htr->to_ds = true;
+ htr->from_ds = true;
+ }
+}
+
+int mt7915_mcu_sta_update_hdr_trans(struct mt7915_dev *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct sk_buff *skb;
+
+ skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, MT7915_WTBL_UPDATE_MAX_SIZE);
+ if (!skb)
+ return -ENOMEM;
+
+ wtbl_hdr = mt7915_mcu_alloc_wtbl_req(dev, msta, WTBL_SET, NULL, &skb);
+ mt7915_mcu_wtbl_hdr_trans_tlv(skb, vif, sta, NULL, wtbl_hdr);
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD_WTBL_UPDATE,
+ true);
+}
+
int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
@@ -1708,8 +1712,8 @@ int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
&skb);
mt7915_mcu_wtbl_smps_tlv(skb, sta, sta_wtbl, wtbl_hdr);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
}
static void
@@ -2010,8 +2014,8 @@ mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif,
mt7915_mcu_sta_bfer_tlv(skb, sta, vif, phy, enable);
- r = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ r = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
if (r)
return r;
}
@@ -2026,8 +2030,8 @@ mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif,
mt7915_mcu_sta_bfee_tlv(skb, sta, phy);
- r = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ r = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
if (r)
return r;
}
@@ -2194,8 +2198,8 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta);
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
}
static int
@@ -2217,11 +2221,11 @@ mt7915_mcu_add_group(struct mt7915_dev *dev, struct ieee80211_vif *vif,
.action = cpu_to_le32(MT_STA_BSS_GROUP),
.wlan_idx_lo = to_wcid_lo(msta->wcid.idx),
.wlan_idx_hi = to_wcid_hi(msta->wcid.idx),
- .val = cpu_to_le32(mvif->idx),
+ .val = cpu_to_le32(mvif->idx % 16),
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_DRR_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_DRR_CTRL, &req,
+ sizeof(req), true);
}
int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif,
@@ -2277,12 +2281,13 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
sta_wtbl, &skb);
if (enable) {
mt7915_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr);
+ mt7915_mcu_wtbl_hdr_trans_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr);
if (sta)
mt7915_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr);
}
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
}
int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev,
@@ -2327,13 +2332,14 @@ int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev,
ra->phy.sgi = ra->phy.mcs * 15;
out:
- return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_EXT_CMD_STA_REC_UPDATE, true);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
}
-int mt7915_mcu_add_dev_info(struct mt7915_dev *dev,
+int mt7915_mcu_add_dev_info(struct mt7915_phy *phy,
struct ieee80211_vif *vif, bool enable)
{
+ struct mt7915_dev *dev = phy->dev;
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct {
struct req_hdr {
@@ -2365,9 +2371,12 @@ int mt7915_mcu_add_dev_info(struct mt7915_dev *dev,
},
};
+ if (mvif->omac_idx >= REPEATER_BSSID_START)
+ return mt7915_mcu_muar_config(phy, vif, false, enable);
+
memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE,
- &data, sizeof(data), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE,
+ &data, sizeof(data), true);
}
static void
@@ -2458,30 +2467,8 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw,
mt7915_mcu_beacon_cont(dev, rskb, skb, bcn, &offs);
dev_kfree_skb(skb);
- return __mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
- MCU_EXT_CMD_BSS_INFO_UPDATE, true);
-}
-
-static int mt7915_mcu_send_firmware(struct mt7915_dev *dev, const void *data,
- int len)
-{
- int ret = 0, cur_len;
-
- while (len > 0) {
- cur_len = min_t(int, 4096 - sizeof(struct mt7915_mcu_txd),
- len);
-
- ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER,
- data, cur_len, false);
- if (ret)
- break;
-
- data += cur_len;
- len -= cur_len;
- mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false);
- }
-
- return ret;
+ return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
+ MCU_EXT_CMD_BSS_INFO_UPDATE, true);
}
static int mt7915_mcu_start_firmware(struct mt7915_dev *dev, u32 addr,
@@ -2495,8 +2482,8 @@ static int mt7915_mcu_start_firmware(struct mt7915_dev *dev, u32 addr,
.addr = cpu_to_le32(addr),
};
- return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ, &req,
+ sizeof(req), true);
}
static int mt7915_mcu_restart(struct mt76_dev *dev)
@@ -2508,8 +2495,8 @@ static int mt7915_mcu_restart(struct mt76_dev *dev)
.power_mode = 1,
};
- return __mt76_mcu_send_msg(dev, -MCU_CMD_NIC_POWER_CTRL, &req,
- sizeof(req), false);
+ return mt76_mcu_send_msg(dev, -MCU_CMD_NIC_POWER_CTRL, &req,
+ sizeof(req), false);
}
static int mt7915_mcu_patch_sem_ctrl(struct mt7915_dev *dev, bool get)
@@ -2520,8 +2507,8 @@ static int mt7915_mcu_patch_sem_ctrl(struct mt7915_dev *dev, bool get)
.op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE),
};
- return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_SEM_CONTROL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_SEM_CONTROL, &req,
+ sizeof(req), true);
}
static int mt7915_mcu_start_patch(struct mt7915_dev *dev)
@@ -2533,8 +2520,8 @@ static int mt7915_mcu_start_patch(struct mt7915_dev *dev)
.check_crc = 0,
};
- return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_FINISH_REQ,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_FINISH_REQ, &req,
+ sizeof(req), true);
}
static int mt7915_driver_own(struct mt7915_dev *dev)
@@ -2570,7 +2557,7 @@ static int mt7915_mcu_init_download(struct mt7915_dev *dev, u32 addr,
else
attr = -MCU_CMD_TARGET_ADDRESS_LEN_REQ;
- return __mt76_mcu_send_msg(&dev->mt76, attr, &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, attr, &req, sizeof(req), true);
}
static int mt7915_load_patch(struct mt7915_dev *dev)
@@ -2629,7 +2616,8 @@ static int mt7915_load_patch(struct mt7915_dev *dev)
goto out;
}
- ret = mt7915_mcu_send_firmware(dev, dl, len);
+ ret = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER,
+ dl, len);
if (ret) {
dev_err(dev->mt76.dev, "Failed to send patch\n");
goto out;
@@ -2697,7 +2685,8 @@ mt7915_mcu_send_ram_firmware(struct mt7915_dev *dev,
return err;
}
- err = mt7915_mcu_send_firmware(dev, data + offset, len);
+ err = mt76_mcu_send_firmware(&dev->mt76, -MCU_CMD_FW_SCATTER,
+ data + offset, len);
if (err) {
dev_err(dev->mt76.dev, "Failed to send firmware.\n");
return err;
@@ -2810,7 +2799,7 @@ static int mt7915_load_firmware(struct mt7915_dev *dev)
return -EIO;
}
- mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false);
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);
dev_dbg(dev->mt76.dev, "Firmware init done\n");
@@ -2826,8 +2815,8 @@ int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 ctrl)
.ctrl_val = ctrl
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_LOG_2_HOST,
- &data, sizeof(data), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_LOG_2_HOST, &data,
+ sizeof(data), true);
}
int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level)
@@ -2835,7 +2824,7 @@ int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level)
struct {
u8 ver;
u8 pad;
- u16 len;
+ __le16 len;
u8 level;
u8 rsv[3];
__le32 module_idx;
@@ -2844,8 +2833,21 @@ int mt7915_mcu_fw_dbg_ctrl(struct mt7915_dev *dev, u32 module, u8 level)
.level = level,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_DBG_CTRL,
- &data, sizeof(data), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_FW_DBG_CTRL, &data,
+ sizeof(data), false);
+}
+
+static int mt7915_mcu_set_mwds(struct mt7915_dev *dev, bool enabled)
+{
+ struct {
+ u8 enable;
+ u8 _rsv[3];
+ } __packed req = {
+ .enable = enabled
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MWDS_SUPPORT, &req,
+ sizeof(req), false);
}
int mt7915_mcu_init(struct mt7915_dev *dev)
@@ -2853,12 +2855,12 @@ int mt7915_mcu_init(struct mt7915_dev *dev)
static const struct mt76_mcu_ops mt7915_mcu_ops = {
.headroom = sizeof(struct mt7915_mcu_txd),
.mcu_skb_send_msg = mt7915_mcu_send_message,
- .mcu_send_msg = mt7915_mcu_msg_send,
+ .mcu_parse_response = mt7915_mcu_parse_response,
.mcu_restart = mt7915_mcu_restart,
};
int ret;
- dev->mt76.mcu_ops = &mt7915_mcu_ops,
+ dev->mt76.mcu_ops = &mt7915_mcu_ops;
ret = mt7915_driver_own(dev);
if (ret)
@@ -2870,6 +2872,7 @@ int mt7915_mcu_init(struct mt7915_dev *dev)
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
mt7915_mcu_fw_log_2_host(dev, 0);
+ mt7915_mcu_set_mwds(dev, 1);
return 0;
}
@@ -2916,13 +2919,13 @@ int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band,
};
int ret;
- ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RX_HDR_TRANS,
- &req_trans, sizeof(req_trans), false);
+ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RX_HDR_TRANS,
+ &req_trans, sizeof(req_trans), false);
if (ret)
return ret;
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL,
- &req_mac, sizeof(req_mac), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_MAC_INIT_CTRL,
+ &req_mac, sizeof(req_mac), true);
}
int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable)
@@ -2937,8 +2940,8 @@ int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable)
.enable = enable + 1,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SCS_CTRL, &req,
- sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SCS_CTRL, &req,
+ sizeof(req), false);
}
int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val)
@@ -2957,8 +2960,8 @@ int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val)
.pkt_thresh = cpu_to_le32(0x2),
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PROTECT_CTRL, &req,
+ sizeof(req), true);
}
int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif)
@@ -3011,8 +3014,8 @@ int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif)
else
e->cw_max = cpu_to_le16(10);
}
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE, &req,
+ sizeof(req), true);
}
int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter)
@@ -3042,8 +3045,8 @@ int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter)
.band_idx = band,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL, &req,
+ sizeof(req), true);
}
int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev,
@@ -3063,57 +3066,106 @@ int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev,
.val = val,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL, &req,
+ sizeof(req), true);
}
int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val)
{
struct {
- u32 tag;
- u16 min_lpn;
+ __le32 tag;
+ __le16 min_lpn;
u8 rsv[2];
} __packed req = {
- .tag = 0x1,
- .min_lpn = val,
+ .tag = cpu_to_le32(0x1),
+ .min_lpn = cpu_to_le16(val),
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, &req,
+ sizeof(req), true);
}
int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev,
const struct mt7915_dfs_pulse *pulse)
{
struct {
- u32 tag;
- struct mt7915_dfs_pulse pulse;
+ __le32 tag;
+
+ __le32 max_width; /* us */
+ __le32 max_pwr; /* dbm */
+ __le32 min_pwr; /* dbm */
+ __le32 min_stgr_pri; /* us */
+ __le32 max_stgr_pri; /* us */
+ __le32 min_cr_pri; /* us */
+ __le32 max_cr_pri; /* us */
} __packed req = {
- .tag = 0x3,
+ .tag = cpu_to_le32(0x3),
+
+#define __req_field(field) .field = cpu_to_le32(pulse->field)
+ __req_field(max_width),
+ __req_field(max_pwr),
+ __req_field(min_pwr),
+ __req_field(min_stgr_pri),
+ __req_field(max_stgr_pri),
+ __req_field(min_cr_pri),
+ __req_field(max_cr_pri),
+#undef __req_field
};
- memcpy(&req.pulse, pulse, sizeof(*pulse));
-
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, &req,
+ sizeof(req), true);
}
int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index,
const struct mt7915_dfs_pattern *pattern)
{
struct {
- u32 tag;
- u16 radar_type;
- struct mt7915_dfs_pattern pattern;
+ __le32 tag;
+ __le16 radar_type;
+
+ u8 enb;
+ u8 stgr;
+ u8 min_crpn;
+ u8 max_crpn;
+ u8 min_crpr;
+ u8 min_pw;
+ u32 min_pri;
+ u32 max_pri;
+ u8 max_pw;
+ u8 min_crbn;
+ u8 max_crbn;
+ u8 min_stgpn;
+ u8 max_stgpn;
+ u8 min_stgpr;
+ u8 rsv[2];
+ u32 min_stgpr_diff;
} __packed req = {
- .tag = 0x2,
- .radar_type = index,
+ .tag = cpu_to_le32(0x2),
+ .radar_type = cpu_to_le16(index),
+
+#define __req_field_u8(field) .field = pattern->field
+#define __req_field_u32(field) .field = cpu_to_le32(pattern->field)
+ __req_field_u8(enb),
+ __req_field_u8(stgr),
+ __req_field_u8(min_crpn),
+ __req_field_u8(max_crpn),
+ __req_field_u8(min_crpr),
+ __req_field_u8(min_pw),
+ __req_field_u32(min_pri),
+ __req_field_u32(max_pri),
+ __req_field_u8(max_pw),
+ __req_field_u8(min_crbn),
+ __req_field_u8(max_crbn),
+ __req_field_u8(min_stgpn),
+ __req_field_u8(max_stgpn),
+ __req_field_u8(min_stgpr),
+ __req_field_u32(min_stgpr_diff),
+#undef __req_field_u8
+#undef __req_field_u32
};
- memcpy(&req.pattern, pattern, sizeof(*pattern));
-
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_TH, &req,
+ sizeof(req), true);
}
int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
@@ -3143,11 +3195,20 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
.center_ch = ieee80211_frequency_to_channel(freq1),
.bw = mt7915_mcu_chan_bw(chandef),
.tx_streams_num = hweight8(phy->mt76->antenna_mask),
- .rx_streams = phy->chainmask,
+ .rx_streams = phy->mt76->antenna_mask,
.band_idx = phy != &dev->phy,
.channel_band = chandef->chan->band,
};
+#ifdef CONFIG_NL80211_TESTMODE
+ if (dev->mt76.test.tx_antenna_mask &&
+ (dev->mt76.test.state == MT76_TM_STATE_TX_FRAMES ||
+ dev->mt76.test.state == MT76_TM_STATE_RX_FRAMES)) {
+ req.tx_streams_num = fls(dev->mt76.test.tx_antenna_mask);
+ req.rx_streams = dev->mt76.test.tx_antenna_mask;
+ }
+#endif
+
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) &&
@@ -3165,7 +3226,7 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
req.center_ch2 = ieee80211_frequency_to_channel(freq2);
}
- return __mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
}
int mt7915_mcu_set_eeprom(struct mt7915_dev *dev)
@@ -3179,8 +3240,8 @@ int mt7915_mcu_set_eeprom(struct mt7915_dev *dev)
.format = EE_FORMAT_WHOLE,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
+ &req, sizeof(req), true);
}
int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
@@ -3188,9 +3249,22 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
struct mt7915_mcu_eeprom_info req = {
.addr = cpu_to_le32(round_down(offset, 16)),
};
+ struct mt7915_mcu_eeprom_info *res;
+ struct sk_buff *skb;
+ int ret;
+ u8 *buf;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req,
+ sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ res = (struct mt7915_mcu_eeprom_info *)skb->data;
+ buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr);
+ memcpy(buf, res->data, 16);
+ dev_kfree_skb(skb);
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_ACCESS, &req,
- sizeof(req), true);
+ return 0;
}
int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index)
@@ -3205,11 +3279,11 @@ int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index)
.action = index,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_THERMAL_CTRL, &req,
- sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_THERMAL_CTRL, &req,
+ sizeof(req), true);
}
-int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx)
+int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx)
{
struct {
__le32 cmd;
@@ -3223,8 +3297,8 @@ int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx)
.dump_group = cpu_to_le16(1),
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RATE_CTRL, &req,
- sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_RATE_CTRL, &req,
+ sizeof(req), false);
}
int mt7915_mcu_set_sku(struct mt7915_phy *phy)
@@ -3251,9 +3325,31 @@ int mt7915_mcu_set_sku(struct mt7915_phy *phy)
for (i = 0; i < MT7915_SKU_RATE_NUM; i++)
req.val[i] = hw->conf.power_level * 2 + delta[i];
- return __mt76_mcu_send_msg(&dev->mt76,
- MCU_EXT_CMD_TX_POWER_FEATURE_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76,
+ MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, &req,
+ sizeof(req), true);
+}
+
+int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
+ u8 en)
+{
+ struct {
+ u8 test_mode_en;
+ u8 param_idx;
+ u8 _rsv[2];
+
+ u8 enable;
+ u8 _rsv2[3];
+
+ u8 pad[8];
+ } __packed req = {
+ .test_mode_en = test_mode,
+ .param_idx = param,
+ .enable = en,
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req,
+ sizeof(req), false);
}
int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
@@ -3270,9 +3366,9 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
.sku_enable = enable,
};
- return __mt76_mcu_send_msg(&dev->mt76,
- MCU_EXT_CMD_TX_POWER_FEATURE_CTRL,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76,
+ MCU_EXT_CMD_TX_POWER_FEATURE_CTRL, &req,
+ sizeof(req), true);
}
int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
@@ -3288,8 +3384,8 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
.band = band,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SER_TRIGGER,
- &req, sizeof(req), false);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SER_TRIGGER,
+ &req, sizeof(req), false);
}
int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev)
@@ -3306,8 +3402,8 @@ int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev)
.ibf = false,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXBF_ACTION,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXBF_ACTION, &req,
+ sizeof(req), true);
}
int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev)
@@ -3325,8 +3421,8 @@ int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev)
.snd_mode = MT_BF_PROCESSING,
};
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXBF_ACTION,
- &req, sizeof(req), true);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_TXBF_ACTION, &req,
+ sizeof(req), true);
}
int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif,
@@ -3342,14 +3438,112 @@ int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif,
u8 drop_tx_idx;
u8 sta_idx; /* 256 sta */
u8 rsv[2];
- u32 val;
+ __le32 val;
} __packed req = {
.action = MT_SPR_ENABLE,
.arg_num = 1,
.band_idx = mvif->band_idx,
- .val = enable,
+ .val = cpu_to_le32(enable),
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SPR, &req,
+ sizeof(req), true);
+}
+
+int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct rate_info *rate)
+{
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct mt7915_dev *dev = phy->dev;
+ struct mt76_phy *mphy = phy->mt76;
+ struct {
+ u8 category;
+ u8 band;
+ __le16 wcid;
+ } __packed req = {
+ .category = MCU_PHY_STATE_CONTENTION_RX_RATE,
+ .band = mvif->band_idx,
+ .wcid = cpu_to_le16(msta->wcid.idx),
};
+ struct ieee80211_supported_band *sband;
+ struct mt7915_mcu_phy_rx_info *res;
+ struct sk_buff *skb;
+ u16 flags = 0;
+ int ret;
+ int i;
+
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD_PHY_STAT_INFO,
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ res = (struct mt7915_mcu_phy_rx_info *)skb->data;
+
+ rate->mcs = res->rate;
+ rate->nss = res->nsts + 1;
+
+ switch (res->mode) {
+ case MT_PHY_TYPE_CCK:
+ case MT_PHY_TYPE_OFDM:
+ if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
+ sband = &mphy->sband_5g.sband;
+ else
+ sband = &mphy->sband_2g.sband;
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (rate->mcs != (sband->bitrates[i].hw_value & 0xf))
+ continue;
+
+ rate->legacy = sband->bitrates[i].bitrate;
+ break;
+ }
+ break;
+ case MT_PHY_TYPE_HT:
+ case MT_PHY_TYPE_HT_GF:
+ if (rate->mcs > 31)
+ return -EINVAL;
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_SPR,
- &req, sizeof(req), true);
+ flags |= RATE_INFO_FLAGS_MCS;
+
+ if (res->gi)
+ flags |= RATE_INFO_FLAGS_SHORT_GI;
+ break;
+ case MT_PHY_TYPE_VHT:
+ flags |= RATE_INFO_FLAGS_VHT_MCS;
+
+ if (res->gi)
+ flags |= RATE_INFO_FLAGS_SHORT_GI;
+ break;
+ case MT_PHY_TYPE_HE_SU:
+ case MT_PHY_TYPE_HE_EXT_SU:
+ case MT_PHY_TYPE_HE_TB:
+ case MT_PHY_TYPE_HE_MU:
+ rate->he_gi = res->gi;
+
+ flags |= RATE_INFO_FLAGS_HE_MCS;
+ break;
+ default:
+ break;
+ }
+ rate->flags = flags;
+
+ switch (res->bw) {
+ case IEEE80211_STA_RX_BW_160:
+ rate->bw = RATE_INFO_BW_160;
+ break;
+ case IEEE80211_STA_RX_BW_80:
+ rate->bw = RATE_INFO_BW_80;
+ break;
+ case IEEE80211_STA_RX_BW_40:
+ rate->bw = RATE_INFO_BW_40;
+ break;
+ default:
+ rate->bw = RATE_INFO_BW_20;
+ break;
+ }
+
+ dev_kfree_skb(skb);
+
+ return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index c656d66385c4..cd1a4256c843 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -46,6 +46,11 @@ enum {
MCU_EXT_EVENT_RATE_REPORT = 0x87,
};
+enum {
+ MCU_ATE_SET_TRX = 0x1,
+ MCU_ATE_SET_FREQ_OFFSET = 0xa,
+};
+
struct mt7915_mcu_rxd {
__le32 rxd[6];
@@ -153,6 +158,18 @@ struct mt7915_mcu_ra_info {
u8 prob_down_pending;
} __packed;
+
+struct mt7915_mcu_phy_rx_info {
+ u8 category;
+ u8 rate;
+ u8 mode;
+ u8 nsts;
+ u8 gi;
+ u8 coding;
+ u8 stbc;
+ u8 bw;
+};
+
#define MT_RA_RATE_NSS GENMASK(8, 6)
#define MT_RA_RATE_MCS GENMASK(3, 0)
#define MT_RA_RATE_TX_MODE GENMASK(12, 9)
@@ -201,19 +218,24 @@ enum {
MCU_EXT_CMD_EDCA_UPDATE = 0x27,
MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A,
MCU_EXT_CMD_THERMAL_CTRL = 0x2c,
+ MCU_EXT_CMD_WTBL_UPDATE = 0x32,
MCU_EXT_CMD_SET_DRR_CTRL = 0x36,
MCU_EXT_CMD_SET_RDD_CTRL = 0x3a,
+ MCU_EXT_CMD_ATE_CTRL = 0x3d,
MCU_EXT_CMD_PROTECT_CTRL = 0x3e,
MCU_EXT_CMD_MAC_INIT_CTRL = 0x46,
MCU_EXT_CMD_RX_HDR_TRANS = 0x47,
+ MCU_EXT_CMD_MUAR_UPDATE = 0x48,
MCU_EXT_CMD_SET_RX_PATH = 0x4e,
MCU_EXT_CMD_TX_POWER_FEATURE_CTRL = 0x58,
+ MCU_EXT_CMD_MWDS_SUPPORT = 0x80,
MCU_EXT_CMD_SET_SER_TRIGGER = 0x81,
MCU_EXT_CMD_SCS_CTRL = 0x82,
MCU_EXT_CMD_RATE_CTRL = 0x87,
MCU_EXT_CMD_FW_DBG_CTRL = 0x95,
MCU_EXT_CMD_SET_RDD_TH = 0x9d,
MCU_EXT_CMD_SET_SPR = 0xa8,
+ MCU_EXT_CMD_PHY_STAT_INFO = 0xad,
};
enum {
@@ -247,6 +269,14 @@ enum {
EE_FORMAT_MULTIPLE,
};
+enum {
+ MCU_PHY_STATE_TX_RATE,
+ MCU_PHY_STATE_RX_RATE,
+ MCU_PHY_STATE_RSSI,
+ MCU_PHY_STATE_CONTENTION_RX_RATE,
+ MCU_PHY_STATE_OFDMLQ_CNINFO,
+};
+
#define STA_TYPE_STA BIT(0)
#define STA_TYPE_AP BIT(1)
#define STA_TYPE_ADHOC BIT(2)
@@ -354,15 +384,6 @@ struct bss_info_ext_bss {
u8 rsv[8];
} __packed;
-struct bss_info_sync_mode {
- __le16 tag;
- __le16 len;
- __le16 bcn_interval;
- u8 enable;
- u8 dtim_period;
- u8 rsv[8];
-} __packed;
-
struct bss_info_bmc_rate {
__le16 tag;
__le16 len;
@@ -480,7 +501,7 @@ enum {
BSS_INFO_LQ_RM, /* obsoleted */
BSS_INFO_EXT_BSS,
BSS_INFO_BMC_RATE, /* for bmc rate control in CR4 */
- BSS_INFO_SYNC_MODE,
+ BSS_INFO_SYNC_MODE, /* obsoleted */
BSS_INFO_RA,
BSS_INFO_HW_AMSDU,
BSS_INFO_BSS_COLOR,
@@ -551,6 +572,15 @@ struct wtbl_vht {
u8 rsv[4];
} __packed;
+struct wtbl_hdr_trans {
+ __le16 tag;
+ __le16 len;
+ u8 to_ds;
+ u8 from_ds;
+ u8 no_rx_trans;
+ u8 _rsv;
+};
+
enum {
MT_BA_TYPE_INVALID,
MT_BA_TYPE_ORIGINATOR,
@@ -972,6 +1002,7 @@ enum {
sizeof(struct wtbl_rx) + \
sizeof(struct wtbl_ht) + \
sizeof(struct wtbl_vht) + \
+ sizeof(struct wtbl_hdr_trans) +\
sizeof(struct wtbl_ba) + \
sizeof(struct wtbl_smps))
@@ -997,8 +1028,7 @@ enum {
sizeof(struct bss_info_hw_amsdu) +\
sizeof(struct bss_info_he) + \
sizeof(struct bss_info_bmc_rate) +\
- sizeof(struct bss_info_ext_bss) +\
- sizeof(struct bss_info_sync_mode))
+ sizeof(struct bss_info_ext_bss))
#define MT7915_BEACON_UPDATE_SIZE (sizeof(struct sta_req_hdr) + \
sizeof(struct bss_info_bcn_csa) + \
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index 4b8908fa7eda..0339abf360d3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -9,7 +9,7 @@
#include "../mt76.h"
#include "regs.h"
-#define MT7915_MAX_INTERFACES 4
+#define MT7915_MAX_INTERFACES 32
#define MT7915_MAX_WMM_SETS 4
#define MT7915_WTBL_SIZE 288
#define MT7915_WTBL_RESERVED (MT7915_WTBL_SIZE - 1)
@@ -32,6 +32,7 @@
#define MT7915_EEPROM_SIZE 3584
#define MT7915_TOKEN_SIZE 8192
+#define MT7915_TOKEN_FREE_THR 64
#define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7915_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
@@ -112,8 +113,10 @@ struct mt7915_phy {
struct ieee80211_sband_iftype_data iftype[2][NUM_NL80211_IFTYPES];
+ struct ieee80211_vif *monitor_vif;
+
u32 rxfilter;
- u32 omac_mask;
+ u64 omac_mask;
u16 noise;
u16 chainmask;
@@ -159,11 +162,27 @@ struct mt7915_dev {
u32 hw_pattern;
spinlock_t token_lock;
+ int token_count;
struct idr token;
s8 **rate_power; /* TODO: use mt76_rate_power */
+ bool dbdc_support;
bool fw_debug;
+
+#ifdef CONFIG_NL80211_TESTMODE
+ struct {
+ u32 *reg_backup;
+
+ s32 last_freq_offset;
+ u8 last_rcpi[4];
+ s8 last_ib_rssi[4];
+ s8 last_wb_rssi[4];
+ u8 last_snr;
+
+ u8 spe_idx;
+ } test;
+#endif
};
enum {
@@ -171,24 +190,13 @@ enum {
HW_BSSID_1,
HW_BSSID_2,
HW_BSSID_3,
- HW_BSSID_MAX,
+ HW_BSSID_MAX = HW_BSSID_3,
EXT_BSSID_START = 0x10,
EXT_BSSID_1,
- EXT_BSSID_2,
- EXT_BSSID_3,
- EXT_BSSID_4,
- EXT_BSSID_5,
- EXT_BSSID_6,
- EXT_BSSID_7,
- EXT_BSSID_8,
- EXT_BSSID_9,
- EXT_BSSID_10,
- EXT_BSSID_11,
- EXT_BSSID_12,
- EXT_BSSID_13,
- EXT_BSSID_14,
- EXT_BSSID_15,
- EXT_BSSID_END
+ EXT_BSSID_15 = 0x1f,
+ EXT_BSSID_MAX = EXT_BSSID_15,
+ REPEATER_BSSID_START = 0x20,
+ REPEATER_BSSID_MAX = 0x3f,
};
enum {
@@ -264,15 +272,14 @@ static inline u8 mt7915_lmac_mapping(struct mt7915_dev *dev, u8 ac)
extern const struct ieee80211_ops mt7915_ops;
extern struct pci_driver mt7915_pci_driver;
+extern const struct mt76_testmode_ops mt7915_testmode_ops;
u32 mt7915_reg_map(struct mt7915_dev *dev, u32 addr);
int mt7915_register_device(struct mt7915_dev *dev);
void mt7915_unregister_device(struct mt7915_dev *dev);
-int mt7915_register_ext_phy(struct mt7915_dev *dev);
-void mt7915_unregister_ext_phy(struct mt7915_dev *dev);
int mt7915_eeprom_init(struct mt7915_dev *dev);
-u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset);
+void mt7915_eeprom_parse_band_config(struct mt7915_phy *phy);
int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
struct ieee80211_channel *chan,
u8 chain_idx);
@@ -281,7 +288,7 @@ int mt7915_dma_init(struct mt7915_dev *dev);
void mt7915_dma_prefetch(struct mt7915_dev *dev);
void mt7915_dma_cleanup(struct mt7915_dev *dev);
int mt7915_mcu_init(struct mt7915_dev *dev);
-int mt7915_mcu_add_dev_info(struct mt7915_dev *dev,
+int mt7915_mcu_add_dev_info(struct mt7915_phy *phy,
struct ieee80211_vif *vif, bool enable);
int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
struct ieee80211_vif *vif, int enable);
@@ -289,6 +296,9 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable);
int mt7915_mcu_add_sta_adv(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable);
+int mt7915_mcu_sta_update_hdr_trans(struct mt7915_dev *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
struct ieee80211_ampdu_params *params,
bool add);
@@ -306,6 +316,7 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
+int mt7915_set_channel(struct mt7915_phy *phy);
int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd);
int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif);
int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev,
@@ -314,6 +325,8 @@ int mt7915_mcu_set_eeprom(struct mt7915_dev *dev);
int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset);
int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable,
bool hdr_trans);
+int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
+ u8 en);
int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable);
int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band);
int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val);
@@ -327,8 +340,10 @@ int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev,
const struct mt7915_dfs_pulse *pulse);
int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index,
const struct mt7915_dfs_pattern *pattern);
-int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx);
int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index);
+int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx);
+int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct rate_info *rate);
int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd,
u8 index, u8 rx_sel, u8 val);
int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 ctrl);
@@ -428,11 +443,13 @@ mt7915_l2_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val)
bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask);
void mt7915_mac_reset_counters(struct mt7915_phy *phy);
void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy);
+void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy);
void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, bool beacon);
void mt7915_mac_set_timing(struct mt7915_phy *phy);
int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb);
+void mt7915_mac_fill_rx_vector(struct mt7915_dev *dev, struct sk_buff *skb);
void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb);
int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
@@ -446,6 +463,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
+int mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc);
void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
index fe62b4d853e4..aeb86fbea41c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
@@ -21,8 +21,14 @@ static void
mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
{
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
+ static const u32 rx_irq_mask[] = {
+ [MT_RXQ_MAIN] = MT_INT_RX_DONE_DATA0,
+ [MT_RXQ_EXT] = MT_INT_RX_DONE_DATA1,
+ [MT_RXQ_MCU] = MT_INT_RX_DONE_WM,
+ [MT_RXQ_MCU_WA] = MT_INT_RX_DONE_WA,
+ };
- mt7915_irq_enable(dev, MT_INT_RX_DONE(q));
+ mt7915_irq_enable(dev, rx_irq_mask[q]);
}
/* TODO: support 2/4/6/8 MSI-X vectors */
@@ -49,14 +55,17 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
if (intr & MT_INT_TX_DONE_MCU)
napi_schedule(&dev->mt76.tx_napi);
- if (intr & MT_INT_RX_DONE_DATA)
- napi_schedule(&dev->mt76.napi[0]);
+ if (intr & MT_INT_RX_DONE_DATA0)
+ napi_schedule(&dev->mt76.napi[MT_RXQ_MAIN]);
+
+ if (intr & MT_INT_RX_DONE_DATA1)
+ napi_schedule(&dev->mt76.napi[MT_RXQ_EXT]);
if (intr & MT_INT_RX_DONE_WM)
- napi_schedule(&dev->mt76.napi[1]);
+ napi_schedule(&dev->mt76.napi[MT_RXQ_MCU]);
if (intr & MT_INT_RX_DONE_WA)
- napi_schedule(&dev->mt76.napi[2]);
+ napi_schedule(&dev->mt76.napi[MT_RXQ_MCU_WA]);
if (intr & MT_INT_MCU_CMD) {
u32 val = mt76_rr(dev, MT_MCU_CMD);
@@ -140,7 +149,7 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
dev = container_of(mdev, struct mt7915_dev, mt76);
ret = mt7915_alloc_device(pdev, dev);
if (ret)
- return ret;
+ goto error;
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
mdev->rev = (mt7915_l1_rr(dev, MT_HW_CHIPID) << 16) |
@@ -163,7 +172,8 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
return 0;
error:
- ieee80211_free_hw(mt76_hw(dev));
+ mt76_free_device(&dev->mt76);
+
return ret;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
index 64327153b7fa..848703e6eb7c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
@@ -51,6 +51,9 @@
#define MT_WF_TMAC_BASE(_band) ((_band) ? 0xa1000 : 0x21000)
#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs))
+#define MT_TMAC_TCR0(_band) MT_WF_TMAC(_band, 0)
+#define MT_TMAC_TCR0_TBTT_STOP_CTRL BIT(25)
+
#define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, 0x090)
#define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, 0x094)
#define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0)
@@ -67,11 +70,13 @@
#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17)
#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18)
-/* DMA Band 0 */
-#define MT_WF_DMA_BASE 0x21e00
-#define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs))
+#define MT_TMAC_TRCR0(_band) MT_WF_TMAC(_band, 0x09c)
+#define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0)
+
+#define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00)
+#define MT_WF_DMA(_band, ofs) (MT_WF_DMA_BASE(_band) + (ofs))
-#define MT_DMA_DCR0 MT_WF_DMA(0x000)
+#define MT_DMA_DCR0(_band) MT_WF_DMA(_band, 0x000)
#define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3)
#define MT_DMA_DCR0_RXD_G5_EN BIT(23)
@@ -166,10 +171,33 @@
#define MT_WF_AGG_BASE(_band) ((_band) ? 0xa0800 : 0x20800)
#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs))
+#define MT_AGG_AWSCR0(_band, _n) MT_WF_AGG(_band, 0x05c + (_n) * 4)
+#define MT_AGG_PCR0(_band, _n) MT_WF_AGG(_band, 0x06c + (_n) * 4)
+#define MT_AGG_PCR0_MM_PROT BIT(0)
+#define MT_AGG_PCR0_GF_PROT BIT(1)
+#define MT_AGG_PCR0_BW20_PROT BIT(2)
+#define MT_AGG_PCR0_BW40_PROT BIT(4)
+#define MT_AGG_PCR0_BW80_PROT BIT(6)
+#define MT_AGG_PCR0_ERP_PROT GENMASK(12, 8)
+#define MT_AGG_PCR0_VHT_PROT BIT(13)
+#define MT_AGG_PCR0_PTA_WIN_DIS BIT(15)
+
+#define MT_AGG_PCR1_RTS0_NUM_THRES GENMASK(31, 23)
+#define MT_AGG_PCR1_RTS0_LEN_THRES GENMASK(19, 0)
+
#define MT_AGG_ACR0(_band) MT_WF_AGG(_band, 0x084)
#define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0)
#define MT_AGG_ACR_BAR_RATE GENMASK(29, 16)
+#define MT_AGG_MRCR(_band) MT_WF_AGG(_band, 0x098)
+#define MT_AGG_MRCR_BAR_CNT_LIMIT GENMASK(15, 12)
+#define MT_AGG_MRCR_LAST_RTS_CTS_RN BIT(6)
+#define MT_AGG_MRCR_RTS_FAIL_LIMIT GENMASK(11, 7)
+#define MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT GENMASK(28, 24)
+
+#define MT_AGG_ATCR1(_band) MT_WF_AGG(_band, 0x0f0)
+#define MT_AGG_ATCR3(_band) MT_WF_AGG(_band, 0x0f4)
+
/* ARB: band 0(0x20c00), band 1(0xa0c00) */
#define MT_WF_ARB_BASE(_band) ((_band) ? 0xa0c00 : 0x20c00)
#define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs))
@@ -178,6 +206,8 @@
#define MT_ARB_SCR_TX_DISABLE BIT(8)
#define MT_ARB_SCR_RX_DISABLE BIT(9)
+#define MT_ARB_DRNGR0(_band, _n) MT_WF_ARB(_band, 0x194 + (_n) * 4)
+
/* RMAC: band 0(0x21400), band 1(0xa1400) */
#define MT_WF_RMAC_BASE(_band) ((_band) ? 0xa1400 : 0x21400)
#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))
@@ -308,11 +338,11 @@
#define MT_INT_SOURCE_CSR MT_WFDMA_EXT_CSR(0x10)
#define MT_INT_MASK_CSR MT_WFDMA_EXT_CSR(0x14)
-#define MT_INT_RX_DONE_DATA BIT(16)
+#define MT_INT_RX_DONE_DATA0 BIT(16)
+#define MT_INT_RX_DONE_DATA1 BIT(17)
#define MT_INT_RX_DONE_WM BIT(0)
#define MT_INT_RX_DONE_WA BIT(1)
-#define MT_INT_RX_DONE(_n) ((_n) ? BIT((_n) - 1) : BIT(16))
-#define MT_INT_RX_DONE_ALL (BIT(0) | BIT(1) | BIT(16))
+#define MT_INT_RX_DONE_ALL (BIT(0) | BIT(1) | GENMASK(17, 16))
#define MT_INT_TX_DONE_MCU_WA BIT(15)
#define MT_INT_TX_DONE_FWDL BIT(26)
#define MT_INT_TX_DONE_MCU_WM BIT(27)
@@ -385,11 +415,19 @@
#define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs))
#define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188)
+#define MT_WF_IRPI_BASE 0x83006000
+#define MT_WF_IRPI(ofs) (MT_WF_IRPI_BASE + ((ofs) << 16))
+
/* PHY: band 0(0x83080000), band 1(0x83090000) */
#define MT_WF_PHY_BASE 0x83080000
#define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs))
#define MT_WF_PHY_RX_CTRL1(_phy) MT_WF_PHY(0x2004 + ((_phy) << 16))
+#define MT_WF_PHY_RX_CTRL1_IPI_EN GENMASK(2, 0)
#define MT_WF_PHY_RX_CTRL1_STSCNT_EN GENMASK(11, 9)
+#define MT_WF_PHY_RXTD12(_phy) MT_WF_PHY(0x8230 + ((_phy) << 16))
+#define MT_WF_PHY_RXTD12_IRPI_SW_CLR_ONLY BIT(18)
+#define MT_WF_PHY_RXTD12_IRPI_SW_CLR BIT(29)
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
new file mode 100644
index 000000000000..9ee82e2d262c
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2020 MediaTek Inc. */
+
+#include "mt7915.h"
+#include "mac.h"
+#include "mcu.h"
+#include "testmode.h"
+
+enum {
+ TM_CHANGED_TXPOWER,
+ TM_CHANGED_FREQ_OFFSET,
+
+ /* must be last */
+ NUM_TM_CHANGED
+};
+
+static const u8 tm_change_map[] = {
+ [TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER,
+ [TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET,
+};
+
+struct reg_band {
+ u32 band[2];
+};
+
+#define REG_BAND(_reg) \
+ { .band[0] = MT_##_reg(0), .band[1] = MT_##_reg(1) }
+#define REG_BAND_IDX(_reg, _idx) \
+ { .band[0] = MT_##_reg(0, _idx), .band[1] = MT_##_reg(1, _idx) }
+
+static const struct reg_band reg_backup_list[] = {
+ REG_BAND_IDX(AGG_PCR0, 0),
+ REG_BAND_IDX(AGG_PCR0, 1),
+ REG_BAND_IDX(AGG_AWSCR0, 0),
+ REG_BAND_IDX(AGG_AWSCR0, 1),
+ REG_BAND_IDX(AGG_AWSCR0, 2),
+ REG_BAND_IDX(AGG_AWSCR0, 3),
+ REG_BAND(AGG_MRCR),
+ REG_BAND(TMAC_TFCR0),
+ REG_BAND(TMAC_TCR0),
+ REG_BAND(AGG_ATCR1),
+ REG_BAND(AGG_ATCR3),
+ REG_BAND(TMAC_TRCR0),
+ REG_BAND(TMAC_ICR0),
+ REG_BAND_IDX(ARB_DRNGR0, 0),
+ REG_BAND_IDX(ARB_DRNGR0, 1),
+ REG_BAND(WF_RFCR),
+ REG_BAND(WF_RFCR1),
+};
+
+static int
+mt7915_tm_set_tx_power(struct mt7915_phy *phy)
+{
+ struct mt7915_dev *dev = phy->dev;
+ struct mt76_phy *mphy = phy->mt76;
+ struct cfg80211_chan_def *chandef = &mphy->chandef;
+ int freq = chandef->center_freq1;
+ int ret;
+ struct {
+ u8 format_id;
+ u8 dbdc_idx;
+ s8 tx_power;
+ u8 ant_idx; /* Only 0 is valid */
+ u8 center_chan;
+ u8 rsv[3];
+ } __packed req = {
+ .format_id = 0xf,
+ .dbdc_idx = phy != &dev->phy,
+ .center_chan = ieee80211_frequency_to_channel(freq),
+ };
+ u8 *tx_power = NULL;
+
+ if (dev->mt76.test.state != MT76_TM_STATE_OFF)
+ tx_power = dev->mt76.test.tx_power;
+
+ /* Tx power of the other antennas are the same as antenna 0 */
+ if (tx_power && tx_power[0])
+ req.tx_power = tx_power[0];
+
+ ret = mt76_mcu_send_msg(&dev->mt76,
+ MCU_EXT_CMD_TX_POWER_FEATURE_CTRL,
+ &req, sizeof(req), false);
+
+ return ret;
+}
+
+static int
+mt7915_tm_set_freq_offset(struct mt7915_dev *dev, bool en, u32 val)
+{
+ struct mt7915_tm_cmd req = {
+ .testmode_en = en,
+ .param_idx = MCU_ATE_SET_FREQ_OFFSET,
+ .param.freq.freq_offset = cpu_to_le32(val),
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req,
+ sizeof(req), false);
+}
+
+static int
+mt7915_tm_mode_ctrl(struct mt7915_dev *dev, bool enable)
+{
+ struct {
+ u8 format_id;
+ bool enable;
+ u8 rsv[2];
+ } __packed req = {
+ .format_id = 0x6,
+ .enable = enable,
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76,
+ MCU_EXT_CMD_TX_POWER_FEATURE_CTRL,
+ &req, sizeof(req), false);
+}
+
+static int
+mt7915_tm_set_trx(struct mt7915_dev *dev, struct mt7915_phy *phy,
+ int type, bool en)
+{
+ struct mt7915_tm_cmd req = {
+ .testmode_en = 1,
+ .param_idx = MCU_ATE_SET_TRX,
+ .param.trx.type = type,
+ .param.trx.enable = en,
+ .param.trx.band = phy != &dev->phy,
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_ATE_CTRL, &req,
+ sizeof(req), false);
+}
+
+static void
+mt7915_tm_reg_backup_restore(struct mt7915_dev *dev, struct mt7915_phy *phy)
+{
+ int n_regs = ARRAY_SIZE(reg_backup_list);
+ bool ext_phy = phy != &dev->phy;
+ u32 *b = dev->test.reg_backup;
+ int i;
+
+ if (dev->mt76.test.state == MT76_TM_STATE_OFF) {
+ for (i = 0; i < n_regs; i++)
+ mt76_wr(dev, reg_backup_list[i].band[ext_phy], b[i]);
+ return;
+ }
+
+ if (b)
+ return;
+
+ b = devm_kzalloc(dev->mt76.dev, 4 * n_regs, GFP_KERNEL);
+ if (!b)
+ return;
+
+ dev->test.reg_backup = b;
+ for (i = 0; i < n_regs; i++)
+ b[i] = mt76_rr(dev, reg_backup_list[i].band[ext_phy]);
+
+ mt76_clear(dev, MT_AGG_PCR0(ext_phy, 0), MT_AGG_PCR0_MM_PROT |
+ MT_AGG_PCR0_GF_PROT | MT_AGG_PCR0_ERP_PROT |
+ MT_AGG_PCR0_VHT_PROT | MT_AGG_PCR0_BW20_PROT |
+ MT_AGG_PCR0_BW40_PROT | MT_AGG_PCR0_BW80_PROT);
+ mt76_set(dev, MT_AGG_PCR0(ext_phy, 0), MT_AGG_PCR0_PTA_WIN_DIS);
+
+ mt76_wr(dev, MT_AGG_PCR0(ext_phy, 1), MT_AGG_PCR1_RTS0_NUM_THRES |
+ MT_AGG_PCR1_RTS0_LEN_THRES);
+
+ mt76_clear(dev, MT_AGG_MRCR(ext_phy), MT_AGG_MRCR_BAR_CNT_LIMIT |
+ MT_AGG_MRCR_LAST_RTS_CTS_RN | MT_AGG_MRCR_RTS_FAIL_LIMIT |
+ MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT);
+
+ mt76_rmw(dev, MT_AGG_MRCR(ext_phy), MT_AGG_MRCR_RTS_FAIL_LIMIT |
+ MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT,
+ FIELD_PREP(MT_AGG_MRCR_RTS_FAIL_LIMIT, 1) |
+ FIELD_PREP(MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT, 1));
+
+ mt76_wr(dev, MT_TMAC_TFCR0(ext_phy), 0);
+ mt76_clear(dev, MT_TMAC_TCR0(ext_phy), MT_TMAC_TCR0_TBTT_STOP_CTRL);
+
+ /* config rx filter for testmode rx */
+ mt76_wr(dev, MT_WF_RFCR(ext_phy), 0xcf70a);
+ mt76_wr(dev, MT_WF_RFCR1(ext_phy), 0);
+}
+
+static void
+mt7915_tm_init(struct mt7915_dev *dev)
+{
+ bool en = !(dev->mt76.test.state == MT76_TM_STATE_OFF);
+
+ if (!test_bit(MT76_STATE_RUNNING, &dev->phy.mt76->state))
+ return;
+
+ mt7915_tm_mode_ctrl(dev, en);
+ mt7915_tm_reg_backup_restore(dev, &dev->phy);
+ mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_TXRX, !en);
+}
+
+static void
+mt7915_tm_set_tx_frames(struct mt7915_dev *dev, bool en)
+{
+ static const u8 spe_idx_map[] = {0, 0, 1, 0, 3, 2, 4, 0,
+ 9, 8, 6, 10, 16, 12, 18, 0};
+ struct sk_buff *skb = dev->mt76.test.tx_skb;
+ struct ieee80211_tx_info *info;
+
+ mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_RX_RXV, false);
+
+ if (en) {
+ u8 tx_ant = dev->mt76.test.tx_antenna_mask;
+
+ mutex_unlock(&dev->mt76.mutex);
+ mt7915_set_channel(&dev->phy);
+ mutex_lock(&dev->mt76.mutex);
+
+ mt7915_mcu_set_chan_info(&dev->phy, MCU_EXT_CMD_SET_RX_PATH);
+ dev->test.spe_idx = spe_idx_map[tx_ant];
+ }
+
+ mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_TX, en);
+
+ if (!en || !skb)
+ return;
+
+ info = IEEE80211_SKB_CB(skb);
+ info->control.vif = dev->phy.monitor_vif;
+}
+
+static void
+mt7915_tm_set_rx_frames(struct mt7915_dev *dev, bool en)
+{
+ if (en) {
+ mutex_unlock(&dev->mt76.mutex);
+ mt7915_set_channel(&dev->phy);
+ mutex_lock(&dev->mt76.mutex);
+
+ mt7915_mcu_set_chan_info(&dev->phy, MCU_EXT_CMD_SET_RX_PATH);
+ }
+
+ mt7915_tm_set_trx(dev, &dev->phy, TM_MAC_RX_RXV, en);
+}
+
+static void
+mt7915_tm_update_params(struct mt7915_dev *dev, u32 changed)
+{
+ struct mt76_testmode_data *td = &dev->mt76.test;
+ bool en = dev->mt76.test.state != MT76_TM_STATE_OFF;
+
+ if (changed & BIT(TM_CHANGED_FREQ_OFFSET))
+ mt7915_tm_set_freq_offset(dev, en, en ? td->freq_offset : 0);
+ if (changed & BIT(TM_CHANGED_TXPOWER))
+ mt7915_tm_set_tx_power(&dev->phy);
+}
+
+static int
+mt7915_tm_set_state(struct mt76_dev *mdev, enum mt76_testmode_state state)
+{
+ struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
+ struct mt76_testmode_data *td = &mdev->test;
+ enum mt76_testmode_state prev_state = td->state;
+
+ mdev->test.state = state;
+
+ if (prev_state == MT76_TM_STATE_TX_FRAMES)
+ mt7915_tm_set_tx_frames(dev, false);
+ else if (state == MT76_TM_STATE_TX_FRAMES)
+ mt7915_tm_set_tx_frames(dev, true);
+ else if (prev_state == MT76_TM_STATE_RX_FRAMES)
+ mt7915_tm_set_rx_frames(dev, false);
+ else if (state == MT76_TM_STATE_RX_FRAMES)
+ mt7915_tm_set_rx_frames(dev, true);
+ else if (prev_state == MT76_TM_STATE_OFF || state == MT76_TM_STATE_OFF)
+ mt7915_tm_init(dev);
+
+ if ((state == MT76_TM_STATE_IDLE &&
+ prev_state == MT76_TM_STATE_OFF) ||
+ (state == MT76_TM_STATE_OFF &&
+ prev_state == MT76_TM_STATE_IDLE)) {
+ u32 changed = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
+ u16 cur = tm_change_map[i];
+
+ if (td->param_set[cur / 32] & BIT(cur % 32))
+ changed |= BIT(i);
+ }
+
+ mt7915_tm_update_params(dev, changed);
+ }
+
+ return 0;
+}
+
+static int
+mt7915_tm_set_params(struct mt76_dev *mdev, struct nlattr **tb,
+ enum mt76_testmode_state new_state)
+{
+ struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
+ struct mt76_testmode_data *td = &dev->mt76.test;
+ u32 changed = 0;
+ int i;
+
+ BUILD_BUG_ON(NUM_TM_CHANGED >= 32);
+
+ if (new_state == MT76_TM_STATE_OFF ||
+ td->state == MT76_TM_STATE_OFF)
+ return 0;
+
+ if (td->tx_antenna_mask & ~dev->phy.chainmask)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
+ if (tb[tm_change_map[i]])
+ changed |= BIT(i);
+ }
+
+ mt7915_tm_update_params(dev, changed);
+
+ return 0;
+}
+
+static int
+mt7915_tm_dump_stats(struct mt76_dev *mdev, struct sk_buff *msg)
+{
+ struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
+ void *rx, *rssi;
+ int i;
+
+ rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX);
+ if (!rx)
+ return -ENOMEM;
+
+ if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, dev->test.last_freq_offset))
+ return -ENOMEM;
+
+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI);
+ if (!rssi)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(dev->test.last_rcpi); i++)
+ if (nla_put_u8(msg, i, dev->test.last_rcpi[i]))
+ return -ENOMEM;
+
+ nla_nest_end(msg, rssi);
+
+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_IB_RSSI);
+ if (!rssi)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(dev->test.last_ib_rssi); i++)
+ if (nla_put_s8(msg, i, dev->test.last_ib_rssi[i]))
+ return -ENOMEM;
+
+ nla_nest_end(msg, rssi);
+
+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_WB_RSSI);
+ if (!rssi)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(dev->test.last_wb_rssi); i++)
+ if (nla_put_s8(msg, i, dev->test.last_wb_rssi[i]))
+ return -ENOMEM;
+
+ nla_nest_end(msg, rssi);
+
+ if (nla_put_u8(msg, MT76_TM_RX_ATTR_SNR, dev->test.last_snr))
+ return -ENOMEM;
+
+ nla_nest_end(msg, rx);
+
+ return 0;
+}
+
+const struct mt76_testmode_ops mt7915_testmode_ops = {
+ .set_state = mt7915_tm_set_state,
+ .set_params = mt7915_tm_set_params,
+ .dump_stats = mt7915_tm_dump_stats,
+};
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h
new file mode 100644
index 000000000000..964f2d7fde3a
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: ISC
+/* Copyright (C) 2020 MediaTek Inc. */
+
+#ifndef __MT7915_TESTMODE_H
+#define __MT7915_TESTMODE_H
+
+struct mt7915_tm_trx {
+ u8 type;
+ u8 enable;
+ u8 band;
+ u8 rsv;
+};
+
+struct mt7915_tm_freq_offset {
+ u8 band;
+ __le32 freq_offset;
+};
+
+struct mt7915_tm_cmd {
+ u8 testmode_en;
+ u8 param_idx;
+ u8 _rsv[2];
+ union {
+ __le32 data;
+ struct mt7915_tm_trx trx;
+ struct mt7915_tm_freq_offset freq;
+ u8 test[72];
+ } param;
+} __packed;
+
+enum {
+ TM_MAC_TX = 1,
+ TM_MAC_RX,
+ TM_MAC_TXRX,
+ TM_MAC_TXRX_RXV,
+ TM_MAC_RXV,
+ TM_MAC_RX_RXV,
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c
index 9a4d95a2a707..62b5b912818f 100644
--- a/drivers/net/wireless/mediatek/mt76/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/sdio.c
@@ -36,46 +36,49 @@ mt76s_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid)
return 0;
}
-static int mt76s_alloc_tx(struct mt76_dev *dev)
+static struct mt76_queue *mt76s_alloc_tx_queue(struct mt76_dev *dev)
{
struct mt76_queue *q;
- int i;
-
- for (i = 0; i < MT_TXQ_MCU_WA; i++) {
- q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL);
- if (!q)
- return -ENOMEM;
- spin_lock_init(&q->lock);
- q->hw_idx = i;
- dev->q_tx[i] = q;
+ q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL);
+ if (!q)
+ return ERR_PTR(-ENOMEM);
- q->entry = devm_kcalloc(dev->dev,
- MT_NUM_TX_ENTRIES, sizeof(*q->entry),
- GFP_KERNEL);
- if (!q->entry)
- return -ENOMEM;
+ spin_lock_init(&q->lock);
+ q->entry = devm_kcalloc(dev->dev,
+ MT_NUM_TX_ENTRIES, sizeof(*q->entry),
+ GFP_KERNEL);
+ if (!q->entry)
+ return ERR_PTR(-ENOMEM);
- q->ndesc = MT_NUM_TX_ENTRIES;
- }
+ q->ndesc = MT_NUM_TX_ENTRIES;
- return 0;
+ return q;
}
-void mt76s_stop_txrx(struct mt76_dev *dev)
+static int mt76s_alloc_tx(struct mt76_dev *dev)
{
- struct mt76_sdio *sdio = &dev->sdio;
+ struct mt76_queue *q;
+ int i;
- cancel_work_sync(&sdio->tx.xmit_work);
- cancel_work_sync(&sdio->tx.status_work);
- cancel_work_sync(&sdio->rx.recv_work);
- cancel_work_sync(&sdio->rx.net_work);
- cancel_work_sync(&sdio->stat_work);
- clear_bit(MT76_READING_STATS, &dev->phy.state);
+ for (i = 0; i <= MT_TXQ_PSD; i++) {
+ q = mt76s_alloc_tx_queue(dev);
+ if (IS_ERR(q))
+ return PTR_ERR(q);
- mt76_tx_status_check(dev, NULL, true);
+ q->qid = i;
+ dev->phy.q_tx[i] = q;
+ }
+
+ q = mt76s_alloc_tx_queue(dev);
+ if (IS_ERR(q))
+ return PTR_ERR(q);
+
+ q->qid = MT_MCUQ_WM;
+ dev->q_mcu[MT_MCUQ_WM] = q;
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(mt76s_stop_txrx);
int mt76s_alloc_queues(struct mt76_dev *dev)
{
@@ -131,11 +134,32 @@ mt76s_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
return nframes;
}
-static void mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
+static void mt76s_net_worker(struct mt76_worker *w)
+{
+ struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
+ net_worker);
+ struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
+ int i, nframes;
+
+ do {
+ nframes = 0;
+
+ local_bh_disable();
+ rcu_read_lock();
+
+ mt76_for_each_q_rx(dev, i)
+ nframes += mt76s_process_rx_queue(dev, &dev->q_rx[i]);
+
+ rcu_read_unlock();
+ local_bh_enable();
+ } while (nframes > 0);
+}
+
+static int mt76s_process_tx_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
- struct mt76_queue *q = dev->q_tx[qid];
+ bool wake, mcu = q == dev->q_mcu[MT_MCUQ_WM];
struct mt76_queue_entry entry;
- bool wake;
+ int nframes = 0;
while (q->queued > 0) {
if (!q->entry[q->tail].done)
@@ -144,12 +168,13 @@ static void mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
entry = q->entry[q->tail];
q->entry[q->tail].done = false;
- if (qid == MT_TXQ_MCU) {
+ if (mcu) {
dev_kfree_skb(entry.skb);
entry.skb = NULL;
}
mt76_queue_tx_complete(dev, q, &entry);
+ nframes++;
}
wake = q->stopped && q->queued < q->ndesc - 8;
@@ -159,13 +184,35 @@ static void mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
if (!q->queued)
wake_up(&dev->tx_wait);
- if (qid == MT_TXQ_MCU)
- return;
+ if (mcu)
+ goto out;
- mt76_txq_schedule(&dev->phy, qid);
+ mt76_txq_schedule(&dev->phy, q->qid);
if (wake)
- ieee80211_wake_queue(dev->hw, qid);
+ ieee80211_wake_queue(dev->hw, q->qid);
+out:
+ return nframes;
+}
+
+static void mt76s_status_worker(struct mt76_worker *w)
+{
+ struct mt76_sdio *sdio = container_of(w, struct mt76_sdio,
+ status_worker);
+ struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
+ int i, nframes;
+
+ do {
+ nframes = mt76s_process_tx_queue(dev, dev->q_mcu[MT_MCUQ_WM]);
+
+ for (i = 0; i <= MT_TXQ_PSD; i++)
+ nframes += mt76s_process_tx_queue(dev,
+ dev->phy.q_tx[i]);
+
+ if (dev->drv->tx_status_data &&
+ !test_and_set_bit(MT76_READING_STATS, &dev->phy.state))
+ queue_work(dev->wq, &dev->sdio.stat_work);
+ } while (nframes > 0);
}
static void mt76s_tx_status_data(struct work_struct *work)
@@ -194,11 +241,10 @@ static void mt76s_tx_status_data(struct work_struct *work)
}
static int
-mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
+mt76s_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta)
{
- struct mt76_queue *q = dev->q_tx[qid];
struct mt76_tx_info tx_info = {
.skb = skb,
};
@@ -209,7 +255,7 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
return -ENOSPC;
skb->prev = skb->next = NULL;
- err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info);
+ err = dev->drv->tx_prepare_skb(dev, NULL, q->qid, wcid, sta, &tx_info);
if (err < 0)
return err;
@@ -222,10 +268,9 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
}
static int
-mt76s_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid,
+mt76s_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, u32 tx_info)
{
- struct mt76_queue *q = dev->q_tx[qid];
int ret = -ENOSPC, len = skb->len, pad;
if (q->queued == q->ndesc)
@@ -257,7 +302,7 @@ static void mt76s_tx_kick(struct mt76_dev *dev, struct mt76_queue *q)
{
struct mt76_sdio *sdio = &dev->sdio;
- queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
+ mt76_worker_schedule(&sdio->txrx_worker);
}
static const struct mt76_queue_ops sdio_queue_ops = {
@@ -266,49 +311,19 @@ static const struct mt76_queue_ops sdio_queue_ops = {
.tx_queue_skb_raw = mt76s_tx_queue_skb_raw,
};
-static void mt76s_tx_work(struct work_struct *work)
-{
- struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
- tx.status_work);
- struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
- int i;
-
- for (i = 0; i < MT_TXQ_MCU_WA; i++)
- mt76s_process_tx_queue(dev, i);
-
- if (dev->drv->tx_status_data &&
- !test_and_set_bit(MT76_READING_STATS, &dev->phy.state))
- queue_work(dev->wq, &dev->sdio.stat_work);
-}
-
-static void mt76s_rx_work(struct work_struct *work)
-{
- struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
- rx.net_work);
- struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
- int i;
-
- /* rx processing */
- local_bh_disable();
- rcu_read_lock();
-
- mt76_for_each_q_rx(dev, i)
- mt76s_process_rx_queue(dev, &dev->q_rx[i]);
-
- rcu_read_unlock();
- local_bh_enable();
-}
-
void mt76s_deinit(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
int i;
- mt76s_stop_txrx(dev);
- if (sdio->txrx_wq) {
- destroy_workqueue(sdio->txrx_wq);
- sdio->txrx_wq = NULL;
- }
+ mt76_worker_teardown(&sdio->txrx_worker);
+ mt76_worker_teardown(&sdio->status_worker);
+ mt76_worker_teardown(&sdio->net_worker);
+
+ cancel_work_sync(&sdio->stat_work);
+ clear_bit(MT76_READING_STATS, &dev->phy.state);
+
+ mt76_tx_status_check(dev, NULL, true);
sdio_claim_host(sdio->func);
sdio_release_irq(sdio->func);
@@ -335,18 +350,23 @@ int mt76s_init(struct mt76_dev *dev, struct sdio_func *func,
const struct mt76_bus_ops *bus_ops)
{
struct mt76_sdio *sdio = &dev->sdio;
+ int err;
- sdio->txrx_wq = alloc_workqueue("mt76s_txrx_wq",
- WQ_UNBOUND | WQ_HIGHPRI,
- WQ_UNBOUND_MAX_ACTIVE);
- if (!sdio->txrx_wq)
- return -ENOMEM;
+ err = mt76_worker_setup(dev->hw, &sdio->status_worker,
+ mt76s_status_worker, "sdio-status");
+ if (err)
+ return err;
+
+ err = mt76_worker_setup(dev->hw, &sdio->net_worker, mt76s_net_worker,
+ "sdio-net");
+ if (err)
+ return err;
+
+ sched_set_fifo_low(sdio->status_worker.task);
+ sched_set_fifo_low(sdio->net_worker.task);
INIT_WORK(&sdio->stat_work, mt76s_tx_status_data);
- INIT_WORK(&sdio->tx.status_work, mt76s_tx_work);
- INIT_WORK(&sdio->rx.net_work, mt76s_rx_work);
- mutex_init(&sdio->sched.lock);
dev->queue_ops = &sdio_queue_ops;
dev->bus = bus_ops;
dev->sdio.func = func;
diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c
index 883f59c7a7e4..581eb56dc4be 100644
--- a/drivers/net/wireless/mediatek/mt76/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/testmode.c
@@ -11,6 +11,8 @@ static const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
[MT76_TM_ATTR_TX_RATE_IDX] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_RATE_SGI] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_RATE_LDPC] = { .type = NLA_U8 },
+ [MT76_TM_ATTR_TX_RATE_STBC] = { .type = NLA_U8 },
+ [MT76_TM_ATTR_TX_LTF] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 },
[MT76_TM_ATTR_TX_POWER] = { .type = NLA_NESTED },
@@ -21,6 +23,7 @@ void mt76_testmode_tx_pending(struct mt76_dev *dev)
{
struct mt76_testmode_data *td = &dev->test;
struct mt76_wcid *wcid = &dev->global_wcid;
+ struct mt76_phy *phy = &dev->phy;
struct sk_buff *skb = td->tx_skb;
struct mt76_queue *q;
int qid;
@@ -29,7 +32,7 @@ void mt76_testmode_tx_pending(struct mt76_dev *dev)
return;
qid = skb_get_queue_mapping(skb);
- q = dev->q_tx[qid];
+ q = phy->q_tx[qid];
spin_lock_bh(&q->lock);
@@ -37,7 +40,8 @@ void mt76_testmode_tx_pending(struct mt76_dev *dev)
q->queued < q->ndesc / 2) {
int ret;
- ret = dev->queue_ops->tx_queue_skb(dev, qid, skb_get(skb), wcid, NULL);
+ ret = dev->queue_ops->tx_queue_skb(dev, q, skb_get(skb), wcid,
+ NULL);
if (ret < 0)
break;
@@ -55,13 +59,14 @@ static int
mt76_testmode_tx_init(struct mt76_dev *dev)
{
struct mt76_testmode_data *td = &dev->test;
+ struct mt76_phy *phy = &dev->phy;
struct ieee80211_tx_info *info;
struct ieee80211_hdr *hdr;
struct sk_buff *skb;
u16 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
IEEE80211_FCTL_FROMDS;
struct ieee80211_tx_rate *rate;
- u8 max_nss = hweight8(dev->phy.antenna_mask);
+ u8 max_nss = hweight8(phy->antenna_mask);
if (td->tx_antenna_mask)
max_nss = min_t(u8, max_nss, hweight8(td->tx_antenna_mask));
@@ -74,28 +79,32 @@ mt76_testmode_tx_init(struct mt76_dev *dev)
td->tx_skb = skb;
hdr = __skb_put_zero(skb, td->tx_msdu_len);
hdr->frame_control = cpu_to_le16(fc);
- memcpy(hdr->addr1, dev->macaddr, sizeof(dev->macaddr));
- memcpy(hdr->addr2, dev->macaddr, sizeof(dev->macaddr));
- memcpy(hdr->addr3, dev->macaddr, sizeof(dev->macaddr));
+ memcpy(hdr->addr1, phy->macaddr, sizeof(phy->macaddr));
+ memcpy(hdr->addr2, phy->macaddr, sizeof(phy->macaddr));
+ memcpy(hdr->addr3, phy->macaddr, sizeof(phy->macaddr));
info = IEEE80211_SKB_CB(skb);
info->flags = IEEE80211_TX_CTL_INJECTED |
IEEE80211_TX_CTL_NO_ACK |
IEEE80211_TX_CTL_NO_PS_BUFFER;
+
+ if (td->tx_rate_mode > MT76_TM_TX_MODE_VHT)
+ goto out;
+
rate = &info->control.rates[0];
rate->count = 1;
rate->idx = td->tx_rate_idx;
switch (td->tx_rate_mode) {
case MT76_TM_TX_MODE_CCK:
- if (dev->phy.chandef.chan->band != NL80211_BAND_2GHZ)
+ if (phy->chandef.chan->band != NL80211_BAND_2GHZ)
return -EINVAL;
if (rate->idx > 4)
return -EINVAL;
break;
case MT76_TM_TX_MODE_OFDM:
- if (dev->phy.chandef.chan->band != NL80211_BAND_2GHZ)
+ if (phy->chandef.chan->band != NL80211_BAND_2GHZ)
break;
if (rate->idx > 8)
@@ -106,7 +115,7 @@ mt76_testmode_tx_init(struct mt76_dev *dev)
case MT76_TM_TX_MODE_HT:
if (rate->idx > 8 * max_nss &&
!(rate->idx == 32 &&
- dev->phy.chandef.width >= NL80211_CHAN_WIDTH_40))
+ phy->chandef.width >= NL80211_CHAN_WIDTH_40))
return -EINVAL;
rate->flags |= IEEE80211_TX_RC_MCS;
@@ -131,8 +140,11 @@ mt76_testmode_tx_init(struct mt76_dev *dev)
if (td->tx_rate_ldpc)
info->flags |= IEEE80211_TX_CTL_LDPC;
+ if (td->tx_rate_stbc)
+ info->flags |= IEEE80211_TX_CTL_STBC;
+
if (td->tx_rate_mode >= MT76_TM_TX_MODE_HT) {
- switch (dev->phy.chandef.width) {
+ switch (phy->chandef.width) {
case NL80211_CHAN_WIDTH_40:
rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
break;
@@ -147,7 +159,7 @@ mt76_testmode_tx_init(struct mt76_dev *dev)
break;
}
}
-
+out:
skb_set_queue_mapping(skb, IEEE80211_AC_BE);
return 0;
@@ -334,8 +346,10 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
0, MT76_TM_TX_MODE_MAX) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_NSS], &td->tx_rate_nss,
1, hweight8(phy->antenna_mask)) ||
- mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_SGI], &td->tx_rate_sgi, 0, 1) ||
+ mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_SGI], &td->tx_rate_sgi, 0, 2) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_LDPC], &td->tx_rate_ldpc, 0, 1) ||
+ mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_STBC], &td->tx_rate_stbc, 0, 1) ||
+ mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_LTF], &td->tx_ltf, 0, 2) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_ANTENNA], &td->tx_antenna_mask, 1,
phy->antenna_mask) ||
mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL],
@@ -472,6 +486,9 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, td->tx_rate_idx) ||
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) ||
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) ||
+ nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) ||
+ (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) &&
+ nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&
nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, td->tx_antenna_mask)) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER_CONTROL) &&
diff --git a/drivers/net/wireless/mediatek/mt76/testmode.h b/drivers/net/wireless/mediatek/mt76/testmode.h
index 691fe5773244..7efad685a17c 100644
--- a/drivers/net/wireless/mediatek/mt76/testmode.h
+++ b/drivers/net/wireless/mediatek/mt76/testmode.h
@@ -25,6 +25,8 @@
* @MT76_TM_ATTR_TX_RATE_IDX: packet tx rate/MCS index (u8)
* @MT76_TM_ATTR_TX_RATE_SGI: packet tx use short guard interval (u8)
* @MT76_TM_ATTR_TX_RATE_LDPC: packet tx enable LDPC (u8)
+ * @MT76_TM_ATTR_TX_RATE_STBC: packet tx enable STBC (u8)
+ * @MT76_TM_ATTR_TX_LTF: packet tx LTF, set 0 to 2 for 1x, 2x, and 4x LTF (u8)
*
* @MT76_TM_ATTR_TX_ANTENNA: tx antenna mask (u8)
* @MT76_TM_ATTR_TX_POWER_CONTROL: enable tx power control (u8)
@@ -50,6 +52,8 @@ enum mt76_testmode_attr {
MT76_TM_ATTR_TX_RATE_IDX,
MT76_TM_ATTR_TX_RATE_SGI,
MT76_TM_ATTR_TX_RATE_LDPC,
+ MT76_TM_ATTR_TX_RATE_STBC,
+ MT76_TM_ATTR_TX_LTF,
MT76_TM_ATTR_TX_ANTENNA,
MT76_TM_ATTR_TX_POWER_CONTROL,
@@ -99,8 +103,9 @@ enum mt76_testmode_stats_attr {
*
* @MT76_TM_RX_ATTR_FREQ_OFFSET: frequency offset (s32)
* @MT76_TM_RX_ATTR_RCPI: received channel power indicator (array, u8)
- * @MT76_TM_RX_ATTR_IB_RSSI: internal inband RSSI (s8)
- * @MT76_TM_RX_ATTR_WB_RSSI: internal wideband RSSI (s8)
+ * @MT76_TM_RX_ATTR_IB_RSSI: internal inband RSSI (array, s8)
+ * @MT76_TM_RX_ATTR_WB_RSSI: internal wideband RSSI (array, s8)
+ * @MT76_TM_RX_ATTR_SNR: signal-to-noise ratio (u8)
*/
enum mt76_testmode_rx_attr {
MT76_TM_RX_ATTR_UNSPEC,
@@ -109,6 +114,7 @@ enum mt76_testmode_rx_attr {
MT76_TM_RX_ATTR_RCPI,
MT76_TM_RX_ATTR_IB_RSSI,
MT76_TM_RX_ATTR_WB_RSSI,
+ MT76_TM_RX_ATTR_SNR,
/* keep last */
NUM_MT76_TM_RX_ATTRS,
@@ -141,12 +147,20 @@ enum mt76_testmode_state {
* @MT76_TM_TX_MODE_OFDM: legacy OFDM mode
* @MT76_TM_TX_MODE_HT: 802.11n MCS
* @MT76_TM_TX_MODE_VHT: 802.11ac MCS
+ * @MT76_TM_TX_MODE_HE_SU: 802.11ax single-user MIMO
+ * @MT76_TM_TX_MODE_HE_EXT_SU: 802.11ax extended-range SU
+ * @MT76_TM_TX_MODE_HE_TB: 802.11ax trigger-based
+ * @MT76_TM_TX_MODE_HE_MU: 802.11ax multi-user MIMO
*/
enum mt76_testmode_tx_mode {
MT76_TM_TX_MODE_CCK,
MT76_TM_TX_MODE_OFDM,
MT76_TM_TX_MODE_HT,
MT76_TM_TX_MODE_VHT,
+ MT76_TM_TX_MODE_HE_SU,
+ MT76_TM_TX_MODE_HE_EXT_SU,
+ MT76_TM_TX_MODE_HE_TB,
+ MT76_TM_TX_MODE_HE_MU,
/* keep last */
NUM_MT76_TM_TX_MODES,
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 44ef4bc7a46e..25627e70bdad 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -225,23 +225,23 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *sk
EXPORT_SYMBOL_GPL(mt76_tx_complete_skb);
static int
-__mt76_tx_queue_skb(struct mt76_dev *dev, int qid, struct sk_buff *skb,
+__mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb,
struct mt76_wcid *wcid, struct ieee80211_sta *sta,
bool *stop)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct mt76_queue *q;
+ struct mt76_queue *q = phy->q_tx[qid];
+ struct mt76_dev *dev = phy->dev;
bool non_aql;
int pending;
int idx;
non_aql = !info->tx_time_est;
- idx = dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid, sta);
+ idx = dev->queue_ops->tx_queue_skb(dev, q, skb, wcid, sta);
if (idx < 0 || !sta || !non_aql)
return idx;
wcid = (struct mt76_wcid *)sta->drv_priv;
- q = dev->q_tx[qid];
q->entry[idx].wcid = wcid->idx;
pending = atomic_inc_return(&wcid->non_aql_packets);
if (stop && pending >= MT_MAX_NON_AQL_PKT)
@@ -272,6 +272,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
}
if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) &&
+ !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
!ieee80211_is_data(hdr->frame_control) &&
!ieee80211_is_bufferable_mmpdu(hdr->frame_control)) {
qid = MT_TXQ_PSD;
@@ -285,17 +286,11 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
if (ext_phy)
info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
- q = dev->q_tx[qid];
+ q = phy->q_tx[qid];
spin_lock_bh(&q->lock);
- __mt76_tx_queue_skb(dev, qid, skb, wcid, sta, NULL);
+ __mt76_tx_queue_skb(phy, qid, skb, wcid, sta, NULL);
dev->queue_ops->kick(dev, q);
-
- if (q->queued > q->ndesc - 8 && !q->stopped) {
- ieee80211_stop_queue(phy->hw, skb_get_queue_mapping(skb));
- q->stopped = true;
- }
-
spin_unlock_bh(&q->lock);
}
EXPORT_SYMBOL_GPL(mt76_tx);
@@ -320,7 +315,7 @@ mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq)
}
static void
-mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta,
+mt76_queue_ps_skb(struct mt76_phy *phy, struct ieee80211_sta *sta,
struct sk_buff *skb, bool last)
{
struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
@@ -332,7 +327,7 @@ mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta,
IEEE80211_TX_CTL_REQ_TX_STATUS;
mt76_skb_set_moredata(skb, !last);
- __mt76_tx_queue_skb(dev, MT_TXQ_PSD, skb, wcid, sta, NULL);
+ __mt76_tx_queue_skb(phy, MT_TXQ_PSD, skb, wcid, sta, NULL);
}
void
@@ -344,7 +339,7 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
struct mt76_phy *phy = hw->priv;
struct mt76_dev *dev = phy->dev;
struct sk_buff *last_skb = NULL;
- struct mt76_queue *hwq = dev->q_tx[MT_TXQ_PSD];
+ struct mt76_queue *hwq = phy->q_tx[MT_TXQ_PSD];
int i;
spin_lock_bh(&hwq->lock);
@@ -363,14 +358,14 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
nframes--;
if (last_skb)
- mt76_queue_ps_skb(dev, sta, last_skb, false);
+ mt76_queue_ps_skb(phy, sta, last_skb, false);
last_skb = skb;
} while (nframes);
}
if (last_skb) {
- mt76_queue_ps_skb(dev, sta, last_skb, true);
+ mt76_queue_ps_skb(phy, sta, last_skb, true);
dev->queue_ops->kick(dev, hwq);
} else {
ieee80211_sta_eosp(sta);
@@ -380,6 +375,13 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
}
EXPORT_SYMBOL_GPL(mt76_release_buffered_frames);
+static bool
+mt76_txq_stopped(struct mt76_queue *q)
+{
+ return q->stopped || q->blocked ||
+ q->queued + MT_TXQ_FREE_THR >= q->ndesc;
+}
+
static int
mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
struct mt76_txq *mtxq)
@@ -409,7 +411,7 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
info->control.rates, 1);
- idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop);
+ idx = __mt76_tx_queue_skb(phy, qid, skb, wcid, txq->sta, &stop);
if (idx < 0)
return idx;
@@ -418,10 +420,7 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
test_bit(MT76_RESET, &phy->state))
return -EBUSY;
- if (stop)
- break;
-
- if (q->queued + MT_TXQ_FREE_THR >= q->ndesc)
+ if (stop || mt76_txq_stopped(q))
break;
skb = mt76_txq_dequeue(phy, mtxq);
@@ -433,7 +432,7 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
info->control.rates, 1);
- idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop);
+ idx = __mt76_tx_queue_skb(phy, qid, skb, wcid, txq->sta, &stop);
if (idx < 0)
break;
@@ -448,8 +447,8 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
static int
mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
{
+ struct mt76_queue *q = phy->q_tx[qid];
struct mt76_dev *dev = phy->dev;
- struct mt76_queue *q = dev->q_tx[qid];
struct ieee80211_txq *txq;
struct mt76_txq *mtxq;
struct mt76_wcid *wcid;
@@ -463,7 +462,14 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
break;
}
- if (q->queued + MT_TXQ_FREE_THR >= q->ndesc)
+ if (dev->queue_ops->tx_cleanup &&
+ q->queued + 2 * MT_TXQ_FREE_THR >= q->ndesc) {
+ spin_unlock_bh(&q->lock);
+ dev->queue_ops->tx_cleanup(dev, q, false);
+ spin_lock_bh(&q->lock);
+ }
+
+ if (mt76_txq_stopped(q))
break;
txq = ieee80211_next_txq(phy->hw, qid);
@@ -538,7 +544,7 @@ void mt76_tx_worker(struct mt76_worker *w)
#endif
}
-void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
+void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta,
bool send_bar)
{
int i;
@@ -551,7 +557,7 @@ void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
if (!txq)
continue;
- hwq = dev->q_tx[mt76_txq_get_qid(txq)];
+ hwq = phy->q_tx[mt76_txq_get_qid(txq)];
mtxq = (struct mt76_txq *)txq->drv_priv;
spin_lock_bh(&hwq->lock);
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index f1ae9ff835b2..dc850109de22 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -627,7 +627,7 @@ static void mt76u_complete_rx(struct urb *urb)
q->head = (q->head + 1) % q->ndesc;
q->queued++;
- tasklet_schedule(&dev->usb.rx_tasklet);
+ mt76_worker_schedule(&dev->usb.rx_worker);
out:
spin_unlock_irqrestore(&q->lock, flags);
}
@@ -665,13 +665,17 @@ mt76u_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
}
mt76u_submit_rx_buf(dev, qid, urb);
}
- if (qid == MT_RXQ_MAIN)
+ if (qid == MT_RXQ_MAIN) {
+ local_bh_disable();
mt76_rx_poll_complete(dev, MT_RXQ_MAIN, NULL);
+ local_bh_enable();
+ }
}
-static void mt76u_rx_tasklet(unsigned long data)
+static void mt76u_rx_worker(struct mt76_worker *w)
{
- struct mt76_dev *dev = (struct mt76_dev *)data;
+ struct mt76_usb *usb = container_of(w, struct mt76_usb, rx_worker);
+ struct mt76_dev *dev = container_of(usb, struct mt76_dev, usb);
int i;
rcu_read_lock();
@@ -737,8 +741,13 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
struct page *page;
int i;
- for (i = 0; i < q->ndesc; i++)
+ for (i = 0; i < q->ndesc; i++) {
+ if (!q->entry[i].urb)
+ continue;
+
mt76u_urb_free(q->entry[i].urb);
+ q->entry[i].urb = NULL;
+ }
if (!q->rx_page.va)
return;
@@ -752,6 +761,8 @@ static void mt76u_free_rx(struct mt76_dev *dev)
{
int i;
+ mt76_worker_teardown(&dev->usb.rx_worker);
+
mt76_for_each_q_rx(dev, i)
mt76u_free_rx_queue(dev, &dev->q_rx[i]);
}
@@ -760,6 +771,8 @@ void mt76u_stop_rx(struct mt76_dev *dev)
{
int i;
+ mt76_worker_disable(&dev->usb.rx_worker);
+
mt76_for_each_q_rx(dev, i) {
struct mt76_queue *q = &dev->q_rx[i];
int j;
@@ -767,8 +780,6 @@ void mt76u_stop_rx(struct mt76_dev *dev)
for (j = 0; j < q->ndesc; j++)
usb_poison_urb(q->entry[j].urb);
}
-
- tasklet_kill(&dev->usb.rx_tasklet);
}
EXPORT_SYMBOL_GPL(mt76u_stop_rx);
@@ -788,20 +799,23 @@ int mt76u_resume_rx(struct mt76_dev *dev)
return err;
}
+ mt76_worker_enable(&dev->usb.rx_worker);
+
return 0;
}
EXPORT_SYMBOL_GPL(mt76u_resume_rx);
-static void mt76u_tx_worker(struct mt76_worker *w)
+static void mt76u_status_worker(struct mt76_worker *w)
{
- struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
+ struct mt76_usb *usb = container_of(w, struct mt76_usb, status_worker);
+ struct mt76_dev *dev = container_of(usb, struct mt76_dev, usb);
struct mt76_queue_entry entry;
struct mt76_queue *q;
bool wake;
int i;
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- q = dev->q_tx[i];
+ q = dev->phy.q_tx[i];
while (q->queued > 0) {
if (!q->entry[q->tail].done)
@@ -820,7 +834,7 @@ static void mt76u_tx_worker(struct mt76_worker *w)
if (!q->queued)
wake_up(&dev->tx_wait);
- mt76_txq_schedule(&dev->phy, i);
+ mt76_worker_schedule(&dev->tx_worker);
if (dev->drv->tx_status_data &&
!test_and_set_bit(MT76_READING_STATS, &dev->phy.state))
@@ -864,7 +878,7 @@ static void mt76u_complete_tx(struct urb *urb)
dev_err(dev->dev, "tx urb failed: %d\n", urb->status);
e->done = true;
- mt76_worker_schedule(&dev->tx_worker);
+ mt76_worker_schedule(&dev->usb.status_worker);
}
static int
@@ -887,11 +901,10 @@ mt76u_tx_setup_buffers(struct mt76_dev *dev, struct sk_buff *skb,
}
static int
-mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
+mt76u_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta)
{
- struct mt76_queue *q = dev->q_tx[qid];
struct mt76_tx_info tx_info = {
.skb = skb,
};
@@ -902,7 +915,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
return -ENOSPC;
skb->prev = skb->next = NULL;
- err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info);
+ err = dev->drv->tx_prepare_skb(dev, NULL, q->qid, wcid, sta, &tx_info);
if (err < 0)
return err;
@@ -970,7 +983,7 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
for (i = 0; i <= MT_TXQ_PSD; i++) {
if (i >= IEEE80211_NUM_ACS) {
- dev->q_tx[i] = dev->q_tx[0];
+ dev->phy.q_tx[i] = dev->phy.q_tx[0];
continue;
}
@@ -980,7 +993,9 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
spin_lock_init(&q->lock);
q->hw_idx = mt76u_ac_to_hwq(dev, i);
- dev->q_tx[i] = q;
+ q->qid = i;
+
+ dev->phy.q_tx[i] = q;
q->entry = devm_kcalloc(dev->dev,
MT_NUM_TX_ENTRIES, sizeof(*q->entry),
@@ -1003,16 +1018,20 @@ static void mt76u_free_tx(struct mt76_dev *dev)
{
int i;
+ mt76_worker_teardown(&dev->usb.status_worker);
+
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
struct mt76_queue *q;
int j;
- q = dev->q_tx[i];
+ q = dev->phy.q_tx[i];
if (!q)
continue;
- for (j = 0; j < q->ndesc; j++)
+ for (j = 0; j < q->ndesc; j++) {
usb_free_urb(q->entry[j].urb);
+ q->entry[j].urb = NULL;
+ }
}
}
@@ -1020,6 +1039,8 @@ void mt76u_stop_tx(struct mt76_dev *dev)
{
int ret;
+ mt76_worker_disable(&dev->usb.status_worker);
+
ret = wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(&dev->phy),
HZ / 5);
if (!ret) {
@@ -1030,7 +1051,7 @@ void mt76u_stop_tx(struct mt76_dev *dev)
dev_err(dev->dev, "timed out waiting for pending tx\n");
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- q = dev->q_tx[i];
+ q = dev->phy.q_tx[i];
if (!q)
continue;
@@ -1044,7 +1065,7 @@ void mt76u_stop_tx(struct mt76_dev *dev)
* will fail to submit urb, cleanup those skb's manually.
*/
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- q = dev->q_tx[i];
+ q = dev->phy.q_tx[i];
if (!q)
continue;
@@ -1061,6 +1082,8 @@ void mt76u_stop_tx(struct mt76_dev *dev)
cancel_work_sync(&dev->usb.stat_work);
clear_bit(MT76_READING_STATS, &dev->phy.state);
+ mt76_worker_enable(&dev->usb.status_worker);
+
mt76_tx_status_check(dev, NULL, true);
}
EXPORT_SYMBOL_GPL(mt76u_stop_tx);
@@ -1103,15 +1126,13 @@ int mt76u_init(struct mt76_dev *dev,
};
struct usb_device *udev = interface_to_usbdev(intf);
struct mt76_usb *usb = &dev->usb;
- int err = -ENOMEM;
+ int err;
mt76u_ops.rr = ext ? mt76u_rr_ext : mt76u_rr;
mt76u_ops.wr = ext ? mt76u_wr_ext : mt76u_wr;
mt76u_ops.rmw = ext ? mt76u_rmw_ext : mt76u_rmw;
mt76u_ops.write_copy = ext ? mt76u_copy_ext : mt76u_copy;
- dev->tx_worker.fn = mt76u_tx_worker;
- tasklet_init(&usb->rx_tasklet, mt76u_rx_tasklet, (unsigned long)dev);
INIT_WORK(&usb->stat_work, mt76u_tx_status_data);
usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0), 1);
@@ -1120,7 +1141,7 @@ int mt76u_init(struct mt76_dev *dev,
usb->data = devm_kmalloc(dev->dev, usb->data_len, GFP_KERNEL);
if (!usb->data)
- goto error;
+ return -ENOMEM;
mutex_init(&usb->usb_ctrl_mtx);
dev->bus = &mt76u_ops;
@@ -1132,14 +1153,22 @@ int mt76u_init(struct mt76_dev *dev,
err = mt76u_set_endpoints(intf, usb);
if (err < 0)
- goto error;
+ return err;
- return 0;
+ err = mt76_worker_setup(dev->hw, &usb->rx_worker, mt76u_rx_worker,
+ "usb-rx");
+ if (err)
+ return err;
+
+ err = mt76_worker_setup(dev->hw, &usb->status_worker,
+ mt76u_status_worker, "usb-status");
+ if (err)
+ return err;
-error:
- destroy_workqueue(dev->wq);
+ sched_set_fifo_low(usb->rx_worker.task);
+ sched_set_fifo_low(usb->status_worker.task);
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(mt76u_init);