summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2021-04-23 23:58:25 +0300
committerDavid S. Miller <davem@davemloft.net>2021-04-23 23:58:25 +0300
commite40fa65c79b59ef662bf3f9e81cc2236fb9581e3 (patch)
treee5fcc43cb633a4100ae83e82e3dcfc25b9c953ec
parent8f8590dd9b6ec232dab6f773b3b800c3f6e2a14a (diff)
parent9382531ec63fc123d1d6ff07b0558b6af4ea724b (diff)
downloadlinux-e40fa65c79b59ef662bf3f9e81cc2236fb9581e3.tar.xz
Merge tag 'wireless-drivers-next-2021-04-23' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says: ==================== wireless-drivers-next patches for v5.13 Third, and final, set of patches for v5.13. We got one more week before the merge window and this includes from that extra week. Smaller features to rtw88 and mt76, but mostly this contains fixes. rtw88 * 8822c: Add gap-k calibration to improve long range performance mt76 * parse rate power limits from DT * debugfs file to test firmware crash * debugfs to disable NAPI threaded mode ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml107
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c3
-rw-r--r--drivers/net/wireless/ath/ath11k/mhi.c15
-rw-r--r--drivers/net/wireless/ath/ath11k/qmi.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c2
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c2
-rw-r--r--drivers/net/wireless/marvell/libertas_tf/libertas_tf.h1
-rw-r--r--drivers/net/wireless/mediatek/mt76/debugfs.c28
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.h1
-rw-r--r--drivers/net/wireless/mediatek/mt76/eeprom.c231
-rw-r--r--drivers/net/wireless/mediatek/mt76/mac80211.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mcu.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h77
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/dma.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mac.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mcu.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c32
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/dma.c47
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/init.c22
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.c44
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/main.c43
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.c198
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mmio.c24
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c16
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c23
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/regs.h11
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac.h54
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c23
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c197
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h37
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c78
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/dma.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c165
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h51
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/init.c85
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.c95
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/main.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.c185
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h19
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/pci.c26
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/regs.h5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/testmode.c22
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c144
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/dma.c240
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/init.c36
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mac.c193
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/main.c62
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mcu.c126
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mcu.h17
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h60
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/pci.c30
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/regs.h17
-rw-r--r--drivers/net/wireless/mediatek/mt76/testmode.c159
-rw-r--r--drivers/net/wireless/mediatek/mt76/testmode.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/tx.c81
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/event.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/core.c32
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/core.h1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/usb.c3
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/wifi.h1
-rw-r--r--drivers/net/wireless/realtek/rtw88/debug.c91
-rw-r--r--drivers/net/wireless/realtek/rtw88/fw.c12
-rw-r--r--drivers/net/wireless/realtek/rtw88/fw.h5
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.h31
-rw-r--r--drivers/net/wireless/realtek/rtw88/pci.c29
-rw-r--r--drivers/net/wireless/realtek/rtw88/pci.h1
-rw-r--r--drivers/net/wireless/realtek/rtw88/reg.h8
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8821c.c3
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822c.c724
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822c.h336
-rw-r--r--drivers/net/wireless/ti/wlcore/debugfs.h2
-rw-r--r--drivers/net/wireless/wl3501.h47
-rw-r--r--drivers/net/wireless/wl3501_cs.c54
81 files changed, 3428 insertions, 1157 deletions
diff --git a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml
index d6f835d17d66..3e2c2e43175e 100644
--- a/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/mediatek,mt76.yaml
@@ -72,6 +72,90 @@ properties:
led-sources:
maxItems: 1
+ power-limits:
+ type: object
+ additionalProperties: false
+ patternProperties:
+ "^r[0-9]+":
+ type: object
+ additionalProperties: false
+ properties:
+ regdomain:
+ $ref: /schemas/types.yaml#/definitions/string
+ description:
+ Regdomain refers to a legal regulatory region. Different
+ countries define different levels of allowable transmitter
+ power, time that a channel can be occupied, and different
+ available channels
+ enum:
+ - FCC
+ - ETSI
+ - JP
+
+ patternProperties:
+ "^txpower-[256]g$":
+ type: object
+ additionalProperties: false
+ patternProperties:
+ "^b[0-9]+$":
+ type: object
+ additionalProperties: false
+ properties:
+ channels:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ minItems: 2
+ maxItems: 2
+ description:
+ Pairs of first and last channel number of the selected
+ band
+
+ rates-cck:
+ $ref: /schemas/types.yaml#/definitions/uint8-array
+ minItems: 4
+ maxItems: 4
+ description:
+ 4 half-dBm per-rate power limit values
+
+ rates-ofdm:
+ $ref: /schemas/types.yaml#/definitions/uint8-array
+ minItems: 8
+ maxItems: 8
+ description:
+ 8 half-dBm per-rate power limit values
+
+ rates-mcs:
+ $ref: /schemas/types.yaml#/definitions/uint8-matrix
+ description:
+ Sets of per-rate power limit values for 802.11n/802.11ac
+ rates for multiple channel bandwidth settings.
+ Each set starts with the number of channel bandwidth
+ settings for which the rate set applies, followed by
+ either 8 or 10 power limit values. The order of the
+ channel bandwidth settings is 20, 40, 80 and 160 MHz.
+ maxItems: 4
+ items:
+ minItems: 9
+ maxItems: 11
+
+ rates-ru:
+ $ref: /schemas/types.yaml#/definitions/uint8-matrix
+ description:
+ Sets of per-rate power limit values for 802.11ax rates
+ for multiple channel bandwidth or resource unit settings.
+ Each set starts with the number of channel bandwidth or
+ resource unit settings for which the rate set applies,
+ followed by 12 power limit values. The order of the
+ channel resource unit settings is RU26, RU52, RU106,
+ RU242/SU20, RU484/SU40, RU996/SU80 and RU2x996/SU160.
+ items:
+ minItems: 13
+ maxItems: 13
+
+ txs-delta:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description:
+ Half-dBm power delta for different numbers of antennas
+
required:
- compatible
- reg
@@ -93,6 +177,29 @@ examples:
led {
led-sources = <2>;
};
+
+ power-limits {
+ r0 {
+ regdomain = "FCC";
+ txpower-5g {
+ b0 {
+ channels = <36 48>;
+ rates-ofdm = /bits/ 8 <23 23 23 23 23 23 23 23>;
+ rates-mcs = /bits/ 8 <1 23 23 23 23 23 23 23 23 23 23>,
+ <3 22 22 22 22 22 22 22 22 22 22>;
+ rates-ru = /bits/ 8 <3 22 22 22 22 22 22 22 22 22 22 22 22>,
+ <4 20 20 20 20 20 20 20 20 20 20 20 20>;
+ };
+ b1 {
+ channels = <100 181>;
+ rates-ofdm = /bits/ 8 <14 14 14 14 14 14 14 14>;
+ rates-mcs = /bits/ 8 <4 14 14 14 14 14 14 14 14 14 14>;
+ txs-delta = <12 9 6>;
+ rates-ru = /bits/ 8 <7 14 14 14 14 14 14 14 14 14 14 14 14>;
+ };
+ };
+ };
+ };
};
};
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index 0a37be6a7d33..fab398046a3f 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -669,7 +669,7 @@ static int ath10k_htc_send_bundle(struct ath10k_htc_ep *ep,
ath10k_dbg(ar, ATH10K_DBG_HTC,
"bundle tx status %d eid %d req count %d count %d len %d\n",
- ret, ep->eid, skb_queue_len(&ep->tx_req_head), cn, bundle_skb->len);
+ ret, ep->eid, skb_queue_len(&ep->tx_req_head), cn, skb_len);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
index d97b33f789e4..7efbe03fbca8 100644
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -592,6 +592,9 @@ static void ath10k_wmi_event_tdls_peer(struct ath10k *ar, struct sk_buff *skb)
GFP_ATOMIC
);
break;
+ default:
+ kfree(tb);
+ return;
}
exit:
diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c
index 626764da4d6f..27b394d115e2 100644
--- a/drivers/net/wireless/ath/ath11k/mhi.c
+++ b/drivers/net/wireless/ath/ath11k/mhi.c
@@ -349,10 +349,19 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
mhi_ctrl->read_reg = ath11k_mhi_op_read_reg;
mhi_ctrl->write_reg = ath11k_mhi_op_write_reg;
- if (ab->hw_rev == ATH11K_HW_QCA6390_HW20)
- ath11k_mhi_config = &ath11k_mhi_config_qca6390;
- else if (ab->hw_rev == ATH11K_HW_QCN9074_HW10)
+ switch (ab->hw_rev) {
+ case ATH11K_HW_QCN9074_HW10:
ath11k_mhi_config = &ath11k_mhi_config_qcn9074;
+ break;
+ case ATH11K_HW_QCA6390_HW20:
+ ath11k_mhi_config = &ath11k_mhi_config_qca6390;
+ break;
+ default:
+ ath11k_err(ab, "failed assign mhi_config for unknown hw rev %d\n",
+ ab->hw_rev);
+ mhi_free_controller(mhi_ctrl);
+ return -EINVAL;
+ }
ret = mhi_register_controller(mhi_ctrl, ath11k_mhi_config);
if (ret) {
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index a612e279ea5b..b5e34d670715 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -2514,7 +2514,7 @@ static int ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi)
ret = ath11k_qmi_request_target_cap(ab);
if (ret < 0) {
- ath11k_warn(ab, "failed to requeqst qmi target capabilities: %d\n",
+ ath11k_warn(ab, "failed to request qmi target capabilities: %d\n",
ret);
return ret;
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index db0c6fa9c9dc..ff61ae34ecdf 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -246,7 +246,7 @@ static unsigned int ath9k_regread(void *hw_priv, u32 reg_offset)
if (unlikely(r)) {
ath_dbg(common, WMI, "REGISTER READ FAILED: (0x%04x, %d)\n",
reg_offset, r);
- return -EIO;
+ return -1;
}
return be32_to_cpu(val);
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 5abc2a5526ec..2ca3b86714a9 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -286,7 +286,7 @@ static bool ath9k_hw_read_revisions(struct ath_hw *ah)
srev = REG_READ(ah, AR_SREV);
- if (srev == -EIO) {
+ if (srev == -1) {
ath_err(ath9k_hw_common(ah),
"Failed to read SREV register");
return false;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index ea78fe527c5d..838b09b23abf 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -151,7 +151,7 @@ static void _brcmf_set_multicast_list(struct work_struct *work)
/* Send down the multicast list first. */
cnt = netdev_mc_count(ndev);
buflen = sizeof(cnt) + (cnt * ETH_ALEN);
- buf = kmalloc(buflen, GFP_ATOMIC);
+ buf = kmalloc(buflen, GFP_KERNEL);
if (!buf)
return;
bufp = buf;
diff --git a/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h b/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h
index 67bbb6a8f113..5d726545d987 100644
--- a/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h
+++ b/drivers/net/wireless/marvell/libertas_tf/libertas_tf.h
@@ -453,7 +453,6 @@ struct cmd_ds_802_11_beacon_set {
u8 beacon[MRVL_MAX_BCN_SIZE];
};
-struct lbtf_private;
struct cmd_ctrl_node;
/** Function Prototype Declaration */
diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c
index d4a6b8108971..fa48cc3a7a8f 100644
--- a/drivers/net/wireless/mediatek/mt76/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/debugfs.c
@@ -25,6 +25,32 @@ mt76_reg_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set,
"0x%08llx\n");
+static int
+mt76_napi_threaded_set(void *data, u64 val)
+{
+ struct mt76_dev *dev = data;
+
+ if (!mt76_is_mmio(dev))
+ return -EOPNOTSUPP;
+
+ if (dev->napi_dev.threaded != val)
+ return dev_set_threaded(&dev->napi_dev, val);
+
+ return 0;
+}
+
+static int
+mt76_napi_threaded_get(void *data, u64 *val)
+{
+ struct mt76_dev *dev = data;
+
+ *val = dev->napi_dev.threaded;
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_napi_threaded, mt76_napi_threaded_get,
+ mt76_napi_threaded_set, "%llu\n");
+
int mt76_queues_read(struct seq_file *s, void *data)
{
struct mt76_dev *dev = dev_get_drvdata(s->private);
@@ -102,6 +128,8 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev)
debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg);
debugfs_create_file_unsafe("regval", 0600, dir, dev,
&fops_regval);
+ debugfs_create_file_unsafe("napi_threaded", 0600, dir, dev,
+ &fops_napi_threaded);
debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom);
if (dev->otp.data)
debugfs_create_blob("otp", 0400, dir, &dev->otp);
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 6ea58aecca41..72b1cc0ecfda 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -602,8 +602,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
return done;
}
-static int
-mt76_dma_rx_poll(struct napi_struct *napi, int budget)
+int mt76_dma_rx_poll(struct napi_struct *napi, int budget)
{
struct mt76_dev *dev;
int qid, done = 0, cur;
@@ -626,9 +625,11 @@ mt76_dma_rx_poll(struct napi_struct *napi, int budget)
return done;
}
+EXPORT_SYMBOL_GPL(mt76_dma_rx_poll);
static int
-mt76_dma_init(struct mt76_dev *dev)
+mt76_dma_init(struct mt76_dev *dev,
+ int (*poll)(struct napi_struct *napi, int budget))
{
int i;
@@ -639,8 +640,7 @@ mt76_dma_init(struct mt76_dev *dev)
dev->napi_dev.threaded = 1;
mt76_for_each_q_rx(dev, i) {
- netif_napi_add(&dev->napi_dev, &dev->napi[i], mt76_dma_rx_poll,
- 64);
+ netif_napi_add(&dev->napi_dev, &dev->napi[i], poll, 64);
mt76_dma_rx_fill(dev, &dev->q_rx[i]);
napi_enable(&dev->napi[i]);
}
diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h
index e7c27697ef04..fdf786f975ea 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.h
+++ b/drivers/net/wireless/mediatek/mt76/dma.h
@@ -45,6 +45,7 @@ enum mt76_mcu_evt_type {
EVT_EVENT_DFS_DETECT_RSP,
};
+int mt76_dma_rx_poll(struct napi_struct *napi, int budget);
void mt76_dma_attach(struct mt76_dev *dev);
void mt76_dma_cleanup(struct mt76_dev *dev);
diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
index 6d895738222a..3b47e85e95e7 100644
--- a/drivers/net/wireless/mediatek/mt76/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
@@ -9,8 +9,7 @@
#include <linux/etherdevice.h>
#include "mt76.h"
-static int
-mt76_get_of_eeprom(struct mt76_dev *dev, int len)
+int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
{
#if defined(CONFIG_OF) && defined(CONFIG_MTD)
struct device_node *np = dev->dev->of_node;
@@ -18,7 +17,6 @@ mt76_get_of_eeprom(struct mt76_dev *dev, int len)
const __be32 *list;
const char *part;
phandle phandle;
- int offset = 0;
int size;
size_t retlen;
int ret;
@@ -54,7 +52,7 @@ mt76_get_of_eeprom(struct mt76_dev *dev, int len)
}
offset = be32_to_cpup(list);
- ret = mtd_read(mtd, offset, len, &retlen, dev->eeprom.data);
+ ret = mtd_read(mtd, offset, len, &retlen, eep);
put_mtd_device(mtd);
if (ret)
goto out_put_node;
@@ -65,7 +63,7 @@ mt76_get_of_eeprom(struct mt76_dev *dev, int len)
}
if (of_property_read_bool(dev->dev->of_node, "big-endian")) {
- u8 *data = (u8 *)dev->eeprom.data;
+ u8 *data = (u8 *)eep;
int i;
/* convert eeprom data in Little Endian */
@@ -86,6 +84,7 @@ out_put_node:
return -ENOENT;
#endif
}
+EXPORT_SYMBOL_GPL(mt76_get_of_eeprom);
void
mt76_eeprom_override(struct mt76_phy *phy)
@@ -104,6 +103,226 @@ mt76_eeprom_override(struct mt76_phy *phy)
}
EXPORT_SYMBOL_GPL(mt76_eeprom_override);
+static bool mt76_string_prop_find(struct property *prop, const char *str)
+{
+ const char *cp = NULL;
+
+ if (!prop || !str || !str[0])
+ return false;
+
+ while ((cp = of_prop_next_string(prop, cp)) != NULL)
+ if (!strcasecmp(cp, str))
+ return true;
+
+ return false;
+}
+
+static struct device_node *
+mt76_find_power_limits_node(struct mt76_dev *dev)
+{
+ struct device_node *np = dev->dev->of_node;
+ const char *const region_names[] = {
+ [NL80211_DFS_ETSI] = "etsi",
+ [NL80211_DFS_FCC] = "fcc",
+ [NL80211_DFS_JP] = "jp",
+ };
+ struct device_node *cur, *fallback = NULL;
+ const char *region_name = NULL;
+
+ if (dev->region < ARRAY_SIZE(region_names))
+ region_name = region_names[dev->region];
+
+ np = of_get_child_by_name(np, "power-limits");
+ if (!np)
+ return NULL;
+
+ for_each_child_of_node(np, cur) {
+ struct property *country = of_find_property(cur, "country", NULL);
+ struct property *regd = of_find_property(cur, "regdomain", NULL);
+
+ if (!country && !regd) {
+ fallback = cur;
+ continue;
+ }
+
+ if (mt76_string_prop_find(country, dev->alpha2) ||
+ mt76_string_prop_find(regd, region_name))
+ return cur;
+ }
+
+ return fallback;
+}
+
+static const __be32 *
+mt76_get_of_array(struct device_node *np, char *name, size_t *len, int min)
+{
+ struct property *prop = of_find_property(np, name, NULL);
+
+ if (!prop || !prop->value || prop->length < min * 4)
+ return NULL;
+
+ *len = prop->length;
+
+ return prop->value;
+}
+
+static struct device_node *
+mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan)
+{
+ struct device_node *cur;
+ const __be32 *val;
+ size_t len;
+
+ for_each_child_of_node(np, cur) {
+ val = mt76_get_of_array(cur, "channels", &len, 2);
+ if (!val)
+ continue;
+
+ while (len >= 2 * sizeof(*val)) {
+ if (chan->hw_value >= be32_to_cpu(val[0]) &&
+ chan->hw_value <= be32_to_cpu(val[1]))
+ return cur;
+
+ val += 2;
+ len -= 2 * sizeof(*val);
+ }
+ }
+
+ return NULL;
+}
+
+static s8
+mt76_get_txs_delta(struct device_node *np, u8 nss)
+{
+ const __be32 *val;
+ size_t len;
+
+ val = mt76_get_of_array(np, "txs-delta", &len, nss);
+ if (!val)
+ return 0;
+
+ return be32_to_cpu(val[nss - 1]);
+}
+
+static void
+mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const __be32 *data,
+ s8 target_power, s8 nss_delta, s8 *max_power)
+{
+ int i;
+
+ if (!data)
+ return;
+
+ for (i = 0; i < pwr_len; i++) {
+ pwr[i] = min_t(s8, target_power,
+ be32_to_cpu(data[i]) + nss_delta);
+ *max_power = max(*max_power, pwr[i]);
+ }
+}
+
+static void
+mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
+ const __be32 *data, size_t len, s8 target_power,
+ s8 nss_delta, s8 *max_power)
+{
+ int i, cur;
+
+ if (!data)
+ return;
+
+ len /= 4;
+ cur = be32_to_cpu(data[0]);
+ for (i = 0; i < pwr_num; i++) {
+ if (len < pwr_len + 1)
+ break;
+
+ mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1,
+ target_power, nss_delta, max_power);
+ if (--cur > 0)
+ continue;
+
+ data += pwr_len + 1;
+ len -= pwr_len + 1;
+ if (!len)
+ break;
+
+ cur = be32_to_cpu(data[0]);
+ }
+}
+
+s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
+ struct ieee80211_channel *chan,
+ struct mt76_power_limits *dest,
+ s8 target_power)
+{
+ struct mt76_dev *dev = phy->dev;
+ struct device_node *np;
+ const __be32 *val;
+ char name[16];
+ u32 mcs_rates = dev->drv->mcs_rates;
+ u32 ru_rates = ARRAY_SIZE(dest->ru[0]);
+ char band;
+ size_t len;
+ s8 max_power = 0;
+ s8 txs_delta;
+
+ if (!mcs_rates)
+ mcs_rates = 10;
+
+ memset(dest, target_power, sizeof(*dest));
+
+ if (!IS_ENABLED(CONFIG_OF))
+ return target_power;
+
+ np = mt76_find_power_limits_node(dev);
+ if (!np)
+ return target_power;
+
+ switch (chan->band) {
+ case NL80211_BAND_2GHZ:
+ band = '2';
+ break;
+ case NL80211_BAND_5GHZ:
+ band = '5';
+ break;
+ default:
+ return target_power;
+ }
+
+ snprintf(name, sizeof(name), "txpower-%cg", band);
+ np = of_get_child_by_name(np, name);
+ if (!np)
+ return target_power;
+
+ np = mt76_find_channel_node(np, chan);
+ if (!np)
+ return target_power;
+
+ txs_delta = mt76_get_txs_delta(np, hweight8(phy->antenna_mask));
+
+ val = mt76_get_of_array(np, "rates-cck", &len, ARRAY_SIZE(dest->cck));
+ mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val,
+ target_power, txs_delta, &max_power);
+
+ val = mt76_get_of_array(np, "rates-ofdm",
+ &len, ARRAY_SIZE(dest->ofdm));
+ mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val,
+ target_power, txs_delta, &max_power);
+
+ val = mt76_get_of_array(np, "rates-mcs", &len, mcs_rates + 1);
+ mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]),
+ ARRAY_SIZE(dest->mcs), val, len,
+ target_power, txs_delta, &max_power);
+
+ val = mt76_get_of_array(np, "rates-ru", &len, ru_rates + 1);
+ mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]),
+ ARRAY_SIZE(dest->ru), val, len,
+ target_power, txs_delta, &max_power);
+
+ return max_power;
+}
+EXPORT_SYMBOL_GPL(mt76_get_rate_power_limits);
+
int
mt76_eeprom_init(struct mt76_dev *dev, int len)
{
@@ -112,6 +331,6 @@ mt76_eeprom_init(struct mt76_dev *dev, int len)
if (!dev->eeprom.data)
return -ENOMEM;
- return !mt76_get_of_eeprom(dev, len);
+ return !mt76_get_of_eeprom(dev, dev->eeprom.data, 0, len);
}
EXPORT_SYMBOL_GPL(mt76_eeprom_init);
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 29ef15ec22fe..977acab0360a 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -428,6 +428,9 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
mutex_init(&dev->mcu.mutex);
dev->tx_worker.fn = mt76_tx_worker;
+ spin_lock_init(&dev->token_lock);
+ idr_init(&dev->token);
+
INIT_LIST_HEAD(&dev->txwi_cache);
for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c
index 70624cd07449..d3a5e2c4f12a 100644
--- a/drivers/net/wireless/mediatek/mt76/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mcu.c
@@ -99,10 +99,6 @@ int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
dev_kfree_skb(skb);
} while (ret == -EAGAIN);
- /* notify driver code to reset the mcu */
- if (ret == -ETIMEDOUT && dev->mcu_ops->mcu_reset)
- dev->mcu_ops->mcu_reset(dev);
-
out:
mutex_unlock(&dev->mcu.mutex);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index d121c176c37c..36ede65919f8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -17,12 +17,14 @@
#include "util.h"
#include "testmode.h"
-#define MT_MCU_RING_SIZE 32
-#define MT_RX_BUF_SIZE 2048
-#define MT_SKB_HEAD_LEN 128
+#define MT_MCU_RING_SIZE 32
+#define MT_RX_BUF_SIZE 2048
+#define MT_SKB_HEAD_LEN 128
-#define MT_MAX_NON_AQL_PKT 16
-#define MT_TXQ_FREE_THR 32
+#define MT_MAX_NON_AQL_PKT 16
+#define MT_TXQ_FREE_THR 32
+
+#define MT76_TOKEN_FREE_THR 64
struct mt76_dev;
struct mt76_phy;
@@ -166,11 +168,11 @@ struct mt76_mcu_ops {
int (*mcu_rd_rp)(struct mt76_dev *dev, u32 base,
struct mt76_reg_pair *rp, int len);
int (*mcu_restart)(struct mt76_dev *dev);
- void (*mcu_reset)(struct mt76_dev *dev);
};
struct mt76_queue_ops {
- int (*init)(struct mt76_dev *dev);
+ int (*init)(struct mt76_dev *dev,
+ int (*poll)(struct napi_struct *napi, int budget));
int (*alloc)(struct mt76_dev *dev, struct mt76_queue *q,
int idx, int n_desc, int bufsize,
@@ -331,6 +333,8 @@ struct mt76_driver_ops {
u32 drv_flags;
u32 survey_flags;
u16 txwi_size;
+ u16 token_size;
+ u8 mcs_rates;
void (*update_survey)(struct mt76_dev *dev);
@@ -538,7 +542,7 @@ struct mt76_testmode_data {
struct sk_buff *tx_skb;
u32 tx_count;
- u16 tx_msdu_len;
+ u16 tx_mpdu_len;
u8 tx_rate_mode;
u8 tx_rate_idx;
@@ -657,6 +661,10 @@ struct mt76_dev {
struct mt76_worker tx_worker;
struct napi_struct tx_napi;
+ spinlock_t token_lock;
+ struct idr token;
+ int token_count;
+
wait_queue_head_t tx_wait;
struct sk_buff_head status_list;
@@ -711,6 +719,13 @@ struct mt76_dev {
};
};
+struct mt76_power_limits {
+ s8 cck[4];
+ s8 ofdm[8];
+ s8 mcs[4][10];
+ s8 ru[7][12];
+};
+
enum mt76_phy_type {
MT_PHY_TYPE_CCK,
MT_PHY_TYPE_OFDM,
@@ -794,7 +809,7 @@ static inline u16 mt76_rev(struct mt76_dev *dev)
#define mt76xx_chip(dev) mt76_chip(&((dev)->mt76))
#define mt76xx_rev(dev) mt76_rev(&((dev)->mt76))
-#define mt76_init_queues(dev) (dev)->mt76.queue_ops->init(&((dev)->mt76))
+#define mt76_init_queues(dev, ...) (dev)->mt76.queue_ops->init(&((dev)->mt76), __VA_ARGS__)
#define mt76_queue_alloc(dev, ...) (dev)->mt76.queue_ops->alloc(&((dev)->mt76), __VA_ARGS__)
#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__)
@@ -829,6 +844,7 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str,
int mt76_eeprom_init(struct mt76_dev *dev, int len);
void mt76_eeprom_override(struct mt76_phy *phy);
+int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len);
struct mt76_queue *
mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
@@ -1006,6 +1022,7 @@ void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta,
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);
void mt76_txq_schedule_all(struct mt76_phy *phy);
+void mt76_tx_worker_run(struct mt76_dev *dev);
void mt76_tx_worker(struct mt76_worker *w);
void mt76_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
@@ -1074,6 +1091,7 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
struct netlink_callback *cb, void *data, int len);
int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state);
+int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len);
static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable)
{
@@ -1194,4 +1212,45 @@ mt76_mcu_skb_send_msg(struct mt76_dev *dev, struct sk_buff *skb, int cmd,
void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, u32 clear, u32 set);
+s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
+ struct ieee80211_channel *chan,
+ struct mt76_power_limits *dest,
+ s8 target_power);
+
+struct mt76_txwi_cache *
+mt76_token_release(struct mt76_dev *dev, int token, bool *wake);
+int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi);
+void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked);
+
+static inline void mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked)
+{
+ spin_lock_bh(&dev->token_lock);
+ __mt76_set_tx_blocked(dev, blocked);
+ spin_unlock_bh(&dev->token_lock);
+}
+
+static inline int
+mt76_token_get(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi)
+{
+ int token;
+
+ spin_lock_bh(&dev->token_lock);
+ token = idr_alloc(&dev->token, *ptxwi, 0, dev->drv->token_size,
+ GFP_ATOMIC);
+ spin_unlock_bh(&dev->token_lock);
+
+ return token;
+}
+
+static inline struct mt76_txwi_cache *
+mt76_token_put(struct mt76_dev *dev, int token)
+{
+ struct mt76_txwi_cache *txwi;
+
+ spin_lock_bh(&dev->token_lock);
+ txwi = idr_remove(&dev->token, token);
+ spin_unlock_bh(&dev->token_lock);
+
+ return txwi;
+}
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
index 2b6244116842..415ea17b9be6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
@@ -219,7 +219,7 @@ int mt7603_dma_init(struct mt7603_dev *dev)
return ret;
mt76_wr(dev, MT_DELAY_INT_CFG, 0);
- ret = mt76_init_queues(dev);
+ ret = mt76_init_queues(dev, mt76_dma_rx_poll);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
index e3a9dd6fbd87..fbceb07c5f37 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
@@ -1445,6 +1445,8 @@ static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev)
mt76_queue_rx_reset(dev, i);
}
+ mt76_tx_status_check(&dev->mt76, NULL, true);
+
mt7603_dma_sched_reset(dev);
mt7603_mac_dma_start(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
index 96b6c8916730..6abfe6b19afa 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
@@ -21,9 +21,8 @@ mt7603_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct mt7603_mcu_rxd *rxd;
if (!skb) {
- dev_err(mdev->dev,
- "MCU message %d (seq %d) timed out\n",
- cmd, seq);
+ dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n",
+ abs(cmd), seq);
dev->mcu_hang = MT7603_WATCHDOG_TIMEOUT;
return -ETIMEDOUT;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
index 1b414220521a..676bb22726d6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
@@ -69,6 +69,7 @@ static int
mt7615_pm_set(void *data, u64 val)
{
struct mt7615_dev *dev = data;
+ struct mt76_connac_pm *pm = &dev->pm;
int ret = 0;
if (!mt7615_wait_for_mcu_init(dev))
@@ -77,6 +78,9 @@ mt7615_pm_set(void *data, u64 val)
if (!mt7615_firmware_offload(dev) || !mt76_is_mmio(&dev->mt76))
return -EOPNOTSUPP;
+ if (val == pm->enable)
+ return 0;
+
mt7615_mutex_acquire(dev);
if (dev->phy.n_beacon_vif) {
@@ -84,7 +88,11 @@ mt7615_pm_set(void *data, u64 val)
goto out;
}
- dev->pm.enable = val;
+ if (!pm->enable) {
+ pm->stats.last_wake_event = jiffies;
+ pm->stats.last_doze_event = jiffies;
+ }
+ pm->enable = val;
out:
mt7615_mutex_release(dev);
@@ -104,6 +112,26 @@ mt7615_pm_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7615_pm_get, mt7615_pm_set, "%lld\n");
static int
+mt7615_pm_stats(struct seq_file *s, void *data)
+{
+ struct mt7615_dev *dev = dev_get_drvdata(s->private);
+ struct mt76_connac_pm *pm = &dev->pm;
+ unsigned long awake_time = pm->stats.awake_time;
+ unsigned long doze_time = pm->stats.doze_time;
+
+ if (!test_bit(MT76_STATE_PM, &dev->mphy.state))
+ awake_time += jiffies - pm->stats.last_wake_event;
+ else
+ doze_time += jiffies - pm->stats.last_doze_event;
+
+ seq_printf(s, "awake time: %14u\ndoze time: %15u\n",
+ jiffies_to_msecs(awake_time),
+ jiffies_to_msecs(doze_time));
+
+ return 0;
+}
+
+static int
mt7615_pm_idle_timeout_set(void *data, u64 val)
{
struct mt7615_dev *dev = data;
@@ -515,6 +543,8 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm);
debugfs_create_file("idle-timeout", 0600, dir, dev,
&fops_pm_idle_timeout);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir,
+ mt7615_pm_stats);
debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir,
mt7615_radio_read);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
index 0ec1c526f583..8004ae5c16a9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -71,15 +71,39 @@ static int mt7615_poll_tx(struct napi_struct *napi, int budget)
struct mt7615_dev *dev;
dev = container_of(napi, struct mt7615_dev, mt76.tx_napi);
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ napi_complete(napi);
+ queue_work(dev->mt76.wq, &dev->pm.wake_work);
+ return 0;
+ }
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
-
- if (napi_complete_done(napi, 0))
+ if (napi_complete(napi))
mt7615_irq_enable(dev, mt7615_tx_mcu_int_mask(dev));
+ mt76_connac_pm_unref(&dev->pm);
+
return 0;
}
+static int mt7615_poll_rx(struct napi_struct *napi, int budget)
+{
+ struct mt7615_dev *dev;
+ int done;
+
+ dev = container_of(napi->dev, struct mt7615_dev, mt76.napi_dev);
+
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ napi_complete(napi);
+ queue_work(dev->mt76.wq, &dev->pm.wake_work);
+ return 0;
+ }
+ done = mt76_dma_rx_poll(napi, budget);
+ mt76_connac_pm_unref(&dev->pm);
+
+ return done;
+}
+
int mt7615_wait_pdma_busy(struct mt7615_dev *dev)
{
struct mt76_dev *mdev = &dev->mt76;
@@ -187,14 +211,19 @@ void mt7615_dma_start(struct mt7615_dev *dev)
if (is_mt7622(&dev->mt76))
mt7622_dma_sched_init(dev);
- if (is_mt7663(&dev->mt76))
+ if (is_mt7663(&dev->mt76)) {
mt7663_dma_sched_init(dev);
+
+ mt76_wr(dev, MT_MCU2HOST_INT_ENABLE, MT7663_MCU_CMD_ERROR_MASK);
+ }
+
}
int mt7615_dma_init(struct mt7615_dev *dev)
{
int rx_ring_size = MT7615_RX_RING_SIZE;
int rx_buf_size = MT_RX_BUF_SIZE;
+ u32 mask;
int ret;
/* Increase buffer size to receive large VHT MPDUs */
@@ -256,7 +285,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)
mt76_wr(dev, MT_DELAY_INT_CFG, 0);
- ret = mt76_init_queues(dev);
+ ret = mt76_init_queues(dev, mt7615_poll_rx);
if (ret < 0)
return ret;
@@ -269,8 +298,14 @@ int mt7615_dma_init(struct mt7615_dev *dev)
MT_WPDMA_GLO_CFG_RX_DMA_BUSY, 0, 1000);
/* enable interrupts for TX/RX rings */
- mt7615_irq_enable(dev, MT_INT_RX_DONE_ALL | mt7615_tx_mcu_int_mask(dev) |
- MT_INT_MCU_CMD);
+
+ mask = MT_INT_RX_DONE_ALL | mt7615_tx_mcu_int_mask(dev);
+ if (is_mt7663(&dev->mt76))
+ mask |= MT7663_INT_MCU_CMD;
+ else
+ mask |= MT_INT_MCU_CMD;
+
+ mt7615_irq_enable(dev, mask);
mt7615_dma_start(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index 1e418740c17b..86341d1f82f3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -252,6 +252,7 @@ void mt7615_init_txpower(struct mt7615_dev *dev,
int delta_idx, delta = mt76_tx_power_nss_delta(n_chains);
u8 *eep = (u8 *)dev->mt76.eeprom.data;
enum nl80211_band band = sband->band;
+ struct mt76_power_limits limits;
u8 rate_val;
delta_idx = mt7615_eeprom_get_power_delta_index(dev, band);
@@ -280,7 +281,11 @@ void mt7615_init_txpower(struct mt7615_dev *dev,
target_power = max(target_power, eep[index]);
}
- target_power = DIV_ROUND_UP(target_power + delta, 2);
+ target_power = mt76_get_rate_power_limits(&dev->mphy, chan,
+ &limits,
+ target_power);
+ target_power += delta;
+ target_power = DIV_ROUND_UP(target_power, 2);
chan->max_power = min_t(int, chan->max_reg_power,
target_power);
chan->orig_mpwr = target_power;
@@ -311,12 +316,18 @@ mt7615_regd_notifier(struct wiphy *wiphy,
memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
dev->mt76.region = request->dfs_region;
+ mt7615_init_txpower(dev, &mphy->sband_2g.sband);
+ mt7615_init_txpower(dev, &mphy->sband_5g.sband);
+
mt7615_mutex_acquire(dev);
if (chandef->chan->flags & IEEE80211_CHAN_RADAR)
mt7615_dfs_init_radar_detector(phy);
- if (mt7615_firmware_offload(phy->dev))
+
+ if (mt7615_firmware_offload(phy->dev)) {
mt76_connac_mcu_set_channel_domain(mphy);
+ mt76_connac_mcu_set_rate_txpower(mphy);
+ }
mt7615_mutex_release(dev);
}
@@ -491,10 +502,13 @@ void mt7615_init_device(struct mt7615_dev *dev)
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
dev->mt76.phy.priv = &dev->phy;
+ dev->mt76.tx_worker.fn = mt7615_tx_worker;
INIT_DELAYED_WORK(&dev->pm.ps_work, mt7615_pm_power_save_work);
INIT_WORK(&dev->pm.wake_work, mt7615_pm_wake_work);
- init_completion(&dev->pm.wake_cmpl);
+ spin_lock_init(&dev->pm.wake.lock);
+ mutex_init(&dev->pm.mutex);
+ init_waitqueue_head(&dev->pm.wait);
spin_lock_init(&dev->pm.txq_lock);
set_bit(MT76_STATE_PM, &dev->mphy.state);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7615_mac_work);
@@ -512,6 +526,8 @@ void mt7615_init_device(struct mt7615_dev *dev)
mt7615_init_wiphy(hw);
dev->pm.idle_timeout = MT7615_PM_TIMEOUT;
+ dev->pm.stats.last_wake_event = jiffies;
+ dev->pm.stats.last_doze_event = jiffies;
mt7615_cap_dbdc_disable(dev);
dev->phy.dfs_state = -1;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index 005c2829d3df..f81a17d56008 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -1465,11 +1465,7 @@ mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
u8 wcid;
trace_mac_tx_free(dev, token);
-
- spin_lock_bh(&dev->token_lock);
- txwi = idr_remove(&dev->token, token);
- spin_unlock_bh(&dev->token_lock);
-
+ txwi = mt76_token_put(mdev, token);
if (!txwi)
return;
@@ -1514,14 +1510,10 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
dev_kfree_skb(skb);
- if (test_bit(MT76_STATE_PM, &dev->phy.mt76->state))
- return;
-
rcu_read_lock();
mt7615_mac_sta_poll(dev);
rcu_read_unlock();
- mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
mt76_worker_schedule(&dev->mt76.tx_worker);
}
@@ -1913,13 +1905,19 @@ void mt7615_pm_wake_work(struct work_struct *work)
pm.wake_work);
mphy = dev->phy.mt76;
- if (!mt7615_mcu_set_drv_ctrl(dev))
+ if (!mt7615_mcu_set_drv_ctrl(dev)) {
+ int i;
+
+ mt76_for_each_q_rx(&dev->mt76, i)
+ napi_schedule(&dev->mt76.napi[i]);
mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
- else
- dev_err(mphy->dev->dev, "failed to wake device\n");
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_WM], false);
+ ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
+ MT7615_WATCHDOG_TIME);
+ }
ieee80211_wake_queues(mphy->hw);
- complete_all(&dev->pm.wake_cmpl);
+ wake_up(&dev->pm.wait);
}
void mt7615_pm_power_save_work(struct work_struct *work)
@@ -1931,6 +1929,10 @@ void mt7615_pm_power_save_work(struct work_struct *work)
pm.ps_work.work);
delta = dev->pm.idle_timeout;
+ if (test_bit(MT76_HW_SCANNING, &dev->mphy.state) ||
+ test_bit(MT76_HW_SCHED_SCANNING, &dev->mphy.state))
+ goto out;
+
if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
delta = dev->pm.last_activity + delta - jiffies;
goto out;
@@ -1973,15 +1975,19 @@ void mt7615_tx_token_put(struct mt7615_dev *dev)
struct mt76_txwi_cache *txwi;
int id;
- spin_lock_bh(&dev->token_lock);
- idr_for_each_entry(&dev->token, txwi, id) {
+ spin_lock_bh(&dev->mt76.token_lock);
+ idr_for_each_entry(&dev->mt76.token, txwi, id) {
mt7615_txp_skb_unmap(&dev->mt76, txwi);
- if (txwi->skb)
- dev_kfree_skb_any(txwi->skb);
+ if (txwi->skb) {
+ struct ieee80211_hw *hw;
+
+ hw = mt76_tx_status_get_hw(&dev->mt76, txwi->skb);
+ ieee80211_free_txskb(hw, txwi->skb);
+ }
mt76_put_txwi(&dev->mt76, txwi);
}
- spin_unlock_bh(&dev->token_lock);
- idr_destroy(&dev->token);
+ spin_unlock_bh(&dev->mt76.token_lock);
+ idr_destroy(&dev->mt76.token);
}
EXPORT_SYMBOL_GPL(mt7615_tx_token_put);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index e30b256784e0..39733b351ac4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -66,6 +66,10 @@ static int mt7615_start(struct ieee80211_hw *hw)
ret = mt76_connac_mcu_set_channel_domain(phy->mt76);
if (ret)
goto out;
+
+ ret = mt76_connac_mcu_set_rate_txpower(phy->mt76);
+ if (ret)
+ goto out;
}
ret = mt7615_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH);
@@ -347,8 +351,7 @@ out:
mt7615_mutex_release(dev);
- mt76_txq_schedule_all(phy->mt76);
-
+ mt76_worker_schedule(&dev->mt76.tx_worker);
if (!mt76_testmode_enabled(phy->mt76))
ieee80211_queue_delayed_work(phy->mt76->hw,
&phy->mt76->mac_work,
@@ -574,8 +577,13 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_PS)
mt76_connac_mcu_set_vif_ps(&dev->mt76, vif);
- if (changed & BSS_CHANGED_ARP_FILTER)
- mt7615_mcu_update_arp_filter(hw, vif, info);
+ if ((changed & BSS_CHANGED_ARP_FILTER) &&
+ mt7615_firmware_offload(dev)) {
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+
+ mt76_connac_mcu_update_arp_filter(&dev->mt76, &mvif->mt76,
+ info);
+ }
if (changed & BSS_CHANGED_ASSOC)
mt7615_mac_set_beacon_filter(phy, vif, info->assoc);
@@ -685,28 +693,25 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw,
break;
}
msta->n_rates = i;
- if (!test_bit(MT76_STATE_PM, &phy->mt76->state))
+ if (mt76_connac_pm_ref(phy->mt76, &dev->pm)) {
mt7615_mac_set_rates(phy, msta, NULL, msta->rates);
+ mt76_connac_pm_unref(&dev->pm);
+ }
spin_unlock_bh(&dev->mt76.lock);
}
-static void
-mt7615_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
+void mt7615_tx_worker(struct mt76_worker *w)
{
- struct mt7615_dev *dev = mt7615_hw_dev(hw);
- struct mt7615_phy *phy = mt7615_hw_phy(hw);
- struct mt76_phy *mphy = phy->mt76;
+ struct mt7615_dev *dev = container_of(w, struct mt7615_dev,
+ mt76.tx_worker);
- if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
- return;
-
- if (test_bit(MT76_STATE_PM, &mphy->state)) {
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
queue_work(dev->mt76.wq, &dev->pm.wake_work);
return;
}
- dev->pm.last_activity = jiffies;
- mt76_worker_schedule(&dev->mt76.tx_worker);
+ mt76_tx_worker_run(&dev->mt76);
+ mt76_connac_pm_unref(&dev->pm);
}
static void mt7615_tx(struct ieee80211_hw *hw,
@@ -734,9 +739,9 @@ static void mt7615_tx(struct ieee80211_hw *hw,
wcid = &msta->wcid;
}
- if (!test_bit(MT76_STATE_PM, &mphy->state)) {
- dev->pm.last_activity = jiffies;
+ if (mt76_connac_pm_ref(mphy, &dev->pm)) {
mt76_tx(mphy, control->sta, wcid, skb);
+ mt76_connac_pm_unref(&dev->pm);
return;
}
@@ -1263,7 +1268,7 @@ const struct ieee80211_ops mt7615_ops = {
.sta_set_decap_offload = mt7615_sta_set_decap_offload,
.ampdu_action = mt7615_ampdu_action,
.set_rts_threshold = mt7615_set_rts_threshold,
- .wake_tx_queue = mt7615_wake_tx_queue,
+ .wake_tx_queue = mt76_wake_tx_queue,
.sta_rate_tbl_update = mt7615_sta_rate_tbl_update,
.sw_scan_start = mt76_sw_scan,
.sw_scan_complete = mt76_sw_scan_complete,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 9b9f8d88e9bb..aa42af9ebfd6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -175,8 +175,8 @@ int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,
int ret = 0;
if (!skb) {
- dev_err(mdev->dev, "Message %ld (seq %d) timeout\n",
- cmd & MCU_CMD_MASK, seq);
+ dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
+ cmd, seq);
return -ETIMEDOUT;
}
@@ -288,16 +288,25 @@ EXPORT_SYMBOL_GPL(mt7622_trigger_hif_int);
static int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
struct mt76_dev *mdev = &dev->mt76;
u32 addr;
int err;
- addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST;
+ if (is_mt7663(mdev)) {
+ /* Clear firmware own via N9 eint */
+ mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN);
+ mt76_poll(dev, MT_CONN_ON_MISC, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);
+
+ addr = MT_CONN_HIF_ON_LPCTL;
+ } else {
+ addr = MT_CFG_LPCR_HOST;
+ }
+
mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN);
mt7622_trigger_hif_int(dev, true);
- addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
err = !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000);
mt7622_trigger_hif_int(dev, false);
@@ -309,15 +318,22 @@ static int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev)
clear_bit(MT76_STATE_PM, &mphy->state);
+ pm->stats.last_wake_event = jiffies;
+ pm->stats.doze_time += pm->stats.last_wake_event -
+ pm->stats.last_doze_event;
+
return 0;
}
static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
- int i;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int i, err = 0;
+
+ mutex_lock(&pm->mutex);
- if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state))
+ if (!test_bit(MT76_STATE_PM, &mphy->state))
goto out;
for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) {
@@ -329,24 +345,31 @@ static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)
if (i == MT7615_DRV_OWN_RETRY_COUNT) {
dev_err(dev->mt76.dev, "driver own failed\n");
- set_bit(MT76_STATE_PM, &mphy->state);
- return -EIO;
+ err = -EIO;
+ goto out;
}
+ clear_bit(MT76_STATE_PM, &mphy->state);
+ pm->stats.last_wake_event = jiffies;
+ pm->stats.doze_time += pm->stats.last_wake_event -
+ pm->stats.last_doze_event;
out:
- dev->pm.last_activity = jiffies;
+ mutex_unlock(&pm->mutex);
- return 0;
+ return err;
}
static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_connac_pm *pm = &dev->pm;
int err = 0;
u32 addr;
- if (test_and_set_bit(MT76_STATE_PM, &mphy->state))
- return 0;
+ mutex_lock(&pm->mutex);
+
+ if (mt76_connac_skip_fw_pmctrl(mphy, pm))
+ goto out;
mt7622_trigger_hif_int(dev, true);
@@ -363,6 +386,12 @@ static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)
mt7622_trigger_hif_int(dev, false);
+ pm->stats.last_doze_event = jiffies;
+ pm->stats.awake_time += pm->stats.last_doze_event -
+ pm->stats.last_wake_event;
+out:
+ mutex_unlock(&pm->mutex);
+
return err;
}
@@ -424,7 +453,7 @@ mt7615_mcu_rx_log_message(struct mt7615_dev *dev, struct sk_buff *skb)
break;
}
- wiphy_info(mt76_hw(dev)->wiphy, "%s: %*s", type,
+ wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type,
(int)(skb->len - sizeof(*rxd)), data);
}
@@ -1333,25 +1362,26 @@ static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)
const struct firmware *fw = NULL;
int len, ret, sem;
+ ret = firmware_request_nowarn(&fw, name, dev->mt76.dev);
+ if (ret)
+ return ret;
+
+ if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
+ dev_err(dev->mt76.dev, "Invalid firmware\n");
+ ret = -EINVAL;
+ goto release_fw;
+ }
+
sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, true);
switch (sem) {
case PATCH_IS_DL:
- return 0;
+ goto release_fw;
case PATCH_NOT_DL_SEM_SUCCESS:
break;
default:
dev_err(dev->mt76.dev, "Failed to get patch semaphore\n");
- return -EAGAIN;
- }
-
- ret = firmware_request_nowarn(&fw, name, dev->mt76.dev);
- if (ret)
- goto out;
-
- if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
- dev_err(dev->mt76.dev, "Invalid firmware\n");
- ret = -EINVAL;
- goto out;
+ ret = -EAGAIN;
+ goto release_fw;
}
hdr = (const struct mt7615_patch_hdr *)(fw->data);
@@ -1380,8 +1410,6 @@ static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)
dev_err(dev->mt76.dev, "Failed to start patch\n");
out:
- release_firmware(fw);
-
sem = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false);
switch (sem) {
case PATCH_REL_SEM_SUCCESS:
@@ -1392,6 +1420,9 @@ out:
break;
}
+release_fw:
+ release_firmware(fw);
+
return ret;
}
@@ -2137,16 +2168,80 @@ static void mt7615_mcu_set_txpower_sku(struct mt7615_phy *phy, u8 *sku)
{
struct mt76_phy *mphy = phy->mt76;
struct ieee80211_hw *hw = mphy->hw;
+ struct mt76_power_limits limits;
+ s8 *limits_array = (s8 *)&limits;
int n_chains = hweight8(mphy->antenna_mask);
int tx_power;
int i;
+ static const u8 sku_mapping[] = {
+#define SKU_FIELD(_type, _field) \
+ [MT_SKU_##_type] = offsetof(struct mt76_power_limits, _field)
+ SKU_FIELD(CCK_1_2, cck[0]),
+ SKU_FIELD(CCK_55_11, cck[2]),
+ SKU_FIELD(OFDM_6_9, ofdm[0]),
+ SKU_FIELD(OFDM_12_18, ofdm[2]),
+ SKU_FIELD(OFDM_24_36, ofdm[4]),
+ SKU_FIELD(OFDM_48, ofdm[6]),
+ SKU_FIELD(OFDM_54, ofdm[7]),
+ SKU_FIELD(HT20_0_8, mcs[0][0]),
+ SKU_FIELD(HT20_32, ofdm[0]),
+ SKU_FIELD(HT20_1_2_9_10, mcs[0][1]),
+ SKU_FIELD(HT20_3_4_11_12, mcs[0][3]),
+ SKU_FIELD(HT20_5_13, mcs[0][5]),
+ SKU_FIELD(HT20_6_14, mcs[0][6]),
+ SKU_FIELD(HT20_7_15, mcs[0][7]),
+ SKU_FIELD(HT40_0_8, mcs[1][0]),
+ SKU_FIELD(HT40_32, ofdm[0]),
+ SKU_FIELD(HT40_1_2_9_10, mcs[1][1]),
+ SKU_FIELD(HT40_3_4_11_12, mcs[1][3]),
+ SKU_FIELD(HT40_5_13, mcs[1][5]),
+ SKU_FIELD(HT40_6_14, mcs[1][6]),
+ SKU_FIELD(HT40_7_15, mcs[1][7]),
+ SKU_FIELD(VHT20_0, mcs[0][0]),
+ SKU_FIELD(VHT20_1_2, mcs[0][1]),
+ SKU_FIELD(VHT20_3_4, mcs[0][3]),
+ SKU_FIELD(VHT20_5_6, mcs[0][5]),
+ SKU_FIELD(VHT20_7, mcs[0][7]),
+ SKU_FIELD(VHT20_8, mcs[0][8]),
+ SKU_FIELD(VHT20_9, mcs[0][9]),
+ SKU_FIELD(VHT40_0, mcs[1][0]),
+ SKU_FIELD(VHT40_1_2, mcs[1][1]),
+ SKU_FIELD(VHT40_3_4, mcs[1][3]),
+ SKU_FIELD(VHT40_5_6, mcs[1][5]),
+ SKU_FIELD(VHT40_7, mcs[1][7]),
+ SKU_FIELD(VHT40_8, mcs[1][8]),
+ SKU_FIELD(VHT40_9, mcs[1][9]),
+ SKU_FIELD(VHT80_0, mcs[2][0]),
+ SKU_FIELD(VHT80_1_2, mcs[2][1]),
+ SKU_FIELD(VHT80_3_4, mcs[2][3]),
+ SKU_FIELD(VHT80_5_6, mcs[2][5]),
+ SKU_FIELD(VHT80_7, mcs[2][7]),
+ SKU_FIELD(VHT80_8, mcs[2][8]),
+ SKU_FIELD(VHT80_9, mcs[2][9]),
+ SKU_FIELD(VHT160_0, mcs[3][0]),
+ SKU_FIELD(VHT160_1_2, mcs[3][1]),
+ SKU_FIELD(VHT160_3_4, mcs[3][3]),
+ SKU_FIELD(VHT160_5_6, mcs[3][5]),
+ SKU_FIELD(VHT160_7, mcs[3][7]),
+ SKU_FIELD(VHT160_8, mcs[3][8]),
+ SKU_FIELD(VHT160_9, mcs[3][9]),
+#undef SKU_FIELD
+ };
tx_power = hw->conf.power_level * 2 -
mt76_tx_power_nss_delta(n_chains);
+
+ tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
+ &limits, tx_power);
mphy->txpower_cur = tx_power;
+ if (is_mt7663(mphy->dev)) {
+ memset(sku, tx_power, MT_SKU_4SS_DELTA + 1);
+ return;
+ }
+
for (i = 0; i < MT_SKU_1SS_DELTA; i++)
- sku[i] = tx_power;
+ sku[i] = limits_array[sku_mapping[i]];
for (i = 0; i < 4; i++) {
int delta = 0;
@@ -2630,53 +2725,6 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
sizeof(req), false);
}
-int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info)
-{
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct mt7615_dev *dev = mt7615_hw_dev(hw);
- struct sk_buff *skb;
- int i, len = min_t(int, info->arp_addr_cnt,
- IEEE80211_BSS_ARP_ADDR_LIST_LEN);
- struct {
- struct {
- u8 bss_idx;
- u8 pad[3];
- } __packed hdr;
- struct mt76_connac_arpns_tlv arp;
- } req_hdr = {
- .hdr = {
- .bss_idx = mvif->mt76.idx,
- },
- .arp = {
- .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP),
- .len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)),
- .ips_num = len,
- .mode = 2, /* update */
- .option = 1,
- },
- };
-
- if (!mt7615_firmware_offload(dev))
- return 0;
-
- skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
- sizeof(req_hdr) + len * sizeof(__be32));
- if (!skb)
- return -ENOMEM;
-
- skb_put_data(skb, &req_hdr, sizeof(req_hdr));
- for (i = 0; i < len; i++) {
- u8 *addr = (u8 *)skb_put(skb, sizeof(__be32));
-
- memcpy(addr, &info->arp_addr_list[i], sizeof(__be32));
- }
-
- return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_OFFLOAD,
- true);
-}
-
int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
index eaa22752e7cd..202ea235415e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
@@ -105,6 +105,7 @@ static void mt7615_irq_tasklet(struct tasklet_struct *t)
{
struct mt7615_dev *dev = from_tasklet(dev, t, irq_tasklet);
u32 intr, mask = 0, tx_mcu_mask = mt7615_tx_mcu_int_mask(dev);
+ u32 mcu_int;
mt76_wr(dev, MT_INT_MASK_CSR, 0);
@@ -128,15 +129,23 @@ static void mt7615_irq_tasklet(struct tasklet_struct *t)
if (intr & MT_INT_RX_DONE(1))
napi_schedule(&dev->mt76.napi[1]);
- if (intr & MT_INT_MCU_CMD) {
- u32 val = mt76_rr(dev, MT_MCU_CMD);
+ if (!(intr & (MT_INT_MCU_CMD | MT7663_INT_MCU_CMD)))
+ return;
- if (val & MT_MCU_CMD_ERROR_MASK) {
- dev->reset_state = val;
- ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
- wake_up(&dev->reset_wait);
- }
+ if (is_mt7663(&dev->mt76)) {
+ mcu_int = mt76_rr(dev, MT_MCU2HOST_INT_STATUS);
+ mcu_int &= MT7663_MCU_CMD_ERROR_MASK;
+ } else {
+ mcu_int = mt76_rr(dev, MT_MCU_CMD);
+ mcu_int &= MT_MCU_CMD_ERROR_MASK;
}
+
+ if (!mcu_int)
+ return;
+
+ dev->reset_state = mcu_int;
+ ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
+ wake_up(&dev->reset_wait);
}
static u32 __mt7615_reg_addr(struct mt7615_dev *dev, u32 addr)
@@ -181,6 +190,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
.survey_flags = SURVEY_INFO_TIME_TX |
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_BSS_RX,
+ .token_size = MT7615_TOKEN_SIZE,
.tx_prepare_skb = mt7615_tx_prepare_skb,
.tx_complete_skb = mt7615_tx_complete_skb,
.rx_skb = mt7615_queue_rx_skb,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 6a50338ec9f5..989f05ed4377 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -263,9 +263,6 @@ struct mt7615_dev {
bool flash_eeprom;
bool dbdc_support;
- spinlock_t token_lock;
- struct idr token;
-
u8 fw_ver;
struct work_struct rate_work;
@@ -508,6 +505,7 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
+void mt7615_tx_worker(struct mt76_worker *w);
void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
void mt7615_tx_token_put(struct mt7615_dev *dev);
void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
@@ -549,9 +547,6 @@ int mt7615_mac_set_beacon_filter(struct mt7615_phy *phy,
bool enable);
int mt7615_mcu_set_bss_pm(struct mt7615_dev *dev, struct ieee80211_vif *vif,
bool enable);
-int mt7615_mcu_update_arp_filter(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info);
int __mt7663_load_firmware(struct mt7615_dev *dev);
u32 mt7615_mcu_reg_rr(struct mt76_dev *dev, u32 offset);
void mt7615_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
index a629d9cb3806..ec8ec1a2033f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
@@ -40,13 +40,16 @@ static int mt7615_init_hardware(struct mt7615_dev *dev)
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
INIT_WORK(&dev->mcu_work, mt7615_pci_init_work);
- spin_lock_init(&dev->token_lock);
- idr_init(&dev->token);
-
ret = mt7615_eeprom_init(dev, addr);
if (ret < 0)
return ret;
+ if (is_mt7663(&dev->mt76)) {
+ /* Reset RGU */
+ mt76_clear(dev, MT_MCU_CIRQ_IRQ_SEL(4), BIT(1));
+ mt76_set(dev, MT_MCU_CIRQ_IRQ_SEL(4), BIT(1));
+ }
+
ret = mt7615_dma_init(dev);
if (ret)
return ret;
@@ -76,7 +79,7 @@ mt7615_led_set_config(struct led_classdev *led_cdev,
mt76 = container_of(led_cdev, struct mt76_dev, led_cdev);
dev = container_of(mt76, struct mt7615_dev, mt76);
- if (test_bit(MT76_STATE_PM, &mt76->phy.state))
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm))
return;
val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xffff) |
@@ -94,6 +97,8 @@ mt7615_led_set_config(struct led_classdev *led_cdev,
val |= MT_LED_CTRL_POLARITY(mt76->led_pin);
addr = mt7615_reg_map(dev, MT_LED_CTRL);
mt76_wr(dev, addr, val);
+
+ mt76_connac_pm_unref(&dev->pm);
}
static int
@@ -164,10 +169,9 @@ void mt7615_unregister_device(struct mt7615_dev *dev)
mt76_unregister_device(&dev->mt76);
if (mcu_running)
mt7615_mcu_exit(dev);
- mt7615_dma_cleanup(dev);
mt7615_tx_token_put(dev);
-
+ mt7615_dma_cleanup(dev);
tasklet_disable(&dev->irq_tasklet);
mt76_free_device(&dev->mt76);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c
index 1b206ccdadf2..d7cbef752f9f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c
@@ -37,9 +37,7 @@ void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
token = le16_to_cpu(txp->hw.msdu_id[0]) &
~MT_MSDU_ID_VALID;
- spin_lock_bh(&dev->token_lock);
- t = idr_remove(&dev->token, token);
- spin_unlock_bh(&dev->token_lock);
+ t = mt76_token_put(mdev, token);
e->skb = t ? t->skb : NULL;
}
@@ -161,9 +159,7 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
t->skb = tx_info->skb;
- spin_lock_bh(&dev->token_lock);
- id = idr_alloc(&dev->token, t, 0, MT7615_TOKEN_SIZE, GFP_ATOMIC);
- spin_unlock_bh(&dev->token_lock);
+ id = mt76_token_get(mdev, &t);
if (id < 0)
return id;
@@ -201,6 +197,8 @@ void mt7615_dma_reset(struct mt7615_dev *dev)
mt76_for_each_q_rx(&dev->mt76, i)
mt76_queue_rx_reset(dev, i);
+ mt76_tx_status_check(&dev->mt76, NULL, true);
+
mt7615_dma_start(dev);
}
EXPORT_SYMBOL_GPL(mt7615_dma_reset);
@@ -208,7 +206,12 @@ EXPORT_SYMBOL_GPL(mt7615_dma_reset);
static void
mt7615_hif_int_event_trigger(struct mt7615_dev *dev, u8 event)
{
- mt76_wr(dev, MT_MCU_INT_EVENT, event);
+ u32 reg = MT_MCU_INT_EVENT;
+
+ if (is_mt7663(&dev->mt76))
+ reg = MT7663_MCU_INT_EVENT;
+
+ mt76_wr(dev, reg, event);
mt7622_trigger_hif_int(dev, true);
mt7622_trigger_hif_int(dev, false);
@@ -303,12 +306,12 @@ void mt7615_mac_reset_work(struct work_struct *work)
mt7615_hif_int_event_trigger(dev, MT_MCU_INT_EVENT_PDMA_STOPPED);
- mt7615_tx_token_put(dev);
- idr_init(&dev->token);
-
if (mt7615_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
mt7615_dma_reset(dev);
+ mt7615_tx_token_put(dev);
+ idr_init(&dev->mt76.token);
+
mt76_wr(dev, MT_WPDMA_MEM_RNG_ERR, 0);
mt7615_hif_int_event_trigger(dev, MT_MCU_INT_EVENT_PDMA_INIT);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
index 190a02670795..63c081bb04d0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
@@ -61,6 +61,11 @@ enum mt7615_reg_base {
#define MT_MCU_PCIE_REMAP_2_BASE GENMASK(31, 19)
#define MT_PCIE_REMAP_BASE_2 ((dev)->reg_map[MT_PCIE_REMAP_BASE2])
+#define MT_MCU_CIRQ_BASE 0xc0000
+#define MT_MCU_CIRQ(ofs) (MT_MCU_CIRQ_BASE + (ofs))
+
+#define MT_MCU_CIRQ_IRQ_SEL(n) MT_MCU_CIRQ((n) << 2)
+
#define MT_HIF(ofs) ((dev)->reg_map[MT_HIF_BASE] + (ofs))
#define MT_HIF_RST MT_HIF(0x100)
#define MT_HIF_LOGIC_RST_N BIT(4)
@@ -88,6 +93,10 @@ enum mt7615_reg_base {
#define MT_CFG_LPCR_HOST_FW_OWN BIT(0)
#define MT_CFG_LPCR_HOST_DRV_OWN BIT(1)
+#define MT_MCU2HOST_INT_STATUS MT_HIF(0x1f0)
+#define MT_MCU2HOST_INT_ENABLE MT_HIF(0x1f4)
+
+#define MT7663_MCU_INT_EVENT MT_HIF(0x108)
#define MT_MCU_INT_EVENT MT_HIF(0x1f8)
#define MT_MCU_INT_EVENT_PDMA_STOPPED BIT(0)
#define MT_MCU_INT_EVENT_PDMA_INIT BIT(1)
@@ -102,6 +111,7 @@ enum mt7615_reg_base {
#define MT_INT_RX_DONE_ALL GENMASK(1, 0)
#define MT_INT_TX_DONE_ALL GENMASK(19, 4)
#define MT_INT_TX_DONE(_n) BIT((_n) + 4)
+#define MT7663_INT_MCU_CMD BIT(29)
#define MT_INT_MCU_CMD BIT(30)
#define MT_WPDMA_GLO_CFG MT_HIF(0x208)
@@ -138,6 +148,7 @@ enum mt7615_reg_base {
#define MT_MCU_CMD_PDMA_ERROR BIT(27)
#define MT_MCU_CMD_PCIE_ERROR BIT(28)
#define MT_MCU_CMD_ERROR_MASK (GENMASK(5, 1) | GENMASK(28, 24))
+#define MT7663_MCU_CMD_ERROR_MASK GENMASK(5, 2)
#define MT_TX_RING_BASE MT_HIF(0x300)
#define MT_RX_RING_BASE MT_HIF(0x400)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
index 4a370b9f7a17..f8d3673c2cae 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
@@ -67,7 +67,7 @@ static int mt7663_usb_sdio_set_rates(struct mt7615_dev *dev,
struct mt7615_rate_desc *rate = &wrd->rate;
struct mt7615_sta *sta = wrd->sta;
u32 w5, w27, addr, val;
- u16 idx = sta->vif->mt76.omac_idx;
+ u16 idx;
lockdep_assert_held(&dev->mt76.mutex);
@@ -119,6 +119,7 @@ static int mt7663_usb_sdio_set_rates(struct mt7615_dev *dev,
sta->rate_probe = sta->rateset[rate->rateset].probe_rate.idx != -1;
+ idx = sta->vif->mt76.omac_idx;
idx = idx > HW_BSSID_MAX ? HW_BSSID_0 : idx;
addr = idx > 1 ? MT_LPON_TCR2(idx): MT_LPON_TCR0(idx);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index b811f3c410a1..6c889b90fd12 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -53,11 +53,25 @@ struct mt76_connac_pm {
} tx_q[IEEE80211_NUM_ACS];
struct work_struct wake_work;
- struct completion wake_cmpl;
+ wait_queue_head_t wait;
+
+ struct {
+ spinlock_t lock;
+ u32 count;
+ } wake;
+ struct mutex mutex;
struct delayed_work ps_work;
unsigned long last_activity;
unsigned long idle_timeout;
+
+ struct {
+ unsigned long last_wake_event;
+ unsigned long awake_time;
+ unsigned long last_doze_event;
+ unsigned long doze_time;
+ unsigned int lp_wake;
+ } stats;
};
struct mt76_connac_coredump {
@@ -84,6 +98,44 @@ void mt76_connac_power_save_sched(struct mt76_phy *phy,
void mt76_connac_free_pending_tx_skbs(struct mt76_connac_pm *pm,
struct mt76_wcid *wcid);
+static inline bool
+mt76_connac_pm_ref(struct mt76_phy *phy, struct mt76_connac_pm *pm)
+{
+ bool ret = false;
+
+ spin_lock_bh(&pm->wake.lock);
+ if (test_bit(MT76_STATE_PM, &phy->state))
+ goto out;
+
+ pm->wake.count++;
+ ret = true;
+out:
+ spin_unlock_bh(&pm->wake.lock);
+
+ return ret;
+}
+
+static inline void
+mt76_connac_pm_unref(struct mt76_connac_pm *pm)
+{
+ spin_lock_bh(&pm->wake.lock);
+ pm->wake.count--;
+ pm->last_activity = jiffies;
+ spin_unlock_bh(&pm->wake.lock);
+}
+
+static inline bool
+mt76_connac_skip_fw_pmctrl(struct mt76_phy *phy, struct mt76_connac_pm *pm)
+{
+ bool ret;
+
+ spin_lock_bh(&pm->wake.lock);
+ ret = pm->wake.count || test_and_set_bit(MT76_STATE_PM, &phy->state);
+ spin_unlock_bh(&pm->wake.lock);
+
+ return ret;
+}
+
static inline void
mt76_connac_mutex_acquire(struct mt76_dev *dev, struct mt76_connac_pm *pm)
__acquires(&dev->mutex)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index c5f5037f5757..6f180c92d413 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -13,17 +13,14 @@ int mt76_connac_pm_wake(struct mt76_phy *phy, struct mt76_connac_pm *pm)
if (!mt76_is_mmio(dev))
return 0;
+ cancel_delayed_work_sync(&pm->ps_work);
if (!test_bit(MT76_STATE_PM, &phy->state))
return 0;
- if (test_bit(MT76_HW_SCANNING, &phy->state) ||
- test_bit(MT76_HW_SCHED_SCANNING, &phy->state))
- return 0;
-
- if (queue_work(dev->wq, &pm->wake_work))
- reinit_completion(&pm->wake_cmpl);
-
- if (!wait_for_completion_timeout(&pm->wake_cmpl, 3 * HZ)) {
+ queue_work(dev->wq, &pm->wake_work);
+ if (!wait_event_timeout(pm->wait,
+ !test_bit(MT76_STATE_PM, &phy->state),
+ 3 * HZ)) {
ieee80211_wake_queues(phy->hw);
return -ETIMEDOUT;
}
@@ -40,17 +37,15 @@ void mt76_connac_power_save_sched(struct mt76_phy *phy,
if (!mt76_is_mmio(dev))
return;
- if (!pm->enable || !test_bit(MT76_STATE_RUNNING, &phy->state))
+ if (!pm->enable)
return;
pm->last_activity = jiffies;
- if (test_bit(MT76_HW_SCANNING, &phy->state) ||
- test_bit(MT76_HW_SCHED_SCANNING, &phy->state))
- return;
-
- if (!test_bit(MT76_STATE_PM, &phy->state))
+ if (!test_bit(MT76_STATE_PM, &phy->state)) {
+ cancel_delayed_work(&phy->mac_work);
queue_delayed_work(dev->wq, &pm->ps_work, pm->idle_timeout);
+ }
}
EXPORT_SYMBOL_GPL(mt76_connac_power_save_sched);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index cc842e3e0027..fe0ab5e5ff81 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -1528,14 +1528,7 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_enable);
int mt76_connac_mcu_chip_config(struct mt76_dev *dev)
{
- struct {
- __le16 id;
- u8 type;
- u8 resp_type;
- __le16 data_size;
- __le16 resv;
- u8 data[320];
- } req = {
+ struct mt76_connac_config req = {
.resp_type = 0,
};
@@ -1546,6 +1539,19 @@ int mt76_connac_mcu_chip_config(struct mt76_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_chip_config);
+int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable)
+{
+ struct mt76_connac_config req = {
+ .resp_type = 0,
+ };
+
+ snprintf(req.data, sizeof(req.data), "KeepFullPwr %d", !enable);
+
+ return mt76_mcu_send_msg(dev, MCU_CMD_CHIP_CONFIG, &req, sizeof(req),
+ false);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_deep_sleep);
+
void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
struct mt76_connac_coredump *coredump)
{
@@ -1560,6 +1566,181 @@ void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_coredump_event);
+static void
+mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku,
+ struct mt76_power_limits *limits,
+ enum nl80211_band band)
+{
+ int max_power = is_mt7921(dev) ? 127 : 63;
+ int i, offset = sizeof(limits->cck);
+
+ memset(sku, max_power, MT_SKU_POWER_LIMIT);
+
+ if (band == NL80211_BAND_2GHZ) {
+ /* cck */
+ memcpy(sku, limits->cck, sizeof(limits->cck));
+ }
+
+ /* ofdm */
+ memcpy(&sku[offset], limits->ofdm, sizeof(limits->ofdm));
+ offset += sizeof(limits->ofdm);
+
+ /* ht */
+ for (i = 0; i < 2; i++) {
+ memcpy(&sku[offset], limits->mcs[i], 8);
+ offset += 8;
+ }
+ sku[offset++] = limits->mcs[0][0];
+
+ /* vht */
+ for (i = 0; i < ARRAY_SIZE(limits->mcs); i++) {
+ memcpy(&sku[offset], limits->mcs[i],
+ ARRAY_SIZE(limits->mcs[i]));
+ offset += 12;
+ }
+
+ if (!is_mt7921(dev))
+ return;
+
+ /* he */
+ for (i = 0; i < ARRAY_SIZE(limits->ru); i++) {
+ memcpy(&sku[offset], limits->ru[i], ARRAY_SIZE(limits->ru[i]));
+ offset += ARRAY_SIZE(limits->ru[i]);
+ }
+}
+
+static int
+mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
+ enum nl80211_band band)
+{
+ struct mt76_dev *dev = phy->dev;
+ int sku_len, batch_len = is_mt7921(dev) ? 8 : 16;
+ static const u8 chan_list_2ghz[] = {
+ 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14
+ };
+ static const u8 chan_list_5ghz[] = {
+ 36, 38, 40, 42, 44, 46, 48,
+ 50, 52, 54, 56, 58, 60, 62,
+ 64, 100, 102, 104, 106, 108, 110,
+ 112, 114, 116, 118, 120, 122, 124,
+ 126, 128, 132, 134, 136, 138, 140,
+ 142, 144, 149, 151, 153, 155, 157,
+ 159, 161, 165
+ };
+ struct mt76_connac_sku_tlv sku_tlbv;
+ int i, n_chan, batch_size, idx = 0;
+ struct mt76_power_limits limits;
+ const u8 *ch_list;
+
+ sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92;
+
+ if (band == NL80211_BAND_2GHZ) {
+ n_chan = ARRAY_SIZE(chan_list_2ghz);
+ ch_list = chan_list_2ghz;
+ } else {
+ n_chan = ARRAY_SIZE(chan_list_5ghz);
+ ch_list = chan_list_5ghz;
+ }
+ batch_size = DIV_ROUND_UP(n_chan, batch_len);
+
+ for (i = 0; i < batch_size; i++) {
+ bool last_msg = i == batch_size - 1;
+ int num_ch = last_msg ? n_chan % batch_len : batch_len;
+ struct mt76_connac_tx_power_limit_tlv tx_power_tlv = {
+ .band = band == NL80211_BAND_2GHZ ? 1 : 2,
+ .n_chan = num_ch,
+ .last_msg = last_msg,
+ };
+ struct sk_buff *skb;
+ int j, err, msg_len;
+
+ msg_len = sizeof(tx_power_tlv) + num_ch * sizeof(sku_tlbv);
+ skb = mt76_mcu_msg_alloc(dev, NULL, msg_len);
+ if (!skb)
+ return -ENOMEM;
+
+ BUILD_BUG_ON(sizeof(dev->alpha2) > sizeof(tx_power_tlv.alpha2));
+ memcpy(tx_power_tlv.alpha2, dev->alpha2, sizeof(dev->alpha2));
+
+ skb_put_data(skb, &tx_power_tlv, sizeof(tx_power_tlv));
+ for (j = 0; j < num_ch; j++, idx++) {
+ struct ieee80211_channel chan = {
+ .hw_value = ch_list[idx],
+ .band = band,
+ };
+
+ mt76_get_rate_power_limits(phy, &chan, &limits, 127);
+
+ sku_tlbv.channel = ch_list[idx];
+ mt76_connac_mcu_build_sku(dev, sku_tlbv.pwr_limit,
+ &limits, band);
+ skb_put_data(skb, &sku_tlbv, sku_len);
+ }
+
+ err = mt76_mcu_skb_send_msg(dev, skb,
+ MCU_CMD_SET_RATE_TX_POWER, false);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy)
+{
+ int err;
+
+ err = mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_2GHZ);
+ if (err < 0)
+ return err;
+
+ return mt76_connac_mcu_rate_txpower_band(phy, NL80211_BAND_5GHZ);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_rate_txpower);
+
+int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev,
+ struct mt76_vif *vif,
+ struct ieee80211_bss_conf *info)
+{
+ struct sk_buff *skb;
+ int i, len = min_t(int, info->arp_addr_cnt,
+ IEEE80211_BSS_ARP_ADDR_LIST_LEN);
+ struct {
+ struct {
+ u8 bss_idx;
+ u8 pad[3];
+ } __packed hdr;
+ struct mt76_connac_arpns_tlv arp;
+ } req_hdr = {
+ .hdr = {
+ .bss_idx = vif->idx,
+ },
+ .arp = {
+ .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP),
+ .len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)),
+ .ips_num = len,
+ .mode = 2, /* update */
+ .option = 1,
+ },
+ };
+
+ skb = mt76_mcu_msg_alloc(dev, NULL,
+ sizeof(req_hdr) + len * sizeof(__be32));
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put_data(skb, &req_hdr, sizeof(req_hdr));
+ for (i = 0; i < len; i++) {
+ u8 *addr = (u8 *)skb_put(skb, sizeof(__be32));
+
+ memcpy(addr, &info->arp_addr_list[i], sizeof(__be32));
+ }
+
+ return mt76_mcu_skb_send_msg(dev, skb, MCU_UNI_CMD_OFFLOAD, true);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_mcu_update_arp_filter);
+
#ifdef CONFIG_PM
const struct wiphy_wowlan_support mt76_connac_wowlan_support = {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index 587097450416..a1096861d04a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -564,6 +564,7 @@ enum {
MCU_CMD_CHIP_CONFIG = MCU_CE_PREFIX | 0xca,
MCU_CMD_FWLOG_2_HOST = MCU_CE_PREFIX | 0xc5,
MCU_CMD_GET_WTBL = MCU_CE_PREFIX | 0xcd,
+ MCU_CMD_GET_TXPWR = MCU_CE_PREFIX | 0xd0,
};
enum {
@@ -895,6 +896,37 @@ struct mt76_sta_cmd_info {
u8 rcpi;
};
+#define MT_SKU_POWER_LIMIT 161
+
+struct mt76_connac_sku_tlv {
+ u8 channel;
+ s8 pwr_limit[MT_SKU_POWER_LIMIT];
+} __packed;
+
+struct mt76_connac_tx_power_limit_tlv {
+ /* DW0 - common info*/
+ u8 ver;
+ u8 pad0;
+ __le16 len;
+ /* DW1 - cmd hint */
+ u8 n_chan; /* # channel */
+ u8 band; /* 2.4GHz - 5GHz */
+ u8 last_msg;
+ u8 pad1;
+ /* DW3 */
+ u8 alpha2[4]; /* regulatory_request.alpha2 */
+ u8 pad2[32];
+} __packed;
+
+struct mt76_connac_config {
+ __le16 id;
+ u8 type;
+ u8 resp_type;
+ __le16 data_size;
+ __le16 resv;
+ u8 data[320];
+} __packed;
+
#define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id)
#define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id)
@@ -987,6 +1019,9 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy,
int mt76_connac_mcu_sched_scan_enable(struct mt76_phy *phy,
struct ieee80211_vif *vif,
bool enable);
+int mt76_connac_mcu_update_arp_filter(struct mt76_dev *dev,
+ struct mt76_vif *vif,
+ struct ieee80211_bss_conf *info);
int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_gtk_rekey_data *key);
@@ -994,6 +1029,8 @@ int mt76_connac_mcu_set_hif_suspend(struct mt76_dev *dev, bool suspend);
void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif);
int mt76_connac_mcu_chip_config(struct mt76_dev *dev);
+int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable);
void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
struct mt76_connac_coredump *coredump);
+int mt76_connac_mcu_set_rate_txpower(struct mt76_phy *phy);
#endif /* __MT76_CONNAC_MCU_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c
index 4aa5c36afeaf..75978820a260 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mcu.c
@@ -17,9 +17,8 @@ int mt76x02_mcu_parse_response(struct mt76_dev *mdev, int cmd,
u32 *rxfce;
if (!skb) {
- dev_err(mdev->dev,
- "MCU message %d (seq %d) timed out\n", cmd,
- seq);
+ dev_err(mdev->dev, "MCU message %02x (seq %d) timed out\n",
+ abs(cmd), seq);
dev->mcu_timeout = 1;
return -ETIMEDOUT;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index fc12824ab74e..b50084bbe83d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -226,7 +226,7 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
if (ret)
return ret;
- ret = mt76_init_queues(dev);
+ ret = mt76_init_queues(dev, mt76_dma_rx_poll);
if (ret)
return ret;
@@ -472,6 +472,8 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
mt76_queue_rx_reset(dev, i);
}
+ mt76_tx_status_check(&dev->mt76, NULL, true);
+
mt76x02_mac_start(dev);
if (dev->ed_monitor)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
index 587d55d240a1..6a8ddeeecbe9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
@@ -299,8 +299,7 @@ mt7915_queues_read(struct seq_file *s, void *data)
}
static void
-mt7915_puts_rate_txpower(struct seq_file *s, s8 *delta,
- s8 txpower_cur, int band)
+mt7915_puts_rate_txpower(struct seq_file *s, struct mt7915_phy *phy)
{
static const char * const sku_group_name[] = {
"CCK", "OFDM", "HT20", "HT40",
@@ -308,24 +307,54 @@ mt7915_puts_rate_txpower(struct seq_file *s, s8 *delta,
"RU26", "RU52", "RU106", "RU242/SU20",
"RU484/SU40", "RU996/SU80", "RU2x996/SU160"
};
- s8 txpower[MT7915_SKU_RATE_NUM];
+ struct mt7915_dev *dev = dev_get_drvdata(s->private);
+ bool ext_phy = phy != &dev->phy;
+ u32 reg_base;
int i, idx = 0;
- for (i = 0; i < MT7915_SKU_RATE_NUM; i++)
- txpower[i] = DIV_ROUND_UP(txpower_cur + delta[i], 2);
+ if (!phy)
+ return;
- for (i = 0; i < MAX_SKU_RATE_GROUP_NUM; i++) {
- const struct sku_group *sku = &mt7915_sku_groups[i];
- u32 offset = sku->offset[band];
+ reg_base = MT_TMAC_FP0R0(ext_phy);
+ seq_printf(s, "\nBand %d\n", ext_phy);
+
+ for (i = 0; i < ARRAY_SIZE(mt7915_sku_group_len); i++) {
+ u8 cnt, mcs_num = mt7915_sku_group_len[i];
+ s8 txpower[12];
+ int j;
+
+ if (i == SKU_HT_BW20 || i == SKU_HT_BW40) {
+ mcs_num = 8;
+ } else if (i >= SKU_VHT_BW20 && i <= SKU_VHT_BW160) {
+ mcs_num = 10;
+ } else if (i == SKU_HE_RU26) {
+ reg_base = MT_TMAC_FP0R18(ext_phy);
+ idx = 0;
+ }
- if (!offset) {
- idx += sku->len;
- continue;
+ for (j = 0, cnt = 0; j < DIV_ROUND_UP(mcs_num, 4); j++) {
+ u32 val;
+
+ if (i == SKU_VHT_BW160 && idx == 60) {
+ reg_base = MT_TMAC_FP0R15(ext_phy);
+ idx = 0;
+ }
+
+ val = mt76_rr(dev, reg_base + (idx / 4) * 4);
+
+ if (idx && idx % 4)
+ val >>= (idx % 4) * 8;
+
+ while (val > 0 && cnt < mcs_num) {
+ s8 pwr = FIELD_GET(MT_TMAC_FP_MASK, val);
+
+ txpower[cnt++] = pwr;
+ val >>= 8;
+ idx++;
+ }
}
- mt76_seq_puts_array(s, sku_group_name[i],
- txpower + idx, sku->len);
- idx += sku->len;
+ mt76_seq_puts_array(s, sku_group_name[i], txpower, mcs_num);
}
}
@@ -333,24 +362,9 @@ static int
mt7915_read_rate_txpower(struct seq_file *s, void *data)
{
struct mt7915_dev *dev = dev_get_drvdata(s->private);
- struct mt76_phy *mphy = &dev->mphy;
- enum nl80211_band band = mphy->chandef.chan->band;
- s8 *delta = dev->rate_power[band];
- s8 txpower_base = mphy->txpower_cur - delta[MT7915_SKU_MAX_DELTA_IDX];
-
- seq_puts(s, "Band 0:\n");
- mt7915_puts_rate_txpower(s, delta, txpower_base, band);
-
- if (dev->mt76.phy2) {
- mphy = dev->mt76.phy2;
- band = mphy->chandef.chan->band;
- delta = dev->rate_power[band];
- txpower_base = mphy->txpower_cur -
- delta[MT7915_SKU_MAX_DELTA_IDX];
-
- seq_puts(s, "Band 1:\n");
- mt7915_puts_rate_txpower(s, delta, txpower_base, band);
- }
+
+ mt7915_puts_rate_txpower(s, &dev->phy);
+ mt7915_puts_rate_txpower(s, mt7915_ext_phy(dev));
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
index 9fe09870f8f0..11d0b760abd7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
@@ -213,7 +213,7 @@ int mt7915_dma_init(struct mt7915_dev *dev)
return ret;
}
- ret = mt76_init_queues(dev);
+ ret = mt76_init_queues(dev, mt76_dma_rx_poll);
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 738ecf8f4fa2..8ededf2e5279 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
@@ -8,12 +8,29 @@ static u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset)
{
u8 *data = dev->mt76.eeprom.data;
- if (data[offset] == 0xff)
+ if (data[offset] == 0xff && !dev->flash_mode)
mt7915_mcu_get_eeprom(dev, offset);
return data[offset];
}
+static int mt7915_eeprom_load_precal(struct mt7915_dev *dev)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ u32 val;
+
+ val = mt7915_eeprom_read(dev, MT_EE_DO_PRE_CAL);
+ if (val != (MT_EE_WIFI_CAL_DPD | MT_EE_WIFI_CAL_GROUP))
+ return 0;
+
+ val = MT_EE_CAL_GROUP_SIZE + MT_EE_CAL_DPD_SIZE;
+ dev->cal = devm_kzalloc(mdev->dev, val, GFP_KERNEL);
+ if (!dev->cal)
+ return -ENOMEM;
+
+ return mt76_get_of_eeprom(mdev, dev->cal, MT_EE_PRECAL, val);
+}
+
static int mt7915_eeprom_load(struct mt7915_dev *dev)
{
int ret;
@@ -22,12 +39,14 @@ static int mt7915_eeprom_load(struct mt7915_dev *dev)
if (ret < 0)
return ret;
- if (ret)
+ if (ret) {
dev->flash_mode = true;
- else
+ ret = mt7915_eeprom_load_precal(dev);
+ } else {
memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE);
+ }
- return 0;
+ return ret;
}
static int mt7915_check_eeprom(struct mt7915_dev *dev)
@@ -151,120 +170,38 @@ int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
return target_power;
}
-static const u8 sku_cck_delta_map[] = {
- SKU_CCK_GROUP0,
- SKU_CCK_GROUP0,
- SKU_CCK_GROUP1,
- SKU_CCK_GROUP1,
-};
-
-static const u8 sku_ofdm_delta_map[] = {
- SKU_OFDM_GROUP0,
- SKU_OFDM_GROUP0,
- SKU_OFDM_GROUP1,
- SKU_OFDM_GROUP1,
- SKU_OFDM_GROUP2,
- SKU_OFDM_GROUP2,
- SKU_OFDM_GROUP3,
- SKU_OFDM_GROUP4,
-};
-
-static const u8 sku_mcs_delta_map[] = {
- SKU_MCS_GROUP0,
- SKU_MCS_GROUP1,
- SKU_MCS_GROUP1,
- SKU_MCS_GROUP2,
- SKU_MCS_GROUP2,
- SKU_MCS_GROUP3,
- SKU_MCS_GROUP4,
- SKU_MCS_GROUP5,
- SKU_MCS_GROUP6,
- SKU_MCS_GROUP7,
- SKU_MCS_GROUP8,
- SKU_MCS_GROUP9,
-};
-
-#define SKU_GROUP(_mode, _len, _ofs_2g, _ofs_5g, _map) \
- [_mode] = { \
- .len = _len, \
- .offset = { \
- _ofs_2g, \
- _ofs_5g, \
- }, \
- .delta_map = _map \
-}
-
-const struct sku_group mt7915_sku_groups[] = {
- SKU_GROUP(SKU_CCK, 4, 0x252, 0, sku_cck_delta_map),
- SKU_GROUP(SKU_OFDM, 8, 0x254, 0x29d, sku_ofdm_delta_map),
-
- SKU_GROUP(SKU_HT_BW20, 8, 0x259, 0x2a2, sku_mcs_delta_map),
- SKU_GROUP(SKU_HT_BW40, 9, 0x262, 0x2ab, sku_mcs_delta_map),
- SKU_GROUP(SKU_VHT_BW20, 12, 0x259, 0x2a2, sku_mcs_delta_map),
- SKU_GROUP(SKU_VHT_BW40, 12, 0x262, 0x2ab, sku_mcs_delta_map),
- SKU_GROUP(SKU_VHT_BW80, 12, 0, 0x2b4, sku_mcs_delta_map),
- SKU_GROUP(SKU_VHT_BW160, 12, 0, 0, sku_mcs_delta_map),
-
- SKU_GROUP(SKU_HE_RU26, 12, 0x27f, 0x2dd, sku_mcs_delta_map),
- SKU_GROUP(SKU_HE_RU52, 12, 0x289, 0x2e7, sku_mcs_delta_map),
- SKU_GROUP(SKU_HE_RU106, 12, 0x293, 0x2f1, sku_mcs_delta_map),
- SKU_GROUP(SKU_HE_RU242, 12, 0x26b, 0x2bf, sku_mcs_delta_map),
- SKU_GROUP(SKU_HE_RU484, 12, 0x275, 0x2c9, sku_mcs_delta_map),
- SKU_GROUP(SKU_HE_RU996, 12, 0, 0x2d3, sku_mcs_delta_map),
- SKU_GROUP(SKU_HE_RU2x996, 12, 0, 0, sku_mcs_delta_map),
-};
-
-static s8
-mt7915_get_sku_delta(struct mt7915_dev *dev, u32 addr)
+s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band)
{
- u32 val = mt7915_eeprom_read(dev, addr);
- s8 delta = FIELD_GET(SKU_DELTA_VAL, val);
+ u32 val;
+ s8 delta;
- if (!(val & SKU_DELTA_EN))
- return 0;
+ if (band == NL80211_BAND_2GHZ)
+ val = mt7915_eeprom_read(dev, MT_EE_RATE_DELTA_2G);
+ else
+ val = mt7915_eeprom_read(dev, MT_EE_RATE_DELTA_5G);
- return val & SKU_DELTA_ADD ? delta : -delta;
-}
+ if (!(val & MT_EE_RATE_DELTA_EN))
+ return 0;
-static void
-mt7915_eeprom_init_sku_band(struct mt7915_dev *dev,
- struct ieee80211_supported_band *sband)
-{
- int i, band = sband->band;
- s8 *rate_power = dev->rate_power[band], max_delta = 0;
- u8 idx = 0;
-
- for (i = 0; i < ARRAY_SIZE(mt7915_sku_groups); i++) {
- const struct sku_group *sku = &mt7915_sku_groups[i];
- u32 offset = sku->offset[band];
- int j;
-
- if (!offset) {
- idx += sku->len;
- continue;
- }
-
- rate_power[idx++] = mt7915_get_sku_delta(dev, offset);
- if (rate_power[idx - 1] > max_delta)
- max_delta = rate_power[idx - 1];
-
- if (i == SKU_HT_BW20 || i == SKU_VHT_BW20)
- offset += 1;
-
- for (j = 1; j < sku->len; j++) {
- u32 addr = offset + sku->delta_map[j];
-
- rate_power[idx++] = mt7915_get_sku_delta(dev, addr);
- if (rate_power[idx - 1] > max_delta)
- max_delta = rate_power[idx - 1];
- }
- }
+ delta = FIELD_GET(MT_EE_RATE_DELTA_MASK, val);
- rate_power[idx] = max_delta;
+ return val & MT_EE_RATE_DELTA_SIGN ? delta : -delta;
}
-void mt7915_eeprom_init_sku(struct mt7915_dev *dev)
-{
- mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_2g.sband);
- mt7915_eeprom_init_sku_band(dev, &dev->mphy.sband_5g.sband);
-}
+const u8 mt7915_sku_group_len[] = {
+ [SKU_CCK] = 4,
+ [SKU_OFDM] = 8,
+ [SKU_HT_BW20] = 8,
+ [SKU_HT_BW40] = 9,
+ [SKU_VHT_BW20] = 12,
+ [SKU_VHT_BW40] = 12,
+ [SKU_VHT_BW80] = 12,
+ [SKU_VHT_BW160] = 12,
+ [SKU_HE_RU26] = 12,
+ [SKU_HE_RU52] = 12,
+ [SKU_HE_RU106] = 12,
+ [SKU_HE_RU242] = 12,
+ [SKU_HE_RU484] = 12,
+ [SKU_HE_RU996] = 12,
+ [SKU_HE_RU2x996] = 12
+};
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
index 3ee8c27bb61b..033fb592bdf0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h
@@ -17,14 +17,25 @@ enum mt7915_eeprom_field {
MT_EE_MAC_ADDR = 0x004,
MT_EE_MAC_ADDR2 = 0x00a,
MT_EE_DDIE_FT_VERSION = 0x050,
+ MT_EE_DO_PRE_CAL = 0x062,
MT_EE_WIFI_CONF = 0x190,
+ MT_EE_RATE_DELTA_2G = 0x252,
+ MT_EE_RATE_DELTA_5G = 0x29d,
MT_EE_TX0_POWER_2G = 0x2fc,
MT_EE_TX0_POWER_5G = 0x34b,
MT_EE_ADIE_FT_VERSION = 0x9a0,
- __MT_EE_MAX = 0xe00
+ __MT_EE_MAX = 0xe00,
+ /* 0xe10 ~ 0x5780 used to save group cal data */
+ MT_EE_PRECAL = 0xe10
};
+#define MT_EE_WIFI_CAL_GROUP BIT(0)
+#define MT_EE_WIFI_CAL_DPD GENMASK(2, 1)
+#define MT_EE_CAL_UNIT 1024
+#define MT_EE_CAL_GROUP_SIZE (44 * MT_EE_CAL_UNIT)
+#define MT_EE_CAL_DPD_SIZE (54 * MT_EE_CAL_UNIT)
+
#define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0)
#define MT_EE_WIFI_CONF0_BAND_SEL GENMASK(7, 6)
#define MT_EE_WIFI_CONF1_BAND_SEL GENMASK(7, 6)
@@ -34,6 +45,10 @@ enum mt7915_eeprom_field {
#define MT_EE_WIFI_CONF7_TSSI0_5G BIT(2)
#define MT_EE_WIFI_CONF7_TSSI1_5G BIT(4)
+#define MT_EE_RATE_DELTA_MASK GENMASK(5, 0)
+#define MT_EE_RATE_DELTA_SIGN BIT(6)
+#define MT_EE_RATE_DELTA_EN BIT(7)
+
enum mt7915_eeprom_band {
MT_EE_BAND_SEL_DEFAULT,
MT_EE_BAND_SEL_5GHZ,
@@ -41,32 +56,6 @@ enum mt7915_eeprom_band {
MT_EE_BAND_SEL_DUAL,
};
-#define SKU_DELTA_VAL GENMASK(5, 0)
-#define SKU_DELTA_ADD BIT(6)
-#define SKU_DELTA_EN BIT(7)
-
-enum mt7915_sku_delta_group {
- SKU_CCK_GROUP0,
- SKU_CCK_GROUP1,
-
- SKU_OFDM_GROUP0 = 0,
- SKU_OFDM_GROUP1,
- SKU_OFDM_GROUP2,
- SKU_OFDM_GROUP3,
- SKU_OFDM_GROUP4,
-
- SKU_MCS_GROUP0 = 0,
- SKU_MCS_GROUP1,
- SKU_MCS_GROUP2,
- SKU_MCS_GROUP3,
- SKU_MCS_GROUP4,
- SKU_MCS_GROUP5,
- SKU_MCS_GROUP6,
- SKU_MCS_GROUP7,
- SKU_MCS_GROUP8,
- SKU_MCS_GROUP9,
-};
-
enum mt7915_sku_rate_group {
SKU_CCK,
SKU_OFDM,
@@ -86,12 +75,6 @@ enum mt7915_sku_rate_group {
MAX_SKU_RATE_GROUP_NUM,
};
-struct sku_group {
- u8 len;
- u16 offset[2];
- const u8 *delta_map;
-};
-
static inline int
mt7915_get_channel_group(int channel)
{
@@ -124,6 +107,6 @@ mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band)
return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF7_TSSI0_2G;
}
-extern const struct sku_group mt7915_sku_groups[];
+extern const u8 mt7915_sku_group_len[MAX_SKU_RATE_GROUP_NUM];
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index 32c371055596..822f3aa6bb8b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -68,6 +68,39 @@ static const struct ieee80211_iface_combination if_comb[] = {
};
static void
+mt7915_init_txpower(struct mt7915_dev *dev,
+ struct ieee80211_supported_band *sband)
+{
+ int i, n_chains = hweight8(dev->mphy.antenna_mask);
+ int nss_delta = mt76_tx_power_nss_delta(n_chains);
+ int pwr_delta = mt7915_eeprom_get_power_delta(dev, sband->band);
+ struct mt76_power_limits limits;
+
+ for (i = 0; i < sband->n_channels; i++) {
+ struct ieee80211_channel *chan = &sband->channels[i];
+ u32 target_power = 0;
+ int j;
+
+ for (j = 0; j < n_chains; j++) {
+ u32 val;
+
+ val = mt7915_eeprom_get_target_power(dev, chan, j);
+ target_power = max(target_power, val);
+ }
+
+ target_power += pwr_delta;
+ target_power = mt76_get_rate_power_limits(&dev->mphy, chan,
+ &limits,
+ target_power);
+ target_power += nss_delta;
+ target_power = DIV_ROUND_UP(target_power, 2);
+ chan->max_power = min_t(int, chan->max_reg_power,
+ target_power);
+ chan->orig_mpwr = target_power;
+ }
+}
+
+static void
mt7915_regd_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
@@ -77,8 +110,12 @@ mt7915_regd_notifier(struct wiphy *wiphy,
struct mt7915_phy *phy = mphy->priv;
struct cfg80211_chan_def *chandef = &mphy->chandef;
+ memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
dev->mt76.region = request->dfs_region;
+ mt7915_init_txpower(dev, &mphy->sband_2g.sband);
+ mt7915_init_txpower(dev, &mphy->sband_5g.sband);
+
if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
return;
@@ -207,38 +244,6 @@ static int mt7915_txbf_init(struct mt7915_dev *dev)
return mt7915_mcu_set_txbf_type(dev);
}
-static void
-mt7915_init_txpower_band(struct mt7915_dev *dev,
- struct ieee80211_supported_band *sband)
-{
- int i, n_chains = hweight8(dev->mphy.antenna_mask);
-
- for (i = 0; i < sband->n_channels; i++) {
- struct ieee80211_channel *chan = &sband->channels[i];
- u32 target_power = 0;
- int j;
-
- for (j = 0; j < n_chains; j++) {
- u32 val;
-
- val = mt7915_eeprom_get_target_power(dev, chan, j);
- target_power = max(target_power, val);
- }
-
- chan->max_power = min_t(int, chan->max_reg_power,
- target_power / 2);
- chan->orig_mpwr = target_power / 2;
- }
-}
-
-static void mt7915_init_txpower(struct mt7915_dev *dev)
-{
- mt7915_init_txpower_band(dev, &dev->mphy.sband_2g.sband);
- mt7915_init_txpower_band(dev, &dev->mphy.sband_5g.sband);
-
- mt7915_eeprom_init_sku(dev);
-}
-
static int mt7915_register_ext_phy(struct mt7915_dev *dev)
{
struct mt7915_phy *phy = mt7915_ext_phy(dev);
@@ -295,7 +300,8 @@ static void mt7915_init_work(struct work_struct *work)
mt7915_mcu_set_eeprom(dev);
mt7915_mac_init(dev);
- mt7915_init_txpower(dev);
+ mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
+ mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
mt7915_txbf_init(dev);
}
@@ -345,9 +351,6 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
INIT_WORK(&dev->init_work, mt7915_init_work);
- spin_lock_init(&dev->token_lock);
- idr_init(&dev->token);
-
dev->dbdc_support = !!(mt76_rr(dev, MT_HW_BOUND) & BIT(5));
/* If MCU was already running, it is likely in a bad state */
@@ -381,6 +384,13 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
if (ret < 0)
return ret;
+
+ if (dev->flash_mode) {
+ ret = mt7915_mcu_apply_group_cal(dev);
+ if (ret)
+ return ret;
+ }
+
/* Beacon and mgmt frames should occupy wcid 0 */
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1);
if (idx)
@@ -740,9 +750,8 @@ void mt7915_unregister_device(struct mt7915_dev *dev)
mt7915_unregister_ext_phy(dev);
mt76_unregister_device(&dev->mt76);
mt7915_mcu_exit(dev);
- mt7915_dma_cleanup(dev);
-
mt7915_tx_token_put(dev);
+ mt7915_dma_cleanup(dev);
mt76_free_device(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 3f3bfead1ce7..7a9759fb79d8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -661,19 +661,18 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
{
#ifdef CONFIG_NL80211_TESTMODE
struct mt76_testmode_data *td = &phy->mt76->test;
+ const struct ieee80211_rate *r;
+ u8 bw, mode, nss = td->tx_rate_nss;
u8 rate_idx = td->tx_rate_idx;
- u8 nss = td->tx_rate_nss;
- u8 bw, mode;
u16 rateval = 0;
u32 val;
+ bool cck = false;
+ int band;
if (skb != phy->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;
@@ -693,7 +692,20 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
case MT76_TM_TX_MODE_HE_MU:
mode = MT_PHY_TYPE_HE_MU;
break;
+ case MT76_TM_TX_MODE_CCK:
+ cck = true;
+ fallthrough;
case MT76_TM_TX_MODE_OFDM:
+ band = phy->mt76->chandef.chan->band;
+ if (band == NL80211_BAND_2GHZ && !cck)
+ rate_idx += 4;
+
+ r = &phy->mt76->hw->wiphy->bands[band]->bitrates[rate_idx];
+ val = cck ? r->hw_value_short : r->hw_value;
+
+ mode = val >> 8;
+ rate_idx = val & 0xff;
+ break;
default:
mode = MT_PHY_TYPE_OFDM;
break;
@@ -748,9 +760,10 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
if (mode >= MT_PHY_TYPE_HE_SU)
val |= FIELD_PREP(MT_TXD6_HELTF, td->tx_ltf);
- if (td->tx_rate_ldpc || bw > 0)
+ if (td->tx_rate_ldpc || (bw > 0 && mode >= MT_PHY_TYPE_HE_SU))
val |= MT_TXD6_LDPC;
+ txwi[3] &= ~cpu_to_le32(MT_TXD3_SN_VALID);
txwi[6] |= cpu_to_le32(val);
txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX,
phy->test.spe_idx));
@@ -961,26 +974,6 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
mt7915_mac_write_txwi_tm(mphy->priv, txwi, skb);
}
-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;
-
- q = mphy->q_tx[0];
- if (blocked == q->blocked)
- return;
-
- q->blocked = blocked;
- if (mphy2) {
- q2 = mphy2->q_tx[0];
- q2->blocked = blocked;
- }
-
- if (!blocked)
- mt76_worker_schedule(&dev->mt76.tx_worker);
-}
-
int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
@@ -1033,15 +1026,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
t->skb = tx_info->skb;
- 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);
-
+ id = mt76_token_consume(mdev, &t);
if (id < 0)
return id;
@@ -1205,15 +1190,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
stat = FIELD_GET(MT_TX_FREE_STATUS, info);
- 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);
-
+ txwi = mt76_token_release(mdev, msdu, &wake);
if (!txwi)
continue;
@@ -1243,11 +1220,8 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *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);
- }
+ if (wake)
+ mt76_set_tx_blocked(&dev->mt76, false);
mt76_worker_schedule(&dev->mt76.tx_worker);
@@ -1276,10 +1250,7 @@ void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
struct mt7915_txp *txp;
txp = mt7915_txwi_to_txp(mdev, e->txwi);
-
- spin_lock_bh(&dev->token_lock);
- t = idr_remove(&dev->token, le16_to_cpu(txp->token));
- spin_unlock_bh(&dev->token_lock);
+ t = mt76_token_put(mdev, le16_to_cpu(txp->token));
e->skb = t ? t->skb : NULL;
}
@@ -1551,6 +1522,8 @@ mt7915_dma_reset(struct mt7915_dev *dev)
mt76_for_each_q_rx(&dev->mt76, i)
mt76_queue_rx_reset(dev, i);
+ mt76_tx_status_check(&dev->mt76, NULL, true);
+
/* re-init prefetch settings after reset */
mt7915_dma_prefetch(dev);
@@ -1573,8 +1546,8 @@ void mt7915_tx_token_put(struct mt7915_dev *dev)
struct mt76_txwi_cache *txwi;
int id;
- spin_lock_bh(&dev->token_lock);
- idr_for_each_entry(&dev->token, txwi, id) {
+ spin_lock_bh(&dev->mt76.token_lock);
+ idr_for_each_entry(&dev->mt76.token, txwi, id) {
mt7915_txp_skb_unmap(&dev->mt76, txwi);
if (txwi->skb) {
struct ieee80211_hw *hw;
@@ -1583,10 +1556,10 @@ void mt7915_tx_token_put(struct mt7915_dev *dev)
ieee80211_free_txskb(hw, txwi->skb);
}
mt76_put_txwi(&dev->mt76, txwi);
- dev->token_count--;
+ dev->mt76.token_count--;
}
- spin_unlock_bh(&dev->token_lock);
- idr_destroy(&dev->token);
+ spin_unlock_bh(&dev->mt76.token_lock);
+ idr_destroy(&dev->mt76.token);
}
/* system error recovery */
@@ -1630,12 +1603,12 @@ void mt7915_mac_reset_work(struct work_struct *work)
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
- mt7915_tx_token_put(dev);
- idr_init(&dev->token);
-
if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
mt7915_dma_reset(dev);
+ mt7915_tx_token_put(dev);
+ idr_init(&dev->mt76.token);
+
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
mt7915_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index 2fd87987312e..e5bd687546b6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -313,6 +313,12 @@ int mt7915_set_channel(struct mt7915_phy *phy)
mt7915_init_dfs_state(phy);
mt76_set_channel(phy->mt76);
+ if (dev->flash_mode) {
+ ret = mt7915_mcu_apply_tx_dpd(phy);
+ if (ret)
+ goto out;
+ }
+
ret = mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(CHANNEL_SWITCH));
if (ret)
goto out;
@@ -423,7 +429,7 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
- ret = mt7915_mcu_set_sku(phy);
+ ret = mt7915_mcu_set_txpower_sku(phy);
if (ret)
return ret;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index 908e74a6b8e6..b3f14ff67c5a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -217,7 +217,7 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
int ret = 0;
if (!skb) {
- dev_err(mdev->dev, "Message %d (seq %d) timeout\n",
+ dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
cmd, seq);
return -ETIMEDOUT;
}
@@ -521,7 +521,7 @@ mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb)
break;
}
- wiphy_info(mt76_hw(dev)->wiphy, "%s: %*s", type,
+ wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type,
(int)(skb->len - sizeof(*rxd)), data);
}
@@ -3327,6 +3327,148 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset)
return 0;
}
+static int mt7915_mcu_set_pre_cal(struct mt7915_dev *dev, u8 idx,
+ u8 *data, u32 len, int cmd)
+{
+ struct {
+ u8 dir;
+ u8 valid;
+ __le16 bitmap;
+ s8 precal;
+ u8 action;
+ u8 band;
+ u8 idx;
+ u8 rsv[4];
+ __le32 len;
+ } req;
+ struct sk_buff *skb;
+
+ skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req) + len);
+ if (!skb)
+ return -ENOMEM;
+
+ req.idx = idx;
+ req.len = cpu_to_le32(len);
+ skb_put_data(skb, &req, sizeof(req));
+ skb_put_data(skb, data, len);
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, false);
+}
+
+int mt7915_mcu_apply_group_cal(struct mt7915_dev *dev)
+{
+ u8 idx = 0, *cal = dev->cal, *eep = dev->mt76.eeprom.data;
+ u32 total = MT_EE_CAL_GROUP_SIZE;
+
+ if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_GROUP))
+ return 0;
+
+ /*
+ * Items: Rx DCOC, RSSI DCOC, Tx TSSI DCOC, Tx LPFG
+ * Tx FDIQ, Tx DCIQ, Rx FDIQ, Rx FIIQ, ADCDCOC
+ */
+ while (total > 0) {
+ int ret, len;
+
+ len = min_t(u32, total, MT_EE_CAL_UNIT);
+
+ ret = mt7915_mcu_set_pre_cal(dev, idx, cal, len,
+ MCU_EXT_CMD(GROUP_PRE_CAL_INFO));
+ if (ret)
+ return ret;
+
+ total -= len;
+ cal += len;
+ idx++;
+ }
+
+ return 0;
+}
+
+static int mt7915_find_freq_idx(const u16 *freqs, int n_freqs, u16 cur)
+{
+ int i;
+
+ for (i = 0; i < n_freqs; i++)
+ if (cur == freqs[i])
+ return i;
+
+ return -1;
+}
+
+static int mt7915_dpd_freq_idx(u16 freq, u8 bw)
+{
+ static const u16 freq_list[] = {
+ 5180, 5200, 5220, 5240,
+ 5260, 5280, 5300, 5320,
+ 5500, 5520, 5540, 5560,
+ 5580, 5600, 5620, 5640,
+ 5660, 5680, 5700, 5745,
+ 5765, 5785, 5805, 5825
+ };
+ int offset_2g = ARRAY_SIZE(freq_list);
+ int idx;
+
+ if (freq < 4000) {
+ if (freq < 2432)
+ return offset_2g;
+ if (freq < 2457)
+ return offset_2g + 1;
+
+ return offset_2g + 2;
+ }
+
+ if (bw == NL80211_CHAN_WIDTH_80P80 || bw == NL80211_CHAN_WIDTH_160)
+ return -1;
+
+ if (bw != NL80211_CHAN_WIDTH_20) {
+ idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
+ freq + 10);
+ if (idx >= 0)
+ return idx;
+
+ idx = mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list),
+ freq - 10);
+ if (idx >= 0)
+ return idx;
+ }
+
+ return mt7915_find_freq_idx(freq_list, ARRAY_SIZE(freq_list), freq);
+}
+
+int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy)
+{
+ struct mt7915_dev *dev = phy->dev;
+ struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
+ u16 total = 2, idx, center_freq = chandef->center_freq1;
+ u8 *cal = dev->cal, *eep = dev->mt76.eeprom.data;
+
+ if (!(eep[MT_EE_DO_PRE_CAL] & MT_EE_WIFI_CAL_DPD))
+ return 0;
+
+ idx = mt7915_dpd_freq_idx(center_freq, chandef->width);
+ if (idx < 0)
+ return -EINVAL;
+
+ /* Items: Tx DPD, Tx Flatness */
+ idx = idx * 2;
+ cal += MT_EE_CAL_GROUP_SIZE;
+
+ while (total--) {
+ int ret;
+
+ cal += (idx * MT_EE_CAL_UNIT);
+ ret = mt7915_mcu_set_pre_cal(dev, idx, cal, MT_EE_CAL_UNIT,
+ MCU_EXT_CMD(DPD_PRE_CAL_INFO));
+ if (ret)
+ return ret;
+
+ idx++;
+ }
+
+ return 0;
+}
+
int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index)
{
struct {
@@ -3361,8 +3503,9 @@ int mt7915_mcu_get_tx_rate(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx)
sizeof(req), false);
}
-int mt7915_mcu_set_sku(struct mt7915_phy *phy)
+int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
{
+#define MT7915_SKU_RATE_NUM 161
struct mt7915_dev *dev = phy->dev;
struct mt76_phy *mphy = phy->mt76;
struct ieee80211_hw *hw = mphy->hw;
@@ -3375,15 +3518,37 @@ int mt7915_mcu_set_sku(struct mt7915_phy *phy)
.format_id = 4,
.dbdc_idx = phy != &dev->phy,
};
- int i;
- s8 *delta;
+ struct mt76_power_limits limits_array;
+ s8 *la = (s8 *)&limits_array;
+ int i, idx, n_chains = hweight8(mphy->antenna_mask);
+ int tx_power;
+
+ tx_power = hw->conf.power_level * 2 -
+ mt76_tx_power_nss_delta(n_chains);
+
+ tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
+ &limits_array, tx_power);
+ mphy->txpower_cur = tx_power;
- delta = dev->rate_power[mphy->chandef.chan->band];
- mphy->txpower_cur = hw->conf.power_level * 2 +
- delta[MT7915_SKU_MAX_DELTA_IDX];
+ for (i = 0, idx = 0; i < ARRAY_SIZE(mt7915_sku_group_len); i++) {
+ u8 mcs_num, len = mt7915_sku_group_len[i];
+ int j;
- for (i = 0; i < MT7915_SKU_RATE_NUM; i++)
- req.val[i] = hw->conf.power_level * 2 + delta[i];
+ if (i >= SKU_HT_BW20 && i <= SKU_VHT_BW160) {
+ mcs_num = 10;
+
+ if (i == SKU_HT_BW20 || i == SKU_VHT_BW20)
+ la = (s8 *)&limits_array + 12;
+ } else {
+ mcs_num = len;
+ }
+
+ for (j = 0; j < min_t(u8, mcs_num, len); j++)
+ req.val[idx + j] = la[j];
+
+ la += mcs_num;
+ idx += len;
+ }
return mt76_mcu_send_msg(&dev->mt76,
MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index 4a932140a7c3..42582a66e42d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -284,6 +284,8 @@ enum {
MCU_EXT_CMD_FW_DBG_CTRL = 0x95,
MCU_EXT_CMD_SET_RDD_TH = 0x9d,
MCU_EXT_CMD_SET_SPR = 0xa8,
+ MCU_EXT_CMD_GROUP_PRE_CAL_INFO = 0xab,
+ MCU_EXT_CMD_DPD_PRE_CAL_INFO = 0xac,
MCU_EXT_CMD_PHY_STAT_INFO = 0xad,
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index dbc70c0d6668..4ea8972d4e2f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -32,17 +32,12 @@
#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 */
#define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */
#define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */
-#define MT7915_SKU_RATE_NUM 161
-#define MT7915_SKU_MAX_DELTA_IDX MT7915_SKU_RATE_NUM
-#define MT7915_SKU_TABLE_SIZE (MT7915_SKU_RATE_NUM + 1)
-
struct mt7915_vif;
struct mt7915_sta;
struct mt7915_dfs_pulse;
@@ -191,16 +186,12 @@ 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 flash_mode;
bool fw_debug;
bool ibf;
+
+ void *cal;
};
enum {
@@ -300,7 +291,7 @@ 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);
-void mt7915_eeprom_init_sku(struct mt7915_dev *dev);
+s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band);
int mt7915_dma_init(struct mt7915_dev *dev);
void mt7915_dma_prefetch(struct mt7915_dev *dev);
void mt7915_dma_cleanup(struct mt7915_dev *dev);
@@ -350,7 +341,7 @@ 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);
int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter);
int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable);
-int mt7915_mcu_set_sku(struct mt7915_phy *phy);
+int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy);
int mt7915_mcu_set_txbf_type(struct mt7915_dev *dev);
int mt7915_mcu_set_txbf_module(struct mt7915_dev *dev);
int mt7915_mcu_set_txbf_sounding(struct mt7915_dev *dev);
@@ -359,6 +350,8 @@ 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_apply_group_cal(struct mt7915_dev *dev);
+int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy);
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,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
index 75769595d1e1..643f171884cf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
@@ -154,28 +154,6 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
return IRQ_HANDLED;
}
-static int
-mt7915_alloc_device(struct pci_dev *pdev, struct mt7915_dev *dev)
-{
-#define NUM_BANDS 2
- int i;
- s8 **sku;
-
- sku = devm_kzalloc(&pdev->dev, NUM_BANDS * sizeof(*sku), GFP_KERNEL);
- if (!sku)
- return -ENOMEM;
-
- for (i = 0; i < NUM_BANDS; i++) {
- sku[i] = devm_kzalloc(&pdev->dev, MT7915_SKU_TABLE_SIZE *
- sizeof(**sku), GFP_KERNEL);
- if (!sku[i])
- return -ENOMEM;
- }
- dev->rate_power = sku;
-
- return 0;
-}
-
static void mt7915_pci_init_hif2(struct mt7915_dev *dev)
{
struct mt7915_hif *hif;
@@ -234,6 +212,7 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
.survey_flags = SURVEY_INFO_TIME_TX |
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_BSS_RX,
+ .token_size = MT7915_TOKEN_SIZE,
.tx_prepare_skb = mt7915_tx_prepare_skb,
.tx_complete_skb = mt7915_tx_complete_skb,
.rx_skb = mt7915_queue_rx_skb,
@@ -270,9 +249,6 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
return -ENOMEM;
dev = container_of(mdev, struct mt7915_dev, mt76);
- ret = mt7915_alloc_device(pdev, dev);
- if (ret)
- goto error;
ret = mt7915_mmio_init(mdev, pcim_iomap_table(pdev)[0], pdev->irq);
if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
index dfb8880657bf..efe0f2904c66 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
@@ -82,6 +82,11 @@
#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17)
#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18)
+#define MT_TMAC_FP0R0(_band) MT_WF_TMAC(_band, 0x020)
+#define MT_TMAC_FP0R15(_band) MT_WF_TMAC(_band, 0x080)
+#define MT_TMAC_FP0R18(_band) MT_WF_TMAC(_band, 0x270)
+#define MT_TMAC_FP_MASK GENMASK(7, 0)
+
#define MT_TMAC_TFCR0(_band) MT_WF_TMAC(_band, 0x1e0)
#define MT_WF_DMA_BASE(_band) ((_band) ? 0xa1e00 : 0x21e00)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
index bd798df748ba..f9d81e36ef09 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c
@@ -257,13 +257,13 @@ mt7915_tm_set_tx_len(struct mt7915_phy *phy, u32 tx_time)
{
struct mt76_phy *mphy = phy->mt76;
struct mt76_testmode_data *td = &mphy->test;
- struct sk_buff *old = td->tx_skb, *new;
struct ieee80211_supported_band *sband;
struct rate_info rate = {};
u16 flags = 0, tx_len;
u32 bitrate;
+ int ret;
- if (!tx_time || !old)
+ if (!tx_time)
return 0;
rate.mcs = td->tx_rate_idx;
@@ -323,21 +323,9 @@ mt7915_tm_set_tx_len(struct mt7915_phy *phy, u32 tx_time)
bitrate = cfg80211_calculate_bitrate(&rate);
tx_len = bitrate * tx_time / 10 / 8;
- if (tx_len < sizeof(struct ieee80211_hdr))
- tx_len = sizeof(struct ieee80211_hdr);
- else if (tx_len > IEEE80211_MAX_FRAME_LEN)
- tx_len = IEEE80211_MAX_FRAME_LEN;
-
- new = alloc_skb(tx_len, GFP_KERNEL);
- if (!new)
- return -ENOMEM;
-
- skb_copy_header(new, old);
- __skb_put_zero(new, tx_len);
- memcpy(new->data, old->data, sizeof(struct ieee80211_hdr));
-
- dev_kfree_skb(old);
- td->tx_skb = new;
+ ret = mt76_testmode_alloc_skb(phy->mt76, tx_len);
+ if (ret)
+ return ret;
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
index 94f0320ab2d4..6ee423dd4027 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
@@ -9,10 +9,13 @@ mt7921_fw_debug_set(void *data, u64 val)
{
struct mt7921_dev *dev = data;
- dev->fw_debug = (u8)val;
+ mt7921_mutex_acquire(dev);
+ dev->fw_debug = (u8)val;
mt7921_mcu_fw_log_2_host(dev, dev->fw_debug);
+ mt7921_mutex_release(dev);
+
return 0;
}
@@ -146,15 +149,100 @@ mt7921_queues_read(struct seq_file *s, void *data)
return 0;
}
+static void
+mt7921_seq_puts_array(struct seq_file *file, const char *str,
+ s8 *val, int len)
+{
+ int i;
+
+ seq_printf(file, "%-16s:", str);
+ for (i = 0; i < len; i++)
+ if (val[i] == 127)
+ seq_printf(file, " %6s", "N.A");
+ else
+ seq_printf(file, " %6d", val[i]);
+ seq_puts(file, "\n");
+}
+
+#define mt7921_print_txpwr_entry(prefix, rate) \
+({ \
+ mt7921_seq_puts_array(s, #prefix " (user)", \
+ txpwr.data[TXPWR_USER].rate, \
+ ARRAY_SIZE(txpwr.data[TXPWR_USER].rate)); \
+ mt7921_seq_puts_array(s, #prefix " (eeprom)", \
+ txpwr.data[TXPWR_EEPROM].rate, \
+ ARRAY_SIZE(txpwr.data[TXPWR_EEPROM].rate)); \
+ mt7921_seq_puts_array(s, #prefix " (tmac)", \
+ txpwr.data[TXPWR_MAC].rate, \
+ ARRAY_SIZE(txpwr.data[TXPWR_MAC].rate)); \
+})
+
+static int
+mt7921_txpwr(struct seq_file *s, void *data)
+{
+ struct mt7921_dev *dev = dev_get_drvdata(s->private);
+ struct mt7921_txpwr txpwr;
+ int ret;
+
+ ret = mt7921_get_txpwr_info(dev, &txpwr);
+ if (ret)
+ return ret;
+
+ seq_printf(s, "Tx power table (channel %d)\n", txpwr.ch);
+ seq_printf(s, "%-16s %6s %6s %6s %6s\n",
+ " ", "1m", "2m", "5m", "11m");
+ mt7921_print_txpwr_entry(CCK, cck);
+
+ seq_printf(s, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n",
+ " ", "6m", "9m", "12m", "18m", "24m", "36m",
+ "48m", "54m");
+ mt7921_print_txpwr_entry(OFDM, ofdm);
+
+ seq_printf(s, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s\n",
+ " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
+ "mcs6", "mcs7");
+ mt7921_print_txpwr_entry(HT20, ht20);
+
+ seq_printf(s, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
+ " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
+ "mcs6", "mcs7", "mcs32");
+ mt7921_print_txpwr_entry(HT40, ht40);
+
+ seq_printf(s, "%-16s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
+ " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
+ "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11");
+ mt7921_print_txpwr_entry(VHT20, vht20);
+ mt7921_print_txpwr_entry(VHT40, vht40);
+ mt7921_print_txpwr_entry(VHT80, vht80);
+ mt7921_print_txpwr_entry(VHT160, vht160);
+ mt7921_print_txpwr_entry(HE26, he26);
+ mt7921_print_txpwr_entry(HE52, he52);
+ mt7921_print_txpwr_entry(HE106, he106);
+ mt7921_print_txpwr_entry(HE242, he242);
+ mt7921_print_txpwr_entry(HE484, he484);
+ mt7921_print_txpwr_entry(HE996, he996);
+ mt7921_print_txpwr_entry(HE996x2, he996x2);
+
+ return 0;
+}
+
static int
mt7921_pm_set(void *data, u64 val)
{
struct mt7921_dev *dev = data;
+ struct mt76_connac_pm *pm = &dev->pm;
struct mt76_phy *mphy = dev->phy.mt76;
+ if (val == pm->enable)
+ return 0;
+
mt7921_mutex_acquire(dev);
- dev->pm.enable = val;
+ if (!pm->enable) {
+ pm->stats.last_wake_event = jiffies;
+ pm->stats.last_doze_event = jiffies;
+ }
+ pm->enable = val;
ieee80211_iterate_active_interfaces(mphy->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
@@ -177,6 +265,29 @@ mt7921_pm_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_pm, mt7921_pm_get, mt7921_pm_set, "%lld\n");
static int
+mt7921_pm_stats(struct seq_file *s, void *data)
+{
+ struct mt7921_dev *dev = dev_get_drvdata(s->private);
+ struct mt76_connac_pm *pm = &dev->pm;
+
+ unsigned long awake_time = pm->stats.awake_time;
+ unsigned long doze_time = pm->stats.doze_time;
+
+ if (!test_bit(MT76_STATE_PM, &dev->mphy.state))
+ awake_time += jiffies - pm->stats.last_wake_event;
+ else
+ doze_time += jiffies - pm->stats.last_doze_event;
+
+ seq_printf(s, "awake time: %14u\ndoze time: %15u\n",
+ jiffies_to_msecs(awake_time),
+ jiffies_to_msecs(doze_time));
+
+ seq_printf(s, "low power wakes: %9d\n", pm->stats.lp_wake);
+
+ return 0;
+}
+
+static int
mt7921_pm_idle_timeout_set(void *data, u64 val)
{
struct mt7921_dev *dev = data;
@@ -199,19 +310,28 @@ mt7921_pm_idle_timeout_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_pm_idle_timeout, mt7921_pm_idle_timeout_get,
mt7921_pm_idle_timeout_set, "%lld\n");
-static int mt7921_config(void *data, u64 val)
+static int mt7921_chip_reset(void *data, u64 val)
{
struct mt7921_dev *dev = data;
- int ret;
-
- mt7921_mutex_acquire(dev);
- ret = mt76_connac_mcu_chip_config(&dev->mt76);
- mt7921_mutex_release(dev);
+ int ret = 0;
+
+ switch (val) {
+ case 1:
+ /* Reset wifisys directly. */
+ mt7921_reset(&dev->mt76);
+ break;
+ default:
+ /* Collect the core dump before reset wifisys. */
+ mt7921_mutex_acquire(dev);
+ ret = mt76_connac_mcu_chip_config(&dev->mt76);
+ mt7921_mutex_release(dev);
+ break;
+ }
return ret;
}
-DEFINE_DEBUGFS_ATTRIBUTE(fops_config, NULL, mt7921_config, "%lld\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_reset, NULL, mt7921_chip_reset, "%lld\n");
int mt7921_init_debugfs(struct mt7921_dev *dev)
{
@@ -225,12 +345,16 @@ int mt7921_init_debugfs(struct mt7921_dev *dev)
mt7921_queues_read);
debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
mt7921_queues_acq);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "txpower_sku", dir,
+ mt7921_txpwr);
debugfs_create_file("tx_stats", 0400, dir, dev, &mt7921_tx_stats_fops);
debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
debugfs_create_file("runtime-pm", 0600, dir, dev, &fops_pm);
debugfs_create_file("idle-timeout", 0600, dir, dev,
&fops_pm_idle_timeout);
- debugfs_create_file("chip_config", 0600, dir, dev, &fops_config);
+ debugfs_create_file("chip_reset", 0600, dir, dev, &fops_reset);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "runtime_pm_stats", dir,
+ mt7921_pm_stats);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
index 992faf82ad09..71e664ee7652 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/dma.c
@@ -53,8 +53,7 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
}
}
-static void
-mt7921_tx_cleanup(struct mt7921_dev *dev)
+void mt7921_tx_cleanup(struct mt7921_dev *dev)
{
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);
@@ -66,15 +65,39 @@ static int mt7921_poll_tx(struct napi_struct *napi, int budget)
dev = container_of(napi, struct mt7921_dev, mt76.tx_napi);
- mt7921_tx_cleanup(dev);
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ napi_complete(napi);
+ queue_work(dev->mt76.wq, &dev->pm.wake_work);
+ return 0;
+ }
- if (napi_complete_done(napi, 0))
+ mt7921_tx_cleanup(dev);
+ if (napi_complete(napi))
mt7921_irq_enable(dev, MT_INT_TX_DONE_ALL);
+ mt76_connac_pm_unref(&dev->pm);
return 0;
}
-void mt7921_dma_prefetch(struct mt7921_dev *dev)
+static int mt7921_poll_rx(struct napi_struct *napi, int budget)
+{
+ struct mt7921_dev *dev;
+ int done;
+
+ dev = container_of(napi->dev, struct mt7921_dev, mt76.napi_dev);
+
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
+ napi_complete(napi);
+ queue_work(dev->mt76.wq, &dev->pm.wake_work);
+ return 0;
+ }
+ done = mt76_dma_rx_poll(napi, budget);
+ mt76_connac_pm_unref(&dev->pm);
+
+ return done;
+}
+
+static void mt7921_dma_prefetch(struct mt7921_dev *dev)
{
#define PREFETCH(base, depth) ((base) << 16 | (depth))
@@ -198,11 +221,160 @@ static u32 mt7921_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
return dev->bus_ops->rmw(mdev, addr, mask, val);
}
-static int mt7921_dmashdl_disabled(struct mt7921_dev *dev)
+static int mt7921_dma_disable(struct mt7921_dev *dev, bool force)
{
- mt76_clear(dev, MT_WFDMA0_GLO_CFG_EXT0, MT_WFDMA0_CSR_TX_DMASHDL_ENABLE);
+ if (force) {
+ /* reset */
+ mt76_clear(dev, MT_WFDMA0_RST,
+ MT_WFDMA0_RST_DMASHDL_ALL_RST |
+ MT_WFDMA0_RST_LOGIC_RST);
+
+ mt76_set(dev, MT_WFDMA0_RST,
+ MT_WFDMA0_RST_DMASHDL_ALL_RST |
+ MT_WFDMA0_RST_LOGIC_RST);
+ }
+
+ /* disable dmashdl */
+ mt76_clear(dev, MT_WFDMA0_GLO_CFG_EXT0,
+ MT_WFDMA0_CSR_TX_DMASHDL_ENABLE);
mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS);
+ /* disable WFDMA0 */
+ mt76_clear(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN |
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
+
+ if (!mt76_poll(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
+ MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int mt7921_dma_enable(struct mt7921_dev *dev)
+{
+ /* configure perfetch settings */
+ mt7921_dma_prefetch(dev);
+
+ /* reset dma idx */
+ mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0);
+
+ /* configure delay interrupt */
+ mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0);
+
+ mt76_set(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_WB_DDONE |
+ MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN |
+ MT_WFDMA0_GLO_CFG_CLK_GAT_DIS |
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
+
+ mt76_set(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
+
+ mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
+
+ /* enable interrupts for TX/RX rings */
+ mt7921_irq_enable(dev,
+ MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
+ MT_INT_MCU_CMD);
+ mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);
+
+ return 0;
+}
+
+static int mt7921_dma_reset(struct mt7921_dev *dev, bool force)
+{
+ int i, err;
+
+ err = mt7921_dma_disable(dev, force);
+ if (err)
+ return err;
+
+ /* reset hw queues */
+ for (i = 0; i < __MT_TXQ_MAX; i++)
+ mt76_queue_reset(dev, dev->mphy.q_tx[i]);
+
+ for (i = 0; i < __MT_MCUQ_MAX; i++)
+ mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
+
+ mt76_for_each_q_rx(&dev->mt76, i)
+ mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
+
+ mt76_tx_status_check(&dev->mt76, NULL, true);
+
+ return mt7921_dma_enable(dev);
+}
+
+int mt7921_wfsys_reset(struct mt7921_dev *dev)
+{
+ mt76_set(dev, 0x70002600, BIT(0));
+ msleep(200);
+ mt76_clear(dev, 0x70002600, BIT(0));
+
+ if (!__mt76_poll_msec(&dev->mt76, MT_WFSYS_SW_RST_B,
+ WFSYS_SW_INIT_DONE, WFSYS_SW_INIT_DONE, 500))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force)
+{
+ int i, err;
+
+ /* clean up hw queues */
+ for (i = 0; i < ARRAY_SIZE(dev->mt76.phy.q_tx); i++)
+ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
+
+ for (i = 0; i < ARRAY_SIZE(dev->mt76.q_mcu); i++)
+ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
+
+ mt76_for_each_q_rx(&dev->mt76, i)
+ mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]);
+
+ if (force) {
+ err = mt7921_wfsys_reset(dev);
+ if (err)
+ return err;
+ }
+ err = mt7921_dma_reset(dev, force);
+ if (err)
+ return err;
+
+ mt76_for_each_q_rx(&dev->mt76, i)
+ mt76_queue_rx_reset(dev, i);
+
+ return 0;
+}
+
+int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev)
+{
+ struct mt76_connac_pm *pm = &dev->pm;
+ int err;
+
+ /* check if the wpdma must be reinitialized */
+ if (mt7921_dma_need_reinit(dev)) {
+ /* disable interrutpts */
+ mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
+ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
+
+ err = mt7921_wpdma_reset(dev, false);
+ if (err) {
+ dev_err(dev->mt76.dev, "wpdma reset failed\n");
+ return err;
+ }
+
+ /* enable interrutpts */
+ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
+ pm->stats.lp_wake++;
+ }
+
return 0;
}
@@ -226,32 +398,10 @@ int mt7921_dma_init(struct mt7921_dev *dev)
mt76_dma_attach(&dev->mt76);
- /* reset */
- mt76_clear(dev, MT_WFDMA0_RST,
- MT_WFDMA0_RST_DMASHDL_ALL_RST |
- MT_WFDMA0_RST_LOGIC_RST);
-
- mt76_set(dev, MT_WFDMA0_RST,
- MT_WFDMA0_RST_DMASHDL_ALL_RST |
- MT_WFDMA0_RST_LOGIC_RST);
-
- ret = mt7921_dmashdl_disabled(dev);
+ ret = mt7921_dma_disable(dev, true);
if (ret)
return ret;
- /* disable WFDMA0 */
- mt76_clear(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
- MT_WFDMA0_GLO_CFG_RX_DMA_EN |
- MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN |
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-
- mt76_poll(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
- MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000);
-
/* init tx queue */
ret = mt7921_init_tx_queues(&dev->phy, MT7921_TXQ_BAND0,
MT7921_TX_RING_SIZE);
@@ -295,7 +445,7 @@ int mt7921_dma_init(struct mt7921_dev *dev)
if (ret)
return ret;
- ret = mt76_init_queues(dev);
+ ret = mt76_init_queues(dev, mt7921_poll_rx);
if (ret < 0)
return ret;
@@ -303,33 +453,7 @@ int mt7921_dma_init(struct mt7921_dev *dev)
mt7921_poll_tx, NAPI_POLL_WEIGHT);
napi_enable(&dev->mt76.tx_napi);
- /* configure perfetch settings */
- mt7921_dma_prefetch(dev);
-
- /* reset dma idx */
- mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0);
-
- /* configure delay interrupt */
- mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0);
-
- mt76_set(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_WB_DDONE |
- MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN |
- MT_WFDMA0_GLO_CFG_CLK_GAT_DIS |
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-
- mt76_set(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
-
- mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
-
- /* enable interrupts for TX/RX rings */
- mt7921_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
- MT_INT_MCU_CMD);
-
- return 0;
+ return mt7921_dma_enable(dev);
}
void mt7921_dma_cleanup(struct mt7921_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 5bb0a7b9e9e5..fe28bf4050c4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -58,12 +58,14 @@ mt7921_regd_notifier(struct wiphy *wiphy,
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct mt7921_dev *dev = mt7921_hw_dev(hw);
+ struct mt7921_phy *phy = mt7921_hw_phy(hw);
memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
dev->mt76.region = request->dfs_region;
mt7921_mutex_acquire(dev);
mt76_connac_mcu_set_channel_domain(hw->priv);
+ mt76_connac_mcu_set_rate_txpower(phy->mt76);
mt7921_mutex_release(dev);
}
@@ -164,23 +166,10 @@ void mt7921_mac_init(struct mt7921_dev *dev)
mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0);
}
-static void mt7921_init_work(struct work_struct *work)
-{
- struct mt7921_dev *dev = container_of(work, struct mt7921_dev,
- init_work);
-
- mt7921_mcu_set_eeprom(dev);
- mt7921_mac_init(dev);
-}
-
static int mt7921_init_hardware(struct mt7921_dev *dev)
{
int ret, idx;
- INIT_WORK(&dev->init_work, mt7921_init_work);
- spin_lock_init(&dev->token_lock);
- idr_init(&dev->token);
-
ret = mt7921_dma_init(dev);
if (ret)
return ret;
@@ -200,6 +189,10 @@ static int mt7921_init_hardware(struct mt7921_dev *dev)
if (ret < 0)
return ret;
+ ret = mt7921_mcu_set_eeprom(dev);
+ if (ret)
+ return ret;
+
/* Beacon and mgmt frames should occupy wcid 0 */
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7921_WTBL_STA - 1);
if (idx)
@@ -210,6 +203,8 @@ static int mt7921_init_hardware(struct mt7921_dev *dev)
dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET;
rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid);
+ mt7921_mac_init(dev);
+
return 0;
}
@@ -221,10 +216,13 @@ int mt7921_register_device(struct mt7921_dev *dev)
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
dev->mt76.phy.priv = &dev->phy;
+ dev->mt76.tx_worker.fn = mt7921_tx_worker;
INIT_DELAYED_WORK(&dev->pm.ps_work, mt7921_pm_power_save_work);
INIT_WORK(&dev->pm.wake_work, mt7921_pm_wake_work);
- init_completion(&dev->pm.wake_cmpl);
+ spin_lock_init(&dev->pm.wake.lock);
+ mutex_init(&dev->pm.mutex);
+ init_waitqueue_head(&dev->pm.wait);
spin_lock_init(&dev->pm.txq_lock);
set_bit(MT76_STATE_PM, &dev->mphy.state);
INIT_LIST_HEAD(&dev->phy.stats_list);
@@ -238,12 +236,15 @@ int mt7921_register_device(struct mt7921_dev *dev)
INIT_WORK(&dev->reset_work, mt7921_mac_reset_work);
+ dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
+ dev->pm.stats.last_wake_event = jiffies;
+ dev->pm.stats.last_doze_event = jiffies;
+
ret = mt7921_init_hardware(dev);
if (ret)
return ret;
mt7921_init_wiphy(hw);
- dev->pm.idle_timeout = MT7921_PM_TIMEOUT;
dev->mphy.sband_2g.sband.ht_cap.cap |=
IEEE80211_HT_CAP_LDPC_CODING |
IEEE80211_HT_CAP_MAX_AMSDU;
@@ -264,16 +265,15 @@ int mt7921_register_device(struct mt7921_dev *dev)
if (ret)
return ret;
- ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
-
return mt7921_init_debugfs(dev);
}
void mt7921_unregister_device(struct mt7921_dev *dev)
{
mt76_unregister_device(&dev->mt76);
- mt7921_mcu_exit(dev);
mt7921_tx_token_put(dev);
+ mt7921_dma_cleanup(dev);
+ mt7921_mcu_exit(dev);
tasklet_disable(&dev->irq_tasklet);
mt76_free_device(&dev->mt76);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index b507f3917830..214bd1859792 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -785,20 +785,6 @@ mt7921_write_hw_txp(struct mt7921_dev *dev, struct mt76_tx_info *tx_info,
}
}
-static void mt7921_set_tx_blocked(struct mt7921_dev *dev, bool blocked)
-{
- struct mt76_phy *mphy = &dev->mphy;
- struct mt76_queue *q;
-
- q = mphy->q_tx[0];
- if (blocked == q->blocked)
- return;
-
- q->blocked = blocked;
- if (!blocked)
- mt76_worker_schedule(&dev->mt76.tx_worker);
-}
-
int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
@@ -824,15 +810,7 @@ int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
t->skb = tx_info->skb;
- spin_lock_bh(&dev->token_lock);
- id = idr_alloc(&dev->token, t, 0, MT7921_TOKEN_SIZE, GFP_ATOMIC);
- if (id >= 0)
- dev->token_count++;
-
- if (dev->token_count >= MT7921_TOKEN_SIZE - MT7921_TOKEN_FREE_THR)
- mt7921_set_tx_blocked(dev, true);
- spin_unlock_bh(&dev->token_lock);
-
+ id = mt76_token_consume(mdev, &t);
if (id < 0)
return id;
@@ -994,15 +972,7 @@ void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb)
msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
stat = FIELD_GET(MT_TX_FREE_STATUS, info);
- spin_lock_bh(&dev->token_lock);
- txwi = idr_remove(&dev->token, msdu);
- if (txwi)
- dev->token_count--;
- if (dev->token_count < MT7921_TOKEN_SIZE - MT7921_TOKEN_FREE_THR &&
- dev->mphy.q_tx[0]->blocked)
- wake = true;
- spin_unlock_bh(&dev->token_lock);
-
+ txwi = mt76_token_release(mdev, msdu, &wake);
if (!txwi)
continue;
@@ -1030,11 +1000,8 @@ void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb)
mt76_put_txwi(mdev, txwi);
}
- if (wake) {
- spin_lock_bh(&dev->token_lock);
- mt7921_set_tx_blocked(dev, false);
- spin_unlock_bh(&dev->token_lock);
- }
+ if (wake)
+ mt76_set_tx_blocked(&dev->mt76, false);
napi_consume_skb(skb, 1);
@@ -1043,13 +1010,7 @@ void mt7921_mac_tx_free(struct mt7921_dev *dev, struct sk_buff *skb)
napi_consume_skb(skb, 1);
}
- if (test_bit(MT76_STATE_PM, &dev->phy.mt76->state))
- return;
-
mt7921_mac_sta_poll(dev);
-
- mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
-
mt76_worker_schedule(&dev->mt76.tx_worker);
}
@@ -1071,11 +1032,8 @@ void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
u16 token;
txp = mt7921_txwi_to_txp(mdev, e->txwi);
-
token = le16_to_cpu(txp->hw.msdu_id[0]) & ~MT_MSDU_ID_VALID;
- spin_lock_bh(&dev->token_lock);
- t = idr_remove(&dev->token, token);
- spin_unlock_bh(&dev->token_lock);
+ t = mt76_token_put(mdev, token);
e->skb = t ? t->skb : NULL;
}
@@ -1210,85 +1168,13 @@ void mt7921_update_channel(struct mt76_dev *mdev)
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
}
-int mt7921_wfsys_reset(struct mt7921_dev *dev)
-{
- mt76_set(dev, 0x70002600, BIT(0));
- msleep(200);
- mt76_clear(dev, 0x70002600, BIT(0));
-
- return __mt76_poll_msec(&dev->mt76, MT_WFSYS_SW_RST_B,
- WFSYS_SW_INIT_DONE, WFSYS_SW_INIT_DONE, 500);
-}
-
-static void
-mt7921_dma_reset(struct mt7921_dev *dev)
-{
- int i;
-
- /* reset */
- mt76_clear(dev, MT_WFDMA0_RST,
- MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST);
-
- mt76_set(dev, MT_WFDMA0_RST,
- MT_WFDMA0_RST_DMASHDL_ALL_RST | MT_WFDMA0_RST_LOGIC_RST);
-
- /* disable WFDMA0 */
- mt76_clear(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN |
- MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN |
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-
- mt76_poll(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
- MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000);
-
- /* reset hw queues */
- for (i = 0; i < __MT_TXQ_MAX; i++)
- mt76_queue_reset(dev, dev->mphy.q_tx[i]);
-
- for (i = 0; i < __MT_MCUQ_MAX; i++)
- mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
-
- mt76_for_each_q_rx(&dev->mt76, i)
- mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
-
- /* configure perfetch settings */
- mt7921_dma_prefetch(dev);
-
- /* reset dma idx */
- mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0);
-
- /* configure delay interrupt */
- mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0);
-
- mt76_set(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_WB_DDONE |
- MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN |
- MT_WFDMA0_GLO_CFG_CLK_GAT_DIS |
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-
- mt76_set(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
-
- mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
-
- /* enable interrupts for TX/RX rings */
- mt7921_irq_enable(dev,
- MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
- MT_INT_MCU_CMD);
-}
-
void mt7921_tx_token_put(struct mt7921_dev *dev)
{
struct mt76_txwi_cache *txwi;
int id;
- spin_lock_bh(&dev->token_lock);
- idr_for_each_entry(&dev->token, txwi, id) {
+ spin_lock_bh(&dev->mt76.token_lock);
+ idr_for_each_entry(&dev->mt76.token, txwi, id) {
mt7921_txp_skb_unmap(&dev->mt76, txwi);
if (txwi->skb) {
struct ieee80211_hw *hw;
@@ -1297,10 +1183,10 @@ void mt7921_tx_token_put(struct mt7921_dev *dev)
ieee80211_free_txskb(hw, txwi->skb);
}
mt76_put_txwi(&dev->mt76, txwi);
- dev->token_count--;
+ dev->mt76.token_count--;
}
- spin_unlock_bh(&dev->token_lock);
- idr_destroy(&dev->token);
+ spin_unlock_bh(&dev->mt76.token_lock);
+ idr_destroy(&dev->mt76.token);
}
static void
@@ -1339,23 +1225,13 @@ mt7921_mac_reset(struct mt7921_dev *dev)
napi_disable(&dev->mt76.tx_napi);
mt7921_tx_token_put(dev);
- idr_init(&dev->token);
-
- /* clean up hw queues */
- for (i = 0; i < ARRAY_SIZE(dev->mt76.phy.q_tx); i++)
- mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
-
- for (i = 0; i < ARRAY_SIZE(dev->mt76.q_mcu); i++)
- mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
-
- mt76_for_each_q_rx(&dev->mt76, i)
- mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]);
+ idr_init(&dev->mt76.token);
- mt7921_wfsys_reset(dev);
- mt7921_dma_reset(dev);
+ err = mt7921_wpdma_reset(dev, true);
+ if (err)
+ return err;
mt76_for_each_q_rx(&dev->mt76, i) {
- mt76_queue_rx_reset(dev, i);
napi_enable(&dev->mt76.napi[i]);
napi_schedule(&dev->mt76.napi[i]);
}
@@ -1365,12 +1241,10 @@ mt7921_mac_reset(struct mt7921_dev *dev)
mt76_worker_enable(&dev->mt76.tx_worker);
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
+ clear_bit(MT76_STATE_PM, &dev->mphy.state);
mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
- mt7921_irq_enable(dev,
- MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
- MT_INT_MCU_CMD);
err = mt7921_run_firmware(dev);
if (err)
@@ -1411,10 +1285,18 @@ void mt7921_mac_reset_work(struct work_struct *work)
if (i == 10)
dev_err(dev->mt76.dev, "chip reset failed\n");
+ if (test_and_clear_bit(MT76_HW_SCANNING, &dev->mphy.state)) {
+ struct cfg80211_scan_info info = {
+ .aborted = true,
+ };
+
+ ieee80211_scan_completed(dev->mphy.hw, &info);
+ }
+
ieee80211_wake_queues(hw);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
- mt7921_vif_connect_iter, 0);
+ mt7921_vif_connect_iter, NULL);
}
void mt7921_reset(struct mt76_dev *mdev)
@@ -1488,25 +1370,20 @@ void mt7921_mac_work(struct work_struct *work)
mac_work.work);
phy = mphy->priv;
- if (test_bit(MT76_STATE_PM, &mphy->state))
- goto out;
-
mt7921_mutex_acquire(phy->dev);
mt76_update_survey(mphy->dev);
- if (++mphy->mac_work_count == 5) {
+ if (++mphy->mac_work_count == 2) {
mphy->mac_work_count = 0;
mt7921_mac_update_mib_stats(phy);
}
- if (++phy->sta_work_count == 10) {
+ if (++phy->sta_work_count == 4) {
phy->sta_work_count = 0;
mt7921_mac_sta_stats_work(phy);
}
mt7921_mutex_release(phy->dev);
-
-out:
ieee80211_queue_delayed_work(phy->mt76->hw, &mphy->mac_work,
MT7921_WATCHDOG_TIME);
}
@@ -1520,13 +1397,19 @@ void mt7921_pm_wake_work(struct work_struct *work)
pm.wake_work);
mphy = dev->phy.mt76;
- if (!mt7921_mcu_drv_pmctrl(dev))
+ if (!mt7921_mcu_drv_pmctrl(dev)) {
+ int i;
+
+ mt76_for_each_q_rx(&dev->mt76, i)
+ napi_schedule(&dev->mt76.napi[i]);
mt76_connac_pm_dequeue_skbs(mphy, &dev->pm);
- else
- dev_err(mphy->dev->dev, "failed to wake device\n");
+ mt7921_tx_cleanup(dev);
+ ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
+ MT7921_WATCHDOG_TIME);
+ }
ieee80211_wake_queues(mphy->hw);
- complete_all(&dev->pm.wake_cmpl);
+ wake_up(&dev->pm.wait);
}
void mt7921_pm_power_save_work(struct work_struct *work)
@@ -1538,6 +1421,10 @@ void mt7921_pm_power_save_work(struct work_struct *work)
pm.ps_work.work);
delta = dev->pm.idle_timeout;
+ if (test_bit(MT76_HW_SCANNING, &dev->mphy.state) ||
+ test_bit(MT76_HW_SCHED_SCANNING, &dev->mphy.state))
+ goto out;
+
if (time_is_after_jiffies(dev->pm.last_activity + delta)) {
delta = dev->pm.last_activity + delta - jiffies;
goto out;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index c888e8249e2f..f4c27aa41048 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -182,6 +182,10 @@ int __mt7921_start(struct mt7921_phy *phy)
if (err)
return err;
+ err = mt76_connac_mcu_set_rate_txpower(phy->mt76);
+ if (err)
+ return err;
+
mt7921_mac_reset_counters(phy);
set_bit(MT76_STATE_RUNNING, &mphy->state);
@@ -391,8 +395,7 @@ out:
clear_bit(MT76_RESET, &phy->mt76->state);
mt7921_mutex_release(dev);
- mt76_txq_schedule_all(phy->mt76);
-
+ mt76_worker_schedule(&dev->mt76.tx_worker);
ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mt76->mac_work,
MT7921_WATCHDOG_TIME);
@@ -619,11 +622,17 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_PS)
mt7921_mcu_uni_bss_ps(dev, vif);
- if (changed & BSS_CHANGED_ASSOC)
+ if (changed & BSS_CHANGED_ASSOC) {
+ mt7921_mcu_sta_add(dev, NULL, vif, true);
mt7921_bss_bcnft_apply(dev, vif, info->assoc);
+ }
+
+ if (changed & BSS_CHANGED_ARP_FILTER) {
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- if (changed & BSS_CHANGED_ARP_FILTER)
- mt7921_mcu_update_arp_filter(hw, vif, info);
+ mt76_connac_mcu_update_arp_filter(&dev->mt76, &mvif->mt76,
+ info);
+ }
mt7921_mutex_release(dev);
}
@@ -634,15 +643,6 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- int rssi = -ewma_rssi_read(&mvif->rssi);
- struct mt76_sta_cmd_info info = {
- .sta = sta,
- .vif = vif,
- .enable = true,
- .cmd = MCU_UNI_CMD_STA_REC_UPDATE,
- .wcid = &msta->wcid,
- .rcpi = to_rcpi(rssi),
- };
int ret, idx;
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7921_WTBL_STA - 1);
@@ -669,7 +669,7 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mt7921_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
- ret = mt76_connac_mcu_add_sta_cmd(&dev->mphy, &info);
+ ret = mt7921_mcu_sta_add(dev, sta, vif, true);
if (ret)
return ret;
@@ -683,18 +683,11 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
{
struct mt7921_dev *dev = container_of(mdev, struct mt7921_dev, mt76);
struct mt7921_sta *msta = (struct mt7921_sta *)sta->drv_priv;
- struct mt76_sta_cmd_info info = {
- .sta = sta,
- .vif = vif,
- .cmd = MCU_UNI_CMD_STA_REC_UPDATE,
- .wcid = &msta->wcid,
- };
mt76_connac_free_pending_tx_skbs(&dev->pm, &msta->wcid);
mt76_connac_pm_wake(&dev->mphy, &dev->pm);
- mt76_connac_mcu_add_sta_cmd(&dev->mphy, &info);
-
+ mt7921_mcu_sta_add(dev, sta, vif, false);
mt7921_mac_wtbl_update(dev, msta->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -717,23 +710,18 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
}
-static void
-mt7921_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
+void mt7921_tx_worker(struct mt76_worker *w)
{
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct mt7921_phy *phy = mt7921_hw_phy(hw);
- struct mt76_phy *mphy = phy->mt76;
-
- if (!test_bit(MT76_STATE_RUNNING, &mphy->state))
- return;
+ struct mt7921_dev *dev = container_of(w, struct mt7921_dev,
+ mt76.tx_worker);
- if (test_bit(MT76_STATE_PM, &mphy->state)) {
+ if (!mt76_connac_pm_ref(&dev->mphy, &dev->pm)) {
queue_work(dev->mt76.wq, &dev->pm.wake_work);
return;
}
- dev->pm.last_activity = jiffies;
- mt76_worker_schedule(&dev->mt76.tx_worker);
+ mt76_txq_schedule_all(&dev->mphy);
+ mt76_connac_pm_unref(&dev->pm);
}
static void mt7921_tx(struct ieee80211_hw *hw,
@@ -761,9 +749,9 @@ static void mt7921_tx(struct ieee80211_hw *hw,
wcid = &mvif->sta.wcid;
}
- if (!test_bit(MT76_STATE_PM, &mphy->state)) {
- dev->pm.last_activity = jiffies;
+ if (mt76_connac_pm_ref(mphy, &dev->pm)) {
mt76_tx(mphy, control->sta, wcid, skb);
+ mt76_connac_pm_unref(&dev->pm);
return;
}
@@ -1192,7 +1180,7 @@ const struct ieee80211_ops mt7921_ops = {
.set_key = mt7921_set_key,
.ampdu_action = mt7921_ampdu_action,
.set_rts_threshold = mt7921_set_rts_threshold,
- .wake_tx_queue = mt7921_wake_tx_queue,
+ .wake_tx_queue = mt76_wake_tx_queue,
.release_buffered_frames = mt76_release_buffered_frames,
.get_txpower = mt76_get_txpower,
.get_stats = mt7921_get_stats,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index aa55667b6ed7..5f3d56d570a5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -160,8 +160,10 @@ mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
int ret = 0;
if (!skb) {
- dev_err(mdev->dev, "Message %d (seq %d) timeout\n",
+ dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
cmd, seq);
+ mt7921_reset(mdev);
+
return -ETIMEDOUT;
}
@@ -500,7 +502,7 @@ mt7921_mcu_debug_msg_event(struct mt7921_dev *dev, struct sk_buff *skb)
if (!msg->content[i])
msg->content[i] = ' ';
}
- wiphy_info(mt76_hw(dev)->wiphy, "%*s", len, msg->content);
+ wiphy_info(mt76_hw(dev)->wiphy, "%.*s", len, msg->content);
}
}
@@ -974,7 +976,6 @@ int mt7921_mcu_init(struct mt7921_dev *dev)
.mcu_skb_send_msg = mt7921_mcu_send_message,
.mcu_parse_response = mt7921_mcu_parse_response,
.mcu_restart = mt7921_mcu_restart,
- .mcu_reset = mt7921_reset,
};
dev->mt76.mcu_ops = &mt7921_mcu_ops;
@@ -1264,12 +1265,35 @@ int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
sizeof(req), false);
}
+int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta,
+ struct ieee80211_vif *vif, bool enable)
+{
+ struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+ int rssi = -ewma_rssi_read(&mvif->rssi);
+ struct mt76_sta_cmd_info info = {
+ .sta = sta,
+ .vif = vif,
+ .enable = enable,
+ .cmd = MCU_UNI_CMD_STA_REC_UPDATE,
+ .rcpi = to_rcpi(rssi),
+ };
+ struct mt7921_sta *msta;
+
+ msta = sta ? (struct mt7921_sta *)sta->drv_priv : NULL;
+ info.wcid = msta ? &msta->wcid : &mvif->sta.wcid;
+
+ return mt76_connac_mcu_add_sta_cmd(&dev->mphy, &info);
+}
+
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
- int i;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int i, err = 0;
+
+ mutex_lock(&pm->mutex);
- if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state))
+ if (!test_bit(MT76_STATE_PM, &mphy->state))
goto out;
for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
@@ -1281,23 +1305,35 @@ int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev)
if (i == MT7921_DRV_OWN_RETRY_COUNT) {
dev_err(dev->mt76.dev, "driver own failed\n");
- mt7921_reset(&dev->mt76);
- return -EIO;
+ err = -EIO;
+ goto out;
}
+ mt7921_wpdma_reinit_cond(dev);
+ clear_bit(MT76_STATE_PM, &mphy->state);
+
+ pm->stats.last_wake_event = jiffies;
+ pm->stats.doze_time += pm->stats.last_wake_event -
+ pm->stats.last_doze_event;
out:
- dev->pm.last_activity = jiffies;
+ mutex_unlock(&pm->mutex);
- return 0;
+ if (err)
+ mt7921_reset(&dev->mt76);
+
+ return err;
}
int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)
{
struct mt76_phy *mphy = &dev->mt76.phy;
- int i;
+ struct mt76_connac_pm *pm = &dev->pm;
+ int i, err = 0;
- if (test_and_set_bit(MT76_STATE_PM, &mphy->state))
- return 0;
+ mutex_lock(&pm->mutex);
+
+ if (mt76_connac_skip_fw_pmctrl(mphy, pm))
+ goto out;
for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN);
@@ -1308,11 +1344,20 @@ int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev)
if (i == MT7921_DRV_OWN_RETRY_COUNT) {
dev_err(dev->mt76.dev, "firmware own failed\n");
- mt7921_reset(&dev->mt76);
- return -EIO;
+ clear_bit(MT76_STATE_PM, &mphy->state);
+ err = -EIO;
}
- return 0;
+ pm->stats.last_doze_event = jiffies;
+ pm->stats.awake_time += pm->stats.last_doze_event -
+ pm->stats.last_wake_event;
+out:
+ mutex_unlock(&pm->mutex);
+
+ if (err)
+ mt7921_reset(&dev->mt76);
+
+ return err;
}
void
@@ -1339,46 +1384,25 @@ mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
}
}
-int mt7921_mcu_update_arp_filter(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info)
+int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr)
{
- struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
- struct mt7921_dev *dev = mt7921_hw_dev(hw);
- struct sk_buff *skb;
- int i, len = min_t(int, info->arp_addr_cnt,
- IEEE80211_BSS_ARP_ADDR_LIST_LEN);
- struct {
- struct {
- u8 bss_idx;
- u8 pad[3];
- } __packed hdr;
- struct mt76_connac_arpns_tlv arp;
- } req_hdr = {
- .hdr = {
- .bss_idx = mvif->mt76.idx,
- },
- .arp = {
- .tag = cpu_to_le16(UNI_OFFLOAD_OFFLOAD_ARP),
- .len = cpu_to_le16(sizeof(struct mt76_connac_arpns_tlv)),
- .ips_num = len,
- .mode = 2, /* update */
- .option = 1,
- },
+ struct mt7921_txpwr_event *event;
+ struct mt7921_txpwr_req req = {
+ .dbdc_idx = 0,
};
+ struct sk_buff *skb;
+ int ret;
- skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
- sizeof(req_hdr) + len * sizeof(__be32));
- if (!skb)
- return -ENOMEM;
+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_CMD_GET_TXPWR,
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
- skb_put_data(skb, &req_hdr, sizeof(req_hdr));
- for (i = 0; i < len; i++) {
- u8 *addr = (u8 *)skb_put(skb, sizeof(__be32));
+ event = (struct mt7921_txpwr_event *)skb->data;
+ WARN_ON(skb->len != le16_to_cpu(event->len));
+ memcpy(txpwr, &event->txpwr, sizeof(event->txpwr));
- memcpy(addr, &info->arp_addr_list[i], sizeof(__be32));
- }
+ dev_kfree_skb(skb);
- return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD_OFFLOAD,
- true);
+ return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
index 13e125f32283..49823d0a3d0a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h
@@ -86,6 +86,7 @@ enum {
MCU_EVENT_CH_PRIVILEGE = 0x18,
MCU_EVENT_SCHED_SCAN_DONE = 0x23,
MCU_EVENT_DBG_MSG = 0x27,
+ MCU_EVENT_TXPWR = 0xd0,
MCU_EVENT_COREDUMP = 0xf0,
};
@@ -390,4 +391,20 @@ struct mt7921_mcu_wlan_info {
__le32 wlan_idx;
struct mt7921_mcu_wlan_info_event event;
} __packed;
+
+struct mt7921_txpwr_req {
+ u8 ver;
+ u8 action;
+ __le16 len;
+ u8 dbdc_idx;
+ u8 rsv[3];
+} __packed;
+
+struct mt7921_txpwr_event {
+ u8 ver;
+ u8 action;
+ __le16 len;
+ struct mt7921_txpwr txpwr;
+} __packed;
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index e3d83d3d954c..59862ea4951c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -18,7 +18,7 @@
#define MT7921_PM_TIMEOUT (HZ / 12)
#define MT7921_HW_SCAN_TIMEOUT (HZ / 10)
-#define MT7921_WATCHDOG_TIME (HZ / 10)
+#define MT7921_WATCHDOG_TIME (HZ / 4)
#define MT7921_RESET_TIMEOUT (30 * HZ)
#define MT7921_TX_RING_SIZE 2048
@@ -35,7 +35,6 @@
#define MT7921_EEPROM_SIZE 3584
#define MT7921_TOKEN_SIZE 8192
-#define MT7921_TOKEN_FREE_THR 64
#define MT7921_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7921_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
@@ -156,16 +155,11 @@ struct mt7921_dev {
u16 chainmask;
- struct work_struct init_work;
struct work_struct reset_work;
struct list_head sta_poll_list;
spinlock_t sta_poll_lock;
- spinlock_t token_lock;
- int token_count;
- struct idr token;
-
u8 fw_debug;
struct mt76_connac_pm pm;
@@ -173,6 +167,36 @@ struct mt7921_dev {
};
enum {
+ TXPWR_USER,
+ TXPWR_EEPROM,
+ TXPWR_MAC,
+ TXPWR_MAX_NUM,
+};
+
+struct mt7921_txpwr {
+ u8 ch;
+ u8 rsv[3];
+ struct {
+ u8 ch;
+ u8 cck[4];
+ u8 ofdm[8];
+ u8 ht20[8];
+ u8 ht40[9];
+ u8 vht20[12];
+ u8 vht40[12];
+ u8 vht80[12];
+ u8 vht160[12];
+ u8 he26[12];
+ u8 he52[12];
+ u8 he106[12];
+ u8 he242[12];
+ u8 he484[12];
+ u8 he996[12];
+ u8 he996x2[12];
+ } data[TXPWR_MAX_NUM];
+};
+
+enum {
MT_LMAC_AC00,
MT_LMAC_AC01,
MT_LMAC_AC02,
@@ -224,16 +248,17 @@ int mt7921_eeprom_get_target_power(struct mt7921_dev *dev,
u8 chain_idx);
void mt7921_eeprom_init_sku(struct mt7921_dev *dev);
int mt7921_dma_init(struct mt7921_dev *dev);
-void mt7921_dma_prefetch(struct mt7921_dev *dev);
+int mt7921_wpdma_reset(struct mt7921_dev *dev, bool force);
+int mt7921_wpdma_reinit_cond(struct mt7921_dev *dev);
void mt7921_dma_cleanup(struct mt7921_dev *dev);
int mt7921_run_firmware(struct mt7921_dev *dev);
int mt7921_mcu_init(struct mt7921_dev *dev);
-int mt7921_mcu_add_bss_info(struct mt7921_phy *phy,
- struct ieee80211_vif *vif, int enable);
int mt7921_mcu_add_key(struct mt7921_dev *dev, struct ieee80211_vif *vif,
struct mt7921_sta *msta, struct ieee80211_key_conf *key,
enum set_key_cmd cmd);
int mt7921_set_channel(struct mt7921_phy *phy);
+int mt7921_mcu_sta_add(struct mt7921_dev *dev, struct ieee80211_sta *sta,
+ struct ieee80211_vif *vif, bool enable);
int mt7921_mcu_set_chan_info(struct mt7921_phy *phy, int cmd);
int mt7921_mcu_set_tx(struct mt7921_dev *dev, struct ieee80211_vif *vif);
int mt7921_mcu_set_eeprom(struct mt7921_dev *dev);
@@ -288,6 +313,11 @@ mt7921_l1_rmw(struct mt7921_dev *dev, u32 addr, u32 mask, u32 val)
#define mt7921_l1_set(dev, addr, val) mt7921_l1_rmw(dev, addr, 0, val)
#define mt7921_l1_clear(dev, addr, val) mt7921_l1_rmw(dev, addr, val, 0)
+static inline bool mt7921_dma_need_reinit(struct mt7921_dev *dev)
+{
+ return !mt76_get_field(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
+}
+
void mt7921_mac_init(struct mt7921_dev *dev);
bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask);
void mt7921_mac_reset_counters(struct mt7921_phy *phy);
@@ -305,10 +335,13 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
void mt7921_mac_work(struct work_struct *work);
void mt7921_mac_reset_work(struct work_struct *work);
void mt7921_reset(struct mt76_dev *mdev);
+void mt7921_tx_cleanup(struct mt7921_dev *dev);
int mt7921_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
+
+void mt7921_tx_worker(struct mt76_worker *w);
void mt7921_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
int mt7921_init_tx_queues(struct mt7921_phy *phy, int idx, int n_desc);
void mt7921_tx_token_put(struct mt7921_dev *dev);
@@ -335,9 +368,6 @@ int mt7921_mcu_uni_bss_bcnft(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool enable);
int mt7921_mcu_set_bss_pm(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool enable);
-int mt7921_mcu_update_arp_filter(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info);
int mt7921_mcu_drv_pmctrl(struct mt7921_dev *dev);
int mt7921_mcu_fw_pmctrl(struct mt7921_dev *dev);
void mt7921_pm_wake_work(struct work_struct *work);
@@ -348,8 +378,6 @@ int mt7921_mac_set_beacon_filter(struct mt7921_phy *phy,
bool enable);
void mt7921_pm_interface_iter(void *priv, u8 *mac, struct ieee80211_vif *vif);
void mt7921_coredump_work(struct work_struct *work);
-int mt7921_mcu_update_arp_filter(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info);
int mt7921_wfsys_reset(struct mt7921_dev *dev);
+int mt7921_get_txpwr_info(struct mt7921_dev *dev, struct mt7921_txpwr *txpwr);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index 40e2086d075c..fa02d934f0bf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -61,6 +61,18 @@ static void mt7921_irq_tasklet(unsigned long data)
if (intr & MT_INT_TX_DONE_MCU)
mask |= MT_INT_TX_DONE_MCU;
+ if (intr & MT_INT_MCU_CMD) {
+ u32 intr_sw;
+
+ intr_sw = mt76_rr(dev, MT_MCU_CMD);
+ /* ack MCU2HOST_SW_INT_STA */
+ mt76_wr(dev, MT_MCU_CMD, intr_sw);
+ if (intr_sw & MT_MCU_CMD_WAKE_RX_PCIE) {
+ mask |= MT_INT_RX_DONE_DATA;
+ intr |= MT_INT_RX_DONE_DATA;
+ }
+ }
+
mt76_set_irq_mask(&dev->mt76, MT_WFDMA0_HOST_INT_ENA, mask, 0);
if (intr & MT_INT_TX_DONE_ALL)
@@ -87,6 +99,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
.survey_flags = SURVEY_INFO_TIME_TX |
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_BSS_RX,
+ .token_size = MT7921_TOKEN_SIZE,
.tx_prepare_skb = mt7921_tx_prepare_skb,
.tx_complete_skb = mt7921_tx_complete_skb,
.rx_skb = mt7921_queue_rx_skb,
@@ -189,13 +202,15 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state)
return err;
}
+ if (!dev->pm.enable)
+ mt76_connac_mcu_set_deep_sleep(&dev->mt76, true);
+
napi_disable(&mdev->tx_napi);
mt76_worker_disable(&mdev->tx_worker);
mt76_for_each_q_rx(mdev, i) {
napi_disable(&mdev->napi[i]);
}
- tasklet_kill(&dev->irq_tasklet);
pci_enable_wake(pdev, pci_choose_state(pdev, state), true);
@@ -210,6 +225,9 @@ static int mt7921_pci_suspend(struct pci_dev *pdev, pm_message_t state)
/* disable interrupt */
mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
+ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
+ synchronize_irq(pdev->irq);
+ tasklet_kill(&dev->irq_tasklet);
err = mt7921_mcu_fw_pmctrl(dev);
if (err)
@@ -227,6 +245,10 @@ restore:
napi_enable(&mdev->napi[i]);
}
napi_enable(&mdev->tx_napi);
+
+ if (!dev->pm.enable)
+ mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
+
if (hif_suspend)
mt76_connac_mcu_set_hif_suspend(mdev, false);
@@ -249,10 +271,13 @@ static int mt7921_pci_resume(struct pci_dev *pdev)
if (err < 0)
return err;
+ mt7921_wpdma_reinit_cond(dev);
+
/* enable interrupt */
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
mt7921_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_MCU_CMD);
+ mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);
/* put dma enabled */
mt76_set(dev, MT_WFDMA0_GLO_CFG,
@@ -266,6 +291,9 @@ static int mt7921_pci_resume(struct pci_dev *pdev)
napi_enable(&mdev->tx_napi);
napi_schedule(&mdev->tx_napi);
+ if (!dev->pm.enable)
+ mt76_connac_mcu_set_deep_sleep(&dev->mt76, false);
+
if (!test_bit(MT76_STATE_SUSPEND, &dev->mphy.state))
err = mt76_connac_mcu_set_hif_suspend(mdev, false);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
index 76ecfea21dce..b6944c867a57 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h
@@ -251,13 +251,16 @@
#define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1)
#define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2)
-#define MT_MCU_CMD MT_WFDMA0(0x1f0)
-#define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1)
-#define MT_MCU_CMD_STOP_DMA BIT(2)
-#define MT_MCU_CMD_RESET_DONE BIT(3)
-#define MT_MCU_CMD_RECOVERY_DONE BIT(4)
-#define MT_MCU_CMD_NORMAL_STATE BIT(5)
-#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
+#define MT_MCU_CMD MT_WFDMA0(0x1f0)
+#define MT_MCU_CMD_WAKE_RX_PCIE BIT(0)
+#define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1)
+#define MT_MCU_CMD_STOP_DMA BIT(2)
+#define MT_MCU_CMD_RESET_DONE BIT(3)
+#define MT_MCU_CMD_RECOVERY_DONE BIT(4)
+#define MT_MCU_CMD_NORMAL_STATE BIT(5)
+#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
+
+#define MT_MCU2HOST_SW_INT_ENA MT_WFDMA0(0x1f4)
#define MT_WFDMA0_HOST_INT_STA MT_WFDMA0(0x200)
#define HOST_RX_DONE_INT_STS0 BIT(0) /* Rx mcu */
diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c
index cc769645afa5..001d0ba5f73e 100644
--- a/drivers/net/wireless/mediatek/mt76/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/testmode.c
@@ -62,36 +62,83 @@ void mt76_testmode_tx_pending(struct mt76_phy *phy)
spin_unlock_bh(&q->lock);
}
+static u32
+mt76_testmode_max_mpdu_len(struct mt76_phy *phy, u8 tx_rate_mode)
+{
+ switch (tx_rate_mode) {
+ case MT76_TM_TX_MODE_HT:
+ return IEEE80211_MAX_MPDU_LEN_HT_7935;
+ case MT76_TM_TX_MODE_VHT:
+ case MT76_TM_TX_MODE_HE_SU:
+ case MT76_TM_TX_MODE_HE_EXT_SU:
+ case MT76_TM_TX_MODE_HE_TB:
+ case MT76_TM_TX_MODE_HE_MU:
+ if (phy->sband_5g.sband.vht_cap.cap &
+ IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991)
+ return IEEE80211_MAX_MPDU_LEN_VHT_7991;
+ return IEEE80211_MAX_MPDU_LEN_VHT_11454;
+ case MT76_TM_TX_MODE_CCK:
+ case MT76_TM_TX_MODE_OFDM:
+ default:
+ return IEEE80211_MAX_FRAME_LEN;
+ }
+}
-static int
-mt76_testmode_tx_init(struct mt76_phy *phy)
+static void
+mt76_testmode_free_skb(struct mt76_phy *phy)
{
struct mt76_testmode_data *td = &phy->test;
- struct ieee80211_tx_info *info;
- struct ieee80211_hdr *hdr;
- struct sk_buff *skb;
+ struct sk_buff *skb = td->tx_skb;
+
+ if (!skb)
+ return;
+
+ if (skb_has_frag_list(skb)) {
+ kfree_skb_list(skb_shinfo(skb)->frag_list);
+ skb_shinfo(skb)->frag_list = NULL;
+ }
+
+ dev_kfree_skb(skb);
+ td->tx_skb = NULL;
+}
+
+int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len)
+{
+#define MT_TXP_MAX_LEN 4095
u16 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
IEEE80211_FCTL_FROMDS;
- struct ieee80211_tx_rate *rate;
- u8 max_nss = hweight8(phy->antenna_mask);
+ struct mt76_testmode_data *td = &phy->test;
bool ext_phy = phy != &phy->dev->phy;
+ struct sk_buff **frag_tail, *head;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_hdr *hdr;
+ u32 max_len, head_len;
+ int nfrags, i;
- if (td->tx_antenna_mask)
- max_nss = min_t(u8, max_nss, hweight8(td->tx_antenna_mask));
+ max_len = mt76_testmode_max_mpdu_len(phy, td->tx_rate_mode);
+ if (len > max_len)
+ len = max_len;
+ else if (len < sizeof(struct ieee80211_hdr))
+ len = sizeof(struct ieee80211_hdr);
- skb = alloc_skb(td->tx_msdu_len, GFP_KERNEL);
- if (!skb)
+ nfrags = len / MT_TXP_MAX_LEN;
+ head_len = nfrags ? MT_TXP_MAX_LEN : len;
+
+ if (len > IEEE80211_MAX_FRAME_LEN)
+ fc |= IEEE80211_STYPE_QOS_DATA;
+
+ head = alloc_skb(head_len, GFP_KERNEL);
+ if (!head)
return -ENOMEM;
- dev_kfree_skb(td->tx_skb);
- td->tx_skb = skb;
- hdr = __skb_put_zero(skb, td->tx_msdu_len);
+ hdr = __skb_put_zero(head, head_len);
hdr->frame_control = cpu_to_le16(fc);
memcpy(hdr->addr1, phy->macaddr, sizeof(phy->macaddr));
memcpy(hdr->addr2, phy->macaddr, sizeof(phy->macaddr));
memcpy(hdr->addr3, phy->macaddr, sizeof(phy->macaddr));
+ skb_set_queue_mapping(head, IEEE80211_AC_BE);
- info = IEEE80211_SKB_CB(skb);
+ info = IEEE80211_SKB_CB(head);
info->flags = IEEE80211_TX_CTL_INJECTED |
IEEE80211_TX_CTL_NO_ACK |
IEEE80211_TX_CTL_NO_PS_BUFFER;
@@ -99,9 +146,60 @@ mt76_testmode_tx_init(struct mt76_phy *phy)
if (ext_phy)
info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
+ frag_tail = &skb_shinfo(head)->frag_list;
+
+ for (i = 0; i < nfrags; i++) {
+ struct sk_buff *frag;
+ u16 frag_len;
+
+ if (i == nfrags - 1)
+ frag_len = len % MT_TXP_MAX_LEN;
+ else
+ frag_len = MT_TXP_MAX_LEN;
+
+ frag = alloc_skb(frag_len, GFP_KERNEL);
+ if (!frag)
+ return -ENOMEM;
+
+ __skb_put_zero(frag, frag_len);
+ head->len += frag->len;
+ head->data_len += frag->len;
+
+ if (*frag_tail) {
+ (*frag_tail)->next = frag;
+ frag_tail = &frag;
+ } else {
+ *frag_tail = frag;
+ }
+ }
+
+ mt76_testmode_free_skb(phy);
+ td->tx_skb = head;
+
+ return 0;
+}
+EXPORT_SYMBOL(mt76_testmode_alloc_skb);
+
+static int
+mt76_testmode_tx_init(struct mt76_phy *phy)
+{
+ struct mt76_testmode_data *td = &phy->test;
+ struct ieee80211_tx_info *info;
+ struct ieee80211_tx_rate *rate;
+ u8 max_nss = hweight8(phy->antenna_mask);
+ int ret;
+
+ ret = mt76_testmode_alloc_skb(phy, td->tx_mpdu_len);
+ if (ret)
+ return ret;
+
if (td->tx_rate_mode > MT76_TM_TX_MODE_VHT)
goto out;
+ if (td->tx_antenna_mask)
+ max_nss = min_t(u8, max_nss, hweight8(td->tx_antenna_mask));
+
+ info = IEEE80211_SKB_CB(td->tx_skb);
rate = &info->control.rates[0];
rate->count = 1;
rate->idx = td->tx_rate_idx;
@@ -171,8 +269,6 @@ mt76_testmode_tx_init(struct mt76_phy *phy)
}
}
out:
- skb_set_queue_mapping(skb, IEEE80211_AC_BE);
-
return 0;
}
@@ -203,8 +299,7 @@ mt76_testmode_tx_stop(struct mt76_phy *phy)
wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued,
MT76_TM_TIMEOUT * HZ);
- dev_kfree_skb(td->tx_skb);
- td->tx_skb = NULL;
+ mt76_testmode_free_skb(phy);
}
static inline void
@@ -224,10 +319,10 @@ mt76_testmode_init_defaults(struct mt76_phy *phy)
{
struct mt76_testmode_data *td = &phy->test;
- if (td->tx_msdu_len > 0)
+ if (td->tx_mpdu_len > 0)
return;
- td->tx_msdu_len = 1024;
+ td->tx_mpdu_len = 1024;
td->tx_count = 1;
td->tx_rate_mode = MT76_TM_TX_MODE_OFDM;
td->tx_rate_nss = 1;
@@ -345,16 +440,6 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (tb[MT76_TM_ATTR_TX_COUNT])
td->tx_count = nla_get_u32(tb[MT76_TM_ATTR_TX_COUNT]);
- if (tb[MT76_TM_ATTR_TX_LENGTH]) {
- u32 val = nla_get_u32(tb[MT76_TM_ATTR_TX_LENGTH]);
-
- if (val > IEEE80211_MAX_FRAME_LEN ||
- val < sizeof(struct ieee80211_hdr))
- goto out;
-
- td->tx_msdu_len = val;
- }
-
if (tb[MT76_TM_ATTR_TX_RATE_IDX])
td->tx_rate_idx = nla_get_u8(tb[MT76_TM_ATTR_TX_RATE_IDX]);
@@ -375,6 +460,16 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
&td->tx_power_control, 0, 1))
goto out;
+ if (tb[MT76_TM_ATTR_TX_LENGTH]) {
+ u32 val = nla_get_u32(tb[MT76_TM_ATTR_TX_LENGTH]);
+
+ if (val > mt76_testmode_max_mpdu_len(phy, td->tx_rate_mode) ||
+ val < sizeof(struct ieee80211_hdr))
+ goto out;
+
+ td->tx_mpdu_len = val;
+ }
+
if (tb[MT76_TM_ATTR_TX_IPG])
td->tx_ipg = nla_get_u32(tb[MT76_TM_ATTR_TX_IPG]);
@@ -506,7 +601,7 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
goto out;
if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) ||
- nla_put_u32(msg, MT76_TM_ATTR_TX_LENGTH, td->tx_msdu_len) ||
+ nla_put_u32(msg, MT76_TM_ATTR_TX_LENGTH, td->tx_mpdu_len) ||
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_MODE, td->tx_rate_mode) ||
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_NSS, td->tx_rate_nss) ||
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, td->tx_rate_idx) ||
diff --git a/drivers/net/wireless/mediatek/mt76/testmode.h b/drivers/net/wireless/mediatek/mt76/testmode.h
index e0c706ce9b42..d32a7654c47e 100644
--- a/drivers/net/wireless/mediatek/mt76/testmode.h
+++ b/drivers/net/wireless/mediatek/mt76/testmode.h
@@ -21,7 +21,7 @@
* @MT76_TM_ATTR_TX_COUNT: configured number of frames to send when setting
* state to MT76_TM_STATE_TX_FRAMES (u32)
* @MT76_TM_ATTR_TX_PENDING: pending frames during MT76_TM_STATE_TX_FRAMES (u32)
- * @MT76_TM_ATTR_TX_LENGTH: packet tx msdu length (u32)
+ * @MT76_TM_ATTR_TX_LENGTH: packet tx mpdu length (u32)
* @MT76_TM_ATTR_TX_RATE_MODE: packet tx mode (u8, see &enum mt76_testmode_tx_mode)
* @MT76_TM_ATTR_TX_RATE_NSS: packet tx number of spatial streams (u8)
* @MT76_TM_ATTR_TX_RATE_IDX: packet tx rate/MCS index (u8)
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 451ed60c6296..53ea8de82df0 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -213,7 +213,7 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *sk
if (phy->test.tx_queued == phy->test.tx_done)
wake_up(&dev->tx_wait);
- ieee80211_free_txskb(hw, skb);
+ dev_kfree_skb_any(skb);
return;
}
#endif
@@ -422,8 +422,7 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
return idx;
do {
- if (test_bit(MT76_STATE_PM, &phy->state) ||
- test_bit(MT76_RESET, &phy->state))
+ if (test_bit(MT76_RESET, &phy->state))
return -EBUSY;
if (stop || mt76_txq_stopped(q))
@@ -463,8 +462,7 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
while (1) {
int n_frames = 0;
- if (test_bit(MT76_STATE_PM, &phy->state) ||
- test_bit(MT76_RESET, &phy->state))
+ if (test_bit(MT76_RESET, &phy->state))
return -EBUSY;
if (dev->queue_ops->tx_cleanup &&
@@ -540,10 +538,8 @@ void mt76_txq_schedule_all(struct mt76_phy *phy)
}
EXPORT_SYMBOL_GPL(mt76_txq_schedule_all);
-void mt76_tx_worker(struct mt76_worker *w)
+void mt76_tx_worker_run(struct mt76_dev *dev)
{
- struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
-
mt76_txq_schedule_all(&dev->phy);
if (dev->phy2)
mt76_txq_schedule_all(dev->phy2);
@@ -555,6 +551,14 @@ void mt76_tx_worker(struct mt76_worker *w)
mt76_testmode_tx_pending(dev->phy2);
#endif
}
+EXPORT_SYMBOL_GPL(mt76_tx_worker_run);
+
+void mt76_tx_worker(struct mt76_worker *w)
+{
+ struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
+
+ mt76_tx_worker_run(dev);
+}
void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta,
bool send_bar)
@@ -644,3 +648,64 @@ void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q,
spin_unlock_bh(&q->lock);
}
EXPORT_SYMBOL_GPL(mt76_queue_tx_complete);
+
+void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked)
+{
+ struct mt76_phy *phy = &dev->phy, *phy2 = dev->phy2;
+ struct mt76_queue *q, *q2 = NULL;
+
+ q = phy->q_tx[0];
+ if (blocked == q->blocked)
+ return;
+
+ q->blocked = blocked;
+ if (phy2) {
+ q2 = phy2->q_tx[0];
+ q2->blocked = blocked;
+ }
+
+ if (!blocked)
+ mt76_worker_schedule(&dev->tx_worker);
+}
+EXPORT_SYMBOL_GPL(__mt76_set_tx_blocked);
+
+int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi)
+{
+ int token;
+
+ spin_lock_bh(&dev->token_lock);
+
+ token = idr_alloc(&dev->token, *ptxwi, 0, dev->drv->token_size,
+ GFP_ATOMIC);
+ if (token >= 0)
+ dev->token_count++;
+
+ if (dev->token_count >= dev->drv->token_size - MT76_TOKEN_FREE_THR)
+ __mt76_set_tx_blocked(dev, true);
+
+ spin_unlock_bh(&dev->token_lock);
+
+ return token;
+}
+EXPORT_SYMBOL_GPL(mt76_token_consume);
+
+struct mt76_txwi_cache *
+mt76_token_release(struct mt76_dev *dev, int token, bool *wake)
+{
+ struct mt76_txwi_cache *txwi;
+
+ spin_lock_bh(&dev->token_lock);
+
+ txwi = idr_remove(&dev->token, token);
+ if (txwi)
+ dev->token_count--;
+
+ if (dev->token_count < dev->drv->token_size - MT76_TOKEN_FREE_THR &&
+ dev->phy.q_tx[0]->blocked)
+ *wake = true;
+
+ spin_unlock_bh(&dev->token_lock);
+
+ return txwi;
+}
+EXPORT_SYMBOL_GPL(mt76_token_release);
diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c
index c775c177933b..8dc80574d08d 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/event.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/event.c
@@ -570,8 +570,10 @@ qtnf_event_handle_external_auth(struct qtnf_vif *vif,
return 0;
if (ev->ssid_len) {
- memcpy(auth.ssid.ssid, ev->ssid, ev->ssid_len);
- auth.ssid.ssid_len = ev->ssid_len;
+ int len = clamp_val(ev->ssid_len, 0, IEEE80211_MAX_SSID_LEN);
+
+ memcpy(auth.ssid.ssid, ev->ssid, len);
+ auth.ssid.ssid_len = len;
}
auth.key_mgmt_suite = le32_to_cpu(ev->akm_suite);
diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c
index c9b6ee81dcb9..8efe2f5e5b9f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/core.c
+++ b/drivers/net/wireless/realtek/rtlwifi/core.c
@@ -1018,6 +1018,25 @@ static void send_beacon_frame(struct ieee80211_hw *hw,
}
}
+void rtl_update_beacon_work_callback(struct work_struct *work)
+{
+ struct rtl_works *rtlworks =
+ container_of(work, struct rtl_works, update_beacon_work);
+ struct ieee80211_hw *hw = rtlworks->hw;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_vif *vif = rtlpriv->mac80211.vif;
+
+ if (!vif) {
+ WARN_ONCE(true, "no vif to update beacon\n");
+ return;
+ }
+
+ mutex_lock(&rtlpriv->locks.conf_mutex);
+ send_beacon_frame(hw, vif);
+ mutex_unlock(&rtlpriv->locks.conf_mutex);
+}
+EXPORT_SYMBOL_GPL(rtl_update_beacon_work_callback);
+
static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -1747,6 +1766,18 @@ static void rtl_op_flush(struct ieee80211_hw *hw,
rtlpriv->intf_ops->flush(hw, queues, drop);
}
+static int rtl_op_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ bool set)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192CU)
+ schedule_work(&rtlpriv->works.update_beacon_work);
+
+ return 0;
+}
+
/* Description:
* This routine deals with the Power Configuration CMD
* parsing for RTL8723/RTL8188E Series IC.
@@ -1903,6 +1934,7 @@ const struct ieee80211_ops rtl_ops = {
.sta_add = rtl_op_sta_add,
.sta_remove = rtl_op_sta_remove,
.flush = rtl_op_flush,
+ .set_tim = rtl_op_set_tim,
};
EXPORT_SYMBOL_GPL(rtl_ops);
diff --git a/drivers/net/wireless/realtek/rtlwifi/core.h b/drivers/net/wireless/realtek/rtlwifi/core.h
index 7447ff456710..345161b47442 100644
--- a/drivers/net/wireless/realtek/rtlwifi/core.h
+++ b/drivers/net/wireless/realtek/rtlwifi/core.h
@@ -60,5 +60,6 @@ void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data);
bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb);
bool rtl_btc_status_false(void);
void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igval);
+void rtl_update_beacon_work_callback(struct work_struct *work);
#endif
diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c
index 37a9a03123f3..86a236873254 100644
--- a/drivers/net/wireless/realtek/rtlwifi/usb.c
+++ b/drivers/net/wireless/realtek/rtlwifi/usb.c
@@ -805,6 +805,7 @@ static void rtl_usb_stop(struct ieee80211_hw *hw)
tasklet_kill(&rtlusb->rx_work_tasklet);
cancel_work_sync(&rtlpriv->works.lps_change_work);
+ cancel_work_sync(&rtlpriv->works.update_beacon_work);
flush_workqueue(rtlpriv->works.rtl_wq);
@@ -1031,6 +1032,8 @@ int rtl_usb_probe(struct usb_interface *intf,
rtl_fill_h2c_cmd_work_callback);
INIT_WORK(&rtlpriv->works.lps_change_work,
rtl_lps_change_work_callback);
+ INIT_WORK(&rtlpriv->works.update_beacon_work,
+ rtl_update_beacon_work_callback);
rtlpriv->usb_data_index = 0;
init_completion(&rtlpriv->firmware_loading_complete);
diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h
index 877ed6a1589f..aa07856411b1 100644
--- a/drivers/net/wireless/realtek/rtlwifi/wifi.h
+++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h
@@ -2486,6 +2486,7 @@ struct rtl_works {
struct work_struct lps_change_work;
struct work_struct fill_h2c_cmd;
+ struct work_struct update_beacon_work;
};
struct rtl_debug {
diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c
index 5c44fa87ed2e..18ab472ea46c 100644
--- a/drivers/net/wireless/realtek/rtw88/debug.c
+++ b/drivers/net/wireless/realtek/rtw88/debug.c
@@ -35,9 +35,17 @@ struct rtw_debugfs_priv {
u32 addr;
u32 len;
} read_reg;
+ struct {
+ u8 bit;
+ } dm_cap;
};
};
+static const char * const rtw_dm_cap_strs[] = {
+ [RTW_DM_CAP_NA] = "NA",
+ [RTW_DM_CAP_TXGAPK] = "TXGAPK",
+};
+
static int rtw_debugfs_single_show(struct seq_file *m, void *v)
{
struct rtw_debugfs_priv *debugfs_priv = m->private;
@@ -853,6 +861,83 @@ static int rtw_debugfs_get_fw_crash(struct seq_file *m, void *v)
return 0;
}
+static ssize_t rtw_debugfs_set_dm_cap(struct file *filp,
+ const char __user *buffer,
+ size_t count, loff_t *loff)
+{
+ struct seq_file *seqpriv = (struct seq_file *)filp->private_data;
+ struct rtw_debugfs_priv *debugfs_priv = seqpriv->private;
+ struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ int bit;
+ bool en;
+
+ if (kstrtoint_from_user(buffer, count, 10, &bit))
+ return -EINVAL;
+
+ en = bit > 0;
+ bit = abs(bit);
+
+ if (bit >= RTW_DM_CAP_NUM) {
+ rtw_warn(rtwdev, "unknown DM CAP %d\n", bit);
+ return -EINVAL;
+ }
+
+ if (en)
+ dm_info->dm_flags &= ~BIT(bit);
+ else
+ dm_info->dm_flags |= BIT(bit);
+
+ debugfs_priv->dm_cap.bit = bit;
+
+ return count;
+}
+
+static void dump_gapk_status(struct rtw_dev *rtwdev, struct seq_file *m)
+{
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ struct rtw_gapk_info *txgapk = &rtwdev->dm_info.gapk;
+ int i, path;
+ u32 val;
+
+ seq_printf(m, "\n(%2d) %c%s\n\n", RTW_DM_CAP_TXGAPK,
+ dm_info->dm_flags & BIT(RTW_DM_CAP_TXGAPK) ? '-' : '+',
+ rtw_dm_cap_strs[RTW_DM_CAP_TXGAPK]);
+
+ for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
+ val = rtw_read_rf(rtwdev, path, RF_GAINTX, RFREG_MASK);
+ seq_printf(m, "path %d:\n0x%x = 0x%x\n", path, RF_GAINTX, val);
+
+ for (i = 0; i < RF_HW_OFFSET_NUM; i++)
+ seq_printf(m, "[TXGAPK] offset %d %d\n",
+ txgapk->rf3f_fs[path][i], i);
+ seq_puts(m, "\n");
+ }
+}
+
+static int rtw_debugfs_get_dm_cap(struct seq_file *m, void *v)
+{
+ struct rtw_debugfs_priv *debugfs_priv = m->private;
+ struct rtw_dev *rtwdev = debugfs_priv->rtwdev;
+ struct rtw_dm_info *dm_info = &rtwdev->dm_info;
+ int i;
+
+ switch (debugfs_priv->dm_cap.bit) {
+ case RTW_DM_CAP_TXGAPK:
+ dump_gapk_status(rtwdev, m);
+ break;
+ default:
+ for (i = 1; i < RTW_DM_CAP_NUM; i++) {
+ seq_printf(m, "(%2d) %c%s\n", i,
+ dm_info->dm_flags & BIT(i) ? '-' : '+',
+ rtw_dm_cap_strs[i]);
+ }
+ break;
+ }
+ debugfs_priv->dm_cap.bit = RTW_DM_CAP_NA;
+ return 0;
+}
+
#define rtw_debug_impl_mac(page, addr) \
static struct rtw_debugfs_priv rtw_debug_priv_mac_ ##page = { \
.cb_read = rtw_debug_get_mac_page, \
@@ -961,6 +1046,11 @@ static struct rtw_debugfs_priv rtw_debug_priv_fw_crash = {
.cb_read = rtw_debugfs_get_fw_crash,
};
+static struct rtw_debugfs_priv rtw_debug_priv_dm_cap = {
+ .cb_write = rtw_debugfs_set_dm_cap,
+ .cb_read = rtw_debugfs_get_dm_cap,
+};
+
#define rtw_debugfs_add_core(name, mode, fopname, parent) \
do { \
rtw_debug_priv_ ##name.rtwdev = rtwdev; \
@@ -1035,6 +1125,7 @@ void rtw_debugfs_init(struct rtw_dev *rtwdev)
rtw_debugfs_add_r(rf_dump);
rtw_debugfs_add_r(tx_pwr_tbl);
rtw_debugfs_add_rw(fw_crash);
+ rtw_debugfs_add_rw(dm_cap);
}
#endif /* CONFIG_RTW88_DEBUGFS */
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index c46b34fbe8bf..ea2cd4db1d3c 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -350,6 +350,18 @@ void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para)
}
EXPORT_SYMBOL(rtw_fw_do_iqk);
+void rtw_fw_inform_rfk_status(struct rtw_dev *rtwdev, bool start)
+{
+ u8 h2c_pkt[H2C_PKT_SIZE] = {0};
+
+ SET_H2C_CMD_ID_CLASS(h2c_pkt, H2C_CMD_WIFI_CALIBRATION);
+
+ RFK_SET_INFORM_START(h2c_pkt, start);
+
+ rtw_fw_send_h2c_command(rtwdev, h2c_pkt);
+}
+EXPORT_SYMBOL(rtw_fw_inform_rfk_status);
+
void rtw_fw_query_bt_info(struct rtw_dev *rtwdev)
{
u8 h2c_pkt[H2C_PKT_SIZE] = {0};
diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h
index 5c89a54475dd..7c5b1d75e26f 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.h
+++ b/drivers/net/wireless/realtek/rtw88/fw.h
@@ -354,6 +354,7 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
#define H2C_CMD_WL_CH_INFO 0x66
#define H2C_CMD_QUERY_BT_MP_INFO 0x67
#define H2C_CMD_BT_WIFI_CONTROL 0x69
+#define H2C_CMD_WIFI_CALIBRATION 0x6d
#define H2C_CMD_KEEP_ALIVE 0x03
#define H2C_CMD_DISCONNECT_DECISION 0x04
@@ -542,6 +543,9 @@ static inline void rtw_h2c_pkt_set_header(u8 *h2c_pkt, u8 sub_id)
le32_get_bits(*((__le32 *)(_header) + 0x01), GENMASK(31, 16))
#define GET_FW_DUMP_TLV_VAL(_header) \
le32_get_bits(*((__le32 *)(_header) + 0x02), GENMASK(31, 0))
+
+#define RFK_SET_INFORM_START(h2c_pkt, value) \
+ le32p_replace_bits((__le32 *)(h2c_pkt) + 0x00, value, BIT(8))
static inline struct rtw_c2h_cmd *get_c2h_from_skb(struct sk_buff *skb)
{
u32 pkt_offset;
@@ -557,6 +561,7 @@ void rtw_fw_send_general_info(struct rtw_dev *rtwdev);
void rtw_fw_send_phydm_info(struct rtw_dev *rtwdev);
void rtw_fw_do_iqk(struct rtw_dev *rtwdev, struct rtw_iqk_para *para);
+void rtw_fw_inform_rfk_status(struct rtw_dev *rtwdev, bool start);
void rtw_fw_set_pwr_mode(struct rtw_dev *rtwdev);
void rtw_fw_set_pg_info(struct rtw_dev *rtwdev);
void rtw_fw_query_bt_info(struct rtw_dev *rtwdev);
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
index 56a19b5a00fc..dc3744847ba9 100644
--- a/drivers/net/wireless/realtek/rtw88/main.h
+++ b/drivers/net/wireless/realtek/rtw88/main.h
@@ -1502,6 +1502,28 @@ struct rtw_iqk_info {
} result;
};
+enum rtw_rf_band {
+ RF_BAND_2G_CCK,
+ RF_BAND_2G_OFDM,
+ RF_BAND_5G_L,
+ RF_BAND_5G_M,
+ RF_BAND_5G_H,
+ RF_BAND_MAX
+};
+
+#define RF_GAIN_NUM 11
+#define RF_HW_OFFSET_NUM 10
+
+struct rtw_gapk_info {
+ u32 rf3f_bp[RF_BAND_MAX][RF_GAIN_NUM][RTW_RF_PATH_MAX];
+ u32 rf3f_fs[RTW_RF_PATH_MAX][RF_GAIN_NUM];
+ bool txgapk_bp_done;
+ s8 offset[RF_GAIN_NUM][RTW_RF_PATH_MAX];
+ s8 fianl_offset[RF_GAIN_NUM][RTW_RF_PATH_MAX];
+ u8 read_txgain;
+ u8 channel;
+};
+
struct rtw_cfo_track {
bool is_adjust;
u8 crystal_cap;
@@ -1514,6 +1536,12 @@ struct rtw_cfo_track {
#define RRSR_INIT_2G 0x15f
#define RRSR_INIT_5G 0x150
+enum rtw_dm_cap {
+ RTW_DM_CAP_NA,
+ RTW_DM_CAP_TXGAPK,
+ RTW_DM_CAP_NUM
+};
+
struct rtw_dm_info {
u32 cck_fa_cnt;
u32 ofdm_fa_cnt;
@@ -1582,7 +1610,10 @@ struct rtw_dm_info {
struct ewma_evm ewma_evm[RTW_EVM_NUM];
struct ewma_snr ewma_snr[RTW_SNR_NUM];
+ u32 dm_flags; /* enum rtw_dm_cap */
struct rtw_iqk_info iqk;
+ struct rtw_gapk_info gapk;
+ bool is_bt_iqk_timeout;
};
struct rtw_efuse {
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index b8115b31839e..f59a4c462e3b 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -581,23 +581,30 @@ static int rtw_pci_start(struct rtw_dev *rtwdev)
{
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
+ rtw_pci_napi_start(rtwdev);
+
spin_lock_bh(&rtwpci->irq_lock);
+ rtwpci->running = true;
rtw_pci_enable_interrupt(rtwdev, rtwpci, false);
spin_unlock_bh(&rtwpci->irq_lock);
- rtw_pci_napi_start(rtwdev);
-
return 0;
}
static void rtw_pci_stop(struct rtw_dev *rtwdev)
{
struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv;
+ struct pci_dev *pdev = rtwpci->pdev;
+ spin_lock_bh(&rtwpci->irq_lock);
+ rtwpci->running = false;
+ rtw_pci_disable_interrupt(rtwdev, rtwpci);
+ spin_unlock_bh(&rtwpci->irq_lock);
+
+ synchronize_irq(pdev->irq);
rtw_pci_napi_stop(rtwdev);
spin_lock_bh(&rtwpci->irq_lock);
- rtw_pci_disable_interrupt(rtwdev, rtwpci);
rtw_pci_dma_release(rtwdev, rtwpci);
spin_unlock_bh(&rtwpci->irq_lock);
}
@@ -950,10 +957,12 @@ static int rtw_pci_tx_write(struct rtw_dev *rtwdev,
return ret;
ring = &rtwpci->tx_rings[queue];
+ spin_lock_bh(&rtwpci->irq_lock);
if (avail_desc(ring->r.wp, ring->r.rp, ring->r.len) < 2) {
ieee80211_stop_queue(rtwdev->hw, skb_get_queue_mapping(skb));
ring->queue_stopped = true;
}
+ spin_unlock_bh(&rtwpci->irq_lock);
return 0;
}
@@ -968,7 +977,7 @@ static void rtw_pci_tx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
struct sk_buff *skb;
u32 count;
u32 bd_idx_addr;
- u32 bd_idx, cur_rp;
+ u32 bd_idx, cur_rp, rp_idx;
u16 q_map;
ring = &rtwpci->tx_rings[hw_queue];
@@ -977,6 +986,7 @@ static void rtw_pci_tx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
bd_idx = rtw_read32(rtwdev, bd_idx_addr);
cur_rp = bd_idx >> 16;
cur_rp &= TRX_BD_IDX_MASK;
+ rp_idx = ring->r.rp;
if (cur_rp >= ring->r.rp)
count = cur_rp - ring->r.rp;
else
@@ -1000,12 +1010,15 @@ static void rtw_pci_tx_isr(struct rtw_dev *rtwdev, struct rtw_pci *rtwpci,
}
if (ring->queue_stopped &&
- avail_desc(ring->r.wp, ring->r.rp, ring->r.len) > 4) {
+ avail_desc(ring->r.wp, rp_idx, ring->r.len) > 4) {
q_map = skb_get_queue_mapping(skb);
ieee80211_wake_queue(hw, q_map);
ring->queue_stopped = false;
}
+ if (++rp_idx >= ring->r.len)
+ rp_idx = 0;
+
skb_pull(skb, rtwdev->chip->tx_pkt_desc_sz);
info = IEEE80211_SKB_CB(skb);
@@ -1206,7 +1219,8 @@ static irqreturn_t rtw_pci_interrupt_threadfn(int irq, void *dev)
rtw_fw_c2h_cmd_isr(rtwdev);
/* all of the jobs for this interrupt have been done */
- rtw_pci_enable_interrupt(rtwdev, rtwpci, rx);
+ if (rtwpci->running)
+ rtw_pci_enable_interrupt(rtwdev, rtwpci, rx);
spin_unlock_bh(&rtwpci->irq_lock);
return IRQ_HANDLED;
@@ -1627,7 +1641,8 @@ static int rtw_pci_napi_poll(struct napi_struct *napi, int budget)
if (work_done < budget) {
napi_complete_done(napi, work_done);
spin_lock_bh(&rtwpci->irq_lock);
- rtw_pci_enable_interrupt(rtwdev, rtwpci, false);
+ if (rtwpci->running)
+ rtw_pci_enable_interrupt(rtwdev, rtwpci, false);
spin_unlock_bh(&rtwpci->irq_lock);
/* When ISR happens during polling and before napi_complete
* while no further data is received. Data on the dma_ring will
diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h
index e76fc549a788..0ffae887527a 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.h
+++ b/drivers/net/wireless/realtek/rtw88/pci.h
@@ -211,6 +211,7 @@ struct rtw_pci {
spinlock_t irq_lock;
u32 irq_mask[4];
bool irq_enabled;
+ bool running;
/* napi structure */
struct net_device netdev;
diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h
index 95d29f522e27..f5ce75095e90 100644
--- a/drivers/net/wireless/realtek/rtw88/reg.h
+++ b/drivers/net/wireless/realtek/rtw88/reg.h
@@ -129,6 +129,9 @@
#define REG_MCU_TST_CFG 0x84
#define VAL_FW_TRIGGER 0x1
+#define REG_PMC_DBG_CTRL1 0xa8
+#define BITS_PMC_BT_IQK_STS GENMASK(22, 21)
+
#define REG_EFUSE_ACCESS 0x00CF
#define EFUSE_ACCESS_ON 0x69
#define EFUSE_ACCESS_OFF 0x00
@@ -360,6 +363,7 @@
#define REG_TX_PTCL_CTRL 0x0520
#define BIT_SIFS_BK_EN BIT(12)
#define REG_TXPAUSE 0x0522
+#define BIT_AC_QUEUE GENMASK(7, 0)
#define REG_RD_CTRL 0x0524
#define BIT_DIS_TXOP_CFE BIT(10)
#define BIT_DIS_LSIG_CFE BIT(9)
@@ -644,10 +648,13 @@
#define RF_WLSEL 0x02
#define RF_DTXLOK 0x08
#define RF_CFGCH 0x18
+#define BIT_BAND GENMASK(18, 16)
#define RF_RCK 0x1d
#define RF_LUTWA 0x33
#define RF_LUTWD1 0x3e
#define RF_LUTWD0 0x3f
+#define BIT_GAIN_EXT BIT(12)
+#define BIT_DATA_L GENMASK(11, 0)
#define RF_T_METER 0x42
#define RF_BSPAD 0x54
#define RF_GAINTX 0x56
@@ -664,6 +671,7 @@
#define RF_RCKD 0xde
#define RF_TXADBG 0xde
#define RF_LUTDBG 0xdf
+#define BIT_TXA_TANK BIT(4)
#define RF_LUTWE2 0xee
#define RF_LUTWE 0xef
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
index 33c6cf1206c8..785b8181513f 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c
@@ -581,7 +581,8 @@ static void rtw8821c_query_rx_desc(struct rtw_dev *rtwdev, u8 *rx_desc,
pkt_stat->phy_status = GET_RX_DESC_PHYST(rx_desc);
pkt_stat->icv_err = GET_RX_DESC_ICV_ERR(rx_desc);
pkt_stat->crc_err = GET_RX_DESC_CRC32(rx_desc);
- pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc);
+ pkt_stat->decrypted = !GET_RX_DESC_SWDEC(rx_desc) &&
+ GET_RX_DESC_ENC_TYPE(rx_desc) != RX_DESC_ENC_NONE;
pkt_stat->is_c2h = GET_RX_DESC_C2H(rx_desc);
pkt_stat->pkt_len = GET_RX_DESC_PKT_LEN(rx_desc);
pkt_stat->drv_info_sz = GET_RX_DESC_DRV_INFO_SIZE(rx_desc);
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index 9f05c60c8a03..6cb593cc33c2 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -1095,16 +1095,721 @@ static void rtw8822c_pa_bias(struct rtw_dev *rtwdev)
if (pg_pa_bias == EFUSE_READ_FAIL)
return;
pg_pa_bias = FIELD_GET(PPG_PABIAS_MASK, pg_pa_bias);
- rtw_write_rf(rtwdev, path, 0x60, RF_PABIAS_2G_MASK, pg_pa_bias);
+ rtw_write_rf(rtwdev, path, RF_PA, RF_PABIAS_2G_MASK, pg_pa_bias);
}
for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
rtw_read8_physical_efuse(rtwdev, rf_efuse_5g[path],
&pg_pa_bias);
pg_pa_bias = FIELD_GET(PPG_PABIAS_MASK, pg_pa_bias);
- rtw_write_rf(rtwdev, path, 0x60, RF_PABIAS_5G_MASK, pg_pa_bias);
+ rtw_write_rf(rtwdev, path, RF_PA, RF_PABIAS_5G_MASK, pg_pa_bias);
}
}
+static void rtw8822c_rfk_handshake(struct rtw_dev *rtwdev, bool is_before_k)
+{
+ struct rtw_dm_info *dm = &rtwdev->dm_info;
+ u8 u1b_tmp;
+ u8 u4b_tmp;
+ int ret;
+
+ if (is_before_k) {
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[RFK] WiFi / BT RFK handshake start!!\n");
+
+ if (!dm->is_bt_iqk_timeout) {
+ ret = read_poll_timeout(rtw_read32_mask, u4b_tmp,
+ u4b_tmp == 0, 20, 600000, false,
+ rtwdev, REG_PMC_DBG_CTRL1,
+ BITS_PMC_BT_IQK_STS);
+ if (ret) {
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[RFK] Wait BT IQK finish timeout!!\n");
+ dm->is_bt_iqk_timeout = true;
+ }
+ }
+
+ rtw_fw_inform_rfk_status(rtwdev, true);
+
+ ret = read_poll_timeout(rtw_read8_mask, u1b_tmp,
+ u1b_tmp == 1, 20, 100000, false,
+ rtwdev, REG_ARFR4, BIT_WL_RFK);
+ if (ret)
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[RFK] Send WiFi RFK start H2C cmd FAIL!!\n");
+ } else {
+ rtw_fw_inform_rfk_status(rtwdev, false);
+ ret = read_poll_timeout(rtw_read8_mask, u1b_tmp,
+ u1b_tmp == 1, 20, 100000, false,
+ rtwdev, REG_ARFR4,
+ BIT_WL_RFK);
+ if (ret)
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[RFK] Send WiFi RFK finish H2C cmd FAIL!!\n");
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[RFK] WiFi / BT RFK handshake finish!!\n");
+ }
+}
+
+static void rtw8822c_rfk_power_save(struct rtw_dev *rtwdev,
+ bool is_power_save)
+{
+ u8 path;
+
+ for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
+ rtw_write32_mask(rtwdev, REG_NCTL0, BIT_SEL_PATH, path);
+ rtw_write32_mask(rtwdev, REG_DPD_CTL1_S0, BIT_PS_EN,
+ is_power_save ? 0 : 1);
+ }
+}
+
+static void rtw8822c_txgapk_backup_bb_reg(struct rtw_dev *rtwdev, const u32 reg[],
+ u32 reg_backup[], u32 reg_num)
+{
+ u32 i;
+
+ for (i = 0; i < reg_num; i++) {
+ reg_backup[i] = rtw_read32(rtwdev, reg[i]);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] Backup BB 0x%x = 0x%x\n",
+ reg[i], reg_backup[i]);
+ }
+}
+
+static void rtw8822c_txgapk_reload_bb_reg(struct rtw_dev *rtwdev,
+ const u32 reg[], u32 reg_backup[],
+ u32 reg_num)
+{
+ u32 i;
+
+ for (i = 0; i < reg_num; i++) {
+ rtw_write32(rtwdev, reg[i], reg_backup[i]);
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] Reload BB 0x%x = 0x%x\n",
+ reg[i], reg_backup[i]);
+ }
+}
+
+static bool check_rf_status(struct rtw_dev *rtwdev, u8 status)
+{
+ u8 reg_rf0_a, reg_rf0_b;
+
+ reg_rf0_a = (u8)rtw_read_rf(rtwdev, RF_PATH_A,
+ RF_MODE_TRXAGC, BIT_RF_MODE);
+ reg_rf0_b = (u8)rtw_read_rf(rtwdev, RF_PATH_B,
+ RF_MODE_TRXAGC, BIT_RF_MODE);
+
+ if (reg_rf0_a == status || reg_rf0_b == status)
+ return false;
+
+ return true;
+}
+
+static void rtw8822c_txgapk_tx_pause(struct rtw_dev *rtwdev)
+{
+ bool status;
+ int ret;
+
+ rtw_write8(rtwdev, REG_TXPAUSE, BIT_AC_QUEUE);
+ rtw_write32_mask(rtwdev, REG_TX_FIFO, BIT_STOP_TX, 0x2);
+
+ ret = read_poll_timeout_atomic(check_rf_status, status, status,
+ 2, 5000, false, rtwdev, 2);
+ if (ret)
+ rtw_warn(rtwdev, "failed to pause TX\n");
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] Tx pause!!\n");
+}
+
+static void rtw8822c_txgapk_bb_dpk(struct rtw_dev *rtwdev, u8 path)
+{
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] ======>%s\n", __func__);
+
+ rtw_write32_mask(rtwdev, REG_ENFN, BIT_IQK_DPK_EN, 0x1);
+ rtw_write32_mask(rtwdev, REG_CH_DELAY_EXTR2,
+ BIT_IQK_DPK_CLOCK_SRC, 0x1);
+ rtw_write32_mask(rtwdev, REG_CH_DELAY_EXTR2,
+ BIT_IQK_DPK_RESET_SRC, 0x1);
+ rtw_write32_mask(rtwdev, REG_CH_DELAY_EXTR2, BIT_EN_IOQ_IQK_DPK, 0x1);
+ rtw_write32_mask(rtwdev, REG_CH_DELAY_EXTR2, BIT_TST_IQK2SET_SRC, 0x0);
+ rtw_write32_mask(rtwdev, REG_CCA_OFF, BIT_CCA_ON_BY_PW, 0x1ff);
+
+ if (path == RF_PATH_A) {
+ rtw_write32_mask(rtwdev, REG_RFTXEN_GCK_A,
+ BIT_RFTXEN_GCK_FORCE_ON, 0x1);
+ rtw_write32_mask(rtwdev, REG_3WIRE, BIT_DIS_SHARERX_TXGAT, 0x1);
+ rtw_write32_mask(rtwdev, REG_DIS_SHARE_RX_A,
+ BIT_TX_SCALE_0DB, 0x1);
+ rtw_write32_mask(rtwdev, REG_3WIRE, BIT_3WIRE_EN, 0x0);
+ } else if (path == RF_PATH_B) {
+ rtw_write32_mask(rtwdev, REG_RFTXEN_GCK_B,
+ BIT_RFTXEN_GCK_FORCE_ON, 0x1);
+ rtw_write32_mask(rtwdev, REG_3WIRE2,
+ BIT_DIS_SHARERX_TXGAT, 0x1);
+ rtw_write32_mask(rtwdev, REG_DIS_SHARE_RX_B,
+ BIT_TX_SCALE_0DB, 0x1);
+ rtw_write32_mask(rtwdev, REG_3WIRE2, BIT_3WIRE_EN, 0x0);
+ }
+ rtw_write32_mask(rtwdev, REG_CCKSB, BIT_BBMODE, 0x2);
+}
+
+static void rtw8822c_txgapk_afe_dpk(struct rtw_dev *rtwdev, u8 path)
+{
+ u32 reg;
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] ======>%s\n", __func__);
+
+ if (path == RF_PATH_A) {
+ reg = REG_ANAPAR_A;
+ } else if (path == RF_PATH_B) {
+ reg = REG_ANAPAR_B;
+ } else {
+ rtw_err(rtwdev, "[TXGAPK] unknown path %d!!\n", path);
+ return;
+ }
+
+ rtw_write32_mask(rtwdev, REG_IQK_CTRL, MASKDWORD, MASKDWORD);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x700f0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x700f0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x701f0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x702f0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x703f0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x704f0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x705f0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x706f0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x707f0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x708f0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x709f0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70af0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70bf0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70cf0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70df0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70ef0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70ff0001);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70ff0001);
+}
+
+static void rtw8822c_txgapk_afe_dpk_restore(struct rtw_dev *rtwdev, u8 path)
+{
+ u32 reg;
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] ======>%s\n", __func__);
+
+ if (path == RF_PATH_A) {
+ reg = REG_ANAPAR_A;
+ } else if (path == RF_PATH_B) {
+ reg = REG_ANAPAR_B;
+ } else {
+ rtw_err(rtwdev, "[TXGAPK] unknown path %d!!\n", path);
+ return;
+ }
+ rtw_write32_mask(rtwdev, REG_IQK_CTRL, MASKDWORD, 0xffa1005e);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x700b8041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70144041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70244041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70344041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70444041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x705b8041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70644041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x707b8041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x708b8041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x709b8041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70ab8041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70bb8041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70cb8041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70db8041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70eb8041);
+ rtw_write32_mask(rtwdev, reg, MASKDWORD, 0x70fb8041);
+}
+
+static void rtw8822c_txgapk_bb_dpk_restore(struct rtw_dev *rtwdev, u8 path)
+{
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] ======>%s\n", __func__);
+
+ rtw_write_rf(rtwdev, path, RF_DEBUG, BIT_DE_TX_GAIN, 0x0);
+ rtw_write_rf(rtwdev, path, RF_DIS_BYPASS_TXBB, BIT_TIA_BYPASS, 0x0);
+ rtw_write_rf(rtwdev, path, RF_DIS_BYPASS_TXBB, BIT_TXBB, 0x0);
+
+ rtw_write32_mask(rtwdev, REG_NCTL0, BIT_SEL_PATH, 0x0);
+ rtw_write32_mask(rtwdev, REG_IQK_CTL1, BIT_TX_CFIR, 0x0);
+ rtw_write32_mask(rtwdev, REG_SINGLE_TONE_SW, BIT_IRQ_TEST_MODE, 0x0);
+ rtw_write32_mask(rtwdev, REG_R_CONFIG, MASKBYTE0, 0x00);
+ rtw_write32_mask(rtwdev, REG_NCTL0, BIT_SEL_PATH, 0x1);
+ rtw_write32_mask(rtwdev, REG_IQK_CTL1, BIT_TX_CFIR, 0x0);
+ rtw_write32_mask(rtwdev, REG_SINGLE_TONE_SW, BIT_IRQ_TEST_MODE, 0x0);
+ rtw_write32_mask(rtwdev, REG_R_CONFIG, MASKBYTE0, 0x00);
+ rtw_write32_mask(rtwdev, REG_NCTL0, BIT_SEL_PATH, 0x0);
+ rtw_write32_mask(rtwdev, REG_CCA_OFF, BIT_CCA_ON_BY_PW, 0x0);
+
+ if (path == RF_PATH_A) {
+ rtw_write32_mask(rtwdev, REG_RFTXEN_GCK_A,
+ BIT_RFTXEN_GCK_FORCE_ON, 0x0);
+ rtw_write32_mask(rtwdev, REG_3WIRE, BIT_DIS_SHARERX_TXGAT, 0x0);
+ rtw_write32_mask(rtwdev, REG_DIS_SHARE_RX_A,
+ BIT_TX_SCALE_0DB, 0x0);
+ rtw_write32_mask(rtwdev, REG_3WIRE, BIT_3WIRE_EN, 0x3);
+ } else if (path == RF_PATH_B) {
+ rtw_write32_mask(rtwdev, REG_RFTXEN_GCK_B,
+ BIT_RFTXEN_GCK_FORCE_ON, 0x0);
+ rtw_write32_mask(rtwdev, REG_3WIRE2,
+ BIT_DIS_SHARERX_TXGAT, 0x0);
+ rtw_write32_mask(rtwdev, REG_DIS_SHARE_RX_B,
+ BIT_TX_SCALE_0DB, 0x0);
+ rtw_write32_mask(rtwdev, REG_3WIRE2, BIT_3WIRE_EN, 0x3);
+ }
+
+ rtw_write32_mask(rtwdev, REG_CCKSB, BIT_BBMODE, 0x0);
+ rtw_write32_mask(rtwdev, REG_IQK_CTL1, BIT_CFIR_EN, 0x5);
+}
+
+static bool _rtw8822c_txgapk_gain_valid(struct rtw_dev *rtwdev, u32 gain)
+{
+ if ((FIELD_GET(BIT_GAIN_TX_PAD_H, gain) >= 0xc) &&
+ (FIELD_GET(BIT_GAIN_TX_PAD_L, gain) >= 0xe))
+ return true;
+
+ return false;
+}
+
+static void _rtw8822c_txgapk_write_gain_bb_table(struct rtw_dev *rtwdev,
+ u8 band, u8 path)
+{
+ struct rtw_gapk_info *txgapk = &rtwdev->dm_info.gapk;
+ u32 v, tmp_3f = 0;
+ u8 gain, check_txgain;
+
+ rtw_write32_mask(rtwdev, REG_NCTL0, BIT_SEL_PATH, path);
+
+ switch (band) {
+ case RF_BAND_2G_OFDM:
+ rtw_write32_mask(rtwdev, REG_TABLE_SEL, BIT_Q_GAIN_SEL, 0x0);
+ break;
+ case RF_BAND_5G_L:
+ rtw_write32_mask(rtwdev, REG_TABLE_SEL, BIT_Q_GAIN_SEL, 0x2);
+ break;
+ case RF_BAND_5G_M:
+ rtw_write32_mask(rtwdev, REG_TABLE_SEL, BIT_Q_GAIN_SEL, 0x3);
+ break;
+ case RF_BAND_5G_H:
+ rtw_write32_mask(rtwdev, REG_TABLE_SEL, BIT_Q_GAIN_SEL, 0x4);
+ break;
+ default:
+ break;
+ }
+
+ rtw_write32_mask(rtwdev, REG_TX_GAIN_SET, MASKBYTE0, 0x88);
+
+ check_txgain = 0;
+ for (gain = 0; gain < RF_GAIN_NUM; gain++) {
+ v = txgapk->rf3f_bp[band][gain][path];
+ if (_rtw8822c_txgapk_gain_valid(rtwdev, v)) {
+ if (!check_txgain) {
+ tmp_3f = txgapk->rf3f_bp[band][gain][path];
+ check_txgain = 1;
+ }
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] tx_gain=0x%03X >= 0xCEX\n",
+ txgapk->rf3f_bp[band][gain][path]);
+ } else {
+ tmp_3f = txgapk->rf3f_bp[band][gain][path];
+ }
+
+ rtw_write32_mask(rtwdev, REG_TABLE_SEL, BIT_Q_GAIN, tmp_3f);
+ rtw_write32_mask(rtwdev, REG_TABLE_SEL, BIT_I_GAIN, gain);
+ rtw_write32_mask(rtwdev, REG_TABLE_SEL, BIT_GAIN_RST, 0x1);
+ rtw_write32_mask(rtwdev, REG_TABLE_SEL, BIT_GAIN_RST, 0x0);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] Band=%d 0x1b98[11:0]=0x%03X path=%d\n",
+ band, tmp_3f, path);
+ }
+}
+
+static void rtw8822c_txgapk_write_gain_bb_table(struct rtw_dev *rtwdev)
+{
+ u8 path, band;
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] ======>%s channel=%d\n",
+ __func__, rtwdev->dm_info.gapk.channel);
+
+ for (band = 0; band < RF_BAND_MAX; band++) {
+ for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
+ _rtw8822c_txgapk_write_gain_bb_table(rtwdev,
+ band, path);
+ }
+ }
+}
+
+static void rtw8822c_txgapk_read_offset(struct rtw_dev *rtwdev, u8 path)
+{
+ static const u32 cfg1_1b00[2] = {0x00000d18, 0x00000d2a};
+ static const u32 cfg2_1b00[2] = {0x00000d19, 0x00000d2b};
+ static const u32 set_pi[2] = {REG_RSV_CTRL, REG_WLRF1};
+ static const u32 path_setting[2] = {REG_ORITXCODE, REG_ORITXCODE2};
+ struct rtw_gapk_info *txgapk = &rtwdev->dm_info.gapk;
+ u8 channel = txgapk->channel;
+ u32 val;
+ int i;
+
+ if (path >= ARRAY_SIZE(cfg1_1b00) ||
+ path >= ARRAY_SIZE(cfg2_1b00) ||
+ path >= ARRAY_SIZE(set_pi) ||
+ path >= ARRAY_SIZE(path_setting)) {
+ rtw_warn(rtwdev, "[TXGAPK] wrong path %d\n", path);
+ return;
+ }
+
+ rtw_write32_mask(rtwdev, REG_ANTMAP0, BIT_ANT_PATH, path + 1);
+ rtw_write32_mask(rtwdev, REG_TXLGMAP, MASKDWORD, 0xe4e40000);
+ rtw_write32_mask(rtwdev, REG_TXANTSEG, BIT_ANTSEG, 0x3);
+ rtw_write32_mask(rtwdev, path_setting[path], MASK20BITS, 0x33312);
+ rtw_write32_mask(rtwdev, path_setting[path], BIT_PATH_EN, 0x1);
+ rtw_write32_mask(rtwdev, set_pi[path], BITS_RFC_DIRECT, 0x0);
+ rtw_write_rf(rtwdev, path, RF_LUTDBG, BIT_TXA_TANK, 0x1);
+ rtw_write_rf(rtwdev, path, RF_IDAC, BIT_TX_MODE, 0x820);
+ rtw_write32_mask(rtwdev, REG_NCTL0, BIT_SEL_PATH, path);
+ rtw_write32_mask(rtwdev, REG_IQKSTAT, MASKBYTE0, 0x0);
+
+ rtw_write32_mask(rtwdev, REG_TX_TONE_IDX, MASKBYTE0, 0x018);
+ fsleep(1000);
+ if (channel >= 1 && channel <= 14)
+ rtw_write32_mask(rtwdev, REG_R_CONFIG, MASKBYTE0, BIT_2G_SWING);
+ else
+ rtw_write32_mask(rtwdev, REG_R_CONFIG, MASKBYTE0, BIT_5G_SWING);
+ fsleep(1000);
+
+ rtw_write32_mask(rtwdev, REG_NCTL0, MASKDWORD, cfg1_1b00[path]);
+ rtw_write32_mask(rtwdev, REG_NCTL0, MASKDWORD, cfg2_1b00[path]);
+
+ read_poll_timeout(rtw_read32_mask, val,
+ val == 0x55, 1000, 100000, false,
+ rtwdev, REG_RPT_CIP, BIT_RPT_CIP_STATUS);
+
+ rtw_write32_mask(rtwdev, set_pi[path], BITS_RFC_DIRECT, 0x2);
+ rtw_write32_mask(rtwdev, REG_NCTL0, BIT_SEL_PATH, path);
+ rtw_write32_mask(rtwdev, REG_RXSRAM_CTL, BIT_RPT_EN, 0x1);
+ rtw_write32_mask(rtwdev, REG_RXSRAM_CTL, BIT_RPT_SEL, 0x12);
+ rtw_write32_mask(rtwdev, REG_TX_GAIN_SET, BIT_GAPK_RPT_IDX, 0x3);
+ val = rtw_read32(rtwdev, REG_STAT_RPT);
+
+ txgapk->offset[0][path] = (s8)FIELD_GET(BIT_GAPK_RPT0, val);
+ txgapk->offset[1][path] = (s8)FIELD_GET(BIT_GAPK_RPT1, val);
+ txgapk->offset[2][path] = (s8)FIELD_GET(BIT_GAPK_RPT2, val);
+ txgapk->offset[3][path] = (s8)FIELD_GET(BIT_GAPK_RPT3, val);
+ txgapk->offset[4][path] = (s8)FIELD_GET(BIT_GAPK_RPT4, val);
+ txgapk->offset[5][path] = (s8)FIELD_GET(BIT_GAPK_RPT5, val);
+ txgapk->offset[6][path] = (s8)FIELD_GET(BIT_GAPK_RPT6, val);
+ txgapk->offset[7][path] = (s8)FIELD_GET(BIT_GAPK_RPT7, val);
+
+ rtw_write32_mask(rtwdev, REG_TX_GAIN_SET, BIT_GAPK_RPT_IDX, 0x4);
+ val = rtw_read32(rtwdev, REG_STAT_RPT);
+
+ txgapk->offset[8][path] = (s8)FIELD_GET(BIT_GAPK_RPT0, val);
+ txgapk->offset[9][path] = (s8)FIELD_GET(BIT_GAPK_RPT1, val);
+
+ for (i = 0; i < RF_HW_OFFSET_NUM; i++)
+ if (txgapk->offset[i][path] & BIT(3))
+ txgapk->offset[i][path] = txgapk->offset[i][path] |
+ 0xf0;
+ for (i = 0; i < RF_HW_OFFSET_NUM; i++)
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] offset %d %d path=%d\n",
+ txgapk->offset[i][path], i, path);
+}
+
+static void rtw8822c_txgapk_calculate_offset(struct rtw_dev *rtwdev, u8 path)
+{
+ static const u32 bb_reg[] = {REG_ANTMAP0, REG_TXLGMAP, REG_TXANTSEG,
+ REG_ORITXCODE, REG_ORITXCODE2};
+ struct rtw_gapk_info *txgapk = &rtwdev->dm_info.gapk;
+ u8 channel = txgapk->channel;
+ u32 reg_backup[ARRAY_SIZE(bb_reg)] = {0};
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] ======>%s channel=%d\n",
+ __func__, channel);
+
+ rtw8822c_txgapk_backup_bb_reg(rtwdev, bb_reg,
+ reg_backup, ARRAY_SIZE(bb_reg));
+
+ if (channel >= 1 && channel <= 14) {
+ rtw_write32_mask(rtwdev,
+ REG_SINGLE_TONE_SW, BIT_IRQ_TEST_MODE, 0x0);
+ rtw_write32_mask(rtwdev, REG_NCTL0, BIT_SEL_PATH, path);
+ rtw_write32_mask(rtwdev, REG_R_CONFIG, BIT_IQ_SWITCH, 0x3f);
+ rtw_write32_mask(rtwdev, REG_IQK_CTL1, BIT_TX_CFIR, 0x0);
+ rtw_write_rf(rtwdev, path, RF_DEBUG, BIT_DE_TX_GAIN, 0x1);
+ rtw_write_rf(rtwdev, path, RF_MODE_TRXAGC, RFREG_MASK, 0x5000f);
+ rtw_write_rf(rtwdev, path, RF_TX_GAIN_OFFSET, BIT_RF_GAIN, 0x0);
+ rtw_write_rf(rtwdev, path, RF_RXG_GAIN, BIT_RXG_GAIN, 0x1);
+ rtw_write_rf(rtwdev, path, RF_MODE_TRXAGC, BIT_RXAGC, 0x0f);
+ rtw_write_rf(rtwdev, path, RF_DEBUG, BIT_DE_TRXBW, 0x1);
+ rtw_write_rf(rtwdev, path, RF_BW_TRXBB, BIT_BW_TXBB, 0x1);
+ rtw_write_rf(rtwdev, path, RF_BW_TRXBB, BIT_BW_RXBB, 0x0);
+ rtw_write_rf(rtwdev, path, RF_EXT_TIA_BW, BIT_PW_EXT_TIA, 0x1);
+
+ rtw_write32_mask(rtwdev, REG_IQKSTAT, MASKBYTE0, 0x00);
+ rtw_write32_mask(rtwdev, REG_TABLE_SEL, BIT_Q_GAIN_SEL, 0x0);
+
+ rtw8822c_txgapk_read_offset(rtwdev, path);
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "=============================\n");
+
+ } else {
+ rtw_write32_mask(rtwdev,
+ REG_SINGLE_TONE_SW, BIT_IRQ_TEST_MODE, 0x0);
+ rtw_write32_mask(rtwdev, REG_NCTL0, BIT_SEL_PATH, path);
+ rtw_write32_mask(rtwdev, REG_R_CONFIG, BIT_IQ_SWITCH, 0x3f);
+ rtw_write32_mask(rtwdev, REG_IQK_CTL1, BIT_TX_CFIR, 0x0);
+ rtw_write_rf(rtwdev, path, RF_DEBUG, BIT_DE_TX_GAIN, 0x1);
+ rtw_write_rf(rtwdev, path, RF_MODE_TRXAGC, RFREG_MASK, 0x50011);
+ rtw_write_rf(rtwdev, path, RF_TXA_LB_SW, BIT_TXA_LB_ATT, 0x3);
+ rtw_write_rf(rtwdev, path, RF_TXA_LB_SW, BIT_LB_ATT, 0x3);
+ rtw_write_rf(rtwdev, path, RF_TXA_LB_SW, BIT_LB_SW, 0x1);
+ rtw_write_rf(rtwdev, path,
+ RF_RXA_MIX_GAIN, BIT_RXA_MIX_GAIN, 0x2);
+ rtw_write_rf(rtwdev, path, RF_MODE_TRXAGC, BIT_RXAGC, 0x12);
+ rtw_write_rf(rtwdev, path, RF_DEBUG, BIT_DE_TRXBW, 0x1);
+ rtw_write_rf(rtwdev, path, RF_BW_TRXBB, BIT_BW_RXBB, 0x0);
+ rtw_write_rf(rtwdev, path, RF_EXT_TIA_BW, BIT_PW_EXT_TIA, 0x1);
+ rtw_write_rf(rtwdev, path, RF_MODE_TRXAGC, BIT_RF_MODE, 0x5);
+
+ rtw_write32_mask(rtwdev, REG_IQKSTAT, MASKBYTE0, 0x0);
+
+ if (channel >= 36 && channel <= 64)
+ rtw_write32_mask(rtwdev,
+ REG_TABLE_SEL, BIT_Q_GAIN_SEL, 0x2);
+ else if (channel >= 100 && channel <= 144)
+ rtw_write32_mask(rtwdev,
+ REG_TABLE_SEL, BIT_Q_GAIN_SEL, 0x3);
+ else if (channel >= 149 && channel <= 177)
+ rtw_write32_mask(rtwdev,
+ REG_TABLE_SEL, BIT_Q_GAIN_SEL, 0x4);
+
+ rtw8822c_txgapk_read_offset(rtwdev, path);
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "=============================\n");
+ }
+ rtw8822c_txgapk_reload_bb_reg(rtwdev, bb_reg,
+ reg_backup, ARRAY_SIZE(bb_reg));
+}
+
+static void rtw8822c_txgapk_rf_restore(struct rtw_dev *rtwdev, u8 path)
+{
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] ======>%s\n", __func__);
+
+ if (path >= rtwdev->hal.rf_path_num)
+ return;
+
+ rtw_write_rf(rtwdev, path, RF_MODE_TRXAGC, BIT_RF_MODE, 0x3);
+ rtw_write_rf(rtwdev, path, RF_DEBUG, BIT_DE_TRXBW, 0x0);
+ rtw_write_rf(rtwdev, path, RF_EXT_TIA_BW, BIT_PW_EXT_TIA, 0x0);
+}
+
+static u32 rtw8822c_txgapk_cal_gain(struct rtw_dev *rtwdev, u32 gain, s8 offset)
+{
+ u32 gain_x2, new_gain;
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] ======>%s\n", __func__);
+
+ if (_rtw8822c_txgapk_gain_valid(rtwdev, gain)) {
+ new_gain = gain;
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] gain=0x%03X(>=0xCEX) offset=%d new_gain=0x%03X\n",
+ gain, offset, new_gain);
+ return new_gain;
+ }
+
+ gain_x2 = (gain << 1) + offset;
+ new_gain = (gain_x2 >> 1) | (gain_x2 & BIT(0) ? BIT_GAIN_EXT : 0);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] gain=0x%X offset=%d new_gain=0x%X\n",
+ gain, offset, new_gain);
+
+ return new_gain;
+}
+
+static void rtw8822c_txgapk_write_tx_gain(struct rtw_dev *rtwdev)
+{
+ struct rtw_gapk_info *txgapk = &rtwdev->dm_info.gapk;
+ u32 i, j, tmp = 0x20, tmp_3f, v;
+ s8 offset_tmp[RF_GAIN_NUM] = {0};
+ u8 path, band = RF_BAND_2G_OFDM, channel = txgapk->channel;
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] ======>%s\n", __func__);
+
+ if (channel >= 1 && channel <= 14) {
+ tmp = 0x20;
+ band = RF_BAND_2G_OFDM;
+ } else if (channel >= 36 && channel <= 64) {
+ tmp = 0x200;
+ band = RF_BAND_5G_L;
+ } else if (channel >= 100 && channel <= 144) {
+ tmp = 0x280;
+ band = RF_BAND_5G_M;
+ } else if (channel >= 149 && channel <= 177) {
+ tmp = 0x300;
+ band = RF_BAND_5G_H;
+ } else {
+ rtw_err(rtwdev, "[TXGAPK] unknown channel %d!!\n", channel);
+ return;
+ }
+
+ for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
+ for (i = 0; i < RF_GAIN_NUM; i++) {
+ offset_tmp[i] = 0;
+ for (j = i; j < RF_GAIN_NUM; j++) {
+ v = txgapk->rf3f_bp[band][j][path];
+ if (_rtw8822c_txgapk_gain_valid(rtwdev, v))
+ continue;
+
+ offset_tmp[i] += txgapk->offset[j][path];
+ txgapk->fianl_offset[i][path] = offset_tmp[i];
+ }
+
+ v = txgapk->rf3f_bp[band][i][path];
+ if (_rtw8822c_txgapk_gain_valid(rtwdev, v)) {
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] tx_gain=0x%03X >= 0xCEX\n",
+ txgapk->rf3f_bp[band][i][path]);
+ } else {
+ txgapk->rf3f_fs[path][i] = offset_tmp[i];
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] offset %d %d\n",
+ offset_tmp[i], i);
+ }
+ }
+
+ rtw_write_rf(rtwdev, path, RF_LUTWE2, RFREG_MASK, 0x10000);
+ for (i = 0; i < RF_GAIN_NUM; i++) {
+ rtw_write_rf(rtwdev, path,
+ RF_LUTWA, RFREG_MASK, tmp + i);
+
+ tmp_3f = rtw8822c_txgapk_cal_gain(rtwdev,
+ txgapk->rf3f_bp[band][i][path],
+ offset_tmp[i]);
+ rtw_write_rf(rtwdev, path, RF_LUTWD0,
+ BIT_GAIN_EXT | BIT_DATA_L, tmp_3f);
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] 0x33=0x%05X 0x3f=0x%04X\n",
+ tmp + i, tmp_3f);
+ }
+ rtw_write_rf(rtwdev, path, RF_LUTWE2, RFREG_MASK, 0x0);
+ }
+}
+
+static void rtw8822c_txgapk_save_all_tx_gain_table(struct rtw_dev *rtwdev)
+{
+ struct rtw_gapk_info *txgapk = &rtwdev->dm_info.gapk;
+ static const u32 three_wire[2] = {REG_3WIRE, REG_3WIRE2};
+ static const u8 ch_num[RF_BAND_MAX] = {1, 1, 36, 100, 149};
+ static const u8 band_num[RF_BAND_MAX] = {0x0, 0x0, 0x1, 0x3, 0x5};
+ static const u8 cck[RF_BAND_MAX] = {0x1, 0x0, 0x0, 0x0, 0x0};
+ u8 path, band, gain, rf0_idx;
+ u32 rf18, v;
+
+ if (rtwdev->dm_info.dm_flags & BIT(RTW_DM_CAP_TXGAPK))
+ return;
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] ======>%s\n", __func__);
+
+ if (txgapk->read_txgain == 1) {
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] Already Read txgapk->read_txgain return!!!\n");
+ rtw8822c_txgapk_write_gain_bb_table(rtwdev);
+ return;
+ }
+
+ for (band = 0; band < RF_BAND_MAX; band++) {
+ for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
+ rf18 = rtw_read_rf(rtwdev, path, RF_CFGCH, RFREG_MASK);
+
+ rtw_write32_mask(rtwdev,
+ three_wire[path], BIT_3WIRE_EN, 0x0);
+ rtw_write_rf(rtwdev, path,
+ RF_CFGCH, MASKBYTE0, ch_num[band]);
+ rtw_write_rf(rtwdev, path,
+ RF_CFGCH, BIT_BAND, band_num[band]);
+ rtw_write_rf(rtwdev, path,
+ RF_BW_TRXBB, BIT_DBG_CCK_CCA, cck[band]);
+ rtw_write_rf(rtwdev, path,
+ RF_BW_TRXBB, BIT_TX_CCK_IND, cck[band]);
+ gain = 0;
+ for (rf0_idx = 1; rf0_idx < 32; rf0_idx += 3) {
+ rtw_write_rf(rtwdev, path, RF_MODE_TRXAGC,
+ MASKBYTE0, rf0_idx);
+ v = rtw_read_rf(rtwdev, path,
+ RF_TX_RESULT, RFREG_MASK);
+ txgapk->rf3f_bp[band][gain][path] = v & BIT_DATA_L;
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] 0x5f=0x%03X band=%d path=%d\n",
+ txgapk->rf3f_bp[band][gain][path],
+ band, path);
+ gain++;
+ }
+ rtw_write_rf(rtwdev, path, RF_CFGCH, RFREG_MASK, rf18);
+ rtw_write32_mask(rtwdev,
+ three_wire[path], BIT_3WIRE_EN, 0x3);
+ }
+ }
+ rtw8822c_txgapk_write_gain_bb_table(rtwdev);
+ txgapk->read_txgain = 1;
+}
+
+static void rtw8822c_txgapk(struct rtw_dev *rtwdev)
+{
+ static const u32 bb_reg[2] = {REG_TX_PTCL_CTRL, REG_TX_FIFO};
+ struct rtw_gapk_info *txgapk = &rtwdev->dm_info.gapk;
+ u32 bb_reg_backup[2];
+ u8 path;
+
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] ======>%s\n", __func__);
+
+ rtw8822c_txgapk_save_all_tx_gain_table(rtwdev);
+
+ if (txgapk->read_txgain == 0) {
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] txgapk->read_txgain == 0 return!!!\n");
+ return;
+ }
+
+ if (rtwdev->efuse.power_track_type >= 4 &&
+ rtwdev->efuse.power_track_type <= 7) {
+ rtw_dbg(rtwdev, RTW_DBG_RFK,
+ "[TXGAPK] Normal Mode in TSSI mode. return!!!\n");
+ return;
+ }
+
+ rtw8822c_txgapk_backup_bb_reg(rtwdev, bb_reg,
+ bb_reg_backup, ARRAY_SIZE(bb_reg));
+ rtw8822c_txgapk_tx_pause(rtwdev);
+ for (path = 0; path < rtwdev->hal.rf_path_num; path++) {
+ txgapk->channel = rtw_read_rf(rtwdev, path,
+ RF_CFGCH, RFREG_MASK) & MASKBYTE0;
+ rtw8822c_txgapk_bb_dpk(rtwdev, path);
+ rtw8822c_txgapk_afe_dpk(rtwdev, path);
+ rtw8822c_txgapk_calculate_offset(rtwdev, path);
+ rtw8822c_txgapk_rf_restore(rtwdev, path);
+ rtw8822c_txgapk_afe_dpk_restore(rtwdev, path);
+ rtw8822c_txgapk_bb_dpk_restore(rtwdev, path);
+ }
+ rtw8822c_txgapk_write_tx_gain(rtwdev);
+ rtw8822c_txgapk_reload_bb_reg(rtwdev, bb_reg,
+ bb_reg_backup, ARRAY_SIZE(bb_reg));
+}
+
+static void rtw8822c_do_gapk(struct rtw_dev *rtwdev)
+{
+ struct rtw_dm_info *dm = &rtwdev->dm_info;
+
+ if (dm->dm_flags & BIT(RTW_DM_CAP_TXGAPK)) {
+ rtw_dbg(rtwdev, RTW_DBG_RFK, "[TXGAPK] feature disable!!!\n");
+ return;
+ }
+ rtw8822c_rfk_handshake(rtwdev, true);
+ rtw8822c_txgapk(rtwdev);
+ rtw8822c_rfk_handshake(rtwdev, false);
+}
+
static void rtw8822c_rf_init(struct rtw_dev *rtwdev)
{
rtw8822c_rf_dac_cal(rtwdev);
@@ -2546,9 +3251,9 @@ static void rtw8822c_dpk_pre_setting(struct rtw_dev *rtwdev)
rtw_write_rf(rtwdev, path, RF_RXAGC_OFFSET, RFREG_MASK, 0x0);
rtw_write32(rtwdev, REG_NCTL0, 0x8 | (path << 1));
if (rtwdev->dm_info.dpk_info.dpk_band == RTW_BAND_2G)
- rtw_write32(rtwdev, REG_DPD_LUT3, 0x1f100000);
+ rtw_write32(rtwdev, REG_DPD_CTL1_S1, 0x1f100000);
else
- rtw_write32(rtwdev, REG_DPD_LUT3, 0x1f0d0000);
+ rtw_write32(rtwdev, REG_DPD_CTL1_S1, 0x1f0d0000);
rtw_write32_mask(rtwdev, REG_DPD_LUT0, BIT_GLOSS_DB, 0x4);
rtw_write32_mask(rtwdev, REG_IQK_CTL1, BIT_TX_CFIR, 0x3);
}
@@ -2566,11 +3271,11 @@ static u32 rtw8822c_dpk_rf_setting(struct rtw_dev *rtwdev, u8 path)
rtw_write_rf(rtwdev, path, RF_DEBUG, BIT_DE_TX_GAIN, 0x1);
rtw_write_rf(rtwdev, path, RF_DEBUG, BIT_DE_PWR_TRIM, 0x1);
- rtw_write_rf(rtwdev, path, RF_TX_GAIN_OFFSET, BIT_TX_OFFSET_VAL, 0x0);
+ rtw_write_rf(rtwdev, path, RF_TX_GAIN_OFFSET, BIT_BB_GAIN, 0x0);
rtw_write_rf(rtwdev, path, RF_TX_GAIN, RFREG_MASK, ori_txbb);
if (rtwdev->dm_info.dpk_info.dpk_band == RTW_BAND_2G) {
- rtw_write_rf(rtwdev, path, RF_TX_GAIN_OFFSET, BIT_LB_ATT, 0x1);
+ rtw_write_rf(rtwdev, path, RF_TX_GAIN_OFFSET, BIT_RF_GAIN, 0x1);
rtw_write_rf(rtwdev, path, RF_RXG_GAIN, BIT_RXG_GAIN, 0x0);
} else {
rtw_write_rf(rtwdev, path, RF_TXA_LB_SW, BIT_TXA_LB_ATT, 0x0);
@@ -3317,9 +4022,9 @@ static void rtw8822c_dpk_reload_data(struct rtw_dev *rtwdev)
rtw_write32_mask(rtwdev, REG_NCTL0, BIT_SUBPAGE,
0x8 | (path << 1));
if (dpk_info->dpk_band == RTW_BAND_2G)
- rtw_write32(rtwdev, REG_DPD_LUT3, 0x1f100000);
+ rtw_write32(rtwdev, REG_DPD_CTL1_S1, 0x1f100000);
else
- rtw_write32(rtwdev, REG_DPD_LUT3, 0x1f0d0000);
+ rtw_write32(rtwdev, REG_DPD_CTL1_S1, 0x1f0d0000);
rtw_write8(rtwdev, REG_DPD_AGC, dpk_info->dpk_txagc[path]);
@@ -3403,8 +4108,11 @@ static void rtw8822c_do_dpk(struct rtw_dev *rtwdev)
static void rtw8822c_phy_calibration(struct rtw_dev *rtwdev)
{
+ rtw8822c_rfk_power_save(rtwdev, false);
+ rtw8822c_do_gapk(rtwdev);
rtw8822c_do_iqk(rtwdev);
rtw8822c_do_dpk(rtwdev);
+ rtw8822c_rfk_power_save(rtwdev, true);
}
static void rtw8822c_dpk_track(struct rtw_dev *rtwdev)
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.h b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
index e2b134ce0b3f..364afc6d851b 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.h
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.h
@@ -164,180 +164,248 @@ const struct rtw_table name ## _tbl = { \
#define REG_ANAPARLDO_POW_MAC 0x0029
#define BIT_LDOE25_PON BIT(0)
-
#define XCAP_MASK GENMASK(6, 0)
#define CFO_TRK_ENABLE_TH 20
#define CFO_TRK_STOP_TH 10
#define CFO_TRK_ADJ_TH 10
-#define REG_TXDFIR0 0x808
-#define REG_DFIRBW 0x810
-#define REG_ANTMAP0 0x820
-#define REG_ANTMAP 0x824
-#define REG_DYMPRITH 0x86c
-#define REG_DYMENTH0 0x870
-#define REG_DYMENTH 0x874
-#define REG_SBD 0x88c
+#define REG_TXDFIR0 0x808
+#define REG_DFIRBW 0x810
+#define REG_ANTMAP0 0x820
+#define BIT_ANT_PATH GENMASK(1, 0)
+#define REG_ANTMAP 0x824
+#define REG_DYMPRITH 0x86c
+#define REG_DYMENTH0 0x870
+#define REG_DYMENTH 0x874
+#define REG_SBD 0x88c
#define BITS_SUBTUNE GENMASK(15, 12)
-#define REG_DYMTHMIN 0x8a4
-#define REG_TXBWCTL 0x9b0
-#define REG_TXCLK 0x9b4
-#define REG_SCOTRK 0xc30
-#define REG_MRCM 0xc38
-#define REG_AGCSWSH 0xc44
-#define REG_ANTWTPD 0xc54
-#define REG_PT_CHSMO 0xcbc
+#define REG_DYMTHMIN 0x8a4
+
+#define REG_TXBWCTL 0x9b0
+#define REG_TXCLK 0x9b4
+
+#define REG_SCOTRK 0xc30
+#define REG_MRCM 0xc38
+#define REG_AGCSWSH 0xc44
+#define REG_ANTWTPD 0xc54
+#define REG_PT_CHSMO 0xcbc
#define BIT_PT_OPT BIT(21)
-#define REG_ORITXCODE 0x1800
-#define REG_3WIRE 0x180c
+
+#define REG_ORITXCODE 0x1800
+#define BIT_PATH_EN BIT(31)
+#define REG_3WIRE 0x180c
+#define BIT_DIS_SHARERX_TXGAT BIT(27)
#define BIT_3WIRE_TX_EN BIT(0)
#define BIT_3WIRE_RX_EN BIT(1)
+#define BIT_3WIRE_EN GENMASK(1, 0)
#define BIT_3WIRE_PI_ON BIT(28)
-#define REG_ANAPAR_A 0x1830
+#define REG_ANAPAR_A 0x1830
#define BIT_ANAPAR_UPDATE BIT(29)
-#define REG_RXAGCCTL0 0x18ac
+#define REG_RFTXEN_GCK_A 0x1864
+#define BIT_RFTXEN_GCK_FORCE_ON BIT(31)
+#define REG_DIS_SHARE_RX_A 0x186c
+#define BIT_TX_SCALE_0DB BIT(7)
+#define REG_RXAGCCTL0 0x18ac
#define BITS_RXAGC_CCK GENMASK(15, 12)
#define BITS_RXAGC_OFDM GENMASK(8, 4)
-#define REG_DCKA_I_0 0x18bc
-#define REG_DCKA_I_1 0x18c0
-#define REG_DCKA_Q_0 0x18d8
-#define REG_DCKA_Q_1 0x18dc
-#define REG_CCKSB 0x1a00
-#define REG_RXCCKSEL 0x1a04
-#define REG_BGCTRL 0x1a14
+#define REG_DCKA_I_0 0x18bc
+#define REG_DCKA_I_1 0x18c0
+#define REG_DCKA_Q_0 0x18d8
+#define REG_DCKA_Q_1 0x18dc
+
+#define REG_CCKSB 0x1a00
+#define BIT_BBMODE GENMASK(2, 1)
+#define REG_RXCCKSEL 0x1a04
+#define REG_BGCTRL 0x1a14
#define BITS_RX_IQ_WEIGHT (BIT(8) | BIT(9))
-#define REG_TXF0 0x1a20
-#define REG_TXF1 0x1a24
-#define REG_TXF2 0x1a28
-#define REG_CCANRX 0x1a2c
+#define REG_TXF0 0x1a20
+#define REG_TXF1 0x1a24
+#define REG_TXF2 0x1a28
+#define REG_CCANRX 0x1a2c
#define BIT_CCK_FA_RST (BIT(14) | BIT(15))
#define BIT_OFDM_FA_RST (BIT(12) | BIT(13))
-#define REG_CCK_FACNT 0x1a5c
-#define REG_CCKTXONLY 0x1a80
+#define REG_CCK_FACNT 0x1a5c
+#define REG_CCKTXONLY 0x1a80
#define BIT_BB_CCK_CHECK_EN BIT(18)
-#define REG_TXF3 0x1a98
-#define REG_TXF4 0x1a9c
-#define REG_TXF5 0x1aa0
-#define REG_TXF6 0x1aac
-#define REG_TXF7 0x1ab0
-#define REG_CCK_SOURCE 0x1abc
+#define REG_TXF3 0x1a98
+#define REG_TXF4 0x1a9c
+#define REG_TXF5 0x1aa0
+#define REG_TXF6 0x1aac
+#define REG_TXF7 0x1ab0
+#define REG_CCK_SOURCE 0x1abc
#define BIT_NBI_EN BIT(30)
-#define REG_IQKSTAT 0x1b10
-#define REG_TXANT 0x1c28
-#define REG_ENCCK 0x1c3c
-#define BIT_CCK_BLK_EN BIT(1)
-#define BIT_CCK_OFDM_BLK_EN (BIT(0) | BIT(1))
-#define REG_CCAMSK 0x1c80
-#define REG_RSTB 0x1c90
-#define BIT_RSTB_3WIRE BIT(8)
-#define REG_RX_BREAK 0x1d2c
-#define BIT_COM_RX_GCK_EN BIT(31)
-#define REG_RXFNCTL 0x1d30
-#define REG_RXIGI 0x1d70
-#define REG_ENFN 0x1e24
-#define REG_TXANTSEG 0x1e28
-#define REG_TXLGMAP 0x1e2c
-#define REG_CCKPATH 0x1e5c
-#define REG_CNT_CTRL 0x1eb4
-#define BIT_ALL_CNT_RST BIT(25)
-#define REG_OFDM_FACNT 0x2d00
-#define REG_OFDM_FACNT1 0x2d04
-#define REG_OFDM_FACNT2 0x2d08
-#define REG_OFDM_FACNT3 0x2d0c
-#define REG_OFDM_FACNT4 0x2d10
-#define REG_OFDM_FACNT5 0x2d20
-#define REG_RPT_CIP 0x2d9c
-#define REG_OFDM_TXCNT 0x2de0
-#define REG_ORITXCODE2 0x4100
-#define REG_3WIRE2 0x410c
-#define REG_ANAPAR_B 0x4130
-#define REG_RXAGCCTL 0x41ac
-#define REG_DCKB_I_0 0x41bc
-#define REG_DCKB_I_1 0x41c0
-#define REG_DCKB_Q_0 0x41d8
-#define REG_DCKB_Q_1 0x41dc
-
-#define RF_MODE_TRXAGC 0x00
-#define RF_RXAGC_OFFSET 0x19
-#define RF_BW_TRXBB 0x1a
-#define RF_TX_GAIN_OFFSET 0x55
-#define RF_TX_GAIN 0x56
-#define RF_TXA_LB_SW 0x63
-#define RF_RXG_GAIN 0x87
-#define RF_RXA_MIX_GAIN 0x8a
-#define RF_EXT_TIA_BW 0x8f
-#define RF_DEBUG 0xde
#define REG_NCTL0 0x1b00
+#define BIT_SEL_PATH GENMASK(2, 1)
+#define BIT_SUBPAGE GENMASK(3, 0)
#define REG_DPD_CTL0_S0 0x1b04
+#define BIT_GS_PWSF GENMASK(27, 0)
#define REG_DPD_CTL1_S0 0x1b08
+#define BIT_DPD_EN BIT(31)
+#define BIT_PS_EN BIT(7)
+#define REG_IQKSTAT 0x1b10
#define REG_IQK_CTL1 0x1b20
+#define BIT_TX_CFIR GENMASK(31, 30)
+#define BIT_CFIR_EN GENMASK(26, 24)
+#define BIT_BYPASS_DPD BIT(25)
+
+#define REG_TX_TONE_IDX 0x1b2c
#define REG_DPD_LUT0 0x1b44
+#define BIT_GLOSS_DB GENMASK(14, 12)
#define REG_DPD_CTL0_S1 0x1b5c
-#define REG_DPD_LUT3 0x1b60
#define REG_DPD_CTL1_S1 0x1b60
#define REG_DPD_AGC 0x1b67
+#define REG_TABLE_SEL 0x1b98
+#define BIT_I_GAIN GENMASK(19, 16)
+#define BIT_GAIN_RST BIT(15)
+#define BIT_Q_GAIN_SEL GENMASK(14, 12)
+#define BIT_Q_GAIN GENMASK(11, 0)
+#define REG_TX_GAIN_SET 0x1b9c
+#define BIT_GAPK_RPT_IDX GENMASK(11, 8)
#define REG_DPD_CTL0 0x1bb4
+#define REG_SINGLE_TONE_SW 0x1bb8
+#define BIT_IRQ_TEST_MODE BIT(20)
#define REG_R_CONFIG 0x1bcc
+#define BIT_INNER_LB BIT(21)
+#define BIT_IQ_SWITCH GENMASK(5, 0)
+#define BIT_2G_SWING 0x2d
+#define BIT_5G_SWING 0x36
#define REG_RXSRAM_CTL 0x1bd4
+#define BIT_RPT_EN BIT(21)
+#define BIT_RPT_SEL GENMASK(20, 16)
+#define BIT_DPD_CLK GENMASK(7, 4)
#define REG_DPD_CTL11 0x1be4
#define REG_DPD_CTL12 0x1be8
#define REG_DPD_CTL15 0x1bf4
#define REG_DPD_CTL16 0x1bf8
#define REG_STAT_RPT 0x1bfc
+#define BIT_RPT_DGAIN GENMASK(27, 16)
+#define BIT_GAPK_RPT0 GENMASK(3, 0)
+#define BIT_GAPK_RPT1 GENMASK(7, 4)
+#define BIT_GAPK_RPT2 GENMASK(11, 8)
+#define BIT_GAPK_RPT3 GENMASK(15, 12)
+#define BIT_GAPK_RPT4 GENMASK(19, 16)
+#define BIT_GAPK_RPT5 GENMASK(23, 20)
+#define BIT_GAPK_RPT6 GENMASK(27, 24)
+#define BIT_GAPK_RPT7 GENMASK(31, 28)
+
+#define REG_TXANT 0x1c28
+#define REG_IQK_CTRL 0x1c38
+#define REG_ENCCK 0x1c3c
+#define BIT_CCK_BLK_EN BIT(1)
+#define BIT_CCK_OFDM_BLK_EN (BIT(0) | BIT(1))
+#define REG_CCAMSK 0x1c80
+#define REG_RSTB 0x1c90
+#define BIT_RSTB_3WIRE BIT(8)
+#define REG_CH_DELAY_EXTR2 0x1cd0
+#define BIT_TST_IQK2SET_SRC BIT(31)
+#define BIT_EN_IOQ_IQK_DPK BIT(30)
+#define BIT_IQK_DPK_RESET_SRC BIT(29)
+#define BIT_IQK_DPK_CLOCK_SRC BIT(28)
+
+#define REG_RX_BREAK 0x1d2c
+#define BIT_COM_RX_GCK_EN BIT(31)
+#define REG_RXFNCTL 0x1d30
+#define REG_CCA_OFF 0x1d58
+#define BIT_CCA_ON_BY_PW GENMASK(11, 3)
+#define REG_RXIGI 0x1d70
+
+#define REG_ENFN 0x1e24
+#define BIT_IQK_DPK_EN BIT(17)
+#define REG_TXANTSEG 0x1e28
+#define BIT_ANTSEG GENMASK(3, 0)
+#define REG_TXLGMAP 0x1e2c
+#define REG_CCKPATH 0x1e5c
+#define REG_TX_FIFO 0x1e70
+#define BIT_STOP_TX GENMASK(3, 0)
+#define REG_CNT_CTRL 0x1eb4
+#define BIT_ALL_CNT_RST BIT(25)
+
+#define REG_OFDM_FACNT 0x2d00
+#define REG_OFDM_FACNT1 0x2d04
+#define REG_OFDM_FACNT2 0x2d08
+#define REG_OFDM_FACNT3 0x2d0c
+#define REG_OFDM_FACNT4 0x2d10
+#define REG_OFDM_FACNT5 0x2d20
+#define REG_RPT_CIP 0x2d9c
+#define BIT_RPT_CIP_STATUS GENMASK(7, 0)
+#define REG_OFDM_TXCNT 0x2de0
+#define REG_ORITXCODE2 0x4100
+#define REG_3WIRE2 0x410c
+#define REG_ANAPAR_B 0x4130
+#define REG_RFTXEN_GCK_B 0x4164
+#define REG_DIS_SHARE_RX_B 0x416c
#define BIT_EXT_TIA_BW BIT(1)
-#define BIT_DE_TRXBW BIT(2)
-#define BIT_DE_TX_GAIN BIT(16)
-#define BIT_RXG_GAIN BIT(18)
-#define BIT_DE_PWR_TRIM BIT(19)
-#define BIT_INNER_LB BIT(21)
-#define BIT_BYPASS_DPD BIT(25)
-#define BIT_DPD_EN BIT(31)
-#define BIT_SUBPAGE GENMASK(3, 0)
+#define REG_RXAGCCTL 0x41ac
+#define REG_DCKB_I_0 0x41bc
+#define REG_DCKB_I_1 0x41c0
+#define REG_DCKB_Q_0 0x41d8
+#define REG_DCKB_Q_1 0x41dc
+
+#define RF_MODE_TRXAGC 0x00
+#define BIT_RF_MODE GENMASK(19, 16)
+#define BIT_RXAGC GENMASK(9, 5)
#define BIT_TXAGC GENMASK(4, 0)
+#define RF_RXAGC_OFFSET 0x19
+#define RF_BW_TRXBB 0x1a
+#define BIT_TX_CCK_IND BIT(16)
+#define BIT_BW_TXBB GENMASK(14, 12)
+#define BIT_BW_RXBB GENMASK(11, 10)
+#define BIT_DBG_CCK_CCA BIT(1)
+#define RF_TX_GAIN_OFFSET 0x55
+#define BIT_BB_GAIN GENMASK(18, 14)
+#define BIT_RF_GAIN GENMASK(4, 2)
+#define RF_TX_GAIN 0x56
#define BIT_GAIN_TXBB GENMASK(4, 0)
+#define RF_IDAC 0x58
+#define BIT_TX_MODE GENMASK(19, 8)
+#define RF_TX_RESULT 0x5f
+#define BIT_GAIN_TX_PAD_H GENMASK(11, 8)
+#define BIT_GAIN_TX_PAD_L GENMASK(7, 4)
+#define RF_PA 0x60
+#define RF_PABIAS_2G_MASK GENMASK(15, 12)
+#define RF_PABIAS_5G_MASK GENMASK(19, 16)
+#define RF_TXA_LB_SW 0x63
+#define BIT_TXA_LB_ATT GENMASK(15, 14)
+#define BIT_LB_SW GENMASK(13, 12)
#define BIT_LB_ATT GENMASK(4, 2)
+#define RF_RXG_GAIN 0x87
+#define BIT_RXG_GAIN BIT(18)
+#define RF_RXA_MIX_GAIN 0x8a
#define BIT_RXA_MIX_GAIN GENMASK(4, 3)
-#define BIT_IQ_SWITCH GENMASK(5, 0)
-#define BIT_DPD_CLK GENMASK(7, 4)
-#define BIT_RXAGC GENMASK(9, 5)
-#define BIT_BW_RXBB GENMASK(11, 10)
-#define BIT_LB_SW GENMASK(13, 12)
-#define BIT_BW_TXBB GENMASK(14, 12)
-#define BIT_GLOSS_DB GENMASK(14, 12)
-#define BIT_TXA_LB_ATT GENMASK(15, 14)
-#define BIT_TX_OFFSET_VAL GENMASK(18, 14)
-#define BIT_RPT_SEL GENMASK(20, 16)
-#define BIT_GS_PWSF GENMASK(27, 0)
-#define BIT_RPT_DGAIN GENMASK(27, 16)
-#define BIT_TX_CFIR GENMASK(31, 30)
-
-#define PPG_THERMAL_A 0x1ef
-#define PPG_THERMAL_B 0x1b0
-#define RF_THEMAL_MASK GENMASK(19, 16)
-#define PPG_2GL_TXAB 0x1d4
-#define PPG_2GM_TXAB 0x1ee
-#define PPG_2GH_TXAB 0x1d2
-#define PPG_2G_A_MASK GENMASK(3, 0)
-#define PPG_2G_B_MASK GENMASK(7, 4)
-#define PPG_5GL1_TXA 0x1ec
-#define PPG_5GL2_TXA 0x1e8
-#define PPG_5GM1_TXA 0x1e4
-#define PPG_5GM2_TXA 0x1e0
-#define PPG_5GH1_TXA 0x1dc
-#define PPG_5GL1_TXB 0x1eb
-#define PPG_5GL2_TXB 0x1e7
-#define PPG_5GM1_TXB 0x1e3
-#define PPG_5GM2_TXB 0x1df
-#define PPG_5GH1_TXB 0x1db
-#define PPG_5G_MASK GENMASK(4, 0)
-#define PPG_PABIAS_2GA 0x1d6
-#define PPG_PABIAS_2GB 0x1d5
-#define PPG_PABIAS_5GA 0x1d8
-#define PPG_PABIAS_5GB 0x1d7
-#define PPG_PABIAS_MASK GENMASK(3, 0)
-#define RF_PABIAS_2G_MASK GENMASK(15, 12)
-#define RF_PABIAS_5G_MASK GENMASK(19, 16)
+#define RF_EXT_TIA_BW 0x8f
+#define BIT_PW_EXT_TIA BIT(1)
+#define RF_DIS_BYPASS_TXBB 0x9e
+#define BIT_TXBB BIT(10)
+#define BIT_TIA_BYPASS BIT(5)
+#define RF_DEBUG 0xde
+#define BIT_DE_PWR_TRIM BIT(19)
+#define BIT_DE_TX_GAIN BIT(16)
+#define BIT_DE_TRXBW BIT(2)
+#define PPG_THERMAL_B 0x1b0
+#define RF_THEMAL_MASK GENMASK(19, 16)
+#define PPG_2GH_TXAB 0x1d2
+#define PPG_2G_A_MASK GENMASK(3, 0)
+#define PPG_2G_B_MASK GENMASK(7, 4)
+#define PPG_2GL_TXAB 0x1d4
+#define PPG_PABIAS_2GB 0x1d5
+#define PPG_PABIAS_2GA 0x1d6
+#define PPG_PABIAS_MASK GENMASK(3, 0)
+#define PPG_PABIAS_5GB 0x1d7
+#define PPG_PABIAS_5GA 0x1d8
+#define PPG_5G_MASK GENMASK(4, 0)
+#define PPG_5GH1_TXB 0x1db
+#define PPG_5GH1_TXA 0x1dc
+#define PPG_5GM2_TXB 0x1df
+#define PPG_5GM2_TXA 0x1e0
+#define PPG_5GM1_TXB 0x1e3
+#define PPG_5GM1_TXA 0x1e4
+#define PPG_5GL2_TXB 0x1e7
+#define PPG_5GL2_TXA 0x1e8
+#define PPG_5GL1_TXB 0x1eb
+#define PPG_5GL1_TXA 0x1ec
+#define PPG_2GM_TXAB 0x1ee
+#define PPG_THERMAL_A 0x1ef
#endif
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.h b/drivers/net/wireless/ti/wlcore/debugfs.h
index 715edfa5f89f..a9e13e6d65c5 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.h
+++ b/drivers/net/wireless/ti/wlcore/debugfs.h
@@ -84,7 +84,7 @@ static ssize_t sub## _ ##name## _read(struct file *file, \
wl1271_debugfs_update_stats(wl); \
\
for (i = 0; i < len && pos < sizeof(buf); i++) \
- pos += snprintf(buf + pos, sizeof(buf), \
+ pos += snprintf(buf + pos, sizeof(buf) - pos, \
"[%d] = %d\n", i, stats->sub.name[i]); \
\
return wl1271_format_buffer(userbuf, count, ppos, "%s", buf); \
diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h
index 5779ffbe5d0f..91f276dd22a1 100644
--- a/drivers/net/wireless/wl3501.h
+++ b/drivers/net/wireless/wl3501.h
@@ -379,16 +379,7 @@ struct wl3501_get_confirm {
u8 mib_value[100];
};
-struct wl3501_join_req {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- struct iw_mgmt_data_rset operational_rset;
- u16 reserved2;
- u16 timeout;
- u16 probe_delay;
- u8 timestamp[8];
- u8 local_time[8];
+struct wl3501_req {
u16 beacon_period;
u16 dtim_period;
u16 cap_info;
@@ -401,6 +392,19 @@ struct wl3501_join_req {
struct iw_mgmt_data_rset bss_basic_rset;
};
+struct wl3501_join_req {
+ u16 next_blk;
+ u8 sig_id;
+ u8 reserved;
+ struct iw_mgmt_data_rset operational_rset;
+ u16 reserved2;
+ u16 timeout;
+ u16 probe_delay;
+ u8 timestamp[8];
+ u8 local_time[8];
+ struct wl3501_req req;
+};
+
struct wl3501_join_confirm {
u16 next_blk;
u8 sig_id;
@@ -443,16 +447,7 @@ struct wl3501_scan_confirm {
u16 status;
char timestamp[8];
char localtime[8];
- u16 beacon_period;
- u16 dtim_period;
- u16 cap_info;
- u8 bss_type;
- u8 bssid[ETH_ALEN];
- struct iw_mgmt_essid_pset ssid;
- struct iw_mgmt_ds_pset ds_pset;
- struct iw_mgmt_cf_pset cf_pset;
- struct iw_mgmt_ibss_pset ibss_pset;
- struct iw_mgmt_data_rset bss_basic_rset;
+ struct wl3501_req req;
u8 rssi;
};
@@ -471,8 +466,10 @@ struct wl3501_md_req {
u16 size;
u8 pri;
u8 service_class;
- u8 daddr[ETH_ALEN];
- u8 saddr[ETH_ALEN];
+ struct {
+ u8 daddr[ETH_ALEN];
+ u8 saddr[ETH_ALEN];
+ } addr;
};
struct wl3501_md_ind {
@@ -484,8 +481,10 @@ struct wl3501_md_ind {
u8 reception;
u8 pri;
u8 service_class;
- u8 daddr[ETH_ALEN];
- u8 saddr[ETH_ALEN];
+ struct {
+ u8 daddr[ETH_ALEN];
+ u8 saddr[ETH_ALEN];
+ } addr;
};
struct wl3501_md_confirm {
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 8ca5789c7b37..672f5d5f3f2c 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -469,6 +469,7 @@ static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len)
struct wl3501_md_req sig = {
.sig_id = WL3501_SIG_MD_REQ,
};
+ size_t sig_addr_len = sizeof(sig.addr);
u8 *pdata = (char *)data;
int rc = -EIO;
@@ -484,9 +485,9 @@ static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len)
goto out;
}
rc = 0;
- memcpy(&sig.daddr[0], pdata, 12);
- pktlen = len - 12;
- pdata += 12;
+ memcpy(&sig.addr, pdata, sig_addr_len);
+ pktlen = len - sig_addr_len;
+ pdata += sig_addr_len;
sig.data = bf;
if (((*pdata) * 256 + (*(pdata + 1))) > 1500) {
u8 addr4[ETH_ALEN] = {
@@ -589,7 +590,7 @@ static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas)
struct wl3501_join_req sig = {
.sig_id = WL3501_SIG_JOIN_REQ,
.timeout = 10,
- .ds_pset = {
+ .req.ds_pset = {
.el = {
.id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET,
.len = 1,
@@ -598,7 +599,7 @@ static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas)
},
};
- memcpy(&sig.beacon_period, &this->bss_set[stas].beacon_period, 72);
+ memcpy(&sig.req, &this->bss_set[stas].req, sizeof(sig.req));
return wl3501_esbq_exec(this, &sig, sizeof(sig));
}
@@ -666,35 +667,37 @@ static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr)
if (sig.status == WL3501_STATUS_SUCCESS) {
pr_debug("success");
if ((this->net_type == IW_MODE_INFRA &&
- (sig.cap_info & WL3501_MGMT_CAPABILITY_ESS)) ||
+ (sig.req.cap_info & WL3501_MGMT_CAPABILITY_ESS)) ||
(this->net_type == IW_MODE_ADHOC &&
- (sig.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) ||
+ (sig.req.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) ||
this->net_type == IW_MODE_AUTO) {
if (!this->essid.el.len)
matchflag = 1;
else if (this->essid.el.len == 3 &&
!memcmp(this->essid.essid, "ANY", 3))
matchflag = 1;
- else if (this->essid.el.len != sig.ssid.el.len)
+ else if (this->essid.el.len != sig.req.ssid.el.len)
matchflag = 0;
- else if (memcmp(this->essid.essid, sig.ssid.essid,
+ else if (memcmp(this->essid.essid, sig.req.ssid.essid,
this->essid.el.len))
matchflag = 0;
else
matchflag = 1;
if (matchflag) {
for (i = 0; i < this->bss_cnt; i++) {
- if (ether_addr_equal_unaligned(this->bss_set[i].bssid, sig.bssid)) {
+ if (ether_addr_equal_unaligned(this->bss_set[i].req.bssid,
+ sig.req.bssid)) {
matchflag = 0;
break;
}
}
}
if (matchflag && (i < 20)) {
- memcpy(&this->bss_set[i].beacon_period,
- &sig.beacon_period, 73);
+ memcpy(&this->bss_set[i].req,
+ &sig.req, sizeof(sig.req));
this->bss_cnt++;
this->rssi = sig.rssi;
+ this->bss_set[i].rssi = sig.rssi;
}
}
} else if (sig.status == WL3501_STATUS_TIMEOUT) {
@@ -886,19 +889,19 @@ static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr)
if (this->join_sta_bss < this->bss_cnt) {
const int i = this->join_sta_bss;
memcpy(this->bssid,
- this->bss_set[i].bssid, ETH_ALEN);
- this->chan = this->bss_set[i].ds_pset.chan;
+ this->bss_set[i].req.bssid, ETH_ALEN);
+ this->chan = this->bss_set[i].req.ds_pset.chan;
iw_copy_mgmt_info_element(&this->keep_essid.el,
- &this->bss_set[i].ssid.el);
+ &this->bss_set[i].req.ssid.el);
wl3501_mgmt_auth(this);
}
} else {
const int i = this->join_sta_bss;
- memcpy(&this->bssid, &this->bss_set[i].bssid, ETH_ALEN);
- this->chan = this->bss_set[i].ds_pset.chan;
+ memcpy(&this->bssid, &this->bss_set[i].req.bssid, ETH_ALEN);
+ this->chan = this->bss_set[i].req.ds_pset.chan;
iw_copy_mgmt_info_element(&this->keep_essid.el,
- &this->bss_set[i].ssid.el);
+ &this->bss_set[i].req.ssid.el);
wl3501_online(dev);
}
} else {
@@ -980,7 +983,8 @@ static inline void wl3501_md_ind_interrupt(struct net_device *dev,
} else {
skb->dev = dev;
skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */
- skb_copy_to_linear_data(skb, (unsigned char *)&sig.daddr, 12);
+ skb_copy_to_linear_data(skb, (unsigned char *)&sig.addr,
+ sizeof(sig.addr));
wl3501_receive(this, skb->data, pkt_len);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, dev);
@@ -1571,30 +1575,30 @@ static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
for (i = 0; i < this->bss_cnt; ++i) {
iwe.cmd = SIOCGIWAP;
iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].bssid, ETH_ALEN);
+ memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].req.bssid, ETH_ALEN);
current_ev = iwe_stream_add_event(info, current_ev,
extra + IW_SCAN_MAX_DATA,
&iwe, IW_EV_ADDR_LEN);
iwe.cmd = SIOCGIWESSID;
iwe.u.data.flags = 1;
- iwe.u.data.length = this->bss_set[i].ssid.el.len;
+ iwe.u.data.length = this->bss_set[i].req.ssid.el.len;
current_ev = iwe_stream_add_point(info, current_ev,
extra + IW_SCAN_MAX_DATA,
&iwe,
- this->bss_set[i].ssid.essid);
+ this->bss_set[i].req.ssid.essid);
iwe.cmd = SIOCGIWMODE;
- iwe.u.mode = this->bss_set[i].bss_type;
+ iwe.u.mode = this->bss_set[i].req.bss_type;
current_ev = iwe_stream_add_event(info, current_ev,
extra + IW_SCAN_MAX_DATA,
&iwe, IW_EV_UINT_LEN);
iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = this->bss_set[i].ds_pset.chan;
+ iwe.u.freq.m = this->bss_set[i].req.ds_pset.chan;
iwe.u.freq.e = 0;
current_ev = iwe_stream_add_event(info, current_ev,
extra + IW_SCAN_MAX_DATA,
&iwe, IW_EV_FREQ_LEN);
iwe.cmd = SIOCGIWENCODE;
- if (this->bss_set[i].cap_info & WL3501_MGMT_CAPABILITY_PRIVACY)
+ if (this->bss_set[i].req.cap_info & WL3501_MGMT_CAPABILITY_PRIVACY)
iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
else
iwe.u.data.flags = IW_ENCODE_DISABLED;