summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c18
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/qmi.c8
-rw-r--r--drivers/net/wireless/ath/ath11k/Makefile2
-rw-r--r--drivers/net/wireless/ath/ath11k/ahb.c49
-rw-r--r--drivers/net/wireless/ath/ath11k/ahb.h8
-rw-r--r--drivers/net/wireless/ath/ath11k/core.c48
-rw-r--r--drivers/net/wireless/ath/ath11k/core.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/debug.c1108
-rw-r--r--drivers/net/wireless/ath/ath11k/debug.h244
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs.c1112
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs.h217
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c (renamed from drivers/net/wireless/ath/ath11k/debug_htt_stats.c)12
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h (renamed from drivers/net/wireless/ath/ath11k/debug_htt_stats.h)27
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs_sta.c29
-rw-r--r--drivers/net/wireless/ath/ath11k/debugfs_sta.h44
-rw-r--r--drivers/net/wireless/ath/ath11k/dp.c2
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_rx.c15
-rw-r--r--drivers/net/wireless/ath/ath11k/dp_tx.c7
-rw-r--r--drivers/net/wireless/ath/ath11k/htc.c9
-rw-r--r--drivers/net/wireless/ath/ath11k/hw.c8
-rw-r--r--drivers/net/wireless/ath/ath11k/hw.h1
-rw-r--r--drivers/net/wireless/ath/ath11k/mac.c9
-rw-r--r--drivers/net/wireless/ath/ath11k/spectral.c26
-rw-r--r--drivers/net/wireless/ath/ath11k/wmi.c51
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c25
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c19
-rw-r--r--drivers/net/wireless/ath/wcn36xx/hal.h138
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c99
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c663
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h9
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c49
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h14
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c1
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h4
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c3
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c9
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c55
-rw-r--r--drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.c99
-rw-r--r--drivers/net/wireless/cisco/airo.c15
-rw-r--r--drivers/net/wireless/mediatek/mt76/debugfs.c9
-rw-r--r--drivers/net/wireless/mediatek/mt76/dma.c162
-rw-r--r--drivers/net/wireless/mediatek/mt76/mac80211.c43
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h61
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/beacon.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c18
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/dma.c26
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c17
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/init.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mac.c25
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/main.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/pci.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/soc.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c30
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/dma.c55
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/init.c25
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.c42
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/main.c11
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.c190
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mmio.c25
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h21
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/pci.c7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/regs.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/sdio.c38
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c22
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c282
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/testmode.c11
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/usb.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c29
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/init.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h145
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/initvals_init.h159
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/pci.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/phy.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c34
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_dma.h1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mac.c13
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mac.h3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c70
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_usb.h3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_util.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c11
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/dma.c146
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/init.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.c257
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/main.c39
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.c132
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.h33
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h48
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/pci.c30
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/regs.h17
-rw-r--r--drivers/net/wireless/mediatek/mt76/sdio.c160
-rw-r--r--drivers/net/wireless/mediatek/mt76/testmode.c19
-rw-r--r--drivers/net/wireless/mediatek/mt76/tx.c330
-rw-r--r--drivers/net/wireless/mediatek/mt76/usb.c86
-rw-r--r--drivers/net/wireless/mediatek/mt76/util.c28
-rw-r--r--drivers/net/wireless/mediatek/mt76/util.h76
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/debugfs.c34
-rw-r--r--drivers/net/wireless/microchip/wilc1000/mon.c3
-rw-r--r--drivers/net/wireless/quantenna/qtnfmac/core.c1
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c12
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c20
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c10
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c8
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c8
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c8
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c9
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c8
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c9
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c8
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723ae/rf.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c4
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c8
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c6
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c24
-rw-r--r--drivers/net/wireless/realtek/rtw88/main.c5
-rw-r--r--drivers/net/wireless/realtek/rtw88/rtw8822c.c15
-rw-r--r--drivers/net/wireless/ti/wlcore/debugfs.c7
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c1
-rw-r--r--drivers/net/wireless/zydas/zd1201.c6
-rw-r--r--drivers/ssb/pci.c7
140 files changed, 4176 insertions, 3428 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 5f4e1219684b..d73ad60b571c 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -1022,7 +1022,7 @@ static int ath10k_core_check_smbios(struct ath10k *ar)
return 0;
}
-static int ath10k_core_check_dt(struct ath10k *ar)
+int ath10k_core_check_dt(struct ath10k *ar)
{
struct device_node *node;
const char *variant = NULL;
@@ -1043,6 +1043,7 @@ static int ath10k_core_check_dt(struct ath10k *ar)
return 0;
}
+EXPORT_SYMBOL(ath10k_core_check_dt);
static int ath10k_download_fw(struct ath10k *ar)
{
@@ -1437,10 +1438,17 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name,
}
if (ar->id.qmi_ids_valid) {
- scnprintf(name, name_len,
- "bus=%s,qmi-board-id=%x",
- ath10k_bus_str(ar->hif.bus),
- ar->id.qmi_board_id);
+ if (with_variant && ar->id.bdf_ext[0] != '\0')
+ scnprintf(name, name_len,
+ "bus=%s,qmi-board-id=%x,qmi-chip-id=%x%s",
+ ath10k_bus_str(ar->hif.bus),
+ ar->id.qmi_board_id, ar->id.qmi_chip_id,
+ variant);
+ else
+ scnprintf(name, name_len,
+ "bus=%s,qmi-board-id=%x",
+ ath10k_bus_str(ar->hif.bus),
+ ar->id.qmi_board_id);
goto out;
}
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 4cf5bd4896bc..b50ab9e229dc 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -1076,6 +1076,7 @@ struct ath10k {
bool bmi_ids_valid;
bool qmi_ids_valid;
u32 qmi_board_id;
+ u32 qmi_chip_id;
u8 bmi_board_id;
u8 bmi_eboard_id;
u8 bmi_chip_id;
@@ -1315,6 +1316,7 @@ int ath10k_core_register(struct ath10k *ar,
const struct ath10k_bus_params *bus_params);
void ath10k_core_unregister(struct ath10k *ar);
int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type);
+int ath10k_core_check_dt(struct ath10k *ar);
void ath10k_core_free_board_files(struct ath10k *ar);
#endif /* _CORE_H_ */
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index 5468a41e928e..ae6b1f402adf 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -576,6 +576,8 @@ static int ath10k_qmi_cap_send_sync_msg(struct ath10k_qmi *qmi)
if (resp->chip_info_valid) {
qmi->chip_info.chip_id = resp->chip_info.chip_id;
qmi->chip_info.chip_family = resp->chip_info.chip_family;
+ } else {
+ qmi->chip_info.chip_id = 0xFF;
}
if (resp->board_info_valid)
@@ -817,12 +819,18 @@ err_setup_msa:
static int ath10k_qmi_fetch_board_file(struct ath10k_qmi *qmi)
{
struct ath10k *ar = qmi->ar;
+ int ret;
ar->hif.bus = ATH10K_BUS_SNOC;
ar->id.qmi_ids_valid = true;
ar->id.qmi_board_id = qmi->board_info.board_id;
+ ar->id.qmi_chip_id = qmi->chip_info.chip_id;
ar->hw_params.fw.dir = WCN3990_HW_1_0_FW_DIR;
+ ret = ath10k_core_check_dt(ar);
+ if (ret)
+ ath10k_dbg(ar, ATH10K_DBG_QMI, "DT bdf variant name not set.\n");
+
return ath10k_core_fetch_board_file(qmi->ar, ATH10K_BD_IE_BOARD);
}
diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile
index bc4911f0339d..c41d87bd025a 100644
--- a/drivers/net/wireless/ath/ath11k/Makefile
+++ b/drivers/net/wireless/ath/ath11k/Makefile
@@ -18,7 +18,7 @@ ath11k-y += core.o \
dbring.o \
hw.o
-ath11k-$(CONFIG_ATH11K_DEBUGFS) += debug_htt_stats.o debugfs_sta.o
+ath11k-$(CONFIG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o
ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o
ath11k-$(CONFIG_ATH11K_TRACING) += trace.o
ath11k-$(CONFIG_THERMAL) += thermal.o
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index f6e36e58e1fd..430723c64adc 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -323,9 +323,10 @@ static void ath11k_ahb_stop(struct ath11k_base *ab)
static int ath11k_ahb_power_up(struct ath11k_base *ab)
{
+ struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
int ret;
- ret = rproc_boot(ab->tgt_rproc);
+ ret = rproc_boot(ab_ahb->tgt_rproc);
if (ret)
ath11k_err(ab, "failed to boot the remote processor Q6\n");
@@ -334,7 +335,9 @@ static int ath11k_ahb_power_up(struct ath11k_base *ab)
static void ath11k_ahb_power_down(struct ath11k_base *ab)
{
- rproc_shutdown(ab->tgt_rproc);
+ struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+
+ rproc_shutdown(ab_ahb->tgt_rproc);
}
static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
@@ -600,6 +603,28 @@ static const struct ath11k_hif_ops ath11k_ahb_hif_ops = {
.power_up = ath11k_ahb_power_up,
};
+static int ath11k_core_get_rproc(struct ath11k_base *ab)
+{
+ struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+ struct device *dev = ab->dev;
+ struct rproc *prproc;
+ phandle rproc_phandle;
+
+ if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) {
+ ath11k_err(ab, "failed to get q6_rproc handle\n");
+ return -ENOENT;
+ }
+
+ prproc = rproc_get_by_phandle(rproc_phandle);
+ if (!prproc) {
+ ath11k_err(ab, "failed to get rproc\n");
+ return -EINVAL;
+ }
+ ab_ahb->tgt_rproc = prproc;
+
+ return 0;
+}
+
static int ath11k_ahb_probe(struct platform_device *pdev)
{
struct ath11k_base *ab;
@@ -626,7 +651,9 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
return ret;
}
- ab = ath11k_core_alloc(&pdev->dev, 0, ATH11K_BUS_AHB, &ath11k_ahb_bus_params);
+ ab = ath11k_core_alloc(&pdev->dev, sizeof(struct ath11k_ahb),
+ ATH11K_BUS_AHB,
+ &ath11k_ahb_bus_params);
if (!ab) {
dev_err(&pdev->dev, "failed to allocate ath11k base\n");
return -ENOMEM;
@@ -655,6 +682,12 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
ath11k_ahb_init_qmi_ce_config(ab);
+ ret = ath11k_core_get_rproc(ab);
+ if (ret) {
+ ath11k_err(ab, "failed to get rproc: %d\n", ret);
+ goto err_ce_free;
+ }
+
ret = ath11k_core_init(ab);
if (ret) {
ath11k_err(ab, "failed to init core: %d\n", ret);
@@ -685,12 +718,16 @@ err_core_free:
static int ath11k_ahb_remove(struct platform_device *pdev)
{
struct ath11k_base *ab = platform_get_drvdata(pdev);
+ unsigned long left;
reinit_completion(&ab->driver_recovery);
- if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags))
- wait_for_completion_timeout(&ab->driver_recovery,
- ATH11K_AHB_RECOVERY_TIMEOUT);
+ if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {
+ left = wait_for_completion_timeout(&ab->driver_recovery,
+ ATH11K_AHB_RECOVERY_TIMEOUT);
+ if (!left)
+ ath11k_warn(ab, "failed to receive recovery response completion\n");
+ }
set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
cancel_work_sync(&ab->restart_work);
diff --git a/drivers/net/wireless/ath/ath11k/ahb.h b/drivers/net/wireless/ath/ath11k/ahb.h
index 6c7b26ac6545..51e6e4a5f686 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.h
+++ b/drivers/net/wireless/ath/ath11k/ahb.h
@@ -10,4 +10,12 @@
#define ATH11K_AHB_RECOVERY_TIMEOUT (3 * HZ)
struct ath11k_base;
+struct ath11k_ahb {
+ struct rproc *tgt_rproc;
+};
+
+static inline struct ath11k_ahb *ath11k_ahb_priv(struct ath11k_base *ab)
+{
+ return (struct ath11k_ahb *)ab->drv_priv;
+}
#endif
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index ce81702b27d2..0a85f20b6499 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -57,6 +57,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.vdev_start_delay = false,
.htt_peer_map_v2 = true,
.tcl_0_only = false,
+ .spectral_fft_sz = 2,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -86,6 +87,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.vdev_start_delay = false,
.htt_peer_map_v2 = true,
.tcl_0_only = false,
+ .spectral_fft_sz = 4,
},
{
.name = "qca6390 hw2.0",
@@ -115,6 +117,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.vdev_start_delay = true,
.htt_peer_map_v2 = false,
.tcl_0_only = true,
+ .spectral_fft_sz = 0,
},
};
@@ -412,7 +415,7 @@ static int ath11k_core_soc_create(struct ath11k_base *ab)
return ret;
}
- ret = ath11k_debug_soc_create(ab);
+ ret = ath11k_debugfs_soc_create(ab);
if (ret) {
ath11k_err(ab, "failed to create ath11k debugfs\n");
goto err_qmi_deinit;
@@ -427,7 +430,7 @@ static int ath11k_core_soc_create(struct ath11k_base *ab)
return 0;
err_debugfs_reg:
- ath11k_debug_soc_destroy(ab);
+ ath11k_debugfs_soc_destroy(ab);
err_qmi_deinit:
ath11k_qmi_deinit_service(ab);
return ret;
@@ -435,7 +438,7 @@ err_qmi_deinit:
static void ath11k_core_soc_destroy(struct ath11k_base *ab)
{
- ath11k_debug_soc_destroy(ab);
+ ath11k_debugfs_soc_destroy(ab);
ath11k_dp_free(ab);
ath11k_reg_free(ab);
ath11k_qmi_deinit_service(ab);
@@ -445,7 +448,7 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab)
{
int ret;
- ret = ath11k_debug_pdev_create(ab);
+ ret = ath11k_debugfs_pdev_create(ab);
if (ret) {
ath11k_err(ab, "failed to create core pdev debugfs: %d\n", ret);
return ret;
@@ -485,7 +488,7 @@ err_dp_pdev_free:
err_mac_unregister:
ath11k_mac_unregister(ab);
err_pdev_debug:
- ath11k_debug_pdev_destroy(ab);
+ ath11k_debugfs_pdev_destroy(ab);
return ret;
}
@@ -497,7 +500,7 @@ static void ath11k_core_pdev_destroy(struct ath11k_base *ab)
ath11k_mac_unregister(ab);
ath11k_hif_irq_disable(ab);
ath11k_dp_pdev_free(ab);
- ath11k_debug_pdev_destroy(ab);
+ ath11k_debugfs_pdev_destroy(ab);
}
static int ath11k_core_start(struct ath11k_base *ab,
@@ -842,43 +845,10 @@ int ath11k_core_pre_init(struct ath11k_base *ab)
}
EXPORT_SYMBOL(ath11k_core_pre_init);
-static int ath11k_core_get_rproc(struct ath11k_base *ab)
-{
- struct device *dev = ab->dev;
- struct rproc *prproc;
- phandle rproc_phandle;
-
- if (!IS_ENABLED(CONFIG_REMOTEPROC))
- return 0;
-
- if (ab->bus_params.mhi_support)
- return 0;
-
- if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) {
- ath11k_err(ab, "failed to get q6_rproc handle\n");
- return -ENOENT;
- }
-
- prproc = rproc_get_by_phandle(rproc_phandle);
- if (!prproc) {
- ath11k_err(ab, "failed to get rproc\n");
- return -EINVAL;
- }
- ab->tgt_rproc = prproc;
-
- return 0;
-}
-
int ath11k_core_init(struct ath11k_base *ab)
{
int ret;
- ret = ath11k_core_get_rproc(ab);
- if (ret) {
- ath11k_err(ab, "failed to get rproc: %d\n", ret);
- return ret;
- }
-
ret = ath11k_core_soc_create(ab);
if (ret) {
ath11k_err(ab, "failed to create soc core: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 807884687d39..02a87027c4e4 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -648,7 +648,6 @@ struct ath11k_base {
struct ath11k_qmi qmi;
struct ath11k_wmi_base wmi_ab;
struct completion fw_ready;
- struct rproc *tgt_rproc;
int num_radios;
/* HW channel counters frequency value in hertz common to all MACs */
u32 cc_freq_hz;
diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c
index 0ba234ad99b2..c86de95fbdc5 100644
--- a/drivers/net/wireless/ath/ath11k/debug.c
+++ b/drivers/net/wireless/ath/ath11k/debug.c
@@ -6,48 +6,6 @@
#include <linux/vmalloc.h>
#include "core.h"
#include "debug.h"
-#include "wmi.h"
-#include "hal_rx.h"
-#include "dp_tx.h"
-#include "debug_htt_stats.h"
-#include "peer.h"
-
-static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
- "REO2SW1_RING",
- "REO2SW2_RING",
- "REO2SW3_RING",
- "REO2SW4_RING",
- "WBM2REO_LINK_RING",
- "REO2TCL_RING",
- "REO2FW_RING",
- "RELEASE_RING",
- "PPE_RELEASE_RING",
- "TCL2TQM_RING",
- "TQM_RELEASE_RING",
- "REO_RELEASE_RING",
- "WBM2SW0_RELEASE_RING",
- "WBM2SW1_RELEASE_RING",
- "WBM2SW2_RELEASE_RING",
- "WBM2SW3_RELEASE_RING",
- "REO_CMD_RING",
- "REO_STATUS_RING",
-};
-
-static const char *htt_bp_lmac_ring[HTT_SW_LMAC_RING_IDX_MAX] = {
- "FW2RXDMA_BUF_RING",
- "FW2RXDMA_STATUS_RING",
- "FW2RXDMA_LINK_RING",
- "SW2RXDMA_BUF_RING",
- "WBM2RXDMA_LINK_RING",
- "RXDMA2FW_RING",
- "RXDMA2SW_RING",
- "RXDMA2RELEASE_RING",
- "RXDMA2REO_RING",
- "MONITOR_STATUS_RING",
- "MONITOR_BUF_RING",
- "MONITOR_DESC_RING",
- "MONITOR_DEST_RING",
-};
void ath11k_info(struct ath11k_base *ab, const char *fmt, ...)
{
@@ -95,6 +53,7 @@ void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...)
EXPORT_SYMBOL(ath11k_warn);
#ifdef CONFIG_ATH11K_DEBUG
+
void __ath11k_dbg(struct ath11k_base *ab, enum ath11k_debug_mask mask,
const char *fmt, ...)
{
@@ -144,1067 +103,4 @@ void ath11k_dbg_dump(struct ath11k_base *ab,
}
EXPORT_SYMBOL(ath11k_dbg_dump);
-#endif
-
-#ifdef CONFIG_ATH11K_DEBUGFS
-static void ath11k_fw_stats_pdevs_free(struct list_head *head)
-{
- struct ath11k_fw_stats_pdev *i, *tmp;
-
- list_for_each_entry_safe(i, tmp, head, list) {
- list_del(&i->list);
- kfree(i);
- }
-}
-
-static void ath11k_fw_stats_vdevs_free(struct list_head *head)
-{
- struct ath11k_fw_stats_vdev *i, *tmp;
-
- list_for_each_entry_safe(i, tmp, head, list) {
- list_del(&i->list);
- kfree(i);
- }
-}
-
-static void ath11k_fw_stats_bcn_free(struct list_head *head)
-{
- struct ath11k_fw_stats_bcn *i, *tmp;
-
- list_for_each_entry_safe(i, tmp, head, list) {
- list_del(&i->list);
- kfree(i);
- }
-}
-
-static void ath11k_debug_fw_stats_reset(struct ath11k *ar)
-{
- spin_lock_bh(&ar->data_lock);
- ar->debug.fw_stats_done = false;
- ath11k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
- ath11k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
- spin_unlock_bh(&ar->data_lock);
-}
-
-void ath11k_debug_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb)
-{
- struct ath11k_fw_stats stats = {};
- struct ath11k *ar;
- struct ath11k_pdev *pdev;
- bool is_end;
- static unsigned int num_vdev, num_bcn;
- size_t total_vdevs_started = 0;
- int i, ret;
-
- INIT_LIST_HEAD(&stats.pdevs);
- INIT_LIST_HEAD(&stats.vdevs);
- INIT_LIST_HEAD(&stats.bcn);
-
- ret = ath11k_wmi_pull_fw_stats(ab, skb, &stats);
- if (ret) {
- ath11k_warn(ab, "failed to pull fw stats: %d\n", ret);
- goto free;
- }
-
- rcu_read_lock();
- ar = ath11k_mac_get_ar_by_pdev_id(ab, stats.pdev_id);
- if (!ar) {
- rcu_read_unlock();
- ath11k_warn(ab, "failed to get ar for pdev_id %d: %d\n",
- stats.pdev_id, ret);
- goto free;
- }
-
- spin_lock_bh(&ar->data_lock);
-
- if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
- list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
- ar->debug.fw_stats_done = true;
- goto complete;
- }
-
- if (stats.stats_id == WMI_REQUEST_VDEV_STAT) {
- if (list_empty(&stats.vdevs)) {
- ath11k_warn(ab, "empty vdev stats");
- goto complete;
- }
- /* FW sends all the active VDEV stats irrespective of PDEV,
- * hence limit until the count of all VDEVs started
- */
- for (i = 0; i < ab->num_radios; i++) {
- pdev = rcu_dereference(ab->pdevs_active[i]);
- if (pdev && pdev->ar)
- total_vdevs_started += ar->num_started_vdevs;
- }
-
- is_end = ((++num_vdev) == total_vdevs_started);
-
- list_splice_tail_init(&stats.vdevs,
- &ar->debug.fw_stats.vdevs);
-
- if (is_end) {
- ar->debug.fw_stats_done = true;
- num_vdev = 0;
- }
- goto complete;
- }
-
- if (stats.stats_id == WMI_REQUEST_BCN_STAT) {
- if (list_empty(&stats.bcn)) {
- ath11k_warn(ab, "empty bcn stats");
- goto complete;
- }
- /* Mark end until we reached the count of all started VDEVs
- * within the PDEV
- */
- is_end = ((++num_bcn) == ar->num_started_vdevs);
-
- list_splice_tail_init(&stats.bcn,
- &ar->debug.fw_stats.bcn);
-
- if (is_end) {
- ar->debug.fw_stats_done = true;
- num_bcn = 0;
- }
- }
-complete:
- complete(&ar->debug.fw_stats_complete);
- rcu_read_unlock();
- spin_unlock_bh(&ar->data_lock);
-
-free:
- ath11k_fw_stats_pdevs_free(&stats.pdevs);
- ath11k_fw_stats_vdevs_free(&stats.vdevs);
- ath11k_fw_stats_bcn_free(&stats.bcn);
-}
-
-static int ath11k_debug_fw_stats_request(struct ath11k *ar,
- struct stats_request_params *req_param)
-{
- struct ath11k_base *ab = ar->ab;
- unsigned long timeout, time_left;
- int ret;
-
- lockdep_assert_held(&ar->conf_mutex);
-
- /* FW stats can get split when exceeding the stats data buffer limit.
- * In that case, since there is no end marking for the back-to-back
- * received 'update stats' event, we keep a 3 seconds timeout in case,
- * fw_stats_done is not marked yet
- */
- timeout = jiffies + msecs_to_jiffies(3 * HZ);
-
- ath11k_debug_fw_stats_reset(ar);
-
- reinit_completion(&ar->debug.fw_stats_complete);
-
- ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);
-
- if (ret) {
- ath11k_warn(ab, "could not request fw stats (%d)\n",
- ret);
- return ret;
- }
-
- time_left =
- wait_for_completion_timeout(&ar->debug.fw_stats_complete,
- 1 * HZ);
- if (!time_left)
- return -ETIMEDOUT;
-
- for (;;) {
- if (time_after(jiffies, timeout))
- break;
-
- spin_lock_bh(&ar->data_lock);
- if (ar->debug.fw_stats_done) {
- spin_unlock_bh(&ar->data_lock);
- break;
- }
- spin_unlock_bh(&ar->data_lock);
- }
- return 0;
-}
-
-static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)
-{
- struct ath11k *ar = inode->i_private;
- struct ath11k_base *ab = ar->ab;
- struct stats_request_params req_param;
- void *buf = NULL;
- int ret;
-
- mutex_lock(&ar->conf_mutex);
-
- if (ar->state != ATH11K_STATE_ON) {
- ret = -ENETDOWN;
- goto err_unlock;
- }
-
- buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
- if (!buf) {
- ret = -ENOMEM;
- goto err_unlock;
- }
-
- req_param.pdev_id = ar->pdev->pdev_id;
- req_param.vdev_id = 0;
- req_param.stats_id = WMI_REQUEST_PDEV_STAT;
-
- ret = ath11k_debug_fw_stats_request(ar, &req_param);
- if (ret) {
- ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
- goto err_free;
- }
-
- ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
- buf);
-
- file->private_data = buf;
-
- mutex_unlock(&ar->conf_mutex);
- return 0;
-
-err_free:
- vfree(buf);
-
-err_unlock:
- mutex_unlock(&ar->conf_mutex);
- return ret;
-}
-
-static int ath11k_release_pdev_stats(struct inode *inode, struct file *file)
-{
- vfree(file->private_data);
-
- return 0;
-}
-
-static ssize_t ath11k_read_pdev_stats(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- const char *buf = file->private_data;
- size_t len = strlen(buf);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_pdev_stats = {
- .open = ath11k_open_pdev_stats,
- .release = ath11k_release_pdev_stats,
- .read = ath11k_read_pdev_stats,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)
-{
- struct ath11k *ar = inode->i_private;
- struct stats_request_params req_param;
- void *buf = NULL;
- int ret;
-
- mutex_lock(&ar->conf_mutex);
-
- if (ar->state != ATH11K_STATE_ON) {
- ret = -ENETDOWN;
- goto err_unlock;
- }
-
- buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
- if (!buf) {
- ret = -ENOMEM;
- goto err_unlock;
- }
-
- req_param.pdev_id = ar->pdev->pdev_id;
- /* VDEV stats is always sent for all active VDEVs from FW */
- req_param.vdev_id = 0;
- req_param.stats_id = WMI_REQUEST_VDEV_STAT;
-
- ret = ath11k_debug_fw_stats_request(ar, &req_param);
- if (ret) {
- ath11k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
- goto err_free;
- }
-
- ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
- buf);
-
- file->private_data = buf;
-
- mutex_unlock(&ar->conf_mutex);
- return 0;
-
-err_free:
- vfree(buf);
-
-err_unlock:
- mutex_unlock(&ar->conf_mutex);
- return ret;
-}
-
-static int ath11k_release_vdev_stats(struct inode *inode, struct file *file)
-{
- vfree(file->private_data);
-
- return 0;
-}
-
-static ssize_t ath11k_read_vdev_stats(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- const char *buf = file->private_data;
- size_t len = strlen(buf);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_vdev_stats = {
- .open = ath11k_open_vdev_stats,
- .release = ath11k_release_vdev_stats,
- .read = ath11k_read_vdev_stats,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-static int ath11k_open_bcn_stats(struct inode *inode, struct file *file)
-{
- struct ath11k *ar = inode->i_private;
- struct ath11k_vif *arvif;
- struct stats_request_params req_param;
- void *buf = NULL;
- int ret;
-
- mutex_lock(&ar->conf_mutex);
-
- if (ar->state != ATH11K_STATE_ON) {
- ret = -ENETDOWN;
- goto err_unlock;
- }
-
- buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
- if (!buf) {
- ret = -ENOMEM;
- goto err_unlock;
- }
-
- req_param.stats_id = WMI_REQUEST_BCN_STAT;
- req_param.pdev_id = ar->pdev->pdev_id;
-
- /* loop all active VDEVs for bcn stats */
- list_for_each_entry(arvif, &ar->arvifs, list) {
- if (!arvif->is_up)
- continue;
-
- req_param.vdev_id = arvif->vdev_id;
- ret = ath11k_debug_fw_stats_request(ar, &req_param);
- if (ret) {
- ath11k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
- goto err_free;
- }
- }
-
- ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
- buf);
-
- /* since beacon stats request is looped for all active VDEVs, saved fw
- * stats is not freed for each request until done for all active VDEVs
- */
- spin_lock_bh(&ar->data_lock);
- ath11k_fw_stats_bcn_free(&ar->debug.fw_stats.bcn);
- spin_unlock_bh(&ar->data_lock);
-
- file->private_data = buf;
-
- mutex_unlock(&ar->conf_mutex);
- return 0;
-
-err_free:
- vfree(buf);
-
-err_unlock:
- mutex_unlock(&ar->conf_mutex);
- return ret;
-}
-
-static int ath11k_release_bcn_stats(struct inode *inode, struct file *file)
-{
- vfree(file->private_data);
-
- return 0;
-}
-
-static ssize_t ath11k_read_bcn_stats(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- const char *buf = file->private_data;
- size_t len = strlen(buf);
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_bcn_stats = {
- .open = ath11k_open_bcn_stats,
- .release = ath11k_release_bcn_stats,
- .read = ath11k_read_bcn_stats,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-static ssize_t ath11k_read_simulate_fw_crash(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- const char buf[] =
- "To simulate firmware crash write one of the keywords to this file:\n"
- "`assert` - this will send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n"
- "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
-
- return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
-}
-
-/* Simulate firmware crash:
- * 'soft': Call wmi command causing firmware hang. This firmware hang is
- * recoverable by warm firmware reset.
- * 'hard': Force firmware crash by setting any vdev parameter for not allowed
- * vdev id. This is hard firmware crash because it is recoverable only by cold
- * firmware reset.
- */
-static ssize_t ath11k_write_simulate_fw_crash(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ath11k_base *ab = file->private_data;
- struct ath11k_pdev *pdev;
- struct ath11k *ar = ab->pdevs[0].ar;
- char buf[32] = {0};
- ssize_t rc;
- int i, ret, radioup = 0;
-
- for (i = 0; i < ab->num_radios; i++) {
- pdev = &ab->pdevs[i];
- ar = pdev->ar;
- if (ar && ar->state == ATH11K_STATE_ON) {
- radioup = 1;
- break;
- }
- }
- /* filter partial writes and invalid commands */
- if (*ppos != 0 || count >= sizeof(buf) || count == 0)
- return -EINVAL;
-
- rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
- if (rc < 0)
- return rc;
-
- /* drop the possible '\n' from the end */
- if (buf[*ppos - 1] == '\n')
- buf[*ppos - 1] = '\0';
-
- if (radioup == 0) {
- ret = -ENETDOWN;
- goto exit;
- }
-
- if (!strcmp(buf, "assert")) {
- ath11k_info(ab, "simulating firmware assert crash\n");
- ret = ath11k_wmi_force_fw_hang_cmd(ar,
- ATH11K_WMI_FW_HANG_ASSERT_TYPE,
- ATH11K_WMI_FW_HANG_DELAY);
- } else {
- ret = -EINVAL;
- goto exit;
- }
-
- if (ret) {
- ath11k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
- goto exit;
- }
-
- ret = count;
-
-exit:
- return ret;
-}
-
-static const struct file_operations fops_simulate_fw_crash = {
- .read = ath11k_read_simulate_fw_crash,
- .write = ath11k_write_simulate_fw_crash,
- .open = simple_open,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-static ssize_t ath11k_write_enable_extd_tx_stats(struct file *file,
- const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct ath11k *ar = file->private_data;
- u32 filter;
- int ret;
-
- if (kstrtouint_from_user(ubuf, count, 0, &filter))
- return -EINVAL;
-
- mutex_lock(&ar->conf_mutex);
-
- if (ar->state != ATH11K_STATE_ON) {
- ret = -ENETDOWN;
- goto out;
- }
-
- if (filter == ar->debug.extd_tx_stats) {
- ret = count;
- goto out;
- }
-
- ar->debug.extd_tx_stats = filter;
- ret = count;
-
-out:
- mutex_unlock(&ar->conf_mutex);
- return ret;
-}
-
-static ssize_t ath11k_read_enable_extd_tx_stats(struct file *file,
- char __user *ubuf,
- size_t count, loff_t *ppos)
-
-{
- char buf[32] = {0};
- struct ath11k *ar = file->private_data;
- int len = 0;
-
- mutex_lock(&ar->conf_mutex);
- len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
- ar->debug.extd_tx_stats);
- mutex_unlock(&ar->conf_mutex);
-
- return simple_read_from_buffer(ubuf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_extd_tx_stats = {
- .read = ath11k_read_enable_extd_tx_stats,
- .write = ath11k_write_enable_extd_tx_stats,
- .open = simple_open
-};
-
-static ssize_t ath11k_write_extd_rx_stats(struct file *file,
- const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct ath11k *ar = file->private_data;
- struct ath11k_base *ab = ar->ab;
- struct htt_rx_ring_tlv_filter tlv_filter = {0};
- u32 enable, rx_filter = 0, ring_id;
- int i;
- int ret;
-
- if (kstrtouint_from_user(ubuf, count, 0, &enable))
- return -EINVAL;
-
- mutex_lock(&ar->conf_mutex);
-
- if (ar->state != ATH11K_STATE_ON) {
- ret = -ENETDOWN;
- goto exit;
- }
-
- if (enable > 1) {
- ret = -EINVAL;
- goto exit;
- }
-
- if (enable == ar->debug.extd_rx_stats) {
- ret = count;
- goto exit;
- }
-
- if (enable) {
- rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START;
- rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;
- rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;
- rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;
- rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;
- rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;
-
- tlv_filter.rx_filter = rx_filter;
- tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
- tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
- tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
- tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
- HTT_RX_FP_DATA_FILTER_FLASG3;
- } else {
- tlv_filter = ath11k_mac_mon_status_filter_default;
- }
-
- ar->debug.rx_filter = tlv_filter.rx_filter;
-
- for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
- ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
- ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
- HAL_RXDMA_MONITOR_STATUS,
- DP_RX_BUFFER_SIZE, &tlv_filter);
-
- if (ret) {
- ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
- goto exit;
- }
- }
-
- ar->debug.extd_rx_stats = enable;
- ret = count;
-exit:
- mutex_unlock(&ar->conf_mutex);
- return ret;
-}
-
-static ssize_t ath11k_read_extd_rx_stats(struct file *file,
- char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct ath11k *ar = file->private_data;
- char buf[32];
- int len = 0;
-
- mutex_lock(&ar->conf_mutex);
- len = scnprintf(buf, sizeof(buf) - len, "%d\n",
- ar->debug.extd_rx_stats);
- mutex_unlock(&ar->conf_mutex);
-
- return simple_read_from_buffer(ubuf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_extd_rx_stats = {
- .read = ath11k_read_extd_rx_stats,
- .write = ath11k_write_extd_rx_stats,
- .open = simple_open,
-};
-
-static int ath11k_fill_bp_stats(struct ath11k_base *ab,
- struct ath11k_bp_stats *bp_stats,
- char *buf, int len, int size)
-{
- lockdep_assert_held(&ab->base_lock);
-
- len += scnprintf(buf + len, size - len, "count: %u\n",
- bp_stats->count);
- len += scnprintf(buf + len, size - len, "hp: %u\n",
- bp_stats->hp);
- len += scnprintf(buf + len, size - len, "tp: %u\n",
- bp_stats->tp);
- len += scnprintf(buf + len, size - len, "seen before: %ums\n\n",
- jiffies_to_msecs(jiffies - bp_stats->jiffies));
- return len;
-}
-
-static ssize_t ath11k_debug_dump_soc_ring_bp_stats(struct ath11k_base *ab,
- char *buf, int size)
-{
- struct ath11k_bp_stats *bp_stats;
- bool stats_rxd = false;
- u8 i, pdev_idx;
- int len = 0;
-
- len += scnprintf(buf + len, size - len, "\nBackpressure Stats\n");
- len += scnprintf(buf + len, size - len, "==================\n");
-
- spin_lock_bh(&ab->base_lock);
- for (i = 0; i < HTT_SW_UMAC_RING_IDX_MAX; i++) {
- bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[i];
-
- if (!bp_stats->count)
- continue;
-
- len += scnprintf(buf + len, size - len, "Ring: %s\n",
- htt_bp_umac_ring[i]);
- len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
- stats_rxd = true;
- }
-
- for (i = 0; i < HTT_SW_LMAC_RING_IDX_MAX; i++) {
- for (pdev_idx = 0; pdev_idx < MAX_RADIOS; pdev_idx++) {
- bp_stats =
- &ab->soc_stats.bp_stats.lmac_ring_bp_stats[i][pdev_idx];
-
- if (!bp_stats->count)
- continue;
-
- len += scnprintf(buf + len, size - len, "Ring: %s\n",
- htt_bp_lmac_ring[i]);
- len += scnprintf(buf + len, size - len, "pdev: %d\n",
- pdev_idx);
- len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
- stats_rxd = true;
- }
- }
- spin_unlock_bh(&ab->base_lock);
-
- if (!stats_rxd)
- len += scnprintf(buf + len, size - len,
- "No Ring Backpressure stats received\n\n");
-
- return len;
-}
-
-static ssize_t ath11k_debug_dump_soc_dp_stats(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ath11k_base *ab = file->private_data;
- struct ath11k_soc_dp_stats *soc_stats = &ab->soc_stats;
- int len = 0, i, retval;
- const int size = 4096;
- static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
- "Overflow", "MPDU len", "FCS", "Decrypt", "TKIP MIC",
- "Unencrypt", "MSDU len", "MSDU limit", "WiFi parse",
- "AMSDU parse", "SA timeout", "DA timeout",
- "Flow timeout", "Flush req"};
- static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {
- "Desc addr zero", "Desc inval", "AMPDU in non BA",
- "Non BA dup", "BA dup", "Frame 2k jump", "BAR 2k jump",
- "Frame OOR", "BAR OOR", "No BA session",
- "Frame SN equal SSN", "PN check fail", "2k err",
- "PN err", "Desc blocked"};
-
- char *buf;
-
- buf = kzalloc(size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- len += scnprintf(buf + len, size - len, "SOC RX STATS:\n\n");
- len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
- soc_stats->err_ring_pkts);
- len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
- soc_stats->invalid_rbm);
- len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
- for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
- len += scnprintf(buf + len, size - len, "%s: %u\n",
- rxdma_err[i], soc_stats->rxdma_error[i]);
-
- len += scnprintf(buf + len, size - len, "\nREO errors:\n");
- for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
- len += scnprintf(buf + len, size - len, "%s: %u\n",
- reo_err[i], soc_stats->reo_error[i]);
-
- len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
- len += scnprintf(buf + len, size - len,
- "ring0: %u\nring1: %u\nring2: %u\nring3: %u\n",
- soc_stats->hal_reo_error[0],
- soc_stats->hal_reo_error[1],
- soc_stats->hal_reo_error[2],
- soc_stats->hal_reo_error[3]);
-
- len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n");
- len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");
-
- for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
- len += scnprintf(buf + len, size - len, "ring%d: %u\n",
- i, soc_stats->tx_err.desc_na[i]);
-
- len += scnprintf(buf + len, size - len,
- "\nMisc Transmit Failures: %d\n",
- atomic_read(&soc_stats->tx_err.misc_fail));
-
- len += ath11k_debug_dump_soc_ring_bp_stats(ab, buf + len, size - len);
-
- if (len > size)
- len = size;
- retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
- kfree(buf);
-
- return retval;
-}
-
-static const struct file_operations fops_soc_dp_stats = {
- .read = ath11k_debug_dump_soc_dp_stats,
- .open = simple_open,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-int ath11k_debug_pdev_create(struct ath11k_base *ab)
-{
- if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
- return 0;
-
- ab->debugfs_soc = debugfs_create_dir(ab->hw_params.name, ab->debugfs_ath11k);
-
- if (IS_ERR_OR_NULL(ab->debugfs_soc)) {
- if (IS_ERR(ab->debugfs_soc))
- return PTR_ERR(ab->debugfs_soc);
- return -ENOMEM;
- }
-
- debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
- &fops_simulate_fw_crash);
-
- debugfs_create_file("soc_dp_stats", 0600, ab->debugfs_soc, ab,
- &fops_soc_dp_stats);
-
- return 0;
-}
-
-void ath11k_debug_pdev_destroy(struct ath11k_base *ab)
-{
- debugfs_remove_recursive(ab->debugfs_ath11k);
- ab->debugfs_ath11k = NULL;
-}
-
-int ath11k_debug_soc_create(struct ath11k_base *ab)
-{
- ab->debugfs_ath11k = debugfs_create_dir("ath11k", NULL);
-
- if (IS_ERR_OR_NULL(ab->debugfs_ath11k)) {
- if (IS_ERR(ab->debugfs_ath11k))
- return PTR_ERR(ab->debugfs_ath11k);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void ath11k_debug_soc_destroy(struct ath11k_base *ab)
-{
- debugfs_remove_recursive(ab->debugfs_soc);
- ab->debugfs_soc = NULL;
-}
-
-void ath11k_debug_fw_stats_init(struct ath11k *ar)
-{
- struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
- ar->debug.debugfs_pdev);
-
- ar->debug.fw_stats.debugfs_fwstats = fwstats_dir;
-
- /* all stats debugfs files created are under "fw_stats" directory
- * created per PDEV
- */
- debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
- &fops_pdev_stats);
- debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
- &fops_vdev_stats);
- debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
- &fops_bcn_stats);
-
- INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
- INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
- INIT_LIST_HEAD(&ar->debug.fw_stats.bcn);
-
- init_completion(&ar->debug.fw_stats_complete);
-}
-
-static ssize_t ath11k_write_pktlog_filter(struct file *file,
- const char __user *ubuf,
- size_t count, loff_t *ppos)
-{
- struct ath11k *ar = file->private_data;
- struct ath11k_base *ab = ar->ab;
- struct htt_rx_ring_tlv_filter tlv_filter = {0};
- u32 rx_filter = 0, ring_id, filter, mode;
- u8 buf[128] = {0};
- int i, ret;
- ssize_t rc;
-
- mutex_lock(&ar->conf_mutex);
- if (ar->state != ATH11K_STATE_ON) {
- ret = -ENETDOWN;
- goto out;
- }
-
- rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
- if (rc < 0) {
- ret = rc;
- goto out;
- }
- buf[rc] = '\0';
-
- ret = sscanf(buf, "0x%x %u", &filter, &mode);
- if (ret != 2) {
- ret = -EINVAL;
- goto out;
- }
-
- if (filter) {
- ret = ath11k_wmi_pdev_pktlog_enable(ar, filter);
- if (ret) {
- ath11k_warn(ar->ab,
- "failed to enable pktlog filter %x: %d\n",
- ar->debug.pktlog_filter, ret);
- goto out;
- }
- } else {
- ret = ath11k_wmi_pdev_pktlog_disable(ar);
- if (ret) {
- ath11k_warn(ar->ab, "failed to disable pktlog: %d\n", ret);
- goto out;
- }
- }
-
-#define HTT_RX_FILTER_TLV_LITE_MODE \
- (HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
- HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
- HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \
- HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \
- HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE | \
- HTT_RX_FILTER_TLV_FLAGS_MPDU_START)
-
- if (mode == ATH11K_PKTLOG_MODE_FULL) {
- rx_filter = HTT_RX_FILTER_TLV_LITE_MODE |
- HTT_RX_FILTER_TLV_FLAGS_MSDU_START |
- HTT_RX_FILTER_TLV_FLAGS_MSDU_END |
- HTT_RX_FILTER_TLV_FLAGS_MPDU_END |
- HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER |
- HTT_RX_FILTER_TLV_FLAGS_ATTENTION;
- } else if (mode == ATH11K_PKTLOG_MODE_LITE) {
- ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
- HTT_PPDU_STATS_TAG_PKTLOG);
- if (ret) {
- ath11k_err(ar->ab, "failed to enable pktlog lite: %d\n", ret);
- goto out;
- }
-
- rx_filter = HTT_RX_FILTER_TLV_LITE_MODE;
- } else {
- ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
- HTT_PPDU_STATS_TAG_DEFAULT);
- if (ret) {
- ath11k_err(ar->ab, "failed to send htt ppdu stats req: %d\n",
- ret);
- goto out;
- }
- }
-
- tlv_filter.rx_filter = rx_filter;
- if (rx_filter) {
- tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
- tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
- tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
- tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
- HTT_RX_FP_DATA_FILTER_FLASG3;
- }
-
- for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
- ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
- ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id,
- ar->dp.mac_id + i,
- HAL_RXDMA_MONITOR_STATUS,
- DP_RX_BUFFER_SIZE, &tlv_filter);
-
- if (ret) {
- ath11k_warn(ab, "failed to set rx filter for monitor status ring\n");
- goto out;
- }
- }
-
- ath11k_dbg(ab, ATH11K_DBG_WMI, "pktlog filter %d mode %s\n",
- filter, ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite"));
-
- ar->debug.pktlog_filter = filter;
- ar->debug.pktlog_mode = mode;
- ret = count;
-
-out:
- mutex_unlock(&ar->conf_mutex);
- return ret;
-}
-
-static ssize_t ath11k_read_pktlog_filter(struct file *file,
- char __user *ubuf,
- size_t count, loff_t *ppos)
-
-{
- char buf[32] = {0};
- struct ath11k *ar = file->private_data;
- int len = 0;
-
- mutex_lock(&ar->conf_mutex);
- len = scnprintf(buf, sizeof(buf) - len, "%08x %08x\n",
- ar->debug.pktlog_filter,
- ar->debug.pktlog_mode);
- mutex_unlock(&ar->conf_mutex);
-
- return simple_read_from_buffer(ubuf, count, ppos, buf, len);
-}
-
-static const struct file_operations fops_pktlog_filter = {
- .read = ath11k_read_pktlog_filter,
- .write = ath11k_write_pktlog_filter,
- .open = simple_open
-};
-
-static ssize_t ath11k_write_simulate_radar(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ath11k *ar = file->private_data;
- int ret;
-
- ret = ath11k_wmi_simulate_radar(ar);
- if (ret)
- return ret;
-
- return count;
-}
-
-static const struct file_operations fops_simulate_radar = {
- .write = ath11k_write_simulate_radar,
- .open = simple_open
-};
-
-int ath11k_debug_register(struct ath11k *ar)
-{
- struct ath11k_base *ab = ar->ab;
- char pdev_name[5];
- char buf[100] = {0};
-
- snprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
-
- ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
-
- if (IS_ERR_OR_NULL(ar->debug.debugfs_pdev)) {
- if (IS_ERR(ar->debug.debugfs_pdev))
- return PTR_ERR(ar->debug.debugfs_pdev);
-
- return -ENOMEM;
- }
-
- /* Create a symlink under ieee80211/phy* */
- snprintf(buf, 100, "../../ath11k/%pd2", ar->debug.debugfs_pdev);
- debugfs_create_symlink("ath11k", ar->hw->wiphy->debugfsdir, buf);
-
- ath11k_debug_htt_stats_init(ar);
-
- ath11k_debug_fw_stats_init(ar);
-
- debugfs_create_file("ext_tx_stats", 0644,
- ar->debug.debugfs_pdev, ar,
- &fops_extd_tx_stats);
- debugfs_create_file("ext_rx_stats", 0644,
- ar->debug.debugfs_pdev, ar,
- &fops_extd_rx_stats);
- debugfs_create_file("pktlog_filter", 0644,
- ar->debug.debugfs_pdev, ar,
- &fops_pktlog_filter);
-
- if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) {
- debugfs_create_file("dfs_simulate_radar", 0200,
- ar->debug.debugfs_pdev, ar,
- &fops_simulate_radar);
- debugfs_create_bool("dfs_block_radar_events", 0200,
- ar->debug.debugfs_pdev,
- &ar->dfs_block_radar_events);
- }
-
- return 0;
-}
-
-void ath11k_debug_unregister(struct ath11k *ar)
-{
-}
-#endif /* CONFIG_ATH11K_DEBUGFS */
+#endif /* CONFIG_ATH11K_DEBUG */
diff --git a/drivers/net/wireless/ath/ath11k/debug.h b/drivers/net/wireless/ath/ath11k/debug.h
index 55717278ec3f..659a275e2eb3 100644
--- a/drivers/net/wireless/ath/ath11k/debug.h
+++ b/drivers/net/wireless/ath/ath11k/debug.h
@@ -6,11 +6,8 @@
#ifndef _ATH11K_DEBUG_H_
#define _ATH11K_DEBUG_H_
-#include "hal_tx.h"
#include "trace.h"
-
-#define ATH11K_TX_POWER_MAX_VAL 70
-#define ATH11K_TX_POWER_MIN_VAL 0
+#include "debugfs.h"
enum ath11k_debug_mask {
ATH11K_DBG_AHB = 0x00000001,
@@ -31,98 +28,6 @@ enum ath11k_debug_mask {
ATH11K_DBG_ANY = 0xffffffff,
};
-/* htt_dbg_ext_stats_type */
-enum ath11k_dbg_htt_ext_stats_type {
- ATH11K_DBG_HTT_EXT_STATS_RESET = 0,
- ATH11K_DBG_HTT_EXT_STATS_PDEV_TX = 1,
- ATH11K_DBG_HTT_EXT_STATS_PDEV_RX = 2,
- ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_HWQ = 3,
- ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4,
- ATH11K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5,
- ATH11K_DBG_HTT_EXT_STATS_PDEV_TQM = 6,
- ATH11K_DBG_HTT_EXT_STATS_TQM_CMDQ = 7,
- ATH11K_DBG_HTT_EXT_STATS_TX_DE_INFO = 8,
- ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_RATE = 9,
- ATH11K_DBG_HTT_EXT_STATS_PDEV_RX_RATE = 10,
- ATH11K_DBG_HTT_EXT_STATS_PEER_INFO = 11,
- ATH11K_DBG_HTT_EXT_STATS_TX_SELFGEN_INFO = 12,
- ATH11K_DBG_HTT_EXT_STATS_TX_MU_HWQ = 13,
- ATH11K_DBG_HTT_EXT_STATS_RING_IF_INFO = 14,
- ATH11K_DBG_HTT_EXT_STATS_SRNG_INFO = 15,
- ATH11K_DBG_HTT_EXT_STATS_SFM_INFO = 16,
- ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_MU = 17,
- ATH11K_DBG_HTT_EXT_STATS_ACTIVE_PEERS_LIST = 18,
- ATH11K_DBG_HTT_EXT_STATS_PDEV_CCA_STATS = 19,
- ATH11K_DBG_HTT_EXT_STATS_TWT_SESSIONS = 20,
- ATH11K_DBG_HTT_EXT_STATS_REO_RESOURCE_STATS = 21,
- ATH11K_DBG_HTT_EXT_STATS_TX_SOUNDING_INFO = 22,
- ATH11K_DBG_HTT_EXT_STATS_PDEV_OBSS_PD_STATS = 23,
- ATH11K_DBG_HTT_EXT_STATS_RING_BACKPRESSURE_STATS = 24,
-
- /* keep this last */
- ATH11K_DBG_HTT_NUM_EXT_STATS,
-};
-
-struct debug_htt_stats_req {
- bool done;
- u8 pdev_id;
- u8 type;
- u8 peer_addr[ETH_ALEN];
- struct completion cmpln;
- u32 buf_len;
- u8 buf[];
-};
-
-struct ath_pktlog_hdr {
- u16 flags;
- u16 missed_cnt;
- u16 log_type;
- u16 size;
- u32 timestamp;
- u32 type_specific_data;
- u8 payload[];
-};
-
-#define ATH11K_HTT_PEER_STATS_RESET BIT(16)
-
-#define ATH11K_HTT_STATS_BUF_SIZE (1024 * 512)
-#define ATH11K_FW_STATS_BUF_SIZE (1024 * 1024)
-
-enum ath11k_pktlog_filter {
- ATH11K_PKTLOG_RX = 0x000000001,
- ATH11K_PKTLOG_TX = 0x000000002,
- ATH11K_PKTLOG_RCFIND = 0x000000004,
- ATH11K_PKTLOG_RCUPDATE = 0x000000008,
- ATH11K_PKTLOG_EVENT_SMART_ANT = 0x000000020,
- ATH11K_PKTLOG_EVENT_SW = 0x000000040,
- ATH11K_PKTLOG_ANY = 0x00000006f,
-};
-
-enum ath11k_pktlog_mode {
- ATH11K_PKTLOG_MODE_LITE = 1,
- ATH11K_PKTLOG_MODE_FULL = 2,
-};
-
-enum ath11k_pktlog_enum {
- ATH11K_PKTLOG_TYPE_TX_CTRL = 1,
- ATH11K_PKTLOG_TYPE_TX_STAT = 2,
- ATH11K_PKTLOG_TYPE_TX_MSDU_ID = 3,
- ATH11K_PKTLOG_TYPE_RX_STAT = 5,
- ATH11K_PKTLOG_TYPE_RC_FIND = 6,
- ATH11K_PKTLOG_TYPE_RC_UPDATE = 7,
- ATH11K_PKTLOG_TYPE_TX_VIRT_ADDR = 8,
- ATH11K_PKTLOG_TYPE_RX_CBF = 10,
- ATH11K_PKTLOG_TYPE_RX_STATBUF = 22,
- ATH11K_PKTLOG_TYPE_PPDU_STATS = 23,
- ATH11K_PKTLOG_TYPE_LITE_RX = 24,
-};
-
-enum ath11k_dbg_aggr_mode {
- ATH11K_DBG_AGGR_MODE_AUTO,
- ATH11K_DBG_AGGR_MODE_MANUAL,
- ATH11K_DBG_AGGR_MODE_MAX,
-};
-
__printf(2, 3) void ath11k_info(struct ath11k_base *ab, const char *fmt, ...);
__printf(2, 3) void ath11k_err(struct ath11k_base *ab, const char *fmt, ...);
__printf(2, 3) void ath11k_warn(struct ath11k_base *ab, const char *fmt, ...);
@@ -153,153 +58,6 @@ static inline void ath11k_dbg_dump(struct ath11k_base *ab,
}
#endif /* CONFIG_ATH11K_DEBUG */
-#ifdef CONFIG_ATH11K_DEBUGFS
-int ath11k_debug_soc_create(struct ath11k_base *ab);
-void ath11k_debug_soc_destroy(struct ath11k_base *ab);
-int ath11k_debug_pdev_create(struct ath11k_base *ab);
-void ath11k_debug_pdev_destroy(struct ath11k_base *ab);
-int ath11k_debug_register(struct ath11k *ar);
-void ath11k_debug_unregister(struct ath11k *ar);
-void ath11k_dbg_htt_ext_stats_handler(struct ath11k_base *ab,
- struct sk_buff *skb);
-void ath11k_debug_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb);
-
-void ath11k_debug_fw_stats_init(struct ath11k *ar);
-int ath11k_dbg_htt_stats_req(struct ath11k *ar);
-
-static inline bool ath11k_debug_is_pktlog_lite_mode_enabled(struct ath11k *ar)
-{
- return (ar->debug.pktlog_mode == ATH11K_PKTLOG_MODE_LITE);
-}
-
-static inline bool ath11k_debug_is_pktlog_rx_stats_enabled(struct ath11k *ar)
-{
- return (!ar->debug.pktlog_peer_valid && ar->debug.pktlog_mode);
-}
-
-static inline bool ath11k_debug_is_pktlog_peer_valid(struct ath11k *ar, u8 *addr)
-{
- return (ar->debug.pktlog_peer_valid && ar->debug.pktlog_mode &&
- ether_addr_equal(addr, ar->debug.pktlog_peer_addr));
-}
-
-static inline int ath11k_debug_is_extd_tx_stats_enabled(struct ath11k *ar)
-{
- return ar->debug.extd_tx_stats;
-}
-
-static inline int ath11k_debug_is_extd_rx_stats_enabled(struct ath11k *ar)
-{
- return ar->debug.extd_rx_stats;
-}
-
-static inline int ath11k_debug_rx_filter(struct ath11k *ar)
-{
- return ar->debug.rx_filter;
-}
-
-void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, struct dentry *dir);
-void
-ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
- struct ath11k_per_peer_tx_stats *peer_stats,
- u8 legacy_rate_idx);
-void ath11k_update_per_peer_stats_from_txcompl(struct ath11k *ar,
- struct sk_buff *msdu,
- struct hal_tx_status *ts);
-#else
-static inline int ath11k_debug_soc_create(struct ath11k_base *ab)
-{
- return 0;
-}
-
-static inline void ath11k_debug_soc_destroy(struct ath11k_base *ab)
-{
-}
-
-static inline int ath11k_debug_pdev_create(struct ath11k_base *ab)
-{
- return 0;
-}
-
-static inline void ath11k_debug_pdev_destroy(struct ath11k_base *ab)
-{
-}
-
-static inline int ath11k_debug_register(struct ath11k *ar)
-{
- return 0;
-}
-
-static inline void ath11k_debug_unregister(struct ath11k *ar)
-{
-}
-
-static inline void ath11k_dbg_htt_ext_stats_handler(struct ath11k_base *ab,
- struct sk_buff *skb)
-{
-}
-
-static inline void ath11k_debug_fw_stats_process(struct ath11k_base *ab,
- struct sk_buff *skb)
-{
-}
-
-static inline void ath11k_debug_fw_stats_init(struct ath11k *ar)
-{
-}
-
-static inline int ath11k_debug_is_extd_tx_stats_enabled(struct ath11k *ar)
-{
- return 0;
-}
-
-static inline int ath11k_debug_is_extd_rx_stats_enabled(struct ath11k *ar)
-{
- return 0;
-}
-
-static inline int ath11k_dbg_htt_stats_req(struct ath11k *ar)
-{
- return 0;
-}
-
-static inline bool ath11k_debug_is_pktlog_lite_mode_enabled(struct ath11k *ar)
-{
- return false;
-}
-
-static inline bool ath11k_debug_is_pktlog_rx_stats_enabled(struct ath11k *ar)
-{
- return false;
-}
-
-static inline bool ath11k_debug_is_pktlog_peer_valid(struct ath11k *ar, u8 *addr)
-{
- return false;
-}
-
-static inline int ath11k_debug_rx_filter(struct ath11k *ar)
-{
- return 0;
-}
-
-static inline void
-ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
- struct ath11k_per_peer_tx_stats *peer_stats,
- u8 legacy_rate_idx)
-{
-}
-
-static inline void
-ath11k_update_per_peer_stats_from_txcompl(struct ath11k *ar,
- struct sk_buff *msdu,
- struct hal_tx_status *ts)
-{
-}
-
-#endif /* CONFIG_MAC80211_DEBUGFS*/
-
#define ath11k_dbg(ar, dbg_mask, fmt, ...) \
do { \
if (ath11k_debug_mask & dbg_mask) \
diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c
new file mode 100644
index 000000000000..5193b308a992
--- /dev/null
+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
@@ -0,0 +1,1112 @@
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
+ */
+
+#include "debugfs.h"
+
+#include "core.h"
+#include "debug.h"
+#include "wmi.h"
+#include "hal_rx.h"
+#include "dp_tx.h"
+#include "debugfs_htt_stats.h"
+#include "peer.h"
+
+static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
+ "REO2SW1_RING",
+ "REO2SW2_RING",
+ "REO2SW3_RING",
+ "REO2SW4_RING",
+ "WBM2REO_LINK_RING",
+ "REO2TCL_RING",
+ "REO2FW_RING",
+ "RELEASE_RING",
+ "PPE_RELEASE_RING",
+ "TCL2TQM_RING",
+ "TQM_RELEASE_RING",
+ "REO_RELEASE_RING",
+ "WBM2SW0_RELEASE_RING",
+ "WBM2SW1_RELEASE_RING",
+ "WBM2SW2_RELEASE_RING",
+ "WBM2SW3_RELEASE_RING",
+ "REO_CMD_RING",
+ "REO_STATUS_RING",
+};
+
+static const char *htt_bp_lmac_ring[HTT_SW_LMAC_RING_IDX_MAX] = {
+ "FW2RXDMA_BUF_RING",
+ "FW2RXDMA_STATUS_RING",
+ "FW2RXDMA_LINK_RING",
+ "SW2RXDMA_BUF_RING",
+ "WBM2RXDMA_LINK_RING",
+ "RXDMA2FW_RING",
+ "RXDMA2SW_RING",
+ "RXDMA2RELEASE_RING",
+ "RXDMA2REO_RING",
+ "MONITOR_STATUS_RING",
+ "MONITOR_BUF_RING",
+ "MONITOR_DESC_RING",
+ "MONITOR_DEST_RING",
+};
+
+static void ath11k_fw_stats_pdevs_free(struct list_head *head)
+{
+ struct ath11k_fw_stats_pdev *i, *tmp;
+
+ list_for_each_entry_safe(i, tmp, head, list) {
+ list_del(&i->list);
+ kfree(i);
+ }
+}
+
+static void ath11k_fw_stats_vdevs_free(struct list_head *head)
+{
+ struct ath11k_fw_stats_vdev *i, *tmp;
+
+ list_for_each_entry_safe(i, tmp, head, list) {
+ list_del(&i->list);
+ kfree(i);
+ }
+}
+
+static void ath11k_fw_stats_bcn_free(struct list_head *head)
+{
+ struct ath11k_fw_stats_bcn *i, *tmp;
+
+ list_for_each_entry_safe(i, tmp, head, list) {
+ list_del(&i->list);
+ kfree(i);
+ }
+}
+
+static void ath11k_debugfs_fw_stats_reset(struct ath11k *ar)
+{
+ spin_lock_bh(&ar->data_lock);
+ ar->debug.fw_stats_done = false;
+ ath11k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
+ ath11k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
+ spin_unlock_bh(&ar->data_lock);
+}
+
+void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb)
+{
+ struct ath11k_fw_stats stats = {};
+ struct ath11k *ar;
+ struct ath11k_pdev *pdev;
+ bool is_end;
+ static unsigned int num_vdev, num_bcn;
+ size_t total_vdevs_started = 0;
+ int i, ret;
+
+ INIT_LIST_HEAD(&stats.pdevs);
+ INIT_LIST_HEAD(&stats.vdevs);
+ INIT_LIST_HEAD(&stats.bcn);
+
+ ret = ath11k_wmi_pull_fw_stats(ab, skb, &stats);
+ if (ret) {
+ ath11k_warn(ab, "failed to pull fw stats: %d\n", ret);
+ goto free;
+ }
+
+ rcu_read_lock();
+ ar = ath11k_mac_get_ar_by_pdev_id(ab, stats.pdev_id);
+ if (!ar) {
+ rcu_read_unlock();
+ ath11k_warn(ab, "failed to get ar for pdev_id %d: %d\n",
+ stats.pdev_id, ret);
+ goto free;
+ }
+
+ spin_lock_bh(&ar->data_lock);
+
+ if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
+ list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
+ ar->debug.fw_stats_done = true;
+ goto complete;
+ }
+
+ if (stats.stats_id == WMI_REQUEST_VDEV_STAT) {
+ if (list_empty(&stats.vdevs)) {
+ ath11k_warn(ab, "empty vdev stats");
+ goto complete;
+ }
+ /* FW sends all the active VDEV stats irrespective of PDEV,
+ * hence limit until the count of all VDEVs started
+ */
+ for (i = 0; i < ab->num_radios; i++) {
+ pdev = rcu_dereference(ab->pdevs_active[i]);
+ if (pdev && pdev->ar)
+ total_vdevs_started += ar->num_started_vdevs;
+ }
+
+ is_end = ((++num_vdev) == total_vdevs_started);
+
+ list_splice_tail_init(&stats.vdevs,
+ &ar->debug.fw_stats.vdevs);
+
+ if (is_end) {
+ ar->debug.fw_stats_done = true;
+ num_vdev = 0;
+ }
+ goto complete;
+ }
+
+ if (stats.stats_id == WMI_REQUEST_BCN_STAT) {
+ if (list_empty(&stats.bcn)) {
+ ath11k_warn(ab, "empty bcn stats");
+ goto complete;
+ }
+ /* Mark end until we reached the count of all started VDEVs
+ * within the PDEV
+ */
+ is_end = ((++num_bcn) == ar->num_started_vdevs);
+
+ list_splice_tail_init(&stats.bcn,
+ &ar->debug.fw_stats.bcn);
+
+ if (is_end) {
+ ar->debug.fw_stats_done = true;
+ num_bcn = 0;
+ }
+ }
+complete:
+ complete(&ar->debug.fw_stats_complete);
+ rcu_read_unlock();
+ spin_unlock_bh(&ar->data_lock);
+
+free:
+ ath11k_fw_stats_pdevs_free(&stats.pdevs);
+ ath11k_fw_stats_vdevs_free(&stats.vdevs);
+ ath11k_fw_stats_bcn_free(&stats.bcn);
+}
+
+static int ath11k_debugfs_fw_stats_request(struct ath11k *ar,
+ struct stats_request_params *req_param)
+{
+ struct ath11k_base *ab = ar->ab;
+ unsigned long timeout, time_left;
+ int ret;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ /* FW stats can get split when exceeding the stats data buffer limit.
+ * In that case, since there is no end marking for the back-to-back
+ * received 'update stats' event, we keep a 3 seconds timeout in case,
+ * fw_stats_done is not marked yet
+ */
+ timeout = jiffies + msecs_to_jiffies(3 * HZ);
+
+ ath11k_debugfs_fw_stats_reset(ar);
+
+ reinit_completion(&ar->debug.fw_stats_complete);
+
+ ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);
+
+ if (ret) {
+ ath11k_warn(ab, "could not request fw stats (%d)\n",
+ ret);
+ return ret;
+ }
+
+ time_left =
+ wait_for_completion_timeout(&ar->debug.fw_stats_complete,
+ 1 * HZ);
+ if (!time_left)
+ return -ETIMEDOUT;
+
+ for (;;) {
+ if (time_after(jiffies, timeout))
+ break;
+
+ spin_lock_bh(&ar->data_lock);
+ if (ar->debug.fw_stats_done) {
+ spin_unlock_bh(&ar->data_lock);
+ break;
+ }
+ spin_unlock_bh(&ar->data_lock);
+ }
+ return 0;
+}
+
+static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)
+{
+ struct ath11k *ar = inode->i_private;
+ struct ath11k_base *ab = ar->ab;
+ struct stats_request_params req_param;
+ void *buf = NULL;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state != ATH11K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto err_unlock;
+ }
+
+ buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err_unlock;
+ }
+
+ req_param.pdev_id = ar->pdev->pdev_id;
+ req_param.vdev_id = 0;
+ req_param.stats_id = WMI_REQUEST_PDEV_STAT;
+
+ ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
+ if (ret) {
+ ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
+ goto err_free;
+ }
+
+ ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
+ buf);
+
+ file->private_data = buf;
+
+ mutex_unlock(&ar->conf_mutex);
+ return 0;
+
+err_free:
+ vfree(buf);
+
+err_unlock:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static int ath11k_release_pdev_stats(struct inode *inode, struct file *file)
+{
+ vfree(file->private_data);
+
+ return 0;
+}
+
+static ssize_t ath11k_read_pdev_stats(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char *buf = file->private_data;
+ size_t len = strlen(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_pdev_stats = {
+ .open = ath11k_open_pdev_stats,
+ .release = ath11k_release_pdev_stats,
+ .read = ath11k_read_pdev_stats,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)
+{
+ struct ath11k *ar = inode->i_private;
+ struct stats_request_params req_param;
+ void *buf = NULL;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state != ATH11K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto err_unlock;
+ }
+
+ buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err_unlock;
+ }
+
+ req_param.pdev_id = ar->pdev->pdev_id;
+ /* VDEV stats is always sent for all active VDEVs from FW */
+ req_param.vdev_id = 0;
+ req_param.stats_id = WMI_REQUEST_VDEV_STAT;
+
+ ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
+ goto err_free;
+ }
+
+ ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
+ buf);
+
+ file->private_data = buf;
+
+ mutex_unlock(&ar->conf_mutex);
+ return 0;
+
+err_free:
+ vfree(buf);
+
+err_unlock:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static int ath11k_release_vdev_stats(struct inode *inode, struct file *file)
+{
+ vfree(file->private_data);
+
+ return 0;
+}
+
+static ssize_t ath11k_read_vdev_stats(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char *buf = file->private_data;
+ size_t len = strlen(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_vdev_stats = {
+ .open = ath11k_open_vdev_stats,
+ .release = ath11k_release_vdev_stats,
+ .read = ath11k_read_vdev_stats,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static int ath11k_open_bcn_stats(struct inode *inode, struct file *file)
+{
+ struct ath11k *ar = inode->i_private;
+ struct ath11k_vif *arvif;
+ struct stats_request_params req_param;
+ void *buf = NULL;
+ int ret;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state != ATH11K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto err_unlock;
+ }
+
+ buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err_unlock;
+ }
+
+ req_param.stats_id = WMI_REQUEST_BCN_STAT;
+ req_param.pdev_id = ar->pdev->pdev_id;
+
+ /* loop all active VDEVs for bcn stats */
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (!arvif->is_up)
+ continue;
+
+ req_param.vdev_id = arvif->vdev_id;
+ ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
+ goto err_free;
+ }
+ }
+
+ ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
+ buf);
+
+ /* since beacon stats request is looped for all active VDEVs, saved fw
+ * stats is not freed for each request until done for all active VDEVs
+ */
+ spin_lock_bh(&ar->data_lock);
+ ath11k_fw_stats_bcn_free(&ar->debug.fw_stats.bcn);
+ spin_unlock_bh(&ar->data_lock);
+
+ file->private_data = buf;
+
+ mutex_unlock(&ar->conf_mutex);
+ return 0;
+
+err_free:
+ vfree(buf);
+
+err_unlock:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static int ath11k_release_bcn_stats(struct inode *inode, struct file *file)
+{
+ vfree(file->private_data);
+
+ return 0;
+}
+
+static ssize_t ath11k_read_bcn_stats(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char *buf = file->private_data;
+ size_t len = strlen(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_bcn_stats = {
+ .open = ath11k_open_bcn_stats,
+ .release = ath11k_release_bcn_stats,
+ .read = ath11k_read_bcn_stats,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t ath11k_read_simulate_fw_crash(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ const char buf[] =
+ "To simulate firmware crash write one of the keywords to this file:\n"
+ "`assert` - this will send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n"
+ "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
+}
+
+/* Simulate firmware crash:
+ * 'soft': Call wmi command causing firmware hang. This firmware hang is
+ * recoverable by warm firmware reset.
+ * 'hard': Force firmware crash by setting any vdev parameter for not allowed
+ * vdev id. This is hard firmware crash because it is recoverable only by cold
+ * firmware reset.
+ */
+static ssize_t ath11k_write_simulate_fw_crash(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath11k_base *ab = file->private_data;
+ struct ath11k_pdev *pdev;
+ struct ath11k *ar = ab->pdevs[0].ar;
+ char buf[32] = {0};
+ ssize_t rc;
+ int i, ret, radioup = 0;
+
+ for (i = 0; i < ab->num_radios; i++) {
+ pdev = &ab->pdevs[i];
+ ar = pdev->ar;
+ if (ar && ar->state == ATH11K_STATE_ON) {
+ radioup = 1;
+ break;
+ }
+ }
+ /* filter partial writes and invalid commands */
+ if (*ppos != 0 || count >= sizeof(buf) || count == 0)
+ return -EINVAL;
+
+ rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
+ if (rc < 0)
+ return rc;
+
+ /* drop the possible '\n' from the end */
+ if (buf[*ppos - 1] == '\n')
+ buf[*ppos - 1] = '\0';
+
+ if (radioup == 0) {
+ ret = -ENETDOWN;
+ goto exit;
+ }
+
+ if (!strcmp(buf, "assert")) {
+ ath11k_info(ab, "simulating firmware assert crash\n");
+ ret = ath11k_wmi_force_fw_hang_cmd(ar,
+ ATH11K_WMI_FW_HANG_ASSERT_TYPE,
+ ATH11K_WMI_FW_HANG_DELAY);
+ } else {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (ret) {
+ ath11k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
+ goto exit;
+ }
+
+ ret = count;
+
+exit:
+ return ret;
+}
+
+static const struct file_operations fops_simulate_fw_crash = {
+ .read = ath11k_read_simulate_fw_crash,
+ .write = ath11k_write_simulate_fw_crash,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t ath11k_write_enable_extd_tx_stats(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath11k *ar = file->private_data;
+ u32 filter;
+ int ret;
+
+ if (kstrtouint_from_user(ubuf, count, 0, &filter))
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state != ATH11K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto out;
+ }
+
+ if (filter == ar->debug.extd_tx_stats) {
+ ret = count;
+ goto out;
+ }
+
+ ar->debug.extd_tx_stats = filter;
+ ret = count;
+
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static ssize_t ath11k_read_enable_extd_tx_stats(struct file *file,
+ char __user *ubuf,
+ size_t count, loff_t *ppos)
+
+{
+ char buf[32] = {0};
+ struct ath11k *ar = file->private_data;
+ int len = 0;
+
+ mutex_lock(&ar->conf_mutex);
+ len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
+ ar->debug.extd_tx_stats);
+ mutex_unlock(&ar->conf_mutex);
+
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_extd_tx_stats = {
+ .read = ath11k_read_enable_extd_tx_stats,
+ .write = ath11k_write_enable_extd_tx_stats,
+ .open = simple_open
+};
+
+static ssize_t ath11k_write_extd_rx_stats(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath11k *ar = file->private_data;
+ struct ath11k_base *ab = ar->ab;
+ struct htt_rx_ring_tlv_filter tlv_filter = {0};
+ u32 enable, rx_filter = 0, ring_id;
+ int i;
+ int ret;
+
+ if (kstrtouint_from_user(ubuf, count, 0, &enable))
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ if (ar->state != ATH11K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto exit;
+ }
+
+ if (enable > 1) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (enable == ar->debug.extd_rx_stats) {
+ ret = count;
+ goto exit;
+ }
+
+ if (enable) {
+ rx_filter = HTT_RX_FILTER_TLV_FLAGS_MPDU_START;
+ rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;
+ rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;
+ rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;
+ rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;
+ rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;
+
+ tlv_filter.rx_filter = rx_filter;
+ tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
+ tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
+ tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
+ tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
+ HTT_RX_FP_DATA_FILTER_FLASG3;
+ } else {
+ tlv_filter = ath11k_mac_mon_status_filter_default;
+ }
+
+ ar->debug.rx_filter = tlv_filter.rx_filter;
+
+ for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
+ ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
+ ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
+ HAL_RXDMA_MONITOR_STATUS,
+ DP_RX_BUFFER_SIZE, &tlv_filter);
+
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
+ goto exit;
+ }
+ }
+
+ ar->debug.extd_rx_stats = enable;
+ ret = count;
+exit:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static ssize_t ath11k_read_extd_rx_stats(struct file *file,
+ char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath11k *ar = file->private_data;
+ char buf[32];
+ int len = 0;
+
+ mutex_lock(&ar->conf_mutex);
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
+ ar->debug.extd_rx_stats);
+ mutex_unlock(&ar->conf_mutex);
+
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_extd_rx_stats = {
+ .read = ath11k_read_extd_rx_stats,
+ .write = ath11k_write_extd_rx_stats,
+ .open = simple_open,
+};
+
+static int ath11k_fill_bp_stats(struct ath11k_base *ab,
+ struct ath11k_bp_stats *bp_stats,
+ char *buf, int len, int size)
+{
+ lockdep_assert_held(&ab->base_lock);
+
+ len += scnprintf(buf + len, size - len, "count: %u\n",
+ bp_stats->count);
+ len += scnprintf(buf + len, size - len, "hp: %u\n",
+ bp_stats->hp);
+ len += scnprintf(buf + len, size - len, "tp: %u\n",
+ bp_stats->tp);
+ len += scnprintf(buf + len, size - len, "seen before: %ums\n\n",
+ jiffies_to_msecs(jiffies - bp_stats->jiffies));
+ return len;
+}
+
+static ssize_t ath11k_debugfs_dump_soc_ring_bp_stats(struct ath11k_base *ab,
+ char *buf, int size)
+{
+ struct ath11k_bp_stats *bp_stats;
+ bool stats_rxd = false;
+ u8 i, pdev_idx;
+ int len = 0;
+
+ len += scnprintf(buf + len, size - len, "\nBackpressure Stats\n");
+ len += scnprintf(buf + len, size - len, "==================\n");
+
+ spin_lock_bh(&ab->base_lock);
+ for (i = 0; i < HTT_SW_UMAC_RING_IDX_MAX; i++) {
+ bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[i];
+
+ if (!bp_stats->count)
+ continue;
+
+ len += scnprintf(buf + len, size - len, "Ring: %s\n",
+ htt_bp_umac_ring[i]);
+ len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
+ stats_rxd = true;
+ }
+
+ for (i = 0; i < HTT_SW_LMAC_RING_IDX_MAX; i++) {
+ for (pdev_idx = 0; pdev_idx < MAX_RADIOS; pdev_idx++) {
+ bp_stats =
+ &ab->soc_stats.bp_stats.lmac_ring_bp_stats[i][pdev_idx];
+
+ if (!bp_stats->count)
+ continue;
+
+ len += scnprintf(buf + len, size - len, "Ring: %s\n",
+ htt_bp_lmac_ring[i]);
+ len += scnprintf(buf + len, size - len, "pdev: %d\n",
+ pdev_idx);
+ len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
+ stats_rxd = true;
+ }
+ }
+ spin_unlock_bh(&ab->base_lock);
+
+ if (!stats_rxd)
+ len += scnprintf(buf + len, size - len,
+ "No Ring Backpressure stats received\n\n");
+
+ return len;
+}
+
+static ssize_t ath11k_debugfs_dump_soc_dp_stats(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath11k_base *ab = file->private_data;
+ struct ath11k_soc_dp_stats *soc_stats = &ab->soc_stats;
+ int len = 0, i, retval;
+ const int size = 4096;
+ static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
+ "Overflow", "MPDU len", "FCS", "Decrypt", "TKIP MIC",
+ "Unencrypt", "MSDU len", "MSDU limit", "WiFi parse",
+ "AMSDU parse", "SA timeout", "DA timeout",
+ "Flow timeout", "Flush req"};
+ static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {
+ "Desc addr zero", "Desc inval", "AMPDU in non BA",
+ "Non BA dup", "BA dup", "Frame 2k jump", "BAR 2k jump",
+ "Frame OOR", "BAR OOR", "No BA session",
+ "Frame SN equal SSN", "PN check fail", "2k err",
+ "PN err", "Desc blocked"};
+
+ char *buf;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len += scnprintf(buf + len, size - len, "SOC RX STATS:\n\n");
+ len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
+ soc_stats->err_ring_pkts);
+ len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
+ soc_stats->invalid_rbm);
+ len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
+ for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
+ len += scnprintf(buf + len, size - len, "%s: %u\n",
+ rxdma_err[i], soc_stats->rxdma_error[i]);
+
+ len += scnprintf(buf + len, size - len, "\nREO errors:\n");
+ for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
+ len += scnprintf(buf + len, size - len, "%s: %u\n",
+ reo_err[i], soc_stats->reo_error[i]);
+
+ len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
+ len += scnprintf(buf + len, size - len,
+ "ring0: %u\nring1: %u\nring2: %u\nring3: %u\n",
+ soc_stats->hal_reo_error[0],
+ soc_stats->hal_reo_error[1],
+ soc_stats->hal_reo_error[2],
+ soc_stats->hal_reo_error[3]);
+
+ len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n");
+ len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");
+
+ for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
+ len += scnprintf(buf + len, size - len, "ring%d: %u\n",
+ i, soc_stats->tx_err.desc_na[i]);
+
+ len += scnprintf(buf + len, size - len,
+ "\nMisc Transmit Failures: %d\n",
+ atomic_read(&soc_stats->tx_err.misc_fail));
+
+ len += ath11k_debugfs_dump_soc_ring_bp_stats(ab, buf + len, size - len);
+
+ if (len > size)
+ len = size;
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+}
+
+static const struct file_operations fops_soc_dp_stats = {
+ .read = ath11k_debugfs_dump_soc_dp_stats,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+int ath11k_debugfs_pdev_create(struct ath11k_base *ab)
+{
+ if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
+ return 0;
+
+ ab->debugfs_soc = debugfs_create_dir(ab->hw_params.name, ab->debugfs_ath11k);
+
+ if (IS_ERR_OR_NULL(ab->debugfs_soc)) {
+ if (IS_ERR(ab->debugfs_soc))
+ return PTR_ERR(ab->debugfs_soc);
+ return -ENOMEM;
+ }
+
+ debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
+ &fops_simulate_fw_crash);
+
+ debugfs_create_file("soc_dp_stats", 0600, ab->debugfs_soc, ab,
+ &fops_soc_dp_stats);
+
+ return 0;
+}
+
+void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab)
+{
+ debugfs_remove_recursive(ab->debugfs_ath11k);
+ ab->debugfs_ath11k = NULL;
+}
+
+int ath11k_debugfs_soc_create(struct ath11k_base *ab)
+{
+ ab->debugfs_ath11k = debugfs_create_dir("ath11k", NULL);
+
+ if (IS_ERR_OR_NULL(ab->debugfs_ath11k)) {
+ if (IS_ERR(ab->debugfs_ath11k))
+ return PTR_ERR(ab->debugfs_ath11k);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void ath11k_debugfs_soc_destroy(struct ath11k_base *ab)
+{
+ debugfs_remove_recursive(ab->debugfs_soc);
+ ab->debugfs_soc = NULL;
+}
+
+void ath11k_debugfs_fw_stats_init(struct ath11k *ar)
+{
+ struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
+ ar->debug.debugfs_pdev);
+
+ ar->debug.fw_stats.debugfs_fwstats = fwstats_dir;
+
+ /* all stats debugfs files created are under "fw_stats" directory
+ * created per PDEV
+ */
+ debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
+ &fops_pdev_stats);
+ debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
+ &fops_vdev_stats);
+ debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
+ &fops_bcn_stats);
+
+ INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
+ INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
+ INIT_LIST_HEAD(&ar->debug.fw_stats.bcn);
+
+ init_completion(&ar->debug.fw_stats_complete);
+}
+
+static ssize_t ath11k_write_pktlog_filter(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct ath11k *ar = file->private_data;
+ struct ath11k_base *ab = ar->ab;
+ struct htt_rx_ring_tlv_filter tlv_filter = {0};
+ u32 rx_filter = 0, ring_id, filter, mode;
+ u8 buf[128] = {0};
+ int i, ret;
+ ssize_t rc;
+
+ mutex_lock(&ar->conf_mutex);
+ if (ar->state != ATH11K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto out;
+ }
+
+ rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
+ if (rc < 0) {
+ ret = rc;
+ goto out;
+ }
+ buf[rc] = '\0';
+
+ ret = sscanf(buf, "0x%x %u", &filter, &mode);
+ if (ret != 2) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (filter) {
+ ret = ath11k_wmi_pdev_pktlog_enable(ar, filter);
+ if (ret) {
+ ath11k_warn(ar->ab,
+ "failed to enable pktlog filter %x: %d\n",
+ ar->debug.pktlog_filter, ret);
+ goto out;
+ }
+ } else {
+ ret = ath11k_wmi_pdev_pktlog_disable(ar);
+ if (ret) {
+ ath11k_warn(ar->ab, "failed to disable pktlog: %d\n", ret);
+ goto out;
+ }
+ }
+
+#define HTT_RX_FILTER_TLV_LITE_MODE \
+ (HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
+ HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
+ HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \
+ HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \
+ HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE | \
+ HTT_RX_FILTER_TLV_FLAGS_MPDU_START)
+
+ if (mode == ATH11K_PKTLOG_MODE_FULL) {
+ rx_filter = HTT_RX_FILTER_TLV_LITE_MODE |
+ HTT_RX_FILTER_TLV_FLAGS_MSDU_START |
+ HTT_RX_FILTER_TLV_FLAGS_MSDU_END |
+ HTT_RX_FILTER_TLV_FLAGS_MPDU_END |
+ HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER |
+ HTT_RX_FILTER_TLV_FLAGS_ATTENTION;
+ } else if (mode == ATH11K_PKTLOG_MODE_LITE) {
+ ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
+ HTT_PPDU_STATS_TAG_PKTLOG);
+ if (ret) {
+ ath11k_err(ar->ab, "failed to enable pktlog lite: %d\n", ret);
+ goto out;
+ }
+
+ rx_filter = HTT_RX_FILTER_TLV_LITE_MODE;
+ } else {
+ ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
+ HTT_PPDU_STATS_TAG_DEFAULT);
+ if (ret) {
+ ath11k_err(ar->ab, "failed to send htt ppdu stats req: %d\n",
+ ret);
+ goto out;
+ }
+ }
+
+ tlv_filter.rx_filter = rx_filter;
+ if (rx_filter) {
+ tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
+ tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
+ tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
+ tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
+ HTT_RX_FP_DATA_FILTER_FLASG3;
+ }
+
+ for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
+ ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
+ ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id,
+ ar->dp.mac_id + i,
+ HAL_RXDMA_MONITOR_STATUS,
+ DP_RX_BUFFER_SIZE, &tlv_filter);
+
+ if (ret) {
+ ath11k_warn(ab, "failed to set rx filter for monitor status ring\n");
+ goto out;
+ }
+ }
+
+ ath11k_dbg(ab, ATH11K_DBG_WMI, "pktlog filter %d mode %s\n",
+ filter, ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite"));
+
+ ar->debug.pktlog_filter = filter;
+ ar->debug.pktlog_mode = mode;
+ ret = count;
+
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static ssize_t ath11k_read_pktlog_filter(struct file *file,
+ char __user *ubuf,
+ size_t count, loff_t *ppos)
+
+{
+ char buf[32] = {0};
+ struct ath11k *ar = file->private_data;
+ int len = 0;
+
+ mutex_lock(&ar->conf_mutex);
+ len = scnprintf(buf, sizeof(buf) - len, "%08x %08x\n",
+ ar->debug.pktlog_filter,
+ ar->debug.pktlog_mode);
+ mutex_unlock(&ar->conf_mutex);
+
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_pktlog_filter = {
+ .read = ath11k_read_pktlog_filter,
+ .write = ath11k_write_pktlog_filter,
+ .open = simple_open
+};
+
+static ssize_t ath11k_write_simulate_radar(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath11k *ar = file->private_data;
+ int ret;
+
+ ret = ath11k_wmi_simulate_radar(ar);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static const struct file_operations fops_simulate_radar = {
+ .write = ath11k_write_simulate_radar,
+ .open = simple_open
+};
+
+int ath11k_debugfs_register(struct ath11k *ar)
+{
+ struct ath11k_base *ab = ar->ab;
+ char pdev_name[5];
+ char buf[100] = {0};
+
+ snprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
+
+ ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
+
+ if (IS_ERR_OR_NULL(ar->debug.debugfs_pdev)) {
+ if (IS_ERR(ar->debug.debugfs_pdev))
+ return PTR_ERR(ar->debug.debugfs_pdev);
+
+ return -ENOMEM;
+ }
+
+ /* Create a symlink under ieee80211/phy* */
+ snprintf(buf, 100, "../../ath11k/%pd2", ar->debug.debugfs_pdev);
+ debugfs_create_symlink("ath11k", ar->hw->wiphy->debugfsdir, buf);
+
+ ath11k_debugfs_htt_stats_init(ar);
+
+ ath11k_debugfs_fw_stats_init(ar);
+
+ debugfs_create_file("ext_tx_stats", 0644,
+ ar->debug.debugfs_pdev, ar,
+ &fops_extd_tx_stats);
+ debugfs_create_file("ext_rx_stats", 0644,
+ ar->debug.debugfs_pdev, ar,
+ &fops_extd_rx_stats);
+ debugfs_create_file("pktlog_filter", 0644,
+ ar->debug.debugfs_pdev, ar,
+ &fops_pktlog_filter);
+
+ if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) {
+ debugfs_create_file("dfs_simulate_radar", 0200,
+ ar->debug.debugfs_pdev, ar,
+ &fops_simulate_radar);
+ debugfs_create_bool("dfs_block_radar_events", 0200,
+ ar->debug.debugfs_pdev,
+ &ar->dfs_block_radar_events);
+ }
+
+ return 0;
+}
+
+void ath11k_debugfs_unregister(struct ath11k *ar)
+{
+}
diff --git a/drivers/net/wireless/ath/ath11k/debugfs.h b/drivers/net/wireless/ath/ath11k/debugfs.h
new file mode 100644
index 000000000000..e5346af71f24
--- /dev/null
+++ b/drivers/net/wireless/ath/ath11k/debugfs.h
@@ -0,0 +1,217 @@
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _ATH11K_DEBUGFS_H_
+#define _ATH11K_DEBUGFS_H_
+
+#include "hal_tx.h"
+
+#define ATH11K_TX_POWER_MAX_VAL 70
+#define ATH11K_TX_POWER_MIN_VAL 0
+
+/* htt_dbg_ext_stats_type */
+enum ath11k_dbg_htt_ext_stats_type {
+ ATH11K_DBG_HTT_EXT_STATS_RESET = 0,
+ ATH11K_DBG_HTT_EXT_STATS_PDEV_TX = 1,
+ ATH11K_DBG_HTT_EXT_STATS_PDEV_RX = 2,
+ ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_HWQ = 3,
+ ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4,
+ ATH11K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5,
+ ATH11K_DBG_HTT_EXT_STATS_PDEV_TQM = 6,
+ ATH11K_DBG_HTT_EXT_STATS_TQM_CMDQ = 7,
+ ATH11K_DBG_HTT_EXT_STATS_TX_DE_INFO = 8,
+ ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_RATE = 9,
+ ATH11K_DBG_HTT_EXT_STATS_PDEV_RX_RATE = 10,
+ ATH11K_DBG_HTT_EXT_STATS_PEER_INFO = 11,
+ ATH11K_DBG_HTT_EXT_STATS_TX_SELFGEN_INFO = 12,
+ ATH11K_DBG_HTT_EXT_STATS_TX_MU_HWQ = 13,
+ ATH11K_DBG_HTT_EXT_STATS_RING_IF_INFO = 14,
+ ATH11K_DBG_HTT_EXT_STATS_SRNG_INFO = 15,
+ ATH11K_DBG_HTT_EXT_STATS_SFM_INFO = 16,
+ ATH11K_DBG_HTT_EXT_STATS_PDEV_TX_MU = 17,
+ ATH11K_DBG_HTT_EXT_STATS_ACTIVE_PEERS_LIST = 18,
+ ATH11K_DBG_HTT_EXT_STATS_PDEV_CCA_STATS = 19,
+ ATH11K_DBG_HTT_EXT_STATS_TWT_SESSIONS = 20,
+ ATH11K_DBG_HTT_EXT_STATS_REO_RESOURCE_STATS = 21,
+ ATH11K_DBG_HTT_EXT_STATS_TX_SOUNDING_INFO = 22,
+ ATH11K_DBG_HTT_EXT_STATS_PDEV_OBSS_PD_STATS = 23,
+ ATH11K_DBG_HTT_EXT_STATS_RING_BACKPRESSURE_STATS = 24,
+
+ /* keep this last */
+ ATH11K_DBG_HTT_NUM_EXT_STATS,
+};
+
+struct debug_htt_stats_req {
+ bool done;
+ u8 pdev_id;
+ u8 type;
+ u8 peer_addr[ETH_ALEN];
+ struct completion cmpln;
+ u32 buf_len;
+ u8 buf[];
+};
+
+struct ath_pktlog_hdr {
+ u16 flags;
+ u16 missed_cnt;
+ u16 log_type;
+ u16 size;
+ u32 timestamp;
+ u32 type_specific_data;
+ u8 payload[];
+};
+
+#define ATH11K_HTT_PEER_STATS_RESET BIT(16)
+
+#define ATH11K_HTT_STATS_BUF_SIZE (1024 * 512)
+#define ATH11K_FW_STATS_BUF_SIZE (1024 * 1024)
+
+enum ath11k_pktlog_filter {
+ ATH11K_PKTLOG_RX = 0x000000001,
+ ATH11K_PKTLOG_TX = 0x000000002,
+ ATH11K_PKTLOG_RCFIND = 0x000000004,
+ ATH11K_PKTLOG_RCUPDATE = 0x000000008,
+ ATH11K_PKTLOG_EVENT_SMART_ANT = 0x000000020,
+ ATH11K_PKTLOG_EVENT_SW = 0x000000040,
+ ATH11K_PKTLOG_ANY = 0x00000006f,
+};
+
+enum ath11k_pktlog_mode {
+ ATH11K_PKTLOG_MODE_LITE = 1,
+ ATH11K_PKTLOG_MODE_FULL = 2,
+};
+
+enum ath11k_pktlog_enum {
+ ATH11K_PKTLOG_TYPE_TX_CTRL = 1,
+ ATH11K_PKTLOG_TYPE_TX_STAT = 2,
+ ATH11K_PKTLOG_TYPE_TX_MSDU_ID = 3,
+ ATH11K_PKTLOG_TYPE_RX_STAT = 5,
+ ATH11K_PKTLOG_TYPE_RC_FIND = 6,
+ ATH11K_PKTLOG_TYPE_RC_UPDATE = 7,
+ ATH11K_PKTLOG_TYPE_TX_VIRT_ADDR = 8,
+ ATH11K_PKTLOG_TYPE_RX_CBF = 10,
+ ATH11K_PKTLOG_TYPE_RX_STATBUF = 22,
+ ATH11K_PKTLOG_TYPE_PPDU_STATS = 23,
+ ATH11K_PKTLOG_TYPE_LITE_RX = 24,
+};
+
+enum ath11k_dbg_aggr_mode {
+ ATH11K_DBG_AGGR_MODE_AUTO,
+ ATH11K_DBG_AGGR_MODE_MANUAL,
+ ATH11K_DBG_AGGR_MODE_MAX,
+};
+
+#ifdef CONFIG_ATH11K_DEBUGFS
+int ath11k_debugfs_soc_create(struct ath11k_base *ab);
+void ath11k_debugfs_soc_destroy(struct ath11k_base *ab);
+int ath11k_debugfs_pdev_create(struct ath11k_base *ab);
+void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab);
+int ath11k_debugfs_register(struct ath11k *ar);
+void ath11k_debugfs_unregister(struct ath11k *ar);
+void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb);
+
+void ath11k_debugfs_fw_stats_init(struct ath11k *ar);
+
+static inline bool ath11k_debugfs_is_pktlog_lite_mode_enabled(struct ath11k *ar)
+{
+ return (ar->debug.pktlog_mode == ATH11K_PKTLOG_MODE_LITE);
+}
+
+static inline bool ath11k_debugfs_is_pktlog_rx_stats_enabled(struct ath11k *ar)
+{
+ return (!ar->debug.pktlog_peer_valid && ar->debug.pktlog_mode);
+}
+
+static inline bool ath11k_debugfs_is_pktlog_peer_valid(struct ath11k *ar, u8 *addr)
+{
+ return (ar->debug.pktlog_peer_valid && ar->debug.pktlog_mode &&
+ ether_addr_equal(addr, ar->debug.pktlog_peer_addr));
+}
+
+static inline int ath11k_debugfs_is_extd_tx_stats_enabled(struct ath11k *ar)
+{
+ return ar->debug.extd_tx_stats;
+}
+
+static inline int ath11k_debugfs_is_extd_rx_stats_enabled(struct ath11k *ar)
+{
+ return ar->debug.extd_rx_stats;
+}
+
+static inline int ath11k_debugfs_rx_filter(struct ath11k *ar)
+{
+ return ar->debug.rx_filter;
+}
+
+#else
+static inline int ath11k_debugfs_soc_create(struct ath11k_base *ab)
+{
+ return 0;
+}
+
+static inline void ath11k_debugfs_soc_destroy(struct ath11k_base *ab)
+{
+}
+
+static inline int ath11k_debugfs_pdev_create(struct ath11k_base *ab)
+{
+ return 0;
+}
+
+static inline void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab)
+{
+}
+
+static inline int ath11k_debugfs_register(struct ath11k *ar)
+{
+ return 0;
+}
+
+static inline void ath11k_debugfs_unregister(struct ath11k *ar)
+{
+}
+
+static inline void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab,
+ struct sk_buff *skb)
+{
+}
+
+static inline void ath11k_debugfs_fw_stats_init(struct ath11k *ar)
+{
+}
+
+static inline int ath11k_debugfs_is_extd_tx_stats_enabled(struct ath11k *ar)
+{
+ return 0;
+}
+
+static inline int ath11k_debugfs_is_extd_rx_stats_enabled(struct ath11k *ar)
+{
+ return 0;
+}
+
+static inline bool ath11k_debugfs_is_pktlog_lite_mode_enabled(struct ath11k *ar)
+{
+ return false;
+}
+
+static inline bool ath11k_debugfs_is_pktlog_rx_stats_enabled(struct ath11k *ar)
+{
+ return false;
+}
+
+static inline bool ath11k_debugfs_is_pktlog_peer_valid(struct ath11k *ar, u8 *addr)
+{
+ return false;
+}
+
+static inline int ath11k_debugfs_rx_filter(struct ath11k *ar)
+{
+ return 0;
+}
+
+#endif /* CONFIG_MAC80211_DEBUGFS*/
+
+#endif /* _ATH11K_DEBUGFS_H_ */
diff --git a/drivers/net/wireless/ath/ath11k/debug_htt_stats.c b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
index ad3f08a5b031..9191ffa081c2 100644
--- a/drivers/net/wireless/ath/ath11k/debug_htt_stats.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
@@ -8,7 +8,7 @@
#include "dp_tx.h"
#include "dp_rx.h"
#include "debug.h"
-#include "debug_htt_stats.h"
+#include "debugfs_htt_stats.h"
#define HTT_DBG_OUT(buf, len, fmt, ...) \
scnprintf(buf, len, fmt "\n", ##__VA_ARGS__)
@@ -4253,8 +4253,8 @@ static int ath11k_dbg_htt_ext_stats_parse(struct ath11k_base *ab,
return 0;
}
-void ath11k_dbg_htt_ext_stats_handler(struct ath11k_base *ab,
- struct sk_buff *skb)
+void ath11k_debugfs_htt_ext_stats_handler(struct ath11k_base *ab,
+ struct sk_buff *skb)
{
struct ath11k_htt_extd_stats_msg *msg;
struct debug_htt_stats_req *stats_req;
@@ -4402,7 +4402,7 @@ static int ath11k_prep_htt_stats_cfg_params(struct ath11k *ar, u8 type,
return 0;
}
-int ath11k_dbg_htt_stats_req(struct ath11k *ar)
+int ath11k_debugfs_htt_stats_req(struct ath11k *ar)
{
struct debug_htt_stats_req *stats_req = ar->debug.htt_stats.stats_req;
u8 type = stats_req->type;
@@ -4476,7 +4476,7 @@ static int ath11k_open_htt_stats(struct inode *inode, struct file *file)
ar->debug.htt_stats.stats_req = stats_req;
stats_req->type = type;
- ret = ath11k_dbg_htt_stats_req(ar);
+ ret = ath11k_debugfs_htt_stats_req(ar);
if (ret < 0)
goto out;
@@ -4586,7 +4586,7 @@ static const struct file_operations fops_htt_stats_reset = {
.llseek = default_llseek,
};
-void ath11k_debug_htt_stats_init(struct ath11k *ar)
+void ath11k_debugfs_htt_stats_init(struct ath11k *ar)
{
spin_lock_init(&ar->debug.htt_stats.lock);
debugfs_create_file("htt_stats_type", 0600, ar->debug.debugfs_pdev,
diff --git a/drivers/net/wireless/ath/ath11k/debug_htt_stats.h b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
index 682a6ff222bd..74b2086eed9d 100644
--- a/drivers/net/wireless/ath/ath11k/debug_htt_stats.h
+++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h
@@ -1660,8 +1660,6 @@ struct htt_pdev_obss_pd_stats_tlv {
u32 num_obss_tx_ppdu_failure;
};
-void ath11k_debug_htt_stats_init(struct ath11k *ar);
-
struct htt_ring_backpressure_stats_tlv {
u32 pdev_id;
u32 current_head_idx;
@@ -1687,4 +1685,29 @@ struct htt_ring_backpressure_stats_tlv {
u32 backpressure_hist[5];
};
+#ifdef CONFIG_ATH11K_DEBUGFS
+
+void ath11k_debugfs_htt_stats_init(struct ath11k *ar);
+void ath11k_debugfs_htt_ext_stats_handler(struct ath11k_base *ab,
+ struct sk_buff *skb);
+int ath11k_debugfs_htt_stats_req(struct ath11k *ar);
+
+#else /* CONFIG_ATH11K_DEBUGFS */
+
+static inline void ath11k_debugfs_htt_stats_init(struct ath11k *ar)
+{
+}
+
+static inline void ath11k_debugfs_htt_ext_stats_handler(struct ath11k_base *ab,
+ struct sk_buff *skb)
+{
+}
+
+static inline int ath11k_debugfs_htt_stats_req(struct ath11k *ar)
+{
+ return 0;
+}
+
+#endif /* CONFIG_ATH11K_DEBUGFS */
+
#endif
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
index 7308ed254232..270c0edbb10f 100644
--- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c
+++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c
@@ -5,16 +5,16 @@
#include <linux/vmalloc.h>
+#include "debugfs_sta.h"
#include "core.h"
#include "peer.h"
#include "debug.h"
#include "dp_tx.h"
-#include "debug_htt_stats.h"
+#include "debugfs_htt_stats.h"
-void
-ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
- struct ath11k_per_peer_tx_stats *peer_stats,
- u8 legacy_rate_idx)
+void ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
+ struct ath11k_per_peer_tx_stats *peer_stats,
+ u8 legacy_rate_idx)
{
struct rate_info *txrate = &arsta->txrate;
struct ath11k_htt_tx_stats *tx_stats;
@@ -125,9 +125,9 @@ ath11k_accumulate_per_peer_tx_stats(struct ath11k_sta *arsta,
tx_stats->tx_duration += peer_stats->duration;
}
-void ath11k_update_per_peer_stats_from_txcompl(struct ath11k *ar,
- struct sk_buff *msdu,
- struct hal_tx_status *ts)
+void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
+ struct sk_buff *msdu,
+ struct hal_tx_status *ts)
{
struct ath11k_base *ab = ar->ab;
struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;
@@ -200,7 +200,8 @@ void ath11k_update_per_peer_stats_from_txcompl(struct ath11k *ar,
arsta->txrate.nss = arsta->last_txrate.nss;
arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);
- ath11k_accumulate_per_peer_tx_stats(arsta, peer_stats, rate_idx);
+ ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx);
+
err_out:
spin_unlock_bh(&ab->base_lock);
rcu_read_unlock();
@@ -428,7 +429,7 @@ ath11k_dbg_sta_open_htt_peer_stats(struct inode *inode, struct file *file)
ar->debug.htt_stats.stats_req = stats_req;
stats_req->type = ATH11K_DBG_HTT_EXT_STATS_PEER_INFO;
memcpy(stats_req->peer_addr, sta->addr, ETH_ALEN);
- ret = ath11k_dbg_htt_stats_req(ar);
+ ret = ath11k_debugfs_htt_stats_req(ar);
mutex_unlock(&ar->conf_mutex);
if (ret < 0)
goto out;
@@ -820,15 +821,15 @@ static const struct file_operations fops_htt_peer_stats_reset = {
.llseek = default_llseek,
};
-void ath11k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, struct dentry *dir)
+void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct dentry *dir)
{
struct ath11k *ar = hw->priv;
- if (ath11k_debug_is_extd_tx_stats_enabled(ar))
+ if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))
debugfs_create_file("tx_stats", 0400, dir, sta,
&fops_tx_stats);
- if (ath11k_debug_is_extd_rx_stats_enabled(ar))
+ if (ath11k_debugfs_is_extd_rx_stats_enabled(ar))
debugfs_create_file("rx_stats", 0400, dir, sta,
&fops_rx_stats);
diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.h b/drivers/net/wireless/ath/ath11k/debugfs_sta.h
new file mode 100644
index 000000000000..18dc65d9edcf
--- /dev/null
+++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _ATH11K_DEBUGFS_STA_H_
+#define _ATH11K_DEBUGFS_STA_H_
+
+#include <net/mac80211.h>
+
+#include "core.h"
+#include "hal_tx.h"
+
+#ifdef CONFIG_ATH11K_DEBUGFS
+
+void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct dentry *dir);
+void ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
+ struct ath11k_per_peer_tx_stats *peer_stats,
+ u8 legacy_rate_idx);
+void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
+ struct sk_buff *msdu,
+ struct hal_tx_status *ts);
+
+#else /* CONFIG_ATH11K_DEBUGFS */
+
+#define ath11k_debugfs_sta_op_add NULL
+
+static inline void
+ath11k_debugfs_sta_add_tx_stats(struct ath11k_sta *arsta,
+ struct ath11k_per_peer_tx_stats *peer_stats,
+ u8 legacy_rate_idx)
+{
+}
+
+static inline void ath11k_debugfs_sta_update_txcompl(struct ath11k *ar,
+ struct sk_buff *msdu,
+ struct hal_tx_status *ts)
+{
+}
+
+#endif /* CONFIG_ATH11K_DEBUGFS */
+
+#endif /* _ATH11K_DEBUGFS_STA_H_ */
diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c
index 2617ec221775..677e2d9fec11 100644
--- a/drivers/net/wireless/ath/ath11k/dp.c
+++ b/drivers/net/wireless/ath/ath11k/dp.c
@@ -832,7 +832,7 @@ void ath11k_dp_pdev_free(struct ath11k_base *ab)
for (i = 0; i < ab->num_radios; i++) {
ar = ab->pdevs[i].ar;
ath11k_dp_rx_pdev_free(ab, i);
- ath11k_debug_unregister(ar);
+ ath11k_debugfs_unregister(ar);
ath11k_dp_rx_pdev_mon_detach(ar);
}
}
diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index a507c1231a59..345eaa4f20f3 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -9,6 +9,8 @@
#include <crypto/hash.h>
#include "core.h"
#include "debug.h"
+#include "debugfs_htt_stats.h"
+#include "debugfs_sta.h"
#include "hal_desc.h"
#include "hw.h"
#include "dp_rx.h"
@@ -1433,9 +1435,8 @@ ath11k_update_per_peer_tx_stats(struct ath11k *ar,
HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) +
HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags);
- if (ath11k_debug_is_extd_tx_stats_enabled(ar))
- ath11k_accumulate_per_peer_tx_stats(arsta,
- peer_stats, rate_idx);
+ if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))
+ ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx);
}
spin_unlock_bh(&ab->base_lock);
@@ -1511,7 +1512,7 @@ static int ath11k_htt_pull_ppdu_stats(struct ath11k_base *ab,
goto exit;
}
- if (ath11k_debug_is_pktlog_lite_mode_enabled(ar))
+ if (ath11k_debugfs_is_pktlog_lite_mode_enabled(ar))
trace_ath11k_htt_ppdu_stats(ar, skb->data, len);
ppdu_info = ath11k_dp_htt_get_ppdu_desc(ar, ppdu_id);
@@ -1658,7 +1659,7 @@ void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab,
ath11k_htt_pull_ppdu_stats(ab, skb);
break;
case HTT_T2H_MSG_TYPE_EXT_STATS_CONF:
- ath11k_dbg_htt_ext_stats_handler(ab, skb);
+ ath11k_debugfs_htt_ext_stats_handler(ab, skb);
break;
case HTT_T2H_MSG_TYPE_PKTLOG:
ath11k_htt_pktlog(ab, skb);
@@ -2909,7 +2910,7 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
memset(&ppdu_info, 0, sizeof(ppdu_info));
ppdu_info.peer_id = HAL_INVALID_PEERID;
- if (ath11k_debug_is_pktlog_rx_stats_enabled(ar))
+ if (ath11k_debugfs_is_pktlog_rx_stats_enabled(ar))
trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE);
hal_status = ath11k_hal_rx_parse_mon_status(ab, &ppdu_info, skb);
@@ -2937,7 +2938,7 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
arsta = (struct ath11k_sta *)peer->sta->drv_priv;
ath11k_dp_rx_update_peer_stats(arsta, &ppdu_info);
- if (ath11k_debug_is_pktlog_peer_valid(ar, peer->addr))
+ if (ath11k_debugfs_is_pktlog_peer_valid(ar, peer->addr))
trace_ath11k_htt_rxdesc(ar, skb->data, DP_RX_BUFFER_SIZE);
spin_unlock_bh(&ab->base_lock);
diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c
index 5933800ccd64..98209cccd639 100644
--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
@@ -6,6 +6,7 @@
#include "core.h"
#include "dp_tx.h"
#include "debug.h"
+#include "debugfs_sta.h"
#include "hw.h"
#include "peer.h"
@@ -457,7 +458,7 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar,
(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
- if (ath11k_debug_is_extd_tx_stats_enabled(ar)) {
+ if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) {
if (ts->flags & HAL_TX_STATUS_FLAGS_FIRST_MSDU) {
if (ar->last_ppdu_id == 0) {
ar->last_ppdu_id = ts->ppdu_id;
@@ -465,12 +466,12 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar,
ar->cached_ppdu_id == ar->last_ppdu_id) {
ar->cached_ppdu_id = ar->last_ppdu_id;
ar->cached_stats.is_ampdu = true;
- ath11k_update_per_peer_stats_from_txcompl(ar, msdu, ts);
+ ath11k_debugfs_sta_update_txcompl(ar, msdu, ts);
memset(&ar->cached_stats, 0,
sizeof(struct ath11k_per_peer_tx_stats));
} else {
ar->cached_stats.is_ampdu = false;
- ath11k_update_per_peer_stats_from_txcompl(ar, msdu, ts);
+ ath11k_debugfs_sta_update_txcompl(ar, msdu, ts);
memset(&ar->cached_stats, 0,
sizeof(struct ath11k_per_peer_tx_stats));
}
diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c
index e9e354fc11fa..4de2350dfbf3 100644
--- a/drivers/net/wireless/ath/ath11k/htc.c
+++ b/drivers/net/wireless/ath/ath11k/htc.c
@@ -50,15 +50,6 @@ static struct sk_buff *ath11k_htc_build_tx_ctrl_skb(void *ab)
return skb;
}
-static inline void ath11k_htc_restore_tx_skb(struct ath11k_htc *htc,
- struct sk_buff *skb)
-{
- struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
-
- dma_unmap_single(htc->ab->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
- skb_pull(skb, sizeof(struct ath11k_htc_hdr));
-}
-
static void ath11k_htc_prepare_tx_skb(struct ath11k_htc_ep *ep,
struct sk_buff *skb)
{
diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c
index 5f2eb2032118..11a411b76fe4 100644
--- a/drivers/net/wireless/ath/ath11k/hw.c
+++ b/drivers/net/wireless/ath/ath11k/hw.c
@@ -74,7 +74,6 @@ static void ath11k_init_wmi_config_qca6390(struct ath11k_base *ab,
config->beacon_tx_offload_max_vdev = 0x2;
config->num_multicast_filter_entries = 0x20;
config->num_wow_filters = 0x16;
- config->num_keep_alive_pattern = 0x1;
config->num_keep_alive_pattern = 0;
}
@@ -104,7 +103,12 @@ static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab,
config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI;
- config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI;
+
+ if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))
+ config->rx_decap_mode = TARGET_DECAP_MODE_RAW;
+ else
+ config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI;
+
config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS;
config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV;
config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV;
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index 57960a7c09a4..975d44e9c083 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -155,6 +155,7 @@ struct ath11k_hw_params {
bool vdev_start_delay;
bool htt_peer_map_v2;
bool tcl_0_only;
+ u8 spectral_fft_sz;
};
struct ath11k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 7d7b4d80c47f..e0cac9b61af8 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -14,6 +14,7 @@
#include "dp_rx.h"
#include "testmode.h"
#include "peer.h"
+#include "debugfs_sta.h"
#define CHAN2G(_channel, _freq, _flags) { \
.band = NL80211_BAND_2GHZ, \
@@ -2967,7 +2968,7 @@ static int ath11k_mac_station_add(struct ath11k *ar,
ath11k_dbg(ab, ATH11K_DBG_MAC, "Added peer: %pM for VDEV: %d\n",
sta->addr, arvif->vdev_id);
- if (ath11k_debug_is_extd_tx_stats_enabled(ar)) {
+ if (ath11k_debugfs_is_extd_tx_stats_enabled(ar)) {
arsta->tx_stats = kzalloc(sizeof(*arsta->tx_stats), GFP_KERNEL);
if (!arsta->tx_stats) {
ret = -ENOMEM;
@@ -4101,7 +4102,7 @@ static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable)
if (enable) {
tlv_filter = ath11k_mac_mon_status_filter_default;
- tlv_filter.rx_filter = ath11k_debug_rx_filter(ar);
+ tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar);
}
for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
@@ -5873,7 +5874,7 @@ static const struct ieee80211_ops ath11k_ops = {
.sta_statistics = ath11k_mac_op_sta_statistics,
CFG80211_TESTMODE_CMD(ath11k_tm_cmd)
#ifdef CONFIG_ATH11K_DEBUGFS
- .sta_add_debugfs = ath11k_sta_add_debugfs,
+ .sta_add_debugfs = ath11k_debugfs_sta_op_add,
#endif
};
@@ -6233,7 +6234,7 @@ static int __ath11k_mac_register(struct ath11k *ar)
goto err_free;
}
- ret = ath11k_debug_register(ar);
+ ret = ath11k_debugfs_register(ar);
if (ret) {
ath11k_err(ar->ab, "debugfs registration failed: %d\n", ret);
goto err_free;
diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c
index 92fd8a4df1f2..ac2a8cfdc1c0 100644
--- a/drivers/net/wireless/ath/ath11k/spectral.c
+++ b/drivers/net/wireless/ath/ath11k/spectral.c
@@ -17,8 +17,6 @@
#define ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS 32
#define ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS 256
-#define ATH11K_SPECTRAL_SAMPLE_FFT_BIN_MASK 0xFF
-
#define ATH11K_SPECTRAL_SCAN_COUNT_MAX 4095
/* Max channel computed by sum of 2g and 5g band channels */
@@ -557,16 +555,16 @@ static u8 ath11k_spectral_get_max_exp(s8 max_index, u8 max_magnitude,
return max_exp;
}
-static void ath11k_spectral_parse_16bit_fft(u8 *outbins, u8 *inbins, int num_bins)
+static void ath11k_spectral_parse_fft(u8 *outbins, u8 *inbins, int num_bins, u8 fft_sz)
{
- int i;
- __le16 *data = (__le16 *)inbins;
+ int i, j;
i = 0;
+ j = 0;
while (i < num_bins) {
- outbins[i] = (__le16_to_cpu(data[i])) &
- ATH11K_SPECTRAL_SAMPLE_FFT_BIN_MASK;
+ outbins[i] = inbins[j];
i++;
+ j += fft_sz;
}
}
@@ -588,6 +586,12 @@ int ath11k_spectral_process_fft(struct ath11k *ar,
lockdep_assert_held(&ar->spectral.lock);
+ if (!ab->hw_params.spectral_fft_sz) {
+ ath11k_warn(ab, "invalid bin size type for hw rev %d\n",
+ ab->hw_rev);
+ return -EINVAL;
+ }
+
tlv = (struct spectral_tlv *)data;
tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, __le32_to_cpu(tlv->header));
/* convert Dword into bytes */
@@ -649,9 +653,8 @@ int ath11k_spectral_process_fft(struct ath11k *ar,
freq = summary->meta.freq2;
fft_sample->freq2 = __cpu_to_be16(freq);
- ath11k_spectral_parse_16bit_fft(fft_sample->data,
- fft_report->bins,
- num_bins);
+ ath11k_spectral_parse_fft(fft_sample->data, fft_report->bins, num_bins,
+ ab->hw_params.spectral_fft_sz);
fft_sample->max_exp = ath11k_spectral_get_max_exp(fft_sample->max_index,
search.peak_mag,
@@ -959,6 +962,9 @@ int ath11k_spectral_init(struct ath11k_base *ab)
ab->wmi_ab.svc_map))
return 0;
+ if (!ab->hw_params.spectral_fft_sz)
+ return 0;
+
for (i = 0; i < ab->num_radios; i++) {
ar = ab->pdevs[i].ar;
sp = &ar->spectral;
diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c
index adde14a390ec..82392bc7123d 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.c
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
@@ -3342,55 +3342,6 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab)
memset(&init_param, 0, sizeof(init_param));
memset(&config, 0, sizeof(config));
- config.num_vdevs = ab->num_radios * TARGET_NUM_VDEVS;
-
- if (ab->num_radios == 2) {
- config.num_peers = TARGET_NUM_PEERS(DBS);
- config.num_tids = TARGET_NUM_TIDS(DBS);
- } else if (ab->num_radios == 3) {
- config.num_peers = TARGET_NUM_PEERS(DBS_SBS);
- config.num_tids = TARGET_NUM_TIDS(DBS_SBS);
- } else {
- /* Control should not reach here */
- config.num_peers = TARGET_NUM_PEERS(SINGLE);
- config.num_tids = TARGET_NUM_TIDS(SINGLE);
- }
- config.num_offload_peers = TARGET_NUM_OFFLD_PEERS;
- config.num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS;
- config.num_peer_keys = TARGET_NUM_PEER_KEYS;
- config.ast_skid_limit = TARGET_AST_SKID_LIMIT;
- config.tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
- config.rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
- config.rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI;
- config.rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI;
- config.rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI;
- config.rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI;
- config.rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI;
-
- if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))
- config.rx_decap_mode = TARGET_DECAP_MODE_RAW;
-
- config.scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS;
- config.bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV;
- config.roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV;
- config.roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES;
- config.num_mcast_groups = TARGET_NUM_MCAST_GROUPS;
- config.num_mcast_table_elems = TARGET_NUM_MCAST_TABLE_ELEMS;
- config.mcast2ucast_mode = TARGET_MCAST2UCAST_MODE;
- config.tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE;
- config.num_wds_entries = TARGET_NUM_WDS_ENTRIES;
- config.dma_burst_size = TARGET_DMA_BURST_SIZE;
- config.rx_skip_defrag_timeout_dup_detection_check =
- TARGET_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;
- config.vow_config = TARGET_VOW_CONFIG;
- config.gtk_offload_max_vdev = TARGET_GTK_OFFLOAD_MAX_VDEV;
- config.num_msdu_desc = TARGET_NUM_MSDU_DESC;
- config.beacon_tx_offload_max_vdev = ab->num_radios * TARGET_MAX_BCN_OFFLD;
- config.rx_batchmode = TARGET_RX_BATCHMODE;
- config.peer_map_unmap_v2_support = 1;
- config.twt_ap_pdev_count = ab->num_radios;
- config.twt_ap_sta_count = 1000;
-
ab->hw_params.hw_ops->wmi_init_config(ab, &config);
memcpy(&wmi_sc->wlan_resource_config, &config, sizeof(config));
@@ -6301,7 +6252,7 @@ static void ath11k_peer_assoc_conf_event(struct ath11k_base *ab, struct sk_buff
static void ath11k_update_stats_event(struct ath11k_base *ab, struct sk_buff *skb)
{
- ath11k_debug_fw_stats_process(ab, skb);
+ ath11k_debugfs_fw_stats_process(ab, skb);
}
/* PDEV_CTL_FAILSAFE_CHECK_EVENT is received from FW when the frequency scanned
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 2eaba1ccab20..4b41160e5d38 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -161,33 +161,14 @@ static int reg_show(struct seq_file *seq, void *p)
return 0;
}
-static const struct seq_operations register_seq_ops = {
+static const struct seq_operations registers_sops = {
.start = reg_start,
.next = reg_next,
.stop = reg_stop,
.show = reg_show
};
-static int open_file_registers(struct inode *inode, struct file *file)
-{
- struct seq_file *s;
- int res;
- res = seq_open(file, &register_seq_ops);
- if (res == 0) {
- s = file->private_data;
- s->private = inode->i_private;
- }
- return res;
-}
-
-static const struct file_operations fops_registers = {
- .open = open_file_registers,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
- .owner = THIS_MODULE,
-};
-
+DEFINE_SEQ_ATTRIBUTE(registers);
/* debugfs: beacons */
@@ -1005,7 +986,7 @@ ath5k_debug_init_device(struct ath5k_hw *ah)
return;
debugfs_create_file("debug", 0600, phydir, ah, &fops_debug);
- debugfs_create_file("registers", 0400, phydir, ah, &fops_registers);
+ debugfs_create_file("registers", 0400, phydir, ah, &registers_fops);
debugfs_create_file("beacon", 0600, phydir, ah, &fops_beacon);
debugfs_create_file("reset", 0200, phydir, ah, &fops_reset);
debugfs_create_file("antenna", 0600, phydir, ah, &fops_antenna);
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index a4339cca661f..dbc47702a268 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -2639,6 +2639,11 @@ int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 if_idx, u8 traffic_class,
return -EINVAL;
}
+ if (tsid >= 16) {
+ ath6kl_err("invalid tsid: %d\n", tsid);
+ return -EINVAL;
+ }
+
skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
if (!skb)
return -ENOMEM;
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 38f07420f4f9..860da13bfb6a 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -449,10 +449,19 @@ static void hif_usb_stop(void *hif_handle)
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
/* The pending URBs have to be canceled. */
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
&hif_dev->tx.tx_pending, list) {
+ usb_get_urb(tx_buf->urb);
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
usb_kill_urb(tx_buf->urb);
+ list_del(&tx_buf->list);
+ usb_free_urb(tx_buf->urb);
+ kfree(tx_buf->buf);
+ kfree(tx_buf);
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
}
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
}
@@ -762,27 +771,37 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
unsigned long flags;
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
&hif_dev->tx.tx_buf, list) {
+ usb_get_urb(tx_buf->urb);
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
usb_kill_urb(tx_buf->urb);
list_del(&tx_buf->list);
usb_free_urb(tx_buf->urb);
kfree(tx_buf->buf);
kfree(tx_buf);
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
}
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
hif_dev->tx.flags |= HIF_USB_TX_FLUSH;
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
&hif_dev->tx.tx_pending, list) {
+ usb_get_urb(tx_buf->urb);
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
usb_kill_urb(tx_buf->urb);
list_del(&tx_buf->list);
usb_free_urb(tx_buf->urb);
kfree(tx_buf->buf);
kfree(tx_buf);
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
}
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
}
diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h
index 573799274a02..65ef893f2736 100644
--- a/drivers/net/wireless/ath/wcn36xx/hal.h
+++ b/drivers/net/wireless/ath/wcn36xx/hal.h
@@ -726,7 +726,129 @@ enum pe_stats_mask {
#define WCN36XX_HAL_CFG_AP_LINK_MONITOR_TIMEOUT 102
#define WCN36XX_HAL_CFG_BTC_DWELL_TIME_MULTIPLIER 103
#define WCN36XX_HAL_CFG_ENABLE_TDLS_OXYGEN_MODE 104
-#define WCN36XX_HAL_CFG_MAX_PARAMS 105
+#define WCN36XX_HAL_CFG_ENABLE_NAT_KEEP_ALIVE_FILTER 105
+#define WCN36XX_HAL_CFG_ENABLE_SAP_OBSS_PROT 106
+#define WCN36XX_HAL_CFG_PSPOLL_DATA_RECEP_TIMEOUT 107
+#define WCN36XX_HAL_CFG_TDLS_PUAPSD_BUFFER_STA_CAPABLE 108
+#define WCN36XX_HAL_CFG_TDLS_PUAPSD_MASK 109
+#define WCN36XX_HAL_CFG_TDLS_PUAPSD_INACTIVITY_TIME 110
+#define WCN36XX_HAL_CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD 111
+#define WCN36XX_HAL_CFG_ANTENNA_DIVERSITY 112
+#define WCN36XX_HAL_CFG_ATH_DISABLE 113
+#define WCN36XX_HAL_CFG_FLEXCONNECT_POWER_FACTOR 114
+#define WCN36XX_HAL_CFG_ENABLE_ADAPTIVE_RX_DRAIN 115
+#define WCN36XX_HAL_CFG_TDLS_OFF_CHANNEL_CAPABLE 116
+#define WCN36XX_HAL_CFG_MWS_COEX_V1_WAN_FREQ 117
+#define WCN36XX_HAL_CFG_MWS_COEX_V1_WLAN_FREQ 118
+#define WCN36XX_HAL_CFG_MWS_COEX_V1_CONFIG 119
+#define WCN36XX_HAL_CFG_MWS_COEX_V1_CONFIG2 120
+#define WCN36XX_HAL_CFG_MWS_COEX_V2_WAN_FREQ 121
+#define WCN36XX_HAL_CFG_MWS_COEX_V2_WLAN_FREQ 122
+#define WCN36XX_HAL_CFG_MWS_COEX_V2_CONFIG 123
+#define WCN36XX_HAL_CFG_MWS_COEX_V2_CONFIG2 124
+#define WCN36XX_HAL_CFG_MWS_COEX_V3_WAN_FREQ 125
+#define WCN36XX_HAL_CFG_MWS_COEX_V3_WLAN_FREQ 126
+#define WCN36XX_HAL_CFG_MWS_COEX_V3_CONFIG 127
+#define WCN36XX_HAL_CFG_MWS_COEX_V3_CONFIG2 128
+#define WCN36XX_HAL_CFG_MWS_COEX_V4_WAN_FREQ 129
+#define WCN36XX_HAL_CFG_MWS_COEX_V4_WLAN_FREQ 130
+#define WCN36XX_HAL_CFG_MWS_COEX_V4_CONFIG 131
+#define WCN36XX_HAL_CFG_MWS_COEX_V4_CONFIG2 132
+#define WCN36XX_HAL_CFG_MWS_COEX_V5_WAN_FREQ 133
+#define WCN36XX_HAL_CFG_MWS_COEX_V5_WLAN_FREQ 134
+#define WCN36XX_HAL_CFG_MWS_COEX_V5_CONFIG 135
+#define WCN36XX_HAL_CFG_MWS_COEX_V5_CONFIG2 136
+#define WCN36XX_HAL_CFG_MWS_COEX_V6_WAN_FREQ 137
+#define WCN36XX_HAL_CFG_MWS_COEX_V6_WLAN_FREQ 138
+#define WCN36XX_HAL_CFG_MWS_COEX_V6_CONFIG 139
+#define WCN36XX_HAL_CFG_MWS_COEX_V6_CONFIG2 140
+#define WCN36XX_HAL_CFG_MWS_COEX_V7_WAN_FREQ 141
+#define WCN36XX_HAL_CFG_MWS_COEX_V7_WLAN_FREQ 142
+#define WCN36XX_HAL_CFG_MWS_COEX_V7_CONFIG 143
+#define WCN36XX_HAL_CFG_MWS_COEX_V7_CONFIG2 144
+#define WCN36XX_HAL_CFG_MWS_COEX_V8_WAN_FREQ 145
+#define WCN36XX_HAL_CFG_MWS_COEX_V8_WLAN_FREQ 146
+#define WCN36XX_HAL_CFG_MWS_COEX_V8_CONFIG 147
+#define WCN36XX_HAL_CFG_MWS_COEX_V8_CONFIG2 148
+#define WCN36XX_HAL_CFG_MWS_COEX_V9_WAN_FREQ 149
+#define WCN36XX_HAL_CFG_MWS_COEX_V9_WLAN_FREQ 150
+#define WCN36XX_HAL_CFG_MWS_COEX_V9_CONFIG 151
+#define WCN36XX_HAL_CFG_MWS_COEX_V9_CONFIG2 152
+#define WCN36XX_HAL_CFG_MWS_COEX_V10_WAN_FREQ 153
+#define WCN36XX_HAL_CFG_MWS_COEX_V10_WLAN_FREQ 154
+#define WCN36XX_HAL_CFG_MWS_COEX_V10_CONFIG 155
+#define WCN36XX_HAL_CFG_MWS_COEX_V10_CONFIG2 156
+#define WCN36XX_HAL_CFG_MWS_COEX_MODEM_BACKOFF 157
+#define WCN36XX_HAL_CFG_MWS_COEX_CONFIG1 158
+#define WCN36XX_HAL_CFG_MWS_COEX_CONFIG2 159
+#define WCN36XX_HAL_CFG_MWS_COEX_CONFIG3 160
+#define WCN36XX_HAL_CFG_MWS_COEX_CONFIG4 161
+#define WCN36XX_HAL_CFG_MWS_COEX_CONFIG5 162
+#define WCN36XX_HAL_CFG_MWS_COEX_CONFIG6 163
+#define WCN36XX_HAL_CFG_SAR_POWER_BACKOFF 164
+#define WCN36XX_HAL_CFG_GO_LINK_MONITOR_TIMEOUT 165
+#define WCN36XX_HAL_CFG_BTC_STATIC_OPP_WLAN_ACTIVE_WLAN_LEN 166
+#define WCN36XX_HAL_CFG_BTC_STATIC_OPP_WLAN_ACTIVE_BT_LEN 167
+#define WCN36XX_HAL_CFG_BTC_SAP_STATIC_OPP_ACTIVE_WLAN_LEN 168
+#define WCN36XX_HAL_CFG_BTC_SAP_STATIC_OPP_ACTIVE_BT_LEN 169
+#define WCN36XX_HAL_CFG_RMC_FIXED_RATE 170
+#define WCN36XX_HAL_CFG_ASD_PROBE_INTERVAL 171
+#define WCN36XX_HAL_CFG_ASD_TRIGGER_THRESHOLD 172
+#define WCN36XX_HAL_CFG_ASD_RTT_RSSI_HYST_THRESHOLD 173
+#define WCN36XX_HAL_CFG_BTC_CTS2S_ON_STA_DURING_SCO 174
+#define WCN36XX_HAL_CFG_SHORT_PREAMBLE 175
+#define WCN36XX_HAL_CFG_SHORT_SLOT_TIME 176
+#define WCN36XX_HAL_CFG_DELAYED_BA 177
+#define WCN36XX_HAL_CFG_IMMEDIATE_BA 178
+#define WCN36XX_HAL_CFG_DOT11_MODE 179
+#define WCN36XX_HAL_CFG_HT_CAPS 180
+#define WCN36XX_HAL_CFG_AMPDU_PARAMS 181
+#define WCN36XX_HAL_CFG_TX_BF_INFO 182
+#define WCN36XX_HAL_CFG_ASC_CAP_INFO 183
+#define WCN36XX_HAL_CFG_EXT_HT_CAPS 184
+#define WCN36XX_HAL_CFG_QOS_ENABLED 185
+#define WCN36XX_HAL_CFG_WME_ENABLED 186
+#define WCN36XX_HAL_CFG_WSM_ENABLED 187
+#define WCN36XX_HAL_CFG_WMM_ENABLED 188
+#define WCN36XX_HAL_CFG_UAPSD_PER_AC_BITMASK 189
+#define WCN36XX_HAL_CFG_MCS_RATES 190
+#define WCN36XX_HAL_CFG_VHT_CAPS 191
+#define WCN36XX_HAL_CFG_VHT_RX_SUPP_MCS 192
+#define WCN36XX_HAL_CFG_VHT_TX_SUPP_MCS 193
+#define WCN36XX_HAL_CFG_RA_FILTER_ENABLE 194
+#define WCN36XX_HAL_CFG_RA_RATE_LIMIT_INTERVAL 195
+#define WCN36XX_HAL_CFG_BTC_FATAL_HID_NSNIFF_BLK 196
+#define WCN36XX_HAL_CFG_BTC_CRITICAL_HID_NSNIFF_BLK 197
+#define WCN36XX_HAL_CFG_BTC_DYN_A2DP_TX_QUEUE_THOLD 198
+#define WCN36XX_HAL_CFG_BTC_DYN_OPP_TX_QUEUE_THOLD 199
+#define WCN36XX_HAL_CFG_LINK_FAIL_TIMEOUT 200
+#define WCN36XX_HAL_CFG_MAX_UAPSD_CONSEC_SP 201
+#define WCN36XX_HAL_CFG_MAX_UAPSD_CONSEC_RX_CNT 202
+#define WCN36XX_HAL_CFG_MAX_UAPSD_CONSEC_TX_CNT 203
+#define WCN36XX_HAL_CFG_MAX_UAPSD_CONSEC_RX_CNT_MEAS_WINDOW 204
+#define WCN36XX_HAL_CFG_MAX_UAPSD_CONSEC_TX_CNT_MEAS_WINDOW 205
+#define WCN36XX_HAL_CFG_MAX_PSPOLL_IN_WMM_UAPSD_PS_MODE 206
+#define WCN36XX_HAL_CFG_MAX_UAPSD_INACTIVITY_INTERVALS 207
+#define WCN36XX_HAL_CFG_ENABLE_DYNAMIC_WMMPS 208
+#define WCN36XX_HAL_CFG_BURST_MODE_BE_TXOP_VALUE 209
+#define WCN36XX_HAL_CFG_ENABLE_DYNAMIC_RA_START_RATE 210
+#define WCN36XX_HAL_CFG_BTC_FAST_WLAN_CONN_PREF 211
+#define WCN36XX_HAL_CFG_ENABLE_RTSCTS_HTVHT 212
+#define WCN36XX_HAL_CFG_BTC_STATIC_OPP_WLAN_IDLE_WLAN_LEN 213
+#define WCN36XX_HAL_CFG_BTC_STATIC_OPP_WLAN_IDLE_BT_LEN 214
+#define WCN36XX_HAL_CFG_LINK_FAIL_TX_CNT 215
+#define WCN36XX_HAL_CFG_TOGGLE_ARP_BDRATES 216
+#define WCN36XX_HAL_CFG_OPTIMIZE_CA_EVENT 217
+#define WCN36XX_HAL_CFG_EXT_SCAN_CONC_MODE 218
+#define WCN36XX_HAL_CFG_BAR_WAKEUP_HOST_DISABLE 219
+#define WCN36XX_HAL_CFG_SAR_BOFFSET_CORRECTION_ENABLE 220
+#define WCN36XX_HAL_CFG_UNITS_OF_BCN_WAIT_TIME 221
+#define WCN36XX_HAL_CFG_CONS_BCNMISS_COUNT 222
+#define WCN36XX_HAL_CFG_BTC_DISABLE_WLAN_LINK_CRITICAL 223
+#define WCN36XX_HAL_CFG_DISABLE_SCAN_DURING_SCO 224
+#define WCN36XX_HAL_CFG_TRIGGER_NULLFRAME_BEFORE_HB 225
+#define WCN36XX_HAL_CFG_ENABLE_POWERSAVE_OFFLOAD 226
+#define WCN36XX_HAL_CFG_MAX_PARAMS 227
/* Specify the starting bitrate, 11B and 11A/G rates can be specified in
* multiples of 0.5 So for 5.5 mbps => 11. for MCS 0 - 7 rates, Bit 7 should
@@ -1592,9 +1714,15 @@ struct wcn36xx_hal_config_sta_params_v1 {
u8 reserved:4;
/* These rates are the intersection of peer and self capabilities. */
- struct wcn36xx_hal_supported_rates supported_rates;
+ struct wcn36xx_hal_supported_rates_v1 supported_rates;
+
+ u8 vht_capable;
+ u8 vht_tx_channel_width_set;
+
} __packed;
+#define WCN36XX_DIFF_STA_PARAMS_V1_NOVHT 10
+
struct wcn36xx_hal_config_sta_req_msg_v1 {
struct wcn36xx_hal_msg_header header;
struct wcn36xx_hal_config_sta_params_v1 sta_params;
@@ -2015,8 +2143,14 @@ struct wcn36xx_hal_config_bss_params_v1 {
* "STA context"
*/
struct wcn36xx_hal_config_sta_params_v1 sta;
+
+ u8 vht_capable;
+ u8 vht_tx_channel_width_set;
+
} __packed;
+#define WCN36XX_DIFF_BSS_PARAMS_V1_NOVHT (WCN36XX_DIFF_STA_PARAMS_V1_NOVHT + 2)
+
struct wcn36xx_hal_config_bss_req_msg_v1 {
struct wcn36xx_hal_msg_header header;
struct wcn36xx_hal_config_bss_params_v1 bss_params;
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index c5e94ba8f941..706728fba72d 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -39,10 +39,10 @@ MODULE_PARM_DESC(debug_mask, "Debugging mask");
.max_power = 25, \
}
-#define CHAN5G(_freq, _idx) { \
+#define CHAN5G(_freq, _idx, _phy_val) { \
.band = NL80211_BAND_5GHZ, \
.center_freq = (_freq), \
- .hw_value = (_idx), \
+ .hw_value = (_phy_val) << HW_VALUE_PHY_SHIFT | HW_VALUE_CHANNEL(_idx), \
.max_power = 25, \
}
@@ -67,29 +67,29 @@ static struct ieee80211_channel wcn_2ghz_channels[] = {
};
static struct ieee80211_channel wcn_5ghz_channels[] = {
- CHAN5G(5180, 36),
- CHAN5G(5200, 40),
- CHAN5G(5220, 44),
- CHAN5G(5240, 48),
- CHAN5G(5260, 52),
- CHAN5G(5280, 56),
- CHAN5G(5300, 60),
- CHAN5G(5320, 64),
- CHAN5G(5500, 100),
- CHAN5G(5520, 104),
- CHAN5G(5540, 108),
- CHAN5G(5560, 112),
- CHAN5G(5580, 116),
- CHAN5G(5600, 120),
- CHAN5G(5620, 124),
- CHAN5G(5640, 128),
- CHAN5G(5660, 132),
- CHAN5G(5700, 140),
- CHAN5G(5745, 149),
- CHAN5G(5765, 153),
- CHAN5G(5785, 157),
- CHAN5G(5805, 161),
- CHAN5G(5825, 165)
+ CHAN5G(5180, 36, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),
+ CHAN5G(5200, 40, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW),
+ CHAN5G(5220, 44, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),
+ CHAN5G(5240, 48, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH),
+ CHAN5G(5260, 52, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),
+ CHAN5G(5280, 56, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW),
+ CHAN5G(5300, 60, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),
+ CHAN5G(5320, 64, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH),
+ CHAN5G(5500, 100, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),
+ CHAN5G(5520, 104, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW),
+ CHAN5G(5540, 108, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),
+ CHAN5G(5560, 112, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH),
+ CHAN5G(5580, 116, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),
+ CHAN5G(5600, 120, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW),
+ CHAN5G(5620, 124, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),
+ CHAN5G(5640, 128, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH),
+ CHAN5G(5660, 132, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),
+ CHAN5G(5700, 140, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),
+ CHAN5G(5745, 149, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),
+ CHAN5G(5765, 153, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW),
+ CHAN5G(5785, 157, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),
+ CHAN5G(5805, 161, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH),
+ CHAN5G(5825, 165, 0)
};
#define RATE(_bitrate, _hw_rate, _flags) { \
@@ -766,7 +766,16 @@ static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
sta->ht_cap.mcs.rx_mask,
sizeof(sta->ht_cap.mcs.rx_mask));
}
+
+ if (sta->vht_cap.vht_supported) {
+ sta_priv->supported_rates.op_rate_mode = STA_11ac;
+ sta_priv->supported_rates.vht_rx_mcs_map =
+ sta->vht_cap.vht_mcs.rx_mcs_map;
+ sta_priv->supported_rates.vht_tx_mcs_map =
+ sta->vht_cap.vht_mcs.tx_mcs_map;
+ }
}
+
void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates)
{
u16 ofdm_rates[WCN36XX_HAL_NUM_OFDM_RATES] = {
@@ -793,6 +802,14 @@ void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates)
sizeof(*ofdm_rates) * WCN36XX_HAL_NUM_OFDM_RATES);
rates->supported_mcs_set[0] = 0xFF;
}
+
+void wcn36xx_set_default_rates_v1(struct wcn36xx_hal_supported_rates_v1 *rates)
+{
+ rates->op_rate_mode = STA_11ac;
+ rates->vht_rx_mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9;
+ rates->vht_tx_mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9;
+}
+
static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -1184,6 +1201,35 @@ static const struct ieee80211_ops wcn36xx_ops = {
CFG80211_TESTMODE_CMD(wcn36xx_tm_cmd)
};
+static void
+wcn36xx_set_ieee80211_vht_caps(struct ieee80211_sta_vht_cap *vht_cap)
+{
+ vht_cap->vht_supported = true;
+
+ vht_cap->cap = (IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |
+ IEEE80211_VHT_CAP_SHORT_GI_80 |
+ IEEE80211_VHT_CAP_RXSTBC_1 |
+ IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
+ 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |
+ 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);
+
+ vht_cap->vht_mcs.rx_mcs_map =
+ cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |
+ IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);
+
+ vht_cap->vht_mcs.rx_highest = cpu_to_le16(433);
+ vht_cap->vht_mcs.tx_highest = vht_cap->vht_mcs.rx_highest;
+
+ vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;
+}
+
static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
{
static const u32 cipher_suites[] = {
@@ -1210,6 +1256,9 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
if (wcn->rf_id != RF_IRIS_WCN3620)
wcn->hw->wiphy->bands[NL80211_BAND_5GHZ] = &wcn_band_5ghz;
+ if (wcn->rf_id == RF_IRIS_WCN3680)
+ wcn36xx_set_ieee80211_vht_caps(&wcn_band_5ghz.vht_cap);
+
wcn->hw->wiphy->max_scan_ssids = WCN36XX_MAX_SCAN_SSIDS;
wcn->hw->wiphy->max_scan_ie_len = WCN36XX_MAX_SCAN_IE_LEN;
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 4c30036e2e56..766400f7b61c 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -80,6 +80,102 @@ static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = {
WCN36XX_CFG_VAL(ENABLE_DYNAMIC_RA_START_RATE, 133), /* MCS 5 */
};
+static struct wcn36xx_cfg_val wcn3680_cfg_vals[] = {
+ WCN36XX_CFG_VAL(CURRENT_TX_ANTENNA, 1),
+ WCN36XX_CFG_VAL(CURRENT_RX_ANTENNA, 1),
+ WCN36XX_CFG_VAL(LOW_GAIN_OVERRIDE, 0),
+ WCN36XX_CFG_VAL(POWER_STATE_PER_CHAIN, 785),
+ WCN36XX_CFG_VAL(CAL_PERIOD, 5),
+ WCN36XX_CFG_VAL(CAL_CONTROL, 1),
+ WCN36XX_CFG_VAL(PROXIMITY, 0),
+ WCN36XX_CFG_VAL(NETWORK_DENSITY, 3),
+ WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 4096),
+ WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64),
+ WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347),
+ WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 15),
+ WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 15),
+ WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000),
+ WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5),
+ WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10),
+ WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_TWO, 15),
+ WCN36XX_CFG_VAL(FIXED_RATE, 0),
+ WCN36XX_CFG_VAL(RETRYRATE_POLICY, 4),
+ WCN36XX_CFG_VAL(RETRYRATE_SECONDARY, 0),
+ WCN36XX_CFG_VAL(RETRYRATE_TERTIARY, 0),
+ WCN36XX_CFG_VAL(FORCE_POLICY_PROTECTION, 5),
+ WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_24GHZ, 1),
+ WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_5GHZ, 5),
+ WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_24GHZ, 1),
+ WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_5GHZ, 5),
+ WCN36XX_CFG_VAL(MAX_BA_SESSIONS, 40),
+ WCN36XX_CFG_VAL(PS_DATA_INACTIVITY_TIMEOUT, 200),
+ WCN36XX_CFG_VAL(PS_ENABLE_BCN_FILTER, 1),
+ WCN36XX_CFG_VAL(PS_ENABLE_RSSI_MONITOR, 1),
+ WCN36XX_CFG_VAL(NUM_BEACON_PER_RSSI_AVERAGE, 20),
+ WCN36XX_CFG_VAL(STATS_PERIOD, 10),
+ WCN36XX_CFG_VAL(CFP_MAX_DURATION, 30000),
+ WCN36XX_CFG_VAL(FRAME_TRANS_ENABLED, 0),
+ WCN36XX_CFG_VAL(BA_THRESHOLD_HIGH, 128),
+ WCN36XX_CFG_VAL(MAX_BA_BUFFERS, 2560),
+ WCN36XX_CFG_VAL(DYNAMIC_PS_POLL_VALUE, 0),
+ WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1),
+ WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1),
+ WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0),
+ WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_BT, 120000),
+ WCN36XX_CFG_VAL(BTC_STATIC_LEN_LE_WLAN, 30000),
+ WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10),
+ WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0),
+ WCN36XX_CFG_VAL(TDLS_PUAPSD_MASK, 0),
+ WCN36XX_CFG_VAL(TDLS_PUAPSD_BUFFER_STA_CAPABLE, 1),
+ WCN36XX_CFG_VAL(TDLS_PUAPSD_INACTIVITY_TIME, 0),
+ WCN36XX_CFG_VAL(TDLS_PUAPSD_RX_FRAME_THRESHOLD, 10),
+ WCN36XX_CFG_VAL(TDLS_OFF_CHANNEL_CAPABLE, 1),
+ WCN36XX_CFG_VAL(ENABLE_ADAPTIVE_RX_DRAIN, 1),
+ WCN36XX_CFG_VAL(FLEXCONNECT_POWER_FACTOR, 0),
+ WCN36XX_CFG_VAL(ANTENNA_DIVERSITY, 3),
+ WCN36XX_CFG_VAL(ATH_DISABLE, 0),
+ WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_ACTIVE_WLAN_LEN, 60000),
+ WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_ACTIVE_BT_LEN, 90000),
+ WCN36XX_CFG_VAL(BTC_SAP_STATIC_OPP_ACTIVE_WLAN_LEN, 30000),
+ WCN36XX_CFG_VAL(BTC_SAP_STATIC_OPP_ACTIVE_BT_LEN, 30000),
+ WCN36XX_CFG_VAL(ASD_PROBE_INTERVAL, 50),
+ WCN36XX_CFG_VAL(ASD_TRIGGER_THRESHOLD, -60),
+ WCN36XX_CFG_VAL(ASD_RTT_RSSI_HYST_THRESHOLD, 3),
+ WCN36XX_CFG_VAL(BTC_CTS2S_ON_STA_DURING_SCO, 0),
+ WCN36XX_CFG_VAL(RA_FILTER_ENABLE, 0),
+ WCN36XX_CFG_VAL(RA_RATE_LIMIT_INTERVAL, 60),
+ WCN36XX_CFG_VAL(BTC_FATAL_HID_NSNIFF_BLK, 2),
+ WCN36XX_CFG_VAL(BTC_CRITICAL_HID_NSNIFF_BLK, 1),
+ WCN36XX_CFG_VAL(BTC_DYN_A2DP_TX_QUEUE_THOLD, 0),
+ WCN36XX_CFG_VAL(BTC_DYN_OPP_TX_QUEUE_THOLD, 1),
+ WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_SP, 10),
+ WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_RX_CNT, 50),
+ WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_TX_CNT, 50),
+ WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_TX_CNT_MEAS_WINDOW, 500),
+ WCN36XX_CFG_VAL(MAX_UAPSD_CONSEC_RX_CNT_MEAS_WINDOW, 500),
+ WCN36XX_CFG_VAL(MAX_PSPOLL_IN_WMM_UAPSD_PS_MODE, 0),
+ WCN36XX_CFG_VAL(MAX_UAPSD_INACTIVITY_INTERVALS, 10),
+ WCN36XX_CFG_VAL(ENABLE_DYNAMIC_WMMPS, 1),
+ WCN36XX_CFG_VAL(BURST_MODE_BE_TXOP_VALUE, 0),
+ WCN36XX_CFG_VAL(ENABLE_DYNAMIC_RA_START_RATE, 136),
+ WCN36XX_CFG_VAL(BTC_FAST_WLAN_CONN_PREF, 1),
+ WCN36XX_CFG_VAL(ENABLE_RTSCTS_HTVHT, 0),
+ WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_IDLE_WLAN_LEN, 30000),
+ WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_IDLE_BT_LEN, 120000),
+ WCN36XX_CFG_VAL(LINK_FAIL_TX_CNT, 200),
+ WCN36XX_CFG_VAL(TOGGLE_ARP_BDRATES, 0),
+ WCN36XX_CFG_VAL(OPTIMIZE_CA_EVENT, 0),
+ WCN36XX_CFG_VAL(EXT_SCAN_CONC_MODE, 0),
+ WCN36XX_CFG_VAL(BAR_WAKEUP_HOST_DISABLE, 0),
+ WCN36XX_CFG_VAL(SAR_BOFFSET_CORRECTION_ENABLE, 0),
+ WCN36XX_CFG_VAL(BTC_DISABLE_WLAN_LINK_CRITICAL, 5),
+ WCN36XX_CFG_VAL(DISABLE_SCAN_DURING_SCO, 2),
+ WCN36XX_CFG_VAL(CONS_BCNMISS_COUNT, 0),
+ WCN36XX_CFG_VAL(UNITS_OF_BCN_WAIT_TIME, 0),
+ WCN36XX_CFG_VAL(TRIGGER_NULLFRAME_BEFORE_HB, 0),
+ WCN36XX_CFG_VAL(ENABLE_POWERSAVE_OFFLOAD, 0),
+};
+
static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value)
{
struct wcn36xx_hal_cfg *entry;
@@ -122,6 +218,7 @@ static inline u8 is_cap_supported(unsigned long caps, unsigned long flag)
{
return caps & flag ? 1 : 0;
}
+
static void wcn36xx_smd_set_bss_ht_params(struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct wcn36xx_hal_config_bss_params *bss_params)
@@ -146,6 +243,15 @@ static void wcn36xx_smd_set_bss_ht_params(struct ieee80211_vif *vif,
}
}
+static void
+wcn36xx_smd_set_bss_vht_params(struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct wcn36xx_hal_config_bss_params_v1 *bss)
+{
+ if (sta && sta->vht_cap.vht_supported)
+ bss->vht_capable = 1;
+}
+
static void wcn36xx_smd_set_sta_ht_params(struct ieee80211_sta *sta,
struct wcn36xx_hal_config_sta_params *sta_params)
{
@@ -174,6 +280,37 @@ static void wcn36xx_smd_set_sta_ht_params(struct ieee80211_sta *sta,
}
}
+static void wcn36xx_smd_set_sta_vht_params(struct wcn36xx *wcn,
+ struct ieee80211_sta *sta,
+ struct wcn36xx_hal_config_sta_params_v1 *sta_params)
+{
+ if (sta->vht_cap.vht_supported) {
+ unsigned long caps = sta->vht_cap.cap;
+
+ sta_params->vht_capable = sta->vht_cap.vht_supported;
+ sta_params->vht_ldpc_enabled =
+ is_cap_supported(caps, IEEE80211_VHT_CAP_RXLDPC);
+ if (get_feat_caps(wcn->fw_feat_caps, MU_MIMO)) {
+ sta_params->vht_tx_mu_beamformee_capable =
+ is_cap_supported(caps, IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
+ if (sta_params->vht_tx_mu_beamformee_capable)
+ sta_params->vht_tx_bf_enabled = 1;
+ } else {
+ sta_params->vht_tx_mu_beamformee_capable = 0;
+ }
+ sta_params->vht_tx_channel_width_set = 0;
+ }
+}
+
+static void wcn36xx_smd_set_sta_ht_ldpc_params(struct ieee80211_sta *sta,
+ struct wcn36xx_hal_config_sta_params_v1 *sta_params)
+{
+ if (sta->ht_cap.ht_supported) {
+ sta_params->ht_ldpc_enabled =
+ is_cap_supported(sta->ht_cap.cap, IEEE80211_HT_CAP_LDPC_CODING);
+ }
+}
+
static void wcn36xx_smd_set_sta_default_ht_params(
struct wcn36xx_hal_config_sta_params *sta_params)
{
@@ -190,6 +327,31 @@ static void wcn36xx_smd_set_sta_default_ht_params(
sta_params->dsss_cck_mode_40mhz = 1;
}
+static void wcn36xx_smd_set_sta_default_vht_params(struct wcn36xx *wcn,
+ struct wcn36xx_hal_config_sta_params_v1 *sta_params)
+{
+ if (wcn->rf_id == RF_IRIS_WCN3680) {
+ sta_params->vht_capable = 1;
+ sta_params->vht_tx_mu_beamformee_capable = 1;
+ } else {
+ sta_params->vht_capable = 0;
+ sta_params->vht_tx_mu_beamformee_capable = 0;
+ }
+
+ sta_params->vht_ldpc_enabled = 0;
+ sta_params->vht_tx_channel_width_set = 0;
+ sta_params->vht_tx_bf_enabled = 0;
+}
+
+static void wcn36xx_smd_set_sta_default_ht_ldpc_params(struct wcn36xx *wcn,
+ struct wcn36xx_hal_config_sta_params_v1 *sta_params)
+{
+ if (wcn->rf_id == RF_IRIS_WCN3680)
+ sta_params->ht_ldpc_enabled = 1;
+ else
+ sta_params->ht_ldpc_enabled = 0;
+}
+
static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -242,9 +404,10 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
sta_params->aid = sta_priv->aid;
wcn36xx_smd_set_sta_ht_params(sta, sta_params);
memcpy(&sta_params->supported_rates, &sta_priv->supported_rates,
- sizeof(sta_priv->supported_rates));
+ sizeof(struct wcn36xx_hal_supported_rates));
} else {
- wcn36xx_set_default_rates(&sta_params->supported_rates);
+ wcn36xx_set_default_rates((struct wcn36xx_hal_supported_rates *)
+ &sta_params->supported_rates);
wcn36xx_smd_set_sta_default_ht_params(sta_params);
}
}
@@ -291,14 +454,20 @@ static void init_hal_msg(struct wcn36xx_hal_msg_header *hdr,
hdr->len = msg_size + sizeof(*hdr);
}
-#define INIT_HAL_MSG(msg_body, type) \
+#define __INIT_HAL_MSG(msg_body, type, version) \
do { \
memset(&msg_body, 0, sizeof(msg_body)); \
msg_body.header.msg_type = type; \
- msg_body.header.msg_version = WCN36XX_HAL_MSG_VERSION0; \
+ msg_body.header.msg_version = version; \
msg_body.header.len = sizeof(msg_body); \
} while (0) \
+#define INIT_HAL_MSG(msg_body, type) \
+ __INIT_HAL_MSG(msg_body, type, WCN36XX_HAL_MSG_VERSION0)
+
+#define INIT_HAL_MSG_V1(msg_body, type) \
+ __INIT_HAL_MSG(msg_body, type, WCN36XX_HAL_MSG_VERSION1)
+
#define INIT_HAL_PTT_MSG(p_msg_body, ppt_msg_len) \
do { \
memset(p_msg_body, 0, sizeof(*p_msg_body) + ppt_msg_len); \
@@ -450,6 +619,8 @@ int wcn36xx_smd_start(struct wcn36xx *wcn)
int ret;
int i;
size_t len;
+ int cfg_elements;
+ static struct wcn36xx_cfg_val *cfg_vals;
mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_REQ);
@@ -462,9 +633,17 @@ int wcn36xx_smd_start(struct wcn36xx *wcn)
body = (struct wcn36xx_hal_mac_start_req_msg *)wcn->hal_buf;
len = body->header.len;
- for (i = 0; i < ARRAY_SIZE(wcn36xx_cfg_vals); i++) {
- ret = put_cfg_tlv_u32(wcn, &len, wcn36xx_cfg_vals[i].cfg_id,
- wcn36xx_cfg_vals[i].value);
+ if (wcn->rf_id == RF_IRIS_WCN3680) {
+ cfg_vals = wcn3680_cfg_vals;
+ cfg_elements = ARRAY_SIZE(wcn3680_cfg_vals);
+ } else {
+ cfg_vals = wcn36xx_cfg_vals;
+ cfg_elements = ARRAY_SIZE(wcn36xx_cfg_vals);
+ }
+
+ for (i = 0; i < cfg_elements; i++) {
+ ret = put_cfg_tlv_u32(wcn, &len, cfg_vals[i].cfg_id,
+ cfg_vals[i].value);
if (ret)
goto out;
}
@@ -694,8 +873,10 @@ int wcn36xx_smd_start_hw_scan(struct wcn36xx *wcn, struct ieee80211_vif *vif,
msg_body->num_channel = min_t(u8, req->n_channels,
sizeof(msg_body->channels));
- for (i = 0; i < msg_body->num_channel; i++)
- msg_body->channels[i] = req->channels[i]->hw_value;
+ for (i = 0; i < msg_body->num_channel; i++) {
+ msg_body->channels[i] =
+ HW_VALUE_CHANNEL(req->channels[i]->hw_value);
+ }
msg_body->header.len -= WCN36XX_MAX_SCAN_IE_LEN;
@@ -1183,6 +1364,31 @@ static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn,
v1->p2p = orig->p2p;
}
+static void
+wcn36xx_smd_set_sta_params_v1(struct wcn36xx *wcn,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct wcn36xx_hal_config_sta_params_v1 *sta_par)
+{
+ struct wcn36xx_sta *sta_priv = NULL;
+ struct wcn36xx_hal_config_sta_params sta_par_v0;
+
+ wcn36xx_smd_set_sta_params(wcn, vif, sta, &sta_par_v0);
+ wcn36xx_smd_convert_sta_to_v1(wcn, &sta_par_v0, sta_par);
+
+ if (sta) {
+ sta_priv = wcn36xx_sta_to_priv(sta);
+ wcn36xx_smd_set_sta_vht_params(wcn, sta, sta_par);
+ wcn36xx_smd_set_sta_ht_ldpc_params(sta, sta_par);
+ memcpy(&sta_par->supported_rates, &sta_priv->supported_rates,
+ sizeof(sta_par->supported_rates));
+ } else {
+ wcn36xx_set_default_rates_v1(&sta_par->supported_rates);
+ wcn36xx_smd_set_sta_default_vht_params(wcn, sta_par);
+ wcn36xx_smd_set_sta_default_ht_ldpc_params(wcn, sta_par);
+ }
+}
+
static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn,
struct ieee80211_sta *sta,
void *buf,
@@ -1217,53 +1423,69 @@ static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn,
}
static int wcn36xx_smd_config_sta_v1(struct wcn36xx *wcn,
- const struct wcn36xx_hal_config_sta_req_msg *orig)
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
{
struct wcn36xx_hal_config_sta_req_msg_v1 msg_body;
- struct wcn36xx_hal_config_sta_params_v1 *sta = &msg_body.sta_params;
+ struct wcn36xx_hal_config_sta_params_v1 *sta_params;
- INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_STA_REQ);
+ if (wcn->rf_id == RF_IRIS_WCN3680) {
+ INIT_HAL_MSG_V1(msg_body, WCN36XX_HAL_CONFIG_STA_REQ);
+ } else {
+ INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_STA_REQ);
+ msg_body.header.len -= WCN36XX_DIFF_STA_PARAMS_V1_NOVHT;
+ }
+
+ sta_params = &msg_body.sta_params;
- wcn36xx_smd_convert_sta_to_v1(wcn, &orig->sta_params,
- &msg_body.sta_params);
+ wcn36xx_smd_set_sta_params_v1(wcn, vif, sta, sta_params);
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
wcn36xx_dbg(WCN36XX_DBG_HAL,
"hal config sta v1 action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n",
- sta->action, sta->sta_index, sta->bssid_index,
- sta->bssid, sta->type, sta->mac, sta->aid);
+ sta_params->action, sta_params->sta_index, sta_params->bssid_index,
+ sta_params->bssid, sta_params->type, sta_params->mac, sta_params->aid);
return wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
}
-int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+static int wcn36xx_smd_config_sta_v0(struct wcn36xx *wcn,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
{
struct wcn36xx_hal_config_sta_req_msg msg;
struct wcn36xx_hal_config_sta_params *sta_params;
- int ret;
- mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg, WCN36XX_HAL_CONFIG_STA_REQ);
sta_params = &msg.sta_params;
wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params);
- if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
- ret = wcn36xx_smd_config_sta_v1(wcn, &msg);
- } else {
- PREPARE_HAL_BUF(wcn->hal_buf, msg);
+ PREPARE_HAL_BUF(wcn->hal_buf, msg);
- wcn36xx_dbg(WCN36XX_DBG_HAL,
- "hal config sta action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n",
- sta_params->action, sta_params->sta_index,
- sta_params->bssid_index, sta_params->bssid,
- sta_params->type, sta_params->mac, sta_params->aid);
+ wcn36xx_dbg(WCN36XX_DBG_HAL,
+ "hal config sta action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n",
+ sta_params->action, sta_params->sta_index,
+ sta_params->bssid_index, sta_params->bssid,
+ sta_params->type, sta_params->mac, sta_params->aid);
+
+ return wcn36xx_smd_send_and_wait(wcn, msg.header.len);
+}
+
+int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ int ret;
+
+ mutex_lock(&wcn->hal_mutex);
+
+ if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24))
+ ret = wcn36xx_smd_config_sta_v1(wcn, vif, sta);
+ else
+ ret = wcn36xx_smd_config_sta_v0(wcn, vif, sta);
- ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len);
- }
if (ret) {
wcn36xx_err("Sending hal_config_sta failed\n");
goto out;
@@ -1281,89 +1503,197 @@ out:
return ret;
}
+static void wcn36xx_smd_set_bss_params(struct wcn36xx *wcn,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ const u8 *bssid,
+ bool update,
+ struct wcn36xx_hal_config_bss_params *bss)
+{
+ struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+
+ WARN_ON(is_zero_ether_addr(bssid));
+
+ memcpy(&bss->bssid, bssid, ETH_ALEN);
+
+ memcpy(bss->self_mac_addr, vif->addr, ETH_ALEN);
+
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ bss->bss_type = WCN36XX_HAL_INFRASTRUCTURE_MODE;
+
+ /* STA */
+ bss->oper_mode = 1;
+ bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_MODE;
+ } else if (vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_MESH_POINT) {
+ bss->bss_type = WCN36XX_HAL_INFRA_AP_MODE;
+
+ /* AP */
+ bss->oper_mode = 0;
+ bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_SAP_MODE;
+ } else if (vif->type == NL80211_IFTYPE_ADHOC) {
+ bss->bss_type = WCN36XX_HAL_IBSS_MODE;
+
+ /* STA */
+ bss->oper_mode = 1;
+ } else {
+ wcn36xx_warn("Unknown type for bss config: %d\n", vif->type);
+ }
+
+ if (vif->type == NL80211_IFTYPE_STATION)
+ wcn36xx_smd_set_bss_nw_type(wcn, sta, bss);
+ else
+ bss->nw_type = WCN36XX_HAL_11N_NW_TYPE;
+
+ bss->short_slot_time_supported = vif->bss_conf.use_short_slot;
+ bss->lla_coexist = 0;
+ bss->llb_coexist = 0;
+ bss->llg_coexist = 0;
+ bss->rifs_mode = 0;
+ bss->beacon_interval = vif->bss_conf.beacon_int;
+ bss->dtim_period = vif_priv->dtim_period;
+
+ wcn36xx_smd_set_bss_ht_params(vif, sta, bss);
+
+ bss->oper_channel = WCN36XX_HW_CHANNEL(wcn);
+
+ if (conf_is_ht40_minus(&wcn->hw->conf))
+ bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ else if (conf_is_ht40_plus(&wcn->hw->conf))
+ bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ else
+ bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+
+ bss->reserved = 0;
+
+ /* wcn->ssid is only valid in AP and IBSS mode */
+ bss->ssid.length = vif_priv->ssid.length;
+ memcpy(bss->ssid.ssid, vif_priv->ssid.ssid, vif_priv->ssid.length);
+
+ bss->obss_prot_enabled = 0;
+ bss->rmf = 0;
+ bss->max_probe_resp_retry_limit = 0;
+ bss->hidden_ssid = vif->bss_conf.hidden_ssid;
+ bss->proxy_probe_resp = 0;
+ bss->edca_params_valid = 0;
+
+ /* FIXME: set acbe, acbk, acvi and acvo */
+
+ bss->ext_set_sta_key_param_valid = 0;
+
+ /* FIXME: set ext_set_sta_key_param */
+
+ bss->spectrum_mgt_enable = 0;
+ bss->tx_mgmt_power = 0;
+ bss->max_tx_power = WCN36XX_MAX_POWER(wcn);
+ bss->action = update;
+
+ vif_priv->bss_type = bss->bss_type;
+}
+
static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn,
- const struct wcn36xx_hal_config_bss_req_msg *orig)
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta_80211,
+ const u8 *bssid,
+ bool update)
{
struct wcn36xx_hal_config_bss_req_msg_v1 *msg_body;
struct wcn36xx_hal_config_bss_params_v1 *bss;
+ struct wcn36xx_hal_config_bss_params bss_v0;
struct wcn36xx_hal_config_sta_params_v1 *sta;
+ struct cfg80211_chan_def *chandef;
int ret;
msg_body = kzalloc(sizeof(*msg_body), GFP_KERNEL);
if (!msg_body)
return -ENOMEM;
- INIT_HAL_MSG((*msg_body), WCN36XX_HAL_CONFIG_BSS_REQ);
+ if (wcn->rf_id == RF_IRIS_WCN3680) {
+ INIT_HAL_MSG_V1((*msg_body), WCN36XX_HAL_CONFIG_BSS_REQ);
+ } else {
+ INIT_HAL_MSG((*msg_body), WCN36XX_HAL_CONFIG_BSS_REQ);
+ msg_body->header.len -= WCN36XX_DIFF_BSS_PARAMS_V1_NOVHT;
+ }
bss = &msg_body->bss_params;
sta = &bss->sta;
+ memset(&bss_v0, 0x00, sizeof(bss_v0));
+ wcn36xx_smd_set_bss_params(wcn, vif, sta_80211, bssid, update, &bss_v0);
+ wcn36xx_smd_set_sta_params_v1(wcn, vif, sta_80211, sta);
+
/* convert orig to v1 */
- memcpy(bss->bssid, &orig->bss_params.bssid, ETH_ALEN);
- memcpy(bss->self_mac_addr, &orig->bss_params.self_mac_addr, ETH_ALEN);
+ memcpy(bss->bssid, &bss_v0.bssid, ETH_ALEN);
+ memcpy(bss->self_mac_addr, &bss_v0.self_mac_addr, ETH_ALEN);
- bss->bss_type = orig->bss_params.bss_type;
- bss->oper_mode = orig->bss_params.oper_mode;
- bss->nw_type = orig->bss_params.nw_type;
+ bss->bss_type = bss_v0.bss_type;
+ bss->oper_mode = bss_v0.oper_mode;
+ bss->nw_type = bss_v0.nw_type;
bss->short_slot_time_supported =
- orig->bss_params.short_slot_time_supported;
- bss->lla_coexist = orig->bss_params.lla_coexist;
- bss->llb_coexist = orig->bss_params.llb_coexist;
- bss->llg_coexist = orig->bss_params.llg_coexist;
- bss->ht20_coexist = orig->bss_params.ht20_coexist;
- bss->lln_non_gf_coexist = orig->bss_params.lln_non_gf_coexist;
+ bss_v0.short_slot_time_supported;
+ bss->lla_coexist = bss_v0.lla_coexist;
+ bss->llb_coexist = bss_v0.llb_coexist;
+ bss->llg_coexist = bss_v0.llg_coexist;
+ bss->ht20_coexist = bss_v0.ht20_coexist;
+ bss->lln_non_gf_coexist = bss_v0.lln_non_gf_coexist;
bss->lsig_tx_op_protection_full_support =
- orig->bss_params.lsig_tx_op_protection_full_support;
- bss->rifs_mode = orig->bss_params.rifs_mode;
- bss->beacon_interval = orig->bss_params.beacon_interval;
- bss->dtim_period = orig->bss_params.dtim_period;
- bss->tx_channel_width_set = orig->bss_params.tx_channel_width_set;
- bss->oper_channel = orig->bss_params.oper_channel;
- bss->ext_channel = orig->bss_params.ext_channel;
-
- bss->reserved = orig->bss_params.reserved;
-
- memcpy(&bss->ssid, &orig->bss_params.ssid,
- sizeof(orig->bss_params.ssid));
-
- bss->action = orig->bss_params.action;
- bss->rateset = orig->bss_params.rateset;
- bss->ht = orig->bss_params.ht;
- bss->obss_prot_enabled = orig->bss_params.obss_prot_enabled;
- bss->rmf = orig->bss_params.rmf;
- bss->ht_oper_mode = orig->bss_params.ht_oper_mode;
- bss->dual_cts_protection = orig->bss_params.dual_cts_protection;
+ bss_v0.lsig_tx_op_protection_full_support;
+ bss->rifs_mode = bss_v0.rifs_mode;
+ bss->beacon_interval = bss_v0.beacon_interval;
+ bss->dtim_period = bss_v0.dtim_period;
+ bss->tx_channel_width_set = bss_v0.tx_channel_width_set;
+ bss->oper_channel = bss_v0.oper_channel;
+
+ if (wcn->hw->conf.chandef.width == NL80211_CHAN_WIDTH_80) {
+ chandef = &wcn->hw->conf.chandef;
+ bss->ext_channel = HW_VALUE_PHY(chandef->chan->hw_value);
+ } else {
+ bss->ext_channel = bss_v0.ext_channel;
+ }
+
+ bss->reserved = bss_v0.reserved;
+
+ memcpy(&bss->ssid, &bss_v0.ssid,
+ sizeof(bss_v0.ssid));
+
+ bss->action = bss_v0.action;
+ bss->rateset = bss_v0.rateset;
+ bss->ht = bss_v0.ht;
+ bss->obss_prot_enabled = bss_v0.obss_prot_enabled;
+ bss->rmf = bss_v0.rmf;
+ bss->ht_oper_mode = bss_v0.ht_oper_mode;
+ bss->dual_cts_protection = bss_v0.dual_cts_protection;
bss->max_probe_resp_retry_limit =
- orig->bss_params.max_probe_resp_retry_limit;
- bss->hidden_ssid = orig->bss_params.hidden_ssid;
- bss->proxy_probe_resp = orig->bss_params.proxy_probe_resp;
- bss->edca_params_valid = orig->bss_params.edca_params_valid;
-
- memcpy(&bss->acbe, &orig->bss_params.acbe,
- sizeof(orig->bss_params.acbe));
- memcpy(&bss->acbk, &orig->bss_params.acbk,
- sizeof(orig->bss_params.acbk));
- memcpy(&bss->acvi, &orig->bss_params.acvi,
- sizeof(orig->bss_params.acvi));
- memcpy(&bss->acvo, &orig->bss_params.acvo,
- sizeof(orig->bss_params.acvo));
+ bss_v0.max_probe_resp_retry_limit;
+ bss->hidden_ssid = bss_v0.hidden_ssid;
+ bss->proxy_probe_resp = bss_v0.proxy_probe_resp;
+ bss->edca_params_valid = bss_v0.edca_params_valid;
+
+ memcpy(&bss->acbe, &bss_v0.acbe,
+ sizeof(bss_v0.acbe));
+ memcpy(&bss->acbk, &bss_v0.acbk,
+ sizeof(bss_v0.acbk));
+ memcpy(&bss->acvi, &bss_v0.acvi,
+ sizeof(bss_v0.acvi));
+ memcpy(&bss->acvo, &bss_v0.acvo,
+ sizeof(bss_v0.acvo));
bss->ext_set_sta_key_param_valid =
- orig->bss_params.ext_set_sta_key_param_valid;
+ bss_v0.ext_set_sta_key_param_valid;
memcpy(&bss->ext_set_sta_key_param,
- &orig->bss_params.ext_set_sta_key_param,
- sizeof(orig->bss_params.acvo));
+ &bss_v0.ext_set_sta_key_param,
+ sizeof(bss_v0.acvo));
- bss->wcn36xx_hal_persona = orig->bss_params.wcn36xx_hal_persona;
- bss->spectrum_mgt_enable = orig->bss_params.spectrum_mgt_enable;
- bss->tx_mgmt_power = orig->bss_params.tx_mgmt_power;
- bss->max_tx_power = orig->bss_params.max_tx_power;
+ bss->wcn36xx_hal_persona = bss_v0.wcn36xx_hal_persona;
+ bss->spectrum_mgt_enable = bss_v0.spectrum_mgt_enable;
+ bss->tx_mgmt_power = bss_v0.tx_mgmt_power;
+ bss->max_tx_power = bss_v0.max_tx_power;
- wcn36xx_smd_convert_sta_to_v1(wcn, &orig->bss_params.sta, sta);
+ wcn36xx_smd_set_bss_vht_params(vif, sta_80211, bss);
PREPARE_HAL_BUF(wcn->hal_buf, (*msg_body));
@@ -1383,6 +1713,48 @@ static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn,
return ret;
}
+static int wcn36xx_smd_config_bss_v0(struct wcn36xx *wcn,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ const u8 *bssid,
+ bool update)
+{
+ struct wcn36xx_hal_config_bss_req_msg *msg;
+ struct wcn36xx_hal_config_bss_params *bss;
+ struct wcn36xx_hal_config_sta_params *sta_params;
+ int ret;
+
+ msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ INIT_HAL_MSG((*msg), WCN36XX_HAL_CONFIG_BSS_REQ);
+
+ bss = &msg->bss_params;
+ sta_params = &bss->sta;
+
+ wcn36xx_smd_set_bss_params(wcn, vif, sta, bssid, update, bss);
+ wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params);
+
+ PREPARE_HAL_BUF(wcn->hal_buf, (*msg));
+
+ wcn36xx_dbg(WCN36XX_DBG_HAL,
+ "hal config bss bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n",
+ bss->bssid, bss->self_mac_addr, bss->bss_type,
+ bss->oper_mode, bss->nw_type);
+
+ wcn36xx_dbg(WCN36XX_DBG_HAL,
+ "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n",
+ sta_params->bssid, sta_params->action,
+ sta_params->sta_index, sta_params->bssid_index,
+ sta_params->aid, sta_params->type,
+ sta_params->mac);
+
+ ret = wcn36xx_smd_send_and_wait(wcn, msg->header.len);
+ kfree(msg);
+
+ return ret;
+}
static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn,
struct ieee80211_vif *vif,
@@ -1432,121 +1804,15 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, const u8 *bssid,
bool update)
{
- struct wcn36xx_hal_config_bss_req_msg *msg;
- struct wcn36xx_hal_config_bss_params *bss;
- struct wcn36xx_hal_config_sta_params *sta_params;
- struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
int ret;
mutex_lock(&wcn->hal_mutex);
- msg = kzalloc(sizeof(*msg), GFP_KERNEL);
- if (!msg) {
- ret = -ENOMEM;
- goto out;
- }
- INIT_HAL_MSG((*msg), WCN36XX_HAL_CONFIG_BSS_REQ);
-
- bss = &msg->bss_params;
- sta_params = &bss->sta;
-
- WARN_ON(is_zero_ether_addr(bssid));
-
- memcpy(&bss->bssid, bssid, ETH_ALEN);
-
- memcpy(bss->self_mac_addr, vif->addr, ETH_ALEN);
-
- if (vif->type == NL80211_IFTYPE_STATION) {
- bss->bss_type = WCN36XX_HAL_INFRASTRUCTURE_MODE;
-
- /* STA */
- bss->oper_mode = 1;
- bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_MODE;
- } else if (vif->type == NL80211_IFTYPE_AP ||
- vif->type == NL80211_IFTYPE_MESH_POINT) {
- bss->bss_type = WCN36XX_HAL_INFRA_AP_MODE;
-
- /* AP */
- bss->oper_mode = 0;
- bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_SAP_MODE;
- } else if (vif->type == NL80211_IFTYPE_ADHOC) {
- bss->bss_type = WCN36XX_HAL_IBSS_MODE;
-
- /* STA */
- bss->oper_mode = 1;
- } else {
- wcn36xx_warn("Unknown type for bss config: %d\n", vif->type);
- }
- if (vif->type == NL80211_IFTYPE_STATION)
- wcn36xx_smd_set_bss_nw_type(wcn, sta, bss);
+ if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24))
+ ret = wcn36xx_smd_config_bss_v1(wcn, vif, sta, bssid, update);
else
- bss->nw_type = WCN36XX_HAL_11N_NW_TYPE;
-
- bss->short_slot_time_supported = vif->bss_conf.use_short_slot;
- bss->lla_coexist = 0;
- bss->llb_coexist = 0;
- bss->llg_coexist = 0;
- bss->rifs_mode = 0;
- bss->beacon_interval = vif->bss_conf.beacon_int;
- bss->dtim_period = vif_priv->dtim_period;
-
- wcn36xx_smd_set_bss_ht_params(vif, sta, bss);
-
- bss->oper_channel = WCN36XX_HW_CHANNEL(wcn);
-
- if (conf_is_ht40_minus(&wcn->hw->conf))
- bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
- else if (conf_is_ht40_plus(&wcn->hw->conf))
- bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
- else
- bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_NONE;
-
- bss->reserved = 0;
- wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params);
-
- /* wcn->ssid is only valid in AP and IBSS mode */
- bss->ssid.length = vif_priv->ssid.length;
- memcpy(bss->ssid.ssid, vif_priv->ssid.ssid, vif_priv->ssid.length);
-
- bss->obss_prot_enabled = 0;
- bss->rmf = 0;
- bss->max_probe_resp_retry_limit = 0;
- bss->hidden_ssid = vif->bss_conf.hidden_ssid;
- bss->proxy_probe_resp = 0;
- bss->edca_params_valid = 0;
-
- /* FIXME: set acbe, acbk, acvi and acvo */
-
- bss->ext_set_sta_key_param_valid = 0;
-
- /* FIXME: set ext_set_sta_key_param */
-
- bss->spectrum_mgt_enable = 0;
- bss->tx_mgmt_power = 0;
- bss->max_tx_power = WCN36XX_MAX_POWER(wcn);
- bss->action = update;
+ ret = wcn36xx_smd_config_bss_v0(wcn, vif, sta, bssid, update);
- vif_priv->bss_type = bss->bss_type;
-
- wcn36xx_dbg(WCN36XX_DBG_HAL,
- "hal config bss bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n",
- bss->bssid, bss->self_mac_addr, bss->bss_type,
- bss->oper_mode, bss->nw_type);
-
- wcn36xx_dbg(WCN36XX_DBG_HAL,
- "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n",
- sta_params->bssid, sta_params->action,
- sta_params->sta_index, sta_params->bssid_index,
- sta_params->aid, sta_params->type,
- sta_params->mac);
-
- if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
- ret = wcn36xx_smd_config_bss_v1(wcn, msg);
- } else {
- PREPARE_HAL_BUF(wcn->hal_buf, (*msg));
-
- ret = wcn36xx_smd_send_and_wait(wcn, msg->header.len);
- }
if (ret) {
wcn36xx_err("Sending hal_config_bss failed\n");
goto out;
@@ -1556,12 +1822,10 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
sta,
wcn->hal_buf,
wcn->hal_rsp_len);
- if (ret) {
+ if (ret)
wcn36xx_err("hal_config_bss response failed err=%d\n", ret);
- goto out;
- }
+
out:
- kfree(msg);
mutex_unlock(&wcn->hal_mutex);
return ret;
}
@@ -1928,6 +2192,7 @@ out:
mutex_unlock(&wcn->hal_mutex);
return ret;
}
+
int wcn36xx_smd_set_power_params(struct wcn36xx *wcn, bool ignore_dtim)
{
struct wcn36xx_hal_set_power_params_req_msg msg_body;
@@ -1957,6 +2222,7 @@ out:
mutex_unlock(&wcn->hal_mutex);
return ret;
}
+
/* Notice: This function should be called after associated, or else it
* will be invalid
*/
@@ -2636,6 +2902,7 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
kfree(hal_ind_msg);
}
}
+
int wcn36xx_smd_open(struct wcn36xx *wcn)
{
wcn->hal_ind_wq = create_freezable_workqueue("wcn36xx_smd_ind");
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index 342ca0ae7e28..71fa9992b118 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -83,7 +83,11 @@ enum wcn36xx_ampdu_state {
WCN36XX_AMPDU_OPERATIONAL,
};
-#define WCN36XX_HW_CHANNEL(__wcn) (__wcn->hw->conf.chandef.chan->hw_value)
+#define HW_VALUE_PHY_SHIFT 8
+#define HW_VALUE_PHY(hw_value) ((hw_value) >> HW_VALUE_PHY_SHIFT)
+#define HW_VALUE_CHANNEL(hw_value) ((hw_value) & 0xFF)
+#define WCN36XX_HW_CHANNEL(__wcn)\
+ HW_VALUE_CHANNEL(__wcn->hw->conf.chandef.chan->hw_value)
#define WCN36XX_BAND(__wcn) (__wcn->hw->conf.chandef.chan->band)
#define WCN36XX_CENTER_FREQ(__wcn) (__wcn->hw->conf.chandef.chan->center_freq)
#define WCN36XX_LISTEN_INTERVAL(__wcn) (__wcn->hw->conf.listen_interval)
@@ -169,7 +173,7 @@ struct wcn36xx_sta {
u8 bss_dpu_desc_index;
bool is_data_encrypted;
/* Rates */
- struct wcn36xx_hal_supported_rates supported_rates;
+ struct wcn36xx_hal_supported_rates_v1 supported_rates;
spinlock_t ampdu_lock; /* protects next two fields */
enum wcn36xx_ampdu_state ampdu_state[16];
@@ -271,6 +275,7 @@ static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn,
wcn->fw_revision == revision);
}
void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates);
+void wcn36xx_set_default_rates_v1(struct wcn36xx_hal_supported_rates_v1 *rates);
static inline
struct ieee80211_sta *wcn36xx_priv_to_sta(struct wcn36xx_sta *sta_priv)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
index 8b5fda9bb853..a2dbbb977d0c 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -56,6 +56,7 @@
#define RSN_AKM_PSK 2 /* Pre-shared Key */
#define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */
#define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */
+#define RSN_AKM_SAE 8 /* SAE */
#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
#define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3))
#define RSN_CAP_MFPR_MASK BIT(6)
@@ -4242,6 +4243,10 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
wpa_auth |= WPA2_AUTH_1X_SHA256;
break;
+ case RSN_AKM_SAE:
+ brcmf_dbg(TRACE, "RSN_AKM_SAE\n");
+ wpa_auth |= WPA3_AUTH_SAE_PSK;
+ break;
default:
bphy_err(drvr, "Invalid key mgmt info\n");
}
@@ -4259,11 +4264,12 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
brcmf_dbg(TRACE, "MFP Required\n");
mfp = BRCMF_MFP_REQUIRED;
/* Firmware only supports mfp required in
- * combination with WPA2_AUTH_PSK_SHA256 or
- * WPA2_AUTH_1X_SHA256.
+ * combination with WPA2_AUTH_PSK_SHA256,
+ * WPA2_AUTH_1X_SHA256, or WPA3_AUTH_SAE_PSK.
*/
if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
- WPA2_AUTH_1X_SHA256))) {
+ WPA2_AUTH_1X_SHA256 |
+ WPA3_AUTH_SAE_PSK))) {
err = -EINVAL;
goto exit;
}
@@ -4679,6 +4685,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = cfg->pub;
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
+ struct cfg80211_crypto_settings *crypto = &settings->crypto;
const struct brcmf_tlv *ssid_ie;
const struct brcmf_tlv *country_ie;
struct brcmf_ssid_le ssid_le;
@@ -4818,6 +4826,25 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
goto exit;
}
+ if (crypto->psk) {
+ brcmf_dbg(INFO, "using PSK offload\n");
+ profile->use_fwauth |= BIT(BRCMF_PROFILE_FWAUTH_PSK);
+ err = brcmf_set_pmk(ifp, crypto->psk,
+ BRCMF_WSEC_MAX_PSK_LEN);
+ if (err < 0)
+ goto exit;
+ }
+ if (crypto->sae_pwd) {
+ brcmf_dbg(INFO, "using SAE offload\n");
+ profile->use_fwauth |= BIT(BRCMF_PROFILE_FWAUTH_SAE);
+ err = brcmf_set_sae_password(ifp, crypto->sae_pwd,
+ crypto->sae_pwd_len);
+ if (err < 0)
+ goto exit;
+ }
+ if (profile->use_fwauth == 0)
+ profile->use_fwauth = BIT(BRCMF_PROFILE_FWAUTH_NONE);
+
err = brcmf_parse_configure_security(ifp, settings,
NL80211_IFTYPE_AP);
if (err < 0) {
@@ -4904,6 +4931,7 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = cfg->pub;
+ struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
s32 err;
struct brcmf_fil_bss_enable_le bss_enable;
struct brcmf_join_params join_params;
@@ -4915,6 +4943,14 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
/* first to make sure they get processed by fw. */
msleep(400);
+ if (profile->use_fwauth != BIT(BRCMF_PROFILE_FWAUTH_NONE)) {
+ if (profile->use_fwauth & BIT(BRCMF_PROFILE_FWAUTH_PSK))
+ brcmf_set_pmk(ifp, NULL, 0);
+ if (profile->use_fwauth & BIT(BRCMF_PROFILE_FWAUTH_SAE))
+ brcmf_set_sae_password(ifp, NULL, 0);
+ profile->use_fwauth = BIT(BRCMF_PROFILE_FWAUTH_NONE);
+ }
+
if (ifp->vif->mbss) {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1);
return err;
@@ -7063,6 +7099,13 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
wiphy_ext_feature_set(wiphy,
NL80211_EXT_FEATURE_SAE_OFFLOAD);
}
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_FWAUTH)) {
+ wiphy_ext_feature_set(wiphy,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK);
+ if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SAE))
+ wiphy_ext_feature_set(wiphy,
+ NL80211_EXT_FEATURE_SAE_OFFLOAD_AP);
+ }
wiphy->mgmt_stypes = brcmf_txrx_stypes;
wiphy->max_remain_on_channel_duration = 5000;
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
index 333fdf394f95..17817cdb5de2 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
@@ -129,6 +129,19 @@ enum brcmf_profile_fwsup {
};
/**
+ * enum brcmf_profile_fwauth - firmware authenticator profile
+ *
+ * @BRCMF_PROFILE_FWAUTH_NONE: no firmware authenticator
+ * @BRCMF_PROFILE_FWAUTH_PSK: authenticator for WPA/WPA2-PSK
+ * @BRCMF_PROFILE_FWAUTH_SAE: authenticator for SAE
+ */
+enum brcmf_profile_fwauth {
+ BRCMF_PROFILE_FWAUTH_NONE,
+ BRCMF_PROFILE_FWAUTH_PSK,
+ BRCMF_PROFILE_FWAUTH_SAE
+};
+
+/**
* struct brcmf_cfg80211_profile - profile information.
*
* @bssid: bssid of joined/joining ibss.
@@ -140,6 +153,7 @@ struct brcmf_cfg80211_profile {
struct brcmf_cfg80211_security sec;
struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS];
enum brcmf_profile_fwsup use_fwsup;
+ u16 use_fwauth;
bool is_ft;
};
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
index 0dcefbd0c000..7c68d9849324 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -42,6 +42,7 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = {
{ BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" },
{ BRCMF_FEAT_DOT11H, "802.11h" },
{ BRCMF_FEAT_SAE, "sae" },
+ { BRCMF_FEAT_FWAUTH, "idauth" },
};
#ifdef DEBUG
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
index cda3fc1bab7f..d1f4257af696 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -28,6 +28,7 @@
* MONITOR_FMT_HW_RX_HDR: firmware provides monitor packets with hw/ucode header
* DOT11H: firmware supports 802.11h
* SAE: simultaneous authentication of equals
+ * FWAUTH: Firmware authenticator
*/
#define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \
@@ -49,7 +50,8 @@
BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) \
BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \
BRCMF_FEAT_DEF(DOT11H) \
- BRCMF_FEAT_DEF(SAE)
+ BRCMF_FEAT_DEF(SAE) \
+ BRCMF_FEAT_DEF(FWAUTH)
/*
* Quirks:
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
index ac5463838fcf..6f67fefe4b58 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
@@ -1578,6 +1578,9 @@ void brcmf_usb_exit(void)
brcmf_dbg(USB, "Enter\n");
ret = driver_for_each_device(drv, NULL, NULL,
brcmf_usb_reset_device);
+ if (ret)
+ brcmf_err("failed to reset all usb devices %d\n", ret);
+
usb_deregister(&brcmf_usbdrvr);
}
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
index 21691581b532..763e0ec583d7 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/main.c
@@ -5085,13 +5085,6 @@ int brcms_c_up(struct brcms_c_info *wlc)
return 0;
}
-static uint brcms_c_down_del_timer(struct brcms_c_info *wlc)
-{
- uint callbacks = 0;
-
- return callbacks;
-}
-
static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
{
bool dev_gone;
@@ -5201,8 +5194,6 @@ uint brcms_c_down(struct brcms_c_info *wlc)
callbacks++;
wlc->WDarmed = false;
}
- /* cancel all other timers */
- callbacks += brcms_c_down_del_timer(wlc);
wlc->pub->up = false;
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c
index 322bbd71388b..7717eb85a1db 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c
@@ -357,61 +357,6 @@ u16 rxiq_cal_rf_reg[11] = {
RADIO_2064_REG12A,
};
-static const
-struct lcnphy_rx_iqcomp lcnphy_rx_iqcomp_table_rev0[] = {
- {1, 0, 0},
- {2, 0, 0},
- {3, 0, 0},
- {4, 0, 0},
- {5, 0, 0},
- {6, 0, 0},
- {7, 0, 0},
- {8, 0, 0},
- {9, 0, 0},
- {10, 0, 0},
- {11, 0, 0},
- {12, 0, 0},
- {13, 0, 0},
- {14, 0, 0},
- {34, 0, 0},
- {38, 0, 0},
- {42, 0, 0},
- {46, 0, 0},
- {36, 0, 0},
- {40, 0, 0},
- {44, 0, 0},
- {48, 0, 0},
- {52, 0, 0},
- {56, 0, 0},
- {60, 0, 0},
- {64, 0, 0},
- {100, 0, 0},
- {104, 0, 0},
- {108, 0, 0},
- {112, 0, 0},
- {116, 0, 0},
- {120, 0, 0},
- {124, 0, 0},
- {128, 0, 0},
- {132, 0, 0},
- {136, 0, 0},
- {140, 0, 0},
- {149, 0, 0},
- {153, 0, 0},
- {157, 0, 0},
- {161, 0, 0},
- {165, 0, 0},
- {184, 0, 0},
- {188, 0, 0},
- {192, 0, 0},
- {196, 0, 0},
- {200, 0, 0},
- {204, 0, 0},
- {208, 0, 0},
- {212, 0, 0},
- {216, 0, 0},
-};
-
static const u32 lcnphy_23bitgaincode_table[] = {
0x200100,
0x200200,
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.c
index 7526aa441de1..5331b5468e14 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phytbl_lcn.c
@@ -105,105 +105,6 @@ static const u32 dot11lcn_gain_tbl_rev0[] = {
0x00000000,
};
-static const u32 dot11lcn_gain_tbl_rev1[] = {
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000008,
- 0x00000004,
- 0x00000008,
- 0x00000001,
- 0x00000005,
- 0x00000009,
- 0x0000000D,
- 0x00000011,
- 0x00000051,
- 0x00000091,
- 0x00000011,
- 0x00000051,
- 0x00000091,
- 0x000000d1,
- 0x00000053,
- 0x00000093,
- 0x000000d3,
- 0x000000d7,
- 0x00000117,
- 0x00000517,
- 0x00000917,
- 0x00000957,
- 0x00000d57,
- 0x00001157,
- 0x00001197,
- 0x00005197,
- 0x00009197,
- 0x0000d197,
- 0x00011197,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000008,
- 0x00000004,
- 0x00000008,
- 0x00000001,
- 0x00000005,
- 0x00000009,
- 0x0000000D,
- 0x00000011,
- 0x00000051,
- 0x00000091,
- 0x00000011,
- 0x00000051,
- 0x00000091,
- 0x000000d1,
- 0x00000053,
- 0x00000093,
- 0x000000d3,
- 0x000000d7,
- 0x00000117,
- 0x00000517,
- 0x00000917,
- 0x00000957,
- 0x00000d57,
- 0x00001157,
- 0x00005157,
- 0x00009157,
- 0x0000d157,
- 0x00011157,
- 0x00015157,
- 0x00019157,
- 0x0001d157,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
static const u16 dot11lcn_aux_gain_idx_tbl_rev0[] = {
0x0401,
0x0402,
diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c
index dd78c415d6e7..87b9398b03fd 100644
--- a/drivers/net/wireless/cisco/airo.c
+++ b/drivers/net/wireless/cisco/airo.c
@@ -2430,8 +2430,8 @@ void stop_airo_card(struct net_device *dev, int freeres)
iounmap(ai->pcimem);
if (ai->pciaux)
iounmap(ai->pciaux);
- pci_free_consistent(ai->pci, PCI_SHARED_LEN,
- ai->shared, ai->shared_dma);
+ dma_free_coherent(&ai->pci->dev, PCI_SHARED_LEN,
+ ai->shared, ai->shared_dma);
}
}
crypto_free_sync_skcipher(ai->tfm);
@@ -2581,9 +2581,10 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
}
/* Reserve PKTSIZE for each fid and 2K for the Rids */
- ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
+ ai->shared = dma_alloc_coherent(&pci->dev, PCI_SHARED_LEN,
+ &ai->shared_dma, GFP_KERNEL);
if (!ai->shared) {
- airo_print_err("", "Couldn't alloc_consistent %d",
+ airo_print_err("", "Couldn't alloc_coherent %d",
PCI_SHARED_LEN);
goto free_auxmap;
}
@@ -2643,7 +2644,8 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
return 0;
free_shared:
- pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
+ dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared,
+ ai->shared_dma);
free_auxmap:
iounmap(ai->pciaux);
free_memmap:
@@ -2930,7 +2932,8 @@ err_out_reg:
unregister_netdev(dev);
err_out_map:
if (test_bit(FLAG_MPI,&ai->flags) && pci) {
- pci_free_consistent(pci, PCI_SHARED_LEN, ai->shared, ai->shared_dma);
+ dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared,
+ ai->shared_dma);
iounmap(ai->pciaux);
iounmap(ai->pcimem);
mpi_unmap_card(ai->pci);
diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c
index 5d58b16bfe9f..52f583cb1418 100644
--- a/drivers/net/wireless/mediatek/mt76/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/debugfs.c
@@ -31,15 +31,14 @@ int mt76_queues_read(struct seq_file *s, void *data)
int i;
for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++) {
- struct mt76_sw_queue *q = &dev->q_tx[i];
+ struct mt76_queue *q = dev->q_tx[i];
- if (!q->q)
+ if (!q)
continue;
seq_printf(s,
- "%d: queued=%d head=%d tail=%d swq_queued=%d\n",
- i, q->q->queued, q->q->head, q->q->tail,
- q->swq_queued);
+ "%d: queued=%d head=%d tail=%d\n",
+ i, q->queued, q->head, q->tail);
}
return 0;
diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c
index 6c25859dd386..214fc95b8a33 100644
--- a/drivers/net/wireless/mediatek/mt76/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/dma.c
@@ -7,6 +7,76 @@
#include "mt76.h"
#include "dma.h"
+static struct mt76_txwi_cache *
+mt76_alloc_txwi(struct mt76_dev *dev)
+{
+ struct mt76_txwi_cache *t;
+ dma_addr_t addr;
+ u8 *txwi;
+ int size;
+
+ size = L1_CACHE_ALIGN(dev->drv->txwi_size + sizeof(*t));
+ txwi = devm_kzalloc(dev->dev, size, GFP_ATOMIC);
+ if (!txwi)
+ return NULL;
+
+ addr = dma_map_single(dev->dev, txwi, dev->drv->txwi_size,
+ DMA_TO_DEVICE);
+ t = (struct mt76_txwi_cache *)(txwi + dev->drv->txwi_size);
+ t->dma_addr = addr;
+
+ return t;
+}
+
+static struct mt76_txwi_cache *
+__mt76_get_txwi(struct mt76_dev *dev)
+{
+ struct mt76_txwi_cache *t = NULL;
+
+ spin_lock(&dev->lock);
+ if (!list_empty(&dev->txwi_cache)) {
+ t = list_first_entry(&dev->txwi_cache, struct mt76_txwi_cache,
+ list);
+ list_del(&t->list);
+ }
+ spin_unlock(&dev->lock);
+
+ return t;
+}
+
+static struct mt76_txwi_cache *
+mt76_get_txwi(struct mt76_dev *dev)
+{
+ struct mt76_txwi_cache *t = __mt76_get_txwi(dev);
+
+ if (t)
+ return t;
+
+ return mt76_alloc_txwi(dev);
+}
+
+void
+mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t)
+{
+ if (!t)
+ return;
+
+ spin_lock(&dev->lock);
+ list_add(&t->list, &dev->txwi_cache);
+ spin_unlock(&dev->lock);
+}
+EXPORT_SYMBOL_GPL(mt76_put_txwi);
+
+static void
+mt76_free_pending_txwi(struct mt76_dev *dev)
+{
+ struct mt76_txwi_cache *t;
+
+ while ((t = __mt76_get_txwi(dev)) != NULL)
+ dma_unmap_single(dev->dev, t->dma_addr, dev->drv->txwi_size,
+ DMA_TO_DEVICE);
+}
+
static int
mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
int idx, int n_desc, int bufsize,
@@ -49,6 +119,7 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
struct mt76_queue_buf *buf, int nbufs, u32 info,
struct sk_buff *skb, void *txwi)
{
+ struct mt76_queue_entry *entry;
struct mt76_desc *desc;
u32 ctrl;
int i, idx = -1;
@@ -61,10 +132,27 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
for (i = 0; i < nbufs; i += 2, buf += 2) {
u32 buf0 = buf[0].addr, buf1 = 0;
+ idx = q->head;
+ q->head = (q->head + 1) % q->ndesc;
+
+ desc = &q->desc[idx];
+ entry = &q->entry[idx];
+
+ if (buf[0].skip_unmap)
+ entry->skip_buf0 = true;
+ entry->skip_buf1 = i == nbufs - 1;
+
+ entry->dma_addr[0] = buf[0].addr;
+ entry->dma_len[0] = buf[0].len;
+
ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
if (i < nbufs - 1) {
+ entry->dma_addr[1] = buf[1].addr;
+ entry->dma_len[1] = buf[1].len;
buf1 = buf[1].addr;
ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len);
+ if (buf[1].skip_unmap)
+ entry->skip_buf1 = true;
}
if (i == nbufs - 1)
@@ -72,11 +160,6 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
else if (i == nbufs - 2)
ctrl |= MT_DMA_CTL_LAST_SEC1;
- idx = q->head;
- q->head = (q->head + 1) % q->ndesc;
-
- desc = &q->desc[idx];
-
WRITE_ONCE(desc->buf0, cpu_to_le32(buf0));
WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));
WRITE_ONCE(desc->info, cpu_to_le32(info));
@@ -96,24 +179,14 @@ mt76_dma_tx_cleanup_idx(struct mt76_dev *dev, struct mt76_queue *q, int idx,
struct mt76_queue_entry *prev_e)
{
struct mt76_queue_entry *e = &q->entry[idx];
- __le32 __ctrl = READ_ONCE(q->desc[idx].ctrl);
- u32 ctrl = le32_to_cpu(__ctrl);
- if (!e->skip_buf0) {
- __le32 addr = READ_ONCE(q->desc[idx].buf0);
- u32 len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl);
-
- dma_unmap_single(dev->dev, le32_to_cpu(addr), len,
+ if (!e->skip_buf0)
+ dma_unmap_single(dev->dev, e->dma_addr[0], e->dma_len[0],
DMA_TO_DEVICE);
- }
- if (!(ctrl & MT_DMA_CTL_LAST_SEC0)) {
- __le32 addr = READ_ONCE(q->desc[idx].buf1);
- u32 len = FIELD_GET(MT_DMA_CTL_SD_LEN1, ctrl);
-
- dma_unmap_single(dev->dev, le32_to_cpu(addr), len,
+ if (!e->skip_buf1)
+ dma_unmap_single(dev->dev, e->dma_addr[1], e->dma_len[1],
DMA_TO_DEVICE);
- }
if (e->txwi == DMA_DUMMY_DATA)
e->txwi = NULL;
@@ -137,19 +210,17 @@ mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
static void
mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
+ wmb();
writel(q->head, &q->regs->cpu_idx);
}
static void
mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
{
- struct mt76_sw_queue *sq = &dev->q_tx[qid];
- struct mt76_queue *q = sq->q;
+ struct mt76_queue *q = dev->q_tx[qid];
struct mt76_queue_entry entry;
- unsigned int n_swq_queued[8] = {};
- unsigned int n_queued = 0;
bool wake = false;
- int i, last;
+ int last;
if (!q)
return;
@@ -159,16 +230,9 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
else
last = readl(&q->regs->dma_idx);
- while ((q->queued > n_queued) && q->tail != last) {
+ while (q->queued > 0 && q->tail != last) {
mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry);
- if (entry.schedule)
- n_swq_queued[entry.qid]++;
-
- q->tail = (q->tail + 1) % q->ndesc;
- n_queued++;
-
- if (entry.skb)
- dev->drv->tx_complete_skb(dev, qid, &entry);
+ mt76_queue_tx_complete(dev, q, &entry);
if (entry.txwi) {
if (!(dev->drv->drv_flags & MT_DRV_TXWI_NO_FREE))
@@ -178,29 +242,14 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
if (!flush && q->tail == last)
last = readl(&q->regs->dma_idx);
- }
-
- spin_lock_bh(&q->lock);
-
- q->queued -= n_queued;
- for (i = 0; i < 4; i++) {
- if (!n_swq_queued[i])
- continue;
-
- dev->q_tx[i].swq_queued -= n_swq_queued[i];
- }
-
- /* ext PHY */
- for (i = 0; i < 4; i++) {
- if (!n_swq_queued[i])
- continue;
- dev->q_tx[__MT_TXQ_MAX + i].swq_queued -= n_swq_queued[4 + i];
}
if (flush) {
+ spin_lock_bh(&q->lock);
mt76_dma_sync_idx(dev, q);
mt76_dma_kick_queue(dev, q);
+ spin_unlock_bh(&q->lock);
}
wake = wake && q->stopped &&
@@ -211,8 +260,6 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, enum mt76_txq_id qid, bool flush)
if (!q->queued)
wake_up(&dev->tx_wait);
- spin_unlock_bh(&q->lock);
-
if (wake)
ieee80211_wake_queue(dev->hw, qid);
}
@@ -227,7 +274,7 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
void *buf = e->buf;
int buf_len = SKB_WITH_OVERHEAD(q->buf_size);
- buf_addr = le32_to_cpu(READ_ONCE(desc->buf0));
+ buf_addr = e->dma_addr[0];
if (len) {
u32 ctl = le32_to_cpu(READ_ONCE(desc->ctrl));
*len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctl);
@@ -268,7 +315,7 @@ static int
mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid,
struct sk_buff *skb, u32 tx_info)
{
- struct mt76_queue *q = dev->q_tx[qid].q;
+ struct mt76_queue *q = dev->q_tx[qid];
struct mt76_queue_buf buf;
dma_addr_t addr;
@@ -300,7 +347,7 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta)
{
- struct mt76_queue *q = dev->q_tx[qid].q;
+ struct mt76_queue *q = dev->q_tx[qid];
struct mt76_tx_info tx_info = {
.skb = skb,
};
@@ -378,7 +425,7 @@ free:
e.skb = tx_info.skb;
e.txwi = t;
- dev->drv->tx_complete_skb(dev, qid, &e);
+ dev->drv->tx_complete_skb(dev, &e);
mt76_put_txwi(dev, t);
return ret;
}
@@ -612,6 +659,7 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
{
int i;
+ mt76_worker_disable(&dev->tx_worker);
netif_napi_del(&dev->tx_napi);
for (i = 0; i < ARRAY_SIZE(dev->q_tx); i++)
mt76_dma_tx_cleanup(dev, i, true);
@@ -620,5 +668,7 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
netif_napi_del(&dev->napi[i]);
mt76_dma_rx_cleanup(dev, &dev->q_rx[i]);
}
+
+ mt76_free_pending_txwi(dev);
}
EXPORT_SYMBOL_GPL(mt76_dma_cleanup);
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index fbfb991ebd90..4befe7f937a9 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
*/
+#include <linux/sched.h>
#include <linux/of.h>
#include "mt76.h"
@@ -304,11 +305,11 @@ mt76_phy_init(struct mt76_dev *dev, struct ieee80211_hw *hw)
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
- ieee80211_hw_set(hw, TX_AMSDU);
- /* TODO: avoid linearization for SDIO */
- if (!mt76_is_sdio(dev))
+ if (!(dev->drv->drv_flags & MT_DRV_AMSDU_OFFLOAD)) {
+ ieee80211_hw_set(hw, TX_AMSDU);
ieee80211_hw_set(hw, TX_FRAG_LIST);
+ }
ieee80211_hw_set(hw, MFP_CAPABLE);
ieee80211_hw_set(hw, AP_LINK_PS);
@@ -433,14 +434,13 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
skb_queue_head_init(&dev->mcu.res_q);
init_waitqueue_head(&dev->mcu.wait);
mutex_init(&dev->mcu.mutex);
+ dev->tx_worker.fn = mt76_tx_worker;
INIT_LIST_HEAD(&dev->txwi_cache);
for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
skb_queue_head_init(&dev->rx_skb[i]);
- tasklet_init(&dev->tx_tasklet, mt76_tx_tasklet, (unsigned long)dev);
-
dev->wq = alloc_ordered_workqueue("mt76", 0);
if (!dev->wq) {
ieee80211_free_hw(hw);
@@ -483,7 +483,14 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
return ret;
}
- return ieee80211_register_hw(hw);
+ ret = ieee80211_register_hw(hw);
+ if (ret)
+ return ret;
+
+ WARN_ON(mt76_worker_setup(hw, &dev->tx_worker, NULL, "tx"));
+ sched_set_fifo_low(dev->tx_worker.task);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(mt76_register_device);
@@ -500,12 +507,11 @@ EXPORT_SYMBOL_GPL(mt76_unregister_device);
void mt76_free_device(struct mt76_dev *dev)
{
+ mt76_worker_teardown(&dev->tx_worker);
if (dev->wq) {
destroy_workqueue(dev->wq);
dev->wq = NULL;
}
- if (mt76_is_mmio(dev))
- mt76_tx_free(dev);
ieee80211_free_hw(dev->hw);
}
EXPORT_SYMBOL_GPL(mt76_free_device);
@@ -540,7 +546,7 @@ bool mt76_has_tx_pending(struct mt76_phy *phy)
offset = __MT_TXQ_MAX * (phy != &dev->phy);
for (i = 0; i < __MT_TXQ_MAX; i++) {
- q = dev->q_tx[offset + i].q;
+ q = dev->q_tx[offset + i];
if (q && q->queued)
return true;
}
@@ -870,7 +876,6 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
struct ieee80211_hw *hw;
struct mt76_wcid *wcid = status->wcid;
bool ps;
- int i;
hw = mt76_phy_hw(dev, status->ext_phy);
if (ieee80211_is_pspoll(hdr->frame_control) && !wcid) {
@@ -920,20 +925,6 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
dev->drv->sta_ps(dev, sta, ps);
ieee80211_sta_ps_transition(sta, ps);
-
- if (ps)
- return;
-
- for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
- struct mt76_txq *mtxq;
-
- if (!sta->txq[i])
- continue;
-
- mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
- if (!skb_queue_empty(&mtxq->retry_q))
- ieee80211_schedule_txq(hw, sta->txq[i]);
- }
}
void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
@@ -995,8 +986,6 @@ mt76_sta_add(struct mt76_dev *dev, struct ieee80211_vif *vif,
mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
mtxq->wcid = wcid;
-
- mt76_txq_init(dev, sta->txq[i]);
}
ewma_signal_init(&wcid->rssi);
@@ -1024,8 +1013,6 @@ void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
dev->drv->sta_remove(dev, vif, sta);
mt76_tx_status_check(dev, wcid, true);
- for (i = 0; i < ARRAY_SIZE(sta->txq); i++)
- mt76_txq_remove(dev, sta->txq[i]);
mt76_wcid_mask_clear(dev->wcid_mask, idx);
mt76_wcid_mask_clear(dev->wcid_phy_mask, idx);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index af35bc388ae2..a5be66de1cff 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -17,11 +17,13 @@
#include "util.h"
#include "testmode.h"
-#define MT_TX_RING_SIZE 256
#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
+
struct mt76_dev;
struct mt76_phy;
struct mt76_wcid;
@@ -79,7 +81,8 @@ enum mt76_rxq_id {
struct mt76_queue_buf {
dma_addr_t addr;
- int len;
+ u16 len;
+ bool skip_unmap;
};
struct mt76_tx_info {
@@ -99,9 +102,11 @@ struct mt76_queue_entry {
struct urb *urb;
int buf_sz;
};
- enum mt76_txq_id qid;
+ u32 dma_addr[2];
+ u16 dma_len[2];
+ u16 wcid;
bool skip_buf0:1;
- bool schedule:1;
+ bool skip_buf1:1;
bool done:1;
};
@@ -135,13 +140,6 @@ struct mt76_queue {
struct page_frag_cache rx_page;
};
-struct mt76_sw_queue {
- struct mt76_queue *q;
-
- struct list_head swq;
- int swq_queued;
-};
-
struct mt76_mcu_ops {
u32 headroom;
u32 tailroom;
@@ -204,6 +202,7 @@ DECLARE_EWMA(signal, 10, 8);
struct mt76_wcid {
struct mt76_rx_tid __rcu *aggr[IEEE80211_NUM_TIDS];
+ atomic_t non_aql_packets;
unsigned long flags;
struct ewma_signal rssi;
@@ -214,6 +213,7 @@ struct mt76_wcid {
u8 sta:1;
u8 ext_phy:1;
+ u8 amsdu:1;
u8 rx_check_pn;
u8 rx_key_pn[IEEE80211_NUM_TIDS][6];
@@ -226,11 +226,8 @@ struct mt76_wcid {
};
struct mt76_txq {
- struct mt76_sw_queue *swq;
struct mt76_wcid *wcid;
- struct sk_buff_head retry_q;
-
u16 agg_ssn;
bool send_bar;
bool aggr;
@@ -309,6 +306,7 @@ struct mt76_hw_cap {
#define MT_DRV_SW_RX_AIRTIME BIT(2)
#define MT_DRV_RX_DMA_HDR BIT(3)
#define MT_DRV_HW_MGMT_TXQ BIT(4)
+#define MT_DRV_AMSDU_OFFLOAD BIT(5)
struct mt76_driver_ops {
u32 drv_flags;
@@ -322,7 +320,7 @@ struct mt76_driver_ops {
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
- void (*tx_complete_skb)(struct mt76_dev *dev, enum mt76_txq_id qid,
+ void (*tx_complete_skb)(struct mt76_dev *dev,
struct mt76_queue_entry *e);
bool (*tx_status_data)(struct mt76_dev *dev, u8 *update);
@@ -445,14 +443,24 @@ struct mt76_usb {
} mcu;
};
+#define MT76S_XMIT_BUF_SZ (16 * PAGE_SIZE)
struct mt76_sdio {
- struct task_struct *tx_kthread;
- struct task_struct *kthread;
+ struct workqueue_struct *txrx_wq;
+ struct {
+ struct work_struct xmit_work;
+ struct work_struct status_work;
+ } tx;
+ struct {
+ struct work_struct recv_work;
+ struct work_struct net_work;
+ } rx;
+
struct work_struct stat_work;
- unsigned long state;
+ u8 *xmit_buf[MT_TXQ_MCU_WA];
struct sdio_func *func;
+ void *intr_data;
struct {
struct mutex lock;
@@ -593,12 +601,12 @@ struct mt76_dev {
struct sk_buff_head rx_skb[__MT_RXQ_MAX];
struct list_head txwi_cache;
- struct mt76_sw_queue q_tx[2 * __MT_TXQ_MAX];
+ struct mt76_queue *q_tx[2 * __MT_TXQ_MAX];
struct mt76_queue q_rx[__MT_RXQ_MAX];
const struct mt76_queue_ops *queue_ops;
int tx_dma_idx[4];
- struct tasklet_struct tx_tasklet;
+ struct mt76_worker tx_worker;
struct napi_struct tx_napi;
struct delayed_work mac_work;
@@ -892,14 +900,13 @@ static inline bool mt76_testmode_enabled(struct mt76_dev *dev)
void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb);
void mt76_tx(struct mt76_phy *dev, struct ieee80211_sta *sta,
struct mt76_wcid *wcid, struct sk_buff *skb);
-void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq);
-void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq);
void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
bool send_bar);
+void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb);
void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid);
void mt76_txq_schedule_all(struct mt76_phy *phy);
-void mt76_tx_tasklet(unsigned long data);
+void mt76_tx_worker(struct mt76_worker *w);
void mt76_release_buffered_frames(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 tids, int nframes,
@@ -932,7 +939,7 @@ struct sk_buff *mt76_tx_status_skb_get(struct mt76_dev *dev,
struct sk_buff_head *list);
void mt76_tx_status_skb_done(struct mt76_dev *dev, struct sk_buff *skb,
struct sk_buff_head *list);
-void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb);
+void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid, struct sk_buff *skb);
void mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid,
bool flush);
int mt76_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -996,8 +1003,6 @@ mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb)
return hw;
}
-void mt76_tx_free(struct mt76_dev *dev);
-struct mt76_txwi_cache *mt76_get_txwi(struct mt76_dev *dev);
void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t);
void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
struct napi_struct *napi);
@@ -1005,6 +1010,8 @@ void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
struct napi_struct *napi);
void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames);
void mt76_testmode_tx_pending(struct mt76_dev *dev);
+void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q,
+ struct mt76_queue_entry *e);
/* usb */
static inline bool mt76u_urb_error(struct urb *urb)
@@ -1039,7 +1046,7 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,
return usb_bulk_msg(udev, pipe, data, len, actual_len, timeout);
}
-int mt76_skb_adjust_pad(struct sk_buff *skb);
+int mt76_skb_adjust_pad(struct sk_buff *skb, int pad);
int mt76u_vendor_request(struct mt76_dev *dev, u8 req,
u8 req_type, u16 val, u16 offset,
void *buf, size_t len);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c
index 7a41cdf1c4ae..d728c5e43783 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c
@@ -29,7 +29,7 @@ mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY |
FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, mvif->sta.wcid.idx) |
FIELD_PREP(MT_DMA_FQCR0_TARGET_QID,
- dev->mt76.q_tx[MT_TXQ_CAB].q->hw_idx) |
+ dev->mt76.q_tx[MT_TXQ_CAB]->hw_idx) |
FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, 3) |
FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, 8));
@@ -78,7 +78,7 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
data.dev = dev;
__skb_queue_head_init(&data.q);
- q = dev->mt76.q_tx[MT_TXQ_BEACON].q;
+ q = dev->mt76.q_tx[MT_TXQ_BEACON];
spin_lock_bh(&q->lock);
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
@@ -95,7 +95,7 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
if (dev->mt76.csa_complete)
goto out;
- q = dev->mt76.q_tx[MT_TXQ_CAB].q;
+ q = dev->mt76.q_tx[MT_TXQ_CAB];
do {
nframes = skb_queue_len(&data.q);
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
@@ -136,7 +136,7 @@ void mt7603_pre_tbtt_tasklet(unsigned long arg)
out:
mt76_queue_tx_cleanup(dev, MT_TXQ_BEACON, false);
- if (dev->mt76.q_tx[MT_TXQ_BEACON].q->queued >
+ if (dev->mt76.q_tx[MT_TXQ_BEACON]->queued >
hweight8(dev->mt76.beacon_mask))
dev->beacon_check++;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c
index 8ce6880b2bb8..f52165dff422 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c
@@ -70,7 +70,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_edcca, mt7603_edcca_get,
mt7603_edcca_set, "%lld\n");
static int
-mt7603_ampdu_stat_read(struct seq_file *file, void *data)
+mt7603_ampdu_stat_show(struct seq_file *file, void *data)
{
struct mt7603_dev *dev = file->private;
int bound[3], i, range;
@@ -91,18 +91,7 @@ mt7603_ampdu_stat_read(struct seq_file *file, void *data)
return 0;
}
-static int
-mt7603_ampdu_stat_open(struct inode *inode, struct file *f)
-{
- return single_open(f, mt7603_ampdu_stat_read, inode->i_private);
-}
-
-static const struct file_operations fops_ampdu_stat = {
- .open = mt7603_ampdu_stat_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mt7603_ampdu_stat);
void mt7603_init_debugfs(struct mt7603_dev *dev)
{
@@ -112,7 +101,8 @@ void mt7603_init_debugfs(struct mt7603_dev *dev)
if (!dir)
return;
- debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
+ debugfs_create_file("ampdu_stat", 0400, dir, dev,
+ &mt7603_ampdu_stat_fops);
debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir,
mt76_queues_read);
debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
index a08b85281170..d60d00f6f6a0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c
@@ -5,8 +5,7 @@
#include "../dma.h"
static int
-mt7603_init_tx_queue(struct mt7603_dev *dev, struct mt76_sw_queue *q,
- int idx, int n_desc)
+mt7603_init_tx_queue(struct mt7603_dev *dev, int qid, int idx, int n_desc)
{
struct mt76_queue *hwq;
int err;
@@ -19,8 +18,7 @@ mt7603_init_tx_queue(struct mt7603_dev *dev, struct mt76_sw_queue *q,
if (err < 0)
return err;
- INIT_LIST_HEAD(&q->swq);
- q->q = hwq;
+ dev->mt76.q_tx[qid] = hwq;
mt7603_irq_enable(dev, MT_INT_TX_DONE(idx));
@@ -123,7 +121,7 @@ void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
mt76_rx(&dev->mt76, q, skb);
return;
}
- /* fall through */
+ fallthrough;
default:
dev_kfree_skb(skb);
break;
@@ -165,7 +163,7 @@ static int mt7603_poll_tx(struct napi_struct *napi, int budget)
mt7603_mac_sta_poll(dev);
- tasklet_schedule(&dev->mt76.tx_tasklet);
+ mt76_worker_schedule(&dev->mt76.tx_worker);
return 0;
}
@@ -193,29 +191,28 @@ int mt7603_dma_init(struct mt7603_dev *dev)
mt7603_pse_client_reset(dev);
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
- ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[i],
- wmm_queue_map[i],
- MT_TX_RING_SIZE);
+ ret = mt7603_init_tx_queue(dev, i, wmm_queue_map[i],
+ MT7603_TX_RING_SIZE);
if (ret)
return ret;
}
- ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD],
- MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE);
+ ret = mt7603_init_tx_queue(dev, MT_TXQ_PSD,
+ MT_TX_HW_QUEUE_MGMT, MT7603_PSD_RING_SIZE);
if (ret)
return ret;
- ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
+ ret = mt7603_init_tx_queue(dev, MT_TXQ_MCU,
MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
if (ret)
return ret;
- ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_BEACON],
+ ret = mt7603_init_tx_queue(dev, MT_TXQ_BEACON,
MT_TX_HW_QUEUE_BCN, MT_MCU_RING_SIZE);
if (ret)
return ret;
- ret = mt7603_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_CAB],
+ ret = mt7603_init_tx_queue(dev, MT_TXQ_CAB,
MT_TX_HW_QUEUE_BMC, MT_MCU_RING_SIZE);
if (ret)
return ret;
@@ -249,6 +246,5 @@ void mt7603_dma_cleanup(struct mt7603_dev *dev)
MT_WPDMA_GLO_CFG_RX_DMA_EN |
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
- tasklet_kill(&dev->mt76.tx_tasklet);
mt76_dma_cleanup(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c
index 3ee06e2577b8..01f1e0da5ee1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c
@@ -147,8 +147,14 @@ static int mt7603_check_eeprom(struct mt76_dev *dev)
}
}
+static inline bool is_mt7688(struct mt7603_dev *dev)
+{
+ return mt76_rr(dev, MT_EFUSE_BASE + 0x64) & BIT(4);
+}
+
int mt7603_eeprom_init(struct mt7603_dev *dev)
{
+ u8 *eeprom;
int ret;
ret = mt7603_eeprom_load(dev);
@@ -163,9 +169,16 @@ int mt7603_eeprom_init(struct mt7603_dev *dev)
MT7603_EEPROM_SIZE);
}
+ eeprom = (u8 *)dev->mt76.eeprom.data;
dev->mt76.cap.has_2ghz = true;
- memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
- ETH_ALEN);
+ memcpy(dev->mt76.macaddr, eeprom + MT_EE_MAC_ADDR, ETH_ALEN);
+
+ /* Check for 1SS devices */
+ dev->mphy.antenna_mask = 3;
+ if (FIELD_GET(MT_EE_NIC_CONF_0_RX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 ||
+ FIELD_GET(MT_EE_NIC_CONF_0_TX_PATH, eeprom[MT_EE_NIC_CONF_0]) == 1 ||
+ is_mt7688(dev))
+ dev->mphy.antenna_mask = 1;
mt76_eeprom_override(&dev->mt76);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
index b893facfba48..4687d6dc00dc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.h
@@ -85,4 +85,7 @@ enum mt7603_eeprom_source {
MT_EE_SRC_FLASH,
};
+#define MT_EE_NIC_CONF_0_RX_PATH GENMASK(3, 0)
+#define MT_EE_NIC_CONF_0_TX_PATH GENMASK(7, 4)
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
index 94196599797e..c4848fafd270 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
@@ -536,11 +536,6 @@ int mt7603_register_device(struct mt7603_dev *dev)
tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt7603_pre_tbtt_tasklet,
(unsigned long)dev);
- /* Check for 7688, which only has 1SS */
- dev->mphy.antenna_mask = 3;
- if (mt76_rr(dev, MT_EFUSE_BASE + 0x64) & BIT(4))
- dev->mphy.antenna_mask = 1;
-
dev->slottime = 9;
dev->sensitivity_limit = 28;
dev->dynamic_sensitivity = true;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
index 8060c1514396..f665a1c95eed 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
@@ -445,7 +445,7 @@ void mt7603_mac_sta_poll(struct mt7603_dev *dev)
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
for (i = 0; i < 4; i++) {
- struct mt76_queue *q = dev->mt76.q_tx[i].q;
+ struct mt76_queue *q = dev->mt76.q_tx[i];
u8 qidx = q->hw_idx;
u8 tid = ac_to_tid[i];
u32 txtime = airtime[qidx];
@@ -592,7 +592,7 @@ mt7603_mac_fill_rx(struct mt7603_dev *dev, struct sk_buff *skb)
switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) {
case MT_PHY_TYPE_CCK:
cck = true;
- /* fall through */
+ fallthrough;
case MT_PHY_TYPE_OFDM:
i = mt76_get_rate(&dev->mt76, sband, i, cck);
break;
@@ -896,7 +896,7 @@ mt7603_mac_write_txwi(struct mt7603_dev *dev, __le32 *txwi,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data;
struct ieee80211_vif *vif = info->control.vif;
- struct mt76_queue *q = dev->mt76.q_tx[qid].q;
+ struct mt76_queue *q = dev->mt76.q_tx[qid];
struct mt7603_vif *mvif;
int wlan_idx;
int hdr_len = ieee80211_get_hdrlen_from_skb(skb);
@@ -1036,6 +1036,8 @@ int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
IEEE80211_TX_CTL_CLEAR_PS_FILT)) ||
(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
mt7603_wtbl_set_ps(dev, msta, false);
+
+ mt76_tx_check_agg_ssn(sta, tx_info->skb);
}
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
@@ -1161,7 +1163,7 @@ out:
switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) {
case MT_PHY_TYPE_CCK:
cck = true;
- /* fall through */
+ fallthrough;
case MT_PHY_TYPE_OFDM:
if (dev->mphy.chandef.chan->band == NL80211_BAND_5GHZ)
sband = &dev->mphy.sband_5g.sband;
@@ -1269,8 +1271,7 @@ out:
rcu_read_unlock();
}
-void mt7603_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
- struct mt76_queue_entry *e)
+void mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
{
struct mt7603_dev *dev = container_of(mdev, struct mt7603_dev, mt76);
struct sk_buff *skb = e->skb;
@@ -1280,10 +1281,8 @@ void mt7603_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
return;
}
- if (qid < 4)
- dev->tx_hang_check = 0;
-
- mt76_tx_complete_skb(mdev, skb);
+ dev->tx_hang_check = 0;
+ mt76_tx_complete_skb(mdev, e->wcid, skb);
}
static bool
@@ -1403,7 +1402,7 @@ static void mt7603_mac_watchdog_reset(struct mt7603_dev *dev)
/* lock/unlock all queues to ensure that no tx is pending */
mt76_txq_schedule_all(&dev->mphy);
- tasklet_disable(&dev->mt76.tx_tasklet);
+ mt76_worker_disable(&dev->mt76.tx_worker);
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
napi_disable(&dev->mt76.napi[0]);
napi_disable(&dev->mt76.napi[1]);
@@ -1452,7 +1451,7 @@ skip_dma_reset:
clear_bit(MT76_RESET, &dev->mphy.state);
mutex_unlock(&dev->mt76.mutex);
- tasklet_enable(&dev->mt76.tx_tasklet);
+ mt76_worker_enable(&dev->mt76.tx_worker);
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
@@ -1515,7 +1514,7 @@ static bool mt7603_tx_hang(struct mt7603_dev *dev)
int i;
for (i = 0; i < 4; i++) {
- q = dev->mt76.q_tx[i].q;
+ q = dev->mt76.q_tx[i];
if (!q->queued)
continue;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
index 447f2c63ef38..c9226dceb510 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
@@ -75,7 +75,6 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
mtxq->wcid = &mvif->sta.wcid;
- mt76_txq_init(&dev->mt76, vif->txq);
rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
out:
@@ -99,7 +98,6 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
mt7603_beacon_set_timer(dev, mvif->idx, 0);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
- mt76_txq_remove(&dev->mt76, vif->txq);
spin_lock_bh(&dev->sta_poll_lock);
if (!list_empty(&msta->poll_list))
@@ -514,7 +512,7 @@ mt7603_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
u16 cw_max = (1 << 10) - 1;
u32 val;
- queue = dev->mt76.q_tx[queue].q->hw_idx;
+ queue = dev->mt76.q_tx[queue]->hw_idx;
if (params->cw_min)
cw_min = params->cw_min;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
index c86305241e66..2a6e4332ad06 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
@@ -17,6 +17,8 @@
#define MT7603_MCU_RX_RING_SIZE 64
#define MT7603_RX_RING_SIZE 128
+#define MT7603_TX_RING_SIZE 256
+#define MT7603_PSD_RING_SIZE 128
#define MT7603_FIRMWARE_E1 "mt7603_e1.bin"
#define MT7603_FIRMWARE_E2 "mt7603_e2.bin"
@@ -241,8 +243,7 @@ int mt7603_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
-void mt7603_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
- struct mt76_queue_entry *e);
+void mt7603_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
void mt7603_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/pci.c b/drivers/net/wireless/mediatek/mt76/mt7603/pci.c
index 2f2f337e2201..a5845da3547a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/pci.c
@@ -44,6 +44,8 @@ mt76pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
(mt76_rr(dev, MT_HW_REV) & 0xff);
dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+
ret = devm_request_irq(mdev->dev, pdev->irq, mt7603_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c
index de170765e938..ba927033bbe8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c
@@ -35,6 +35,8 @@ mt76_wmac_probe(struct platform_device *pdev)
(mt76_rr(dev, MT_HW_REV) & 0xff);
dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+
ret = devm_request_irq(mdev->dev, irq, mt7603_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
index 88931658a9fb..00ba550fc48f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
@@ -165,15 +165,14 @@ mt7615_reset_test_set(void *data, u64 val)
if (!mt7615_wait_for_mcu_init(dev))
return 0;
- mt7615_mutex_acquire(dev);
-
skb = alloc_skb(1, GFP_KERNEL);
if (!skb)
return -ENOMEM;
skb_put(skb, 1);
- mt76_tx_queue_skb_raw(dev, 0, skb, 0);
+ mt7615_mutex_acquire(dev);
+ mt76_tx_queue_skb_raw(dev, 0, skb, 0);
mt7615_mutex_release(dev);
return 0;
@@ -221,7 +220,7 @@ mt7615_ampdu_stat_read_phy(struct mt7615_phy *phy,
}
static int
-mt7615_ampdu_stat_read(struct seq_file *file, void *data)
+mt7615_ampdu_stat_show(struct seq_file *file, void *data)
{
struct mt7615_dev *dev = file->private;
@@ -235,18 +234,7 @@ mt7615_ampdu_stat_read(struct seq_file *file, void *data)
return 0;
}
-static int
-mt7615_ampdu_stat_open(struct inode *inode, struct file *f)
-{
- return single_open(f, mt7615_ampdu_stat_read, inode->i_private);
-}
-
-static const struct file_operations fops_ampdu_stat = {
- .open = mt7615_ampdu_stat_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mt7615_ampdu_stat);
static void
mt7615_radio_read_phy(struct mt7615_phy *phy, struct seq_file *s)
@@ -340,15 +328,15 @@ mt7615_queues_read(struct seq_file *s, void *data)
int i;
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
- struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id];
+ struct mt76_queue *q = dev->mt76.q_tx[queue_map[i].id];
- if (!q->q)
+ if (!q)
continue;
seq_printf(s,
"%s: queued=%d head=%d tail=%d\n",
- queue_map[i].queue, q->q->queued, q->q->head,
- q->q->tail);
+ queue_map[i].queue, q->queued, q->head,
+ q->tail);
}
return 0;
@@ -393,7 +381,7 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
mt76_queues_read);
debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
mt7615_queues_acq);
- debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
+ debugfs_create_file("ampdu_stat", 0400, dir, dev, &mt7615_ampdu_stat_fops);
debugfs_create_file("scs", 0600, dir, dev, &fops_scs);
debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc);
debugfs_create_file("fw_debug", 0600, dir, dev, &fops_fw_debug);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
index 1231a5ddf9ea..bf8ae14121db 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -12,8 +12,7 @@
#include "mac.h"
static int
-mt7615_init_tx_queue(struct mt7615_dev *dev, struct mt76_sw_queue *q,
- int idx, int n_desc)
+mt7615_init_tx_queue(struct mt7615_dev *dev, int qid, int idx, int n_desc)
{
struct mt76_queue *hwq;
int err;
@@ -26,8 +25,7 @@ mt7615_init_tx_queue(struct mt7615_dev *dev, struct mt76_sw_queue *q,
if (err < 0)
return err;
- INIT_LIST_HEAD(&q->swq);
- q->q = hwq;
+ dev->mt76.q_tx[qid] = hwq;
return 0;
}
@@ -45,19 +43,18 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev)
int i;
for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) {
- ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[i],
- wmm_queue_map[i],
+ ret = mt7615_init_tx_queue(dev, i, wmm_queue_map[i],
MT7615_TX_RING_SIZE / 2);
if (ret)
return ret;
}
- ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD],
+ ret = mt7615_init_tx_queue(dev, MT_TXQ_PSD,
MT7622_TXQ_MGMT, MT7615_TX_MGMT_RING_SIZE);
if (ret)
return ret;
- ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
+ ret = mt7615_init_tx_queue(dev, MT_TXQ_MCU,
MT7622_TXQ_MCU, MT7615_TX_MCU_RING_SIZE);
return ret;
}
@@ -65,10 +62,9 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev)
static int
mt7615_init_tx_queues(struct mt7615_dev *dev)
{
- struct mt76_sw_queue *q;
int ret, i;
- ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_FWDL],
+ ret = mt7615_init_tx_queue(dev, MT_TXQ_FWDL,
MT7615_TXQ_FWDL,
MT7615_TX_FWDL_RING_SIZE);
if (ret)
@@ -77,52 +73,28 @@ mt7615_init_tx_queues(struct mt7615_dev *dev)
if (!is_mt7615(&dev->mt76))
return mt7622_init_tx_queues_multi(dev);
- ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[0], 0,
- MT7615_TX_RING_SIZE);
+ ret = mt7615_init_tx_queue(dev, 0, 0, MT7615_TX_RING_SIZE);
if (ret)
return ret;
- for (i = 1; i < MT_TXQ_MCU; i++) {
- q = &dev->mt76.q_tx[i];
- INIT_LIST_HEAD(&q->swq);
- q->q = dev->mt76.q_tx[0].q;
- }
+ for (i = 1; i < MT_TXQ_MCU; i++)
+ dev->mt76.q_tx[i] = dev->mt76.q_tx[0];
- ret = mt7615_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
- MT7615_TXQ_MCU,
+ ret = mt7615_init_tx_queue(dev, MT_TXQ_MCU, MT7615_TXQ_MCU,
MT7615_TX_MCU_RING_SIZE);
return 0;
}
-static void
-mt7615_tx_cleanup(struct mt7615_dev *dev)
-{
- int i;
-
- mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false);
- mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
- if (is_mt7615(&dev->mt76)) {
- mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
- } else {
- for (i = 0; i < IEEE80211_NUM_ACS; i++)
- mt76_queue_tx_cleanup(dev, i, false);
- }
-}
-
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);
- mt7615_tx_cleanup(dev);
+ mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false);
if (napi_complete_done(napi, 0))
- mt7615_irq_enable(dev, MT_INT_TX_DONE_ALL);
-
- mt7615_tx_cleanup(dev);
-
- tasklet_schedule(&dev->mt76.tx_tasklet);
+ mt7615_irq_enable(dev, mt7615_tx_mcu_int_mask(dev));
return 0;
}
@@ -306,7 +278,7 @@ int mt7615_dma_init(struct mt7615_dev *dev)
MT_WPDMA_GLO_CFG_RX_DMA_EN);
/* enable interrupts for TX/RX rings */
- mt7615_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
+ mt7615_irq_enable(dev, MT_INT_RX_DONE_ALL | mt7615_tx_mcu_int_mask(dev) |
MT_INT_MCU_CMD);
if (is_mt7622(&dev->mt76))
@@ -325,6 +297,5 @@ void mt7615_dma_cleanup(struct mt7615_dev *dev)
MT_WPDMA_GLO_CFG_RX_DMA_EN);
mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_SW_RESET);
- tasklet_kill(&dev->mt76.tx_tasklet);
mt76_dma_cleanup(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
index 22e4eabe6578..f4756bb946c3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
@@ -125,6 +125,9 @@ mt7615_eeprom_parse_hw_band_cap(struct mt7615_dev *dev)
case MT_EE_2GHZ:
dev->mt76.cap.has_2ghz = true;
break;
+ case MT_EE_DBDC:
+ dev->dbdc_support = true;
+ /* fall through */
default:
dev->mt76.cap.has_2ghz = true;
dev->mt76.cap.has_5ghz = true;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index fc1ebabfebac..2a4db46727fb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -217,6 +217,22 @@ static const struct ieee80211_iface_limit if_limits[] = {
}
};
+static const struct ieee80211_iface_combination if_comb_radar[] = {
+ {
+ .limits = if_limits,
+ .n_limits = ARRAY_SIZE(if_limits),
+ .max_interfaces = 4,
+ .num_different_channels = 1,
+ .beacon_int_infra_match = true,
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160) |
+ BIT(NL80211_CHAN_WIDTH_80P80),
+ }
+};
+
static const struct ieee80211_iface_combination if_comb[] = {
{
.limits = if_limits,
@@ -306,8 +322,13 @@ mt7615_init_wiphy(struct ieee80211_hw *hw)
hw->sta_data_size = sizeof(struct mt7615_sta);
hw->vif_data_size = sizeof(struct mt7615_vif);
- wiphy->iface_combinations = if_comb;
- wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+ if (is_mt7663(&phy->dev->mt76)) {
+ wiphy->iface_combinations = if_comb;
+ wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+ } else {
+ wiphy->iface_combinations = if_comb_radar;
+ wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_radar);
+ }
wiphy->reg_notifier = mt7615_regd_notifier;
wiphy->max_sched_scan_plan_interval = MT7615_MAX_SCHED_SCAN_INTERVAL;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index 3dd8dd28690e..8dc645e398fd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -378,7 +378,7 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
switch (FIELD_GET(MT_RXV1_TX_MODE, rxdg0)) {
case MT_PHY_TYPE_CCK:
cck = true;
- /* fall through */
+ fallthrough;
case MT_PHY_TYPE_OFDM:
i = mt76_get_rate(&dev->mt76, sband, i, cck);
break;
@@ -1271,7 +1271,7 @@ out:
switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) {
case MT_PHY_TYPE_CCK:
cck = true;
- /* fall through */
+ fallthrough;
case MT_PHY_TYPE_OFDM:
mphy = &dev->mphy;
if (sta->wcid.ext_phy && dev->mt76.phy2)
@@ -1400,6 +1400,9 @@ mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
{
struct mt76_dev *mdev = &dev->mt76;
struct mt76_txwi_cache *txwi;
+ __le32 *txwi_data;
+ u32 val;
+ u8 wcid;
trace_mac_tx_free(dev, token);
@@ -1410,9 +1413,13 @@ mt7615_mac_tx_free_token(struct mt7615_dev *dev, u16 token)
if (!txwi)
return;
+ txwi_data = (__le32 *)mt76_get_txwi_ptr(mdev, txwi);
+ val = le32_to_cpu(txwi_data[1]);
+ wcid = FIELD_GET(MT_TXD1_WLAN_IDX, val);
+
mt7615_txp_skb_unmap(mdev, txwi);
if (txwi->skb) {
- mt76_tx_complete_skb(mdev, txwi->skb);
+ mt76_tx_complete_skb(mdev, wcid, txwi->skb);
txwi->skb = NULL;
}
@@ -1424,6 +1431,14 @@ static void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
struct mt7615_tx_free *free = (struct mt7615_tx_free *)skb->data;
u8 i, count;
+ mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
+ if (is_mt7615(&dev->mt76)) {
+ mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
+ } else {
+ for (i = 0; i < IEEE80211_NUM_ACS; i++)
+ mt76_queue_tx_cleanup(dev, i, false);
+ }
+
count = FIELD_GET(MT_TX_FREE_MSDU_ID_CNT, le16_to_cpu(free->ctrl));
if (is_mt7615(&dev->mt76)) {
__le16 *token = &free->token[0];
@@ -1439,11 +1454,15 @@ 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();
- tasklet_schedule(&dev->mt76.tx_tasklet);
+ mt7615_pm_power_save_sched(dev);
+ mt76_worker_schedule(&dev->mt76.tx_worker);
}
void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
@@ -1478,7 +1497,7 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
mt76_rx(&dev->mt76, q, skb);
return;
}
- /* fall through */
+ fallthrough;
default:
dev_kfree_skb(skb);
break;
@@ -1845,7 +1864,7 @@ void mt7615_pm_wake_work(struct work_struct *work)
pm.wake_work);
mphy = dev->phy.mt76;
- if (mt7615_driver_own(dev)) {
+ if (mt7615_mcu_set_drv_ctrl(dev)) {
dev_err(mphy->dev->dev, "failed to wake device\n");
goto out;
}
@@ -1853,12 +1872,13 @@ void mt7615_pm_wake_work(struct work_struct *work)
spin_lock_bh(&dev->pm.txq_lock);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
struct mt7615_sta *msta = dev->pm.tx_q[i].msta;
- struct mt76_wcid *wcid = msta ? &msta->wcid : NULL;
struct ieee80211_sta *sta = NULL;
+ struct mt76_wcid *wcid;
if (!dev->pm.tx_q[i].skb)
continue;
+ wcid = msta ? &msta->wcid : &dev->mt76.global_wcid;
if (msta && wcid->sta)
sta = container_of((void *)msta, struct ieee80211_sta,
drv_priv);
@@ -1868,7 +1888,7 @@ void mt7615_pm_wake_work(struct work_struct *work)
}
spin_unlock_bh(&dev->pm.txq_lock);
- tasklet_schedule(&dev->mt76.tx_tasklet);
+ mt76_worker_schedule(&dev->mt76.tx_worker);
out:
ieee80211_wake_queues(mphy->hw);
@@ -1943,7 +1963,7 @@ void mt7615_pm_power_save_work(struct work_struct *work)
goto out;
}
- if (!mt7615_firmware_own(dev))
+ if (!mt7615_mcu_set_fw_ctrl(dev))
return;
out:
queue_delayed_work(dev->mt76.wq, &dev->pm.ps_work, delta);
@@ -2110,7 +2130,7 @@ void mt7615_mac_reset_work(struct work_struct *work)
if (ext_phy)
mt76_txq_schedule_all(ext_phy);
- tasklet_disable(&dev->mt76.tx_tasklet);
+ mt76_worker_disable(&dev->mt76.tx_worker);
napi_disable(&dev->mt76.napi[0]);
napi_disable(&dev->mt76.napi[1]);
napi_disable(&dev->mt76.tx_napi);
@@ -2131,7 +2151,7 @@ void mt7615_mac_reset_work(struct work_struct *work)
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_RESET, &dev->mphy.state);
- tasklet_enable(&dev->mt76.tx_tasklet);
+ mt76_worker_enable(&dev->mt76.tx_worker);
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 2d0b1f49fdbc..3186b7b2ca48 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -205,7 +205,6 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
if (vif->txq) {
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
mtxq->wcid = &mvif->sta.wcid;
- mt76_txq_init(&dev->mt76, vif->txq);
}
ret = mt7615_mcu_add_dev_info(dev, vif, true);
@@ -256,8 +255,6 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
mt7615_mcu_add_dev_info(dev, vif, false);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
- if (vif->txq)
- mt76_txq_remove(&dev->mt76, vif->txq);
dev->mphy.vif_mask &= ~BIT(mvif->idx);
dev->omac_mask &= ~BIT(mvif->omac_idx);
@@ -361,7 +358,10 @@ mt7615_queue_key_update(struct mt7615_dev *dev, enum set_key_cmd cmd,
wd->key.keylen = key->keylen;
wd->key.cmd = cmd;
+ spin_lock_bh(&dev->mt76.lock);
list_add_tail(&wd->node, &dev->wd_head);
+ spin_unlock_bh(&dev->mt76.lock);
+
queue_work(dev->mt76.wq, &dev->wtbl_work);
return 0;
@@ -703,7 +703,8 @@ mt7615_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
return;
}
- tasklet_schedule(&dev->mt76.tx_tasklet);
+ dev->pm.last_activity = jiffies;
+ mt76_worker_schedule(&dev->mt76.tx_worker);
}
static void mt7615_tx(struct ieee80211_hw *hw,
@@ -732,6 +733,7 @@ static void mt7615_tx(struct ieee80211_hw *hw,
}
if (!test_bit(MT76_STATE_PM, &mphy->state)) {
+ dev->pm.last_activity = jiffies;
mt76_tx(mphy, control->sta, wcid, skb);
return;
}
@@ -813,7 +815,6 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_START:
ssn = mt7615_mac_get_sta_tid_sn(dev, msta->wcid.idx, tid);
params->ssn = ssn;
- mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 7781530fb3e6..31b40fb83f6c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -324,6 +324,97 @@ int mt7615_rf_wr(struct mt7615_dev *dev, u32 wf, u32 reg, u32 val)
sizeof(req), false);
}
+static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)
+{
+ if (!is_mt7622(&dev->mt76))
+ return;
+
+ regmap_update_bits(dev->infracfg, MT_INFRACFG_MISC,
+ MT_INFRACFG_MISC_AP2CONN_WAKE,
+ !en * MT_INFRACFG_MISC_AP2CONN_WAKE);
+}
+
+static int mt7615_mcu_drv_pmctrl(struct mt7615_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_dev *mdev = &dev->mt76;
+ u32 addr;
+ int err;
+
+ addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : 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);
+
+ if (err) {
+ dev_err(mdev->dev, "driver own failed\n");
+ return -ETIMEDOUT;
+ }
+
+ clear_bit(MT76_STATE_PM, &mphy->state);
+
+ return 0;
+}
+
+static int mt7615_mcu_lp_drv_pmctrl(struct mt7615_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ int i;
+
+ if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state))
+ goto out;
+
+ for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) {
+ mt76_wr(dev, MT_PCIE_DOORBELL_PUSH, MT_CFG_LPCR_HOST_DRV_OWN);
+ if (mt76_poll_msec(dev, MT_CONN_HIF_ON_LPCTL,
+ MT_CFG_LPCR_HOST_FW_OWN, 0, 50))
+ break;
+ }
+
+ 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;
+ }
+
+out:
+ dev->pm.last_activity = jiffies;
+
+ return 0;
+}
+
+static int mt7615_mcu_fw_pmctrl(struct mt7615_dev *dev)
+{
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ int err = 0;
+ u32 addr;
+
+ if (test_and_set_bit(MT76_STATE_PM, &mphy->state))
+ return 0;
+
+ mt7622_trigger_hif_int(dev, true);
+
+ addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
+ mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN);
+
+ if (is_mt7622(&dev->mt76) &&
+ !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN,
+ MT_CFG_LPCR_HOST_FW_OWN, 3000)) {
+ dev_err(dev->mt76.dev, "Timeout for firmware own\n");
+ clear_bit(MT76_STATE_PM, &mphy->state);
+ err = -EIO;
+ }
+
+ mt7622_trigger_hif_int(dev, false);
+
+ return err;
+}
+
static void
mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
@@ -1106,7 +1197,7 @@ mt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht),
wtbl_tlv, sta_wtbl);
ht = (struct wtbl_ht *)tlv;
- ht->ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING;
+ ht->ldpc = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING);
ht->af = sta->ht_cap.ampdu_factor;
ht->mm = sta->ht_cap.ampdu_density;
ht->ht = 1;
@@ -1124,7 +1215,7 @@ mt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht),
wtbl_tlv, sta_wtbl);
vht = (struct wtbl_vht *)tlv;
- vht->ldpc = sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC,
+ vht->ldpc = !!(sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC);
vht->vht = 1;
af = (sta->vht_cap.cap &
@@ -1314,6 +1405,8 @@ static const struct mt7615_mcu_ops wtbl_update_ops = {
.add_tx_ba = mt7615_mcu_wtbl_tx_ba,
.add_rx_ba = mt7615_mcu_wtbl_rx_ba,
.sta_add = mt7615_mcu_wtbl_sta_add,
+ .set_drv_ctrl = mt7615_mcu_drv_pmctrl,
+ .set_fw_ctrl = mt7615_mcu_fw_pmctrl,
};
static int
@@ -1410,6 +1503,8 @@ static const struct mt7615_mcu_ops sta_update_ops = {
.add_tx_ba = mt7615_mcu_sta_tx_ba,
.add_rx_ba = mt7615_mcu_sta_rx_ba,
.sta_add = mt7615_mcu_add_sta,
+ .set_drv_ctrl = mt7615_mcu_drv_pmctrl,
+ .set_fw_ctrl = mt7615_mcu_fw_pmctrl,
};
static int
@@ -1823,6 +1918,8 @@ static const struct mt7615_mcu_ops uni_update_ops = {
.add_tx_ba = mt7615_mcu_uni_tx_ba,
.add_rx_ba = mt7615_mcu_uni_rx_ba,
.sta_add = mt7615_mcu_uni_add_sta,
+ .set_drv_ctrl = mt7615_mcu_lp_drv_pmctrl,
+ .set_fw_ctrl = mt7615_mcu_fw_pmctrl,
};
static int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data,
@@ -1895,81 +1992,6 @@ static int mt7615_mcu_start_patch(struct mt7615_dev *dev)
&req, sizeof(req), true);
}
-static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)
-{
- if (!is_mt7622(&dev->mt76))
- return;
-
- regmap_update_bits(dev->infracfg, MT_INFRACFG_MISC,
- MT_INFRACFG_MISC_AP2CONN_WAKE,
- !en * MT_INFRACFG_MISC_AP2CONN_WAKE);
-}
-
-int mt7615_driver_own(struct mt7615_dev *dev)
-{
- struct mt76_phy *mphy = &dev->mt76.phy;
- struct mt76_dev *mdev = &dev->mt76;
- int i;
-
- if (!test_and_clear_bit(MT76_STATE_PM, &mphy->state))
- goto out;
-
- mt7622_trigger_hif_int(dev, true);
-
- for (i = 0; i < MT7615_DRV_OWN_RETRY_COUNT; i++) {
- u32 addr;
-
- addr = is_mt7663(mdev) ? MT_PCIE_DOORBELL_PUSH : MT_CFG_LPCR_HOST;
- mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN);
-
- addr = is_mt7663(mdev) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
- if (mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 50))
- break;
- }
-
- mt7622_trigger_hif_int(dev, false);
-
- if (i == MT7615_DRV_OWN_RETRY_COUNT) {
- dev_err(mdev->dev, "driver own failed\n");
- set_bit(MT76_STATE_PM, &mphy->state);
- return -EIO;
- }
-
-out:
- dev->pm.last_activity = jiffies;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(mt7615_driver_own);
-
-int mt7615_firmware_own(struct mt7615_dev *dev)
-{
- struct mt76_phy *mphy = &dev->mt76.phy;
- int err = 0;
- u32 addr;
-
- if (test_and_set_bit(MT76_STATE_PM, &mphy->state))
- return 0;
-
- mt7622_trigger_hif_int(dev, true);
-
- addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
- mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN);
-
- if (is_mt7622(&dev->mt76) &&
- !mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN,
- MT_CFG_LPCR_HOST_FW_OWN, 300)) {
- dev_err(dev->mt76.dev, "Timeout for firmware own\n");
- clear_bit(MT76_STATE_PM, &mphy->state);
- err = -EIO;
- }
-
- mt7622_trigger_hif_int(dev, false);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(mt7615_firmware_own);
-
static int mt7615_load_patch(struct mt7615_dev *dev, u32 addr, const char *name)
{
const struct mt7615_patch_hdr *hdr;
@@ -2452,7 +2474,7 @@ int mt7615_mcu_init(struct mt7615_dev *dev)
dev->mt76.mcu_ops = &mt7615_mcu_ops,
- ret = mt7615_driver_own(dev);
+ ret = mt7615_mcu_drv_pmctrl(dev);
if (ret)
return ret;
@@ -2482,7 +2504,7 @@ EXPORT_SYMBOL_GPL(mt7615_mcu_init);
void mt7615_mcu_exit(struct mt7615_dev *dev)
{
__mt76_mcu_restart(&dev->mt76);
- mt7615_firmware_own(dev);
+ mt7615_mcu_set_fw_ctrl(dev);
skb_queue_purge(&dev->mt76.mcu.res_q);
}
EXPORT_SYMBOL_GPL(mt7615_mcu_exit);
@@ -2847,14 +2869,6 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)
.center_chan2 = ieee80211_frequency_to_channel(freq2),
};
-#ifdef CONFIG_NL80211_TESTMODE
- if (dev->mt76.test.state == MT76_TM_STATE_TX_FRAMES &&
- dev->mt76.test.tx_antenna_mask) {
- req.tx_streams = hweight8(dev->mt76.test.tx_antenna_mask);
- req.rx_streams_mask = dev->mt76.test.tx_antenna_mask;
- }
-#endif
-
if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
@@ -3279,7 +3293,7 @@ static int mt7615_dcoc_freq_idx(u16 freq, u8 bw)
freq = freq_bw40[idx];
break;
}
- /* fall through */
+ fallthrough;
case NL80211_CHAN_WIDTH_40:
idx = mt7615_find_freq_idx(freq_bw40, ARRAY_SIZE(freq_bw40),
freq);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
index 133f93a6ed1b..6de492a4cf02 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
@@ -101,30 +101,29 @@ static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
static void mt7615_irq_tasklet(unsigned long data)
{
struct mt7615_dev *dev = (struct mt7615_dev *)data;
- u32 intr, mask = 0;
+ u32 intr, mask = 0, tx_mcu_mask = mt7615_tx_mcu_int_mask(dev);
mt76_wr(dev, MT_INT_MASK_CSR, 0);
intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
+ intr &= dev->mt76.mmio.irqmask;
mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
- intr &= dev->mt76.mmio.irqmask;
- if (intr & MT_INT_TX_DONE_ALL) {
- mask |= MT_INT_TX_DONE_ALL;
+ mask |= intr & MT_INT_RX_DONE_ALL;
+ if (intr & tx_mcu_mask)
+ mask |= tx_mcu_mask;
+ mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
+
+ if (intr & tx_mcu_mask)
napi_schedule(&dev->mt76.tx_napi);
- }
- if (intr & MT_INT_RX_DONE(0)) {
- mask |= MT_INT_RX_DONE(0);
+ if (intr & MT_INT_RX_DONE(0))
napi_schedule(&dev->mt76.napi[0]);
- }
- if (intr & MT_INT_RX_DONE(1)) {
- mask |= MT_INT_RX_DONE(1);
+ 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);
@@ -135,8 +134,6 @@ static void mt7615_irq_tasklet(unsigned long data)
wake_up(&dev->reset_wait);
}
}
-
- mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
}
static u32 __mt7615_reg_addr(struct mt7615_dev *dev, u32 addr)
@@ -227,6 +224,8 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
bus_ops->rmw = mt7615_rmw;
dev->mt76.bus = bus_ops;
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+
ret = devm_request_irq(mdev->dev, irq, mt7615_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index 571eadc033a3..6a9f9187f76a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -220,6 +220,8 @@ struct mt7615_phy {
#define mt7615_mcu_add_bss_info(phy, ...) (phy->dev)->mcu_ops->add_bss_info((phy), __VA_ARGS__)
#define mt7615_mcu_add_beacon(dev, ...) (dev)->mcu_ops->add_beacon_offload((dev), __VA_ARGS__)
#define mt7615_mcu_set_pm(dev, ...) (dev)->mcu_ops->set_pm_state((dev), __VA_ARGS__)
+#define mt7615_mcu_set_drv_ctrl(dev) (dev)->mcu_ops->set_drv_ctrl((dev))
+#define mt7615_mcu_set_fw_ctrl(dev) (dev)->mcu_ops->set_fw_ctrl((dev))
struct mt7615_mcu_ops {
int (*add_tx_ba)(struct mt7615_dev *dev,
struct ieee80211_ampdu_params *params,
@@ -238,6 +240,8 @@ struct mt7615_mcu_ops {
struct ieee80211_hw *hw,
struct ieee80211_vif *vif, bool enable);
int (*set_pm_state)(struct mt7615_dev *dev, int band, int state);
+ int (*set_drv_ctrl)(struct mt7615_dev *dev);
+ int (*set_fw_ctrl)(struct mt7615_dev *dev);
};
struct mt7615_dev {
@@ -278,6 +282,7 @@ struct mt7615_dev {
bool fw_debug;
bool flash_eeprom;
+ bool dbdc_support;
spinlock_t token_lock;
struct idr token;
@@ -535,6 +540,11 @@ static inline u8 mt7615_lmac_mapping(struct mt7615_dev *dev, u8 ac)
return lmac_queue_map[ac];
}
+static inline u32 mt7615_tx_mcu_int_mask(struct mt7615_dev *dev)
+{
+ return MT_INT_TX_DONE(dev->mt76.q_tx[MT_TXQ_MCU]->hw_idx);
+}
+
void mt7615_dma_reset(struct mt7615_dev *dev);
void mt7615_scan_work(struct work_struct *work);
void mt7615_roc_work(struct work_struct *work);
@@ -608,8 +618,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_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
- struct mt76_queue_entry *e);
+void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
@@ -638,8 +647,6 @@ int mt7615_mcu_set_p2p_oppps(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_channel *chan, int duration);
-int mt7615_firmware_own(struct mt7615_dev *dev);
-int mt7615_driver_own(struct mt7615_dev *dev);
int mt7615_init_debugfs(struct mt7615_dev *dev);
int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq);
@@ -666,7 +673,6 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct mt76_tx_info *tx_info);
bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update);
void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
- enum mt76_txq_id qid,
struct mt76_queue_entry *e);
void mt7663_usb_sdio_wtbl_work(struct work_struct *work);
int mt7663_usb_sdio_register_device(struct mt7615_dev *dev);
@@ -675,9 +681,8 @@ int mt7663u_mcu_init(struct mt7615_dev *dev);
/* sdio */
u32 mt7663s_read_pcr(struct mt7615_dev *dev);
int mt7663s_mcu_init(struct mt7615_dev *dev);
-int mt7663s_driver_own(struct mt7615_dev *dev);
-int mt7663s_firmware_own(struct mt7615_dev *dev);
-int mt7663s_kthread_run(void *data);
+void mt7663s_tx_work(struct work_struct *work);
+void mt7663s_rx_work(struct work_struct *work);
void mt7663s_sdio_irq(struct sdio_func *func);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
index 2328d78e06a1..dbd29d897b29 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
@@ -88,7 +88,7 @@ static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state)
}
napi_disable(&mdev->tx_napi);
- tasklet_kill(&mdev->tx_tasklet);
+ mt76_worker_disable(&mdev->tx_worker);
mt76_for_each_q_rx(mdev, i) {
napi_disable(&mdev->napi[i]);
@@ -118,7 +118,7 @@ static int mt7615_pci_suspend(struct pci_dev *pdev, pm_message_t state)
if (err)
goto restore;
- err = mt7615_firmware_own(dev);
+ err = mt7615_mcu_set_fw_ctrl(dev);
if (err)
goto restore;
@@ -142,7 +142,7 @@ static int mt7615_pci_resume(struct pci_dev *pdev)
bool pdma_reset;
int i, err;
- err = mt7615_driver_own(dev);
+ err = mt7615_mcu_set_drv_ctrl(dev);
if (err < 0)
return err;
@@ -162,6 +162,7 @@ static int mt7615_pci_resume(struct pci_dev *pdev)
if (pdma_reset)
dev_err(mdev->dev, "PDMA engine must be reinitialized\n");
+ mt76_worker_enable(&mdev->tx_worker);
mt76_for_each_q_rx(mdev, i) {
napi_enable(&mdev->napi[i]);
napi_schedule(&mdev->napi[i]);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
index 7224a0078211..06a0f8f7bc89 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c
@@ -25,6 +25,9 @@ static void mt7615_init_work(struct work_struct *work)
mt7615_phy_init(dev);
mt7615_mcu_del_wtbl_all(dev);
mt7615_check_offload_capability(dev);
+
+ if (dev->dbdc_support)
+ mt7615_register_ext_phy(dev);
}
static int mt7615_init_hardware(struct mt7615_dev *dev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c
index 2d67f9a148cd..4cf7c5d34325 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c
@@ -14,8 +14,7 @@
#include "../dma.h"
#include "mac.h"
-void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
- struct mt76_queue_entry *e)
+void mt7615_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
{
if (!e->txwi) {
dev_kfree_skb_any(e->skb);
@@ -45,7 +44,7 @@ void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
}
if (e->skb)
- mt76_tx_complete_skb(mdev, e->skb);
+ mt76_tx_complete_skb(mdev, e->wcid, e->skb);
}
static void
@@ -107,6 +106,7 @@ mt7615_write_fw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info,
/* pass partial skb header to fw */
tx_info->buf[0].len = MT_TXD_SIZE + sizeof(*txp);
tx_info->buf[1].len = MT_CT_PARSE_LEN;
+ tx_info->buf[1].skip_unmap = true;
tx_info->nbuf = MT_CT_DMA_BUF_NUM;
txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
index 9137d9e6b51d..61623f480806 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
@@ -575,7 +575,7 @@ enum mt7615_reg_base {
#define MT_MCU_PTA_BASE 0x81060000
#define MT_MCU_PTA(_n) (MT_MCU_PTA_BASE + (_n))
-#define MT_ANT_SWITCH_CON(n) MT_MCU_PTA(0x0c8)
+#define MT_ANT_SWITCH_CON(_n) MT_MCU_PTA(0x0c8 + ((_n) - 1) * 4)
#define MT_ANT_SWITCH_CON_MODE(_n) (GENMASK(4, 0) << (_n * 8))
#define MT_ANT_SWITCH_CON_MODE1(_n) (GENMASK(3, 0) << (_n * 8))
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
index dabce51117b0..874c929d8552 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio.c
@@ -323,7 +323,7 @@ static int mt7663s_probe(struct sdio_func *func,
{
static const struct mt76_driver_ops drv_ops = {
.txwi_size = MT_USB_TXD_SIZE,
- .drv_flags = MT_DRV_RX_DMA_HDR | MT_DRV_HW_MGMT_TXQ,
+ .drv_flags = MT_DRV_RX_DMA_HDR,
.tx_prepare_skb = mt7663_usb_sdio_tx_prepare_skb,
.tx_complete_skb = mt7663_usb_sdio_tx_complete_skb,
.tx_status_data = mt7663_usb_sdio_tx_status_data,
@@ -346,7 +346,7 @@ static int mt7663s_probe(struct sdio_func *func,
struct ieee80211_ops *ops;
struct mt7615_dev *dev;
struct mt76_dev *mdev;
- int ret;
+ int i, ret;
ops = devm_kmemdup(&func->dev, &mt7615_ops, sizeof(mt7615_ops),
GFP_KERNEL);
@@ -364,23 +364,39 @@ static int mt7663s_probe(struct sdio_func *func,
dev->ops = ops;
sdio_set_drvdata(func, dev);
- mdev->sdio.tx_kthread = kthread_create(mt7663s_kthread_run, dev,
- "mt7663s_tx");
- if (IS_ERR(mdev->sdio.tx_kthread))
- return PTR_ERR(mdev->sdio.tx_kthread);
-
ret = mt76s_init(mdev, func, &mt7663s_ops);
if (ret < 0)
goto err_free;
+ INIT_WORK(&mdev->sdio.tx.xmit_work, mt7663s_tx_work);
+ INIT_WORK(&mdev->sdio.rx.recv_work, mt7663s_rx_work);
+
ret = mt7663s_hw_init(dev, func);
if (ret)
- goto err_free;
+ goto err_deinit;
mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
(mt76_rr(dev, MT_HW_REV) & 0xff);
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
+ mdev->sdio.intr_data = devm_kmalloc(mdev->dev,
+ sizeof(struct mt76s_intr),
+ GFP_KERNEL);
+ if (!mdev->sdio.intr_data) {
+ ret = -ENOMEM;
+ goto err_deinit;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(mdev->sdio.xmit_buf); i++) {
+ mdev->sdio.xmit_buf[i] = devm_kmalloc(mdev->dev,
+ MT76S_XMIT_BUF_SZ,
+ GFP_KERNEL);
+ if (!mdev->sdio.xmit_buf[i]) {
+ ret = -ENOMEM;
+ goto err_deinit;
+ }
+ }
+
ret = mt76s_alloc_queues(&dev->mt76);
if (ret)
goto err_deinit;
@@ -426,9 +442,11 @@ static int mt7663s_suspend(struct device *dev)
return err;
}
+ sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+
mt76s_stop_txrx(&mdev->mt76);
- return mt7663s_firmware_own(mdev);
+ return mt7615_mcu_set_fw_ctrl(mdev);
}
static int mt7663s_resume(struct device *dev)
@@ -437,7 +455,7 @@ static int mt7663s_resume(struct device *dev)
struct mt7615_dev *mdev = sdio_get_drvdata(func);
int err;
- err = mt7663s_driver_own(mdev);
+ err = mt7615_mcu_set_drv_ctrl(mdev);
if (err)
return err;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
index 28b86bec7fc2..38670c00380c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_mcu.c
@@ -53,7 +53,7 @@ mt7663s_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
if (ret)
goto out;
- mt76_queue_kick(dev, mdev->q_tx[MT_TXQ_MCU].q);
+ mt76_queue_kick(dev, mdev->q_tx[MT_TXQ_MCU]);
if (wait_resp)
ret = mt7615_mcu_wait_response(dev, cmd, seq);
@@ -63,7 +63,7 @@ out:
return ret;
}
-int mt7663s_driver_own(struct mt7615_dev *dev)
+static int mt7663s_mcu_drv_pmctrl(struct mt7615_dev *dev)
{
struct sdio_func *func = dev->mt76.sdio.func;
struct mt76_phy *mphy = &dev->mt76.phy;
@@ -75,7 +75,7 @@ int mt7663s_driver_own(struct mt7615_dev *dev)
sdio_claim_host(func);
- sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, 0);
+ sdio_writel(func, WHLPCR_FW_OWN_REQ_CLR, MCR_WHLPCR, NULL);
ret = readx_poll_timeout(mt7663s_read_pcr, dev, status,
status & WHLPCR_IS_DRIVER_OWN, 2000, 1000000);
@@ -95,7 +95,7 @@ out:
return 0;
}
-int mt7663s_firmware_own(struct mt7615_dev *dev)
+static int mt7663s_mcu_fw_pmctrl(struct mt7615_dev *dev)
{
struct sdio_func *func = dev->mt76.sdio.func;
struct mt76_phy *mphy = &dev->mt76.phy;
@@ -107,7 +107,7 @@ int mt7663s_firmware_own(struct mt7615_dev *dev)
sdio_claim_host(func);
- sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, 0);
+ sdio_writel(func, WHLPCR_FW_OWN_REQ_SET, MCR_WHLPCR, NULL);
ret = readx_poll_timeout(mt7663s_read_pcr, dev, status,
!(status & WHLPCR_IS_DRIVER_OWN), 2000, 1000000);
@@ -132,9 +132,10 @@ int mt7663s_mcu_init(struct mt7615_dev *dev)
.mcu_rr = mt7615_mcu_reg_rr,
.mcu_wr = mt7615_mcu_reg_wr,
};
+ struct mt7615_mcu_ops *mcu_ops;
int ret;
- ret = mt7663s_driver_own(dev);
+ ret = mt7663s_mcu_drv_pmctrl(dev);
if (ret)
return ret;
@@ -152,6 +153,15 @@ int mt7663s_mcu_init(struct mt7615_dev *dev)
if (ret)
return ret;
+ mcu_ops = devm_kmemdup(dev->mt76.dev, dev->mcu_ops, sizeof(*mcu_ops),
+ GFP_KERNEL);
+ if (!mcu_ops)
+ return -ENOMEM;
+
+ mcu_ops->set_drv_ctrl = mt7663s_mcu_drv_pmctrl;
+ mcu_ops->set_fw_ctrl = mt7663s_mcu_fw_pmctrl;
+ dev->mcu_ops = mcu_ops;
+
ret = mt7663s_mcu_init_sched(dev);
if (ret)
return ret;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
index 443a4ecdad3a..2486cda3243b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/sdio_txrx.c
@@ -19,21 +19,40 @@
#include "sdio.h"
#include "mac.h"
-static void mt7663s_refill_sched_quota(struct mt7615_dev *dev, u32 *data)
+static int mt7663s_refill_sched_quota(struct mt76_dev *dev, u32 *data)
{
- struct mt76_sdio *sdio = &dev->mt76.sdio;
+ u32 ple_ac_data_quota[] = {
+ FIELD_GET(TXQ_CNT_L, data[4]), /* VO */
+ FIELD_GET(TXQ_CNT_H, data[3]), /* VI */
+ FIELD_GET(TXQ_CNT_L, data[3]), /* BE */
+ FIELD_GET(TXQ_CNT_H, data[2]), /* BK */
+ };
+ u32 pse_ac_data_quota[] = {
+ FIELD_GET(TXQ_CNT_H, data[1]), /* VO */
+ FIELD_GET(TXQ_CNT_L, data[1]), /* VI */
+ FIELD_GET(TXQ_CNT_H, data[0]), /* BE */
+ FIELD_GET(TXQ_CNT_L, data[0]), /* BK */
+ };
+ u32 pse_mcu_quota = FIELD_GET(TXQ_CNT_L, data[2]);
+ u32 pse_data_quota = 0, ple_data_quota = 0;
+ struct mt76_sdio *sdio = &dev->sdio;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pse_ac_data_quota); i++) {
+ pse_data_quota += pse_ac_data_quota[i];
+ ple_data_quota += ple_ac_data_quota[i];
+ }
+
+ if (!pse_data_quota && !ple_data_quota && !pse_mcu_quota)
+ return 0;
mutex_lock(&sdio->sched.lock);
- sdio->sched.pse_data_quota += FIELD_GET(TXQ_CNT_L, data[0]) + /* BK */
- FIELD_GET(TXQ_CNT_H, data[0]) + /* BE */
- FIELD_GET(TXQ_CNT_L, data[1]) + /* VI */
- FIELD_GET(TXQ_CNT_H, data[1]); /* VO */
- sdio->sched.ple_data_quota += FIELD_GET(TXQ_CNT_H, data[2]) + /* BK */
- FIELD_GET(TXQ_CNT_L, data[3]) + /* BE */
- FIELD_GET(TXQ_CNT_H, data[3]) + /* VI */
- FIELD_GET(TXQ_CNT_L, data[4]); /* VO */
- sdio->sched.pse_mcu_quota += FIELD_GET(TXQ_CNT_L, data[2]);
+ sdio->sched.pse_mcu_quota += pse_mcu_quota;
+ sdio->sched.pse_data_quota += pse_data_quota;
+ sdio->sched.ple_data_quota += ple_data_quota;
mutex_unlock(&sdio->sched.lock);
+
+ return pse_data_quota + ple_data_quota + pse_mcu_quota;
}
static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len,
@@ -61,11 +80,11 @@ static struct sk_buff *mt7663s_build_rx_skb(void *data, int data_len,
return skb;
}
-static int mt7663s_rx_run_queue(struct mt7615_dev *dev, enum mt76_rxq_id qid,
+static int mt7663s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid,
struct mt76s_intr *intr)
{
- struct mt76_queue *q = &dev->mt76.q_rx[qid];
- struct mt76_sdio *sdio = &dev->mt76.sdio;
+ struct mt76_queue *q = &dev->q_rx[qid];
+ struct mt76_sdio *sdio = &dev->sdio;
int len = 0, err, i, order;
struct page *page;
u8 *buf;
@@ -86,15 +105,18 @@ static int mt7663s_rx_run_queue(struct mt7615_dev *dev, enum mt76_rxq_id qid,
buf = page_address(page);
+ sdio_claim_host(sdio->func);
err = sdio_readsb(sdio->func, buf, MCR_WRDR(qid), len);
+ sdio_release_host(sdio->func);
+
if (err < 0) {
- dev_err(dev->mt76.dev, "sdio read data failed:%d\n", err);
+ dev_err(dev->dev, "sdio read data failed:%d\n", err);
__free_pages(page, order);
return err;
}
for (i = 0; i < intr->rx.num[qid]; i++) {
- int index = (q->tail + i) % q->ndesc;
+ int index = (q->head + i) % q->ndesc;
struct mt76_queue_entry *e = &q->entry[index];
len = intr->rx.len[qid][i];
@@ -109,160 +131,198 @@ static int mt7663s_rx_run_queue(struct mt7615_dev *dev, enum mt76_rxq_id qid,
__free_pages(page, order);
spin_lock_bh(&q->lock);
- q->tail = (q->tail + i) % q->ndesc;
+ q->head = (q->head + i) % q->ndesc;
q->queued += i;
spin_unlock_bh(&q->lock);
- return err;
+ return i;
}
-static int mt7663s_tx_update_sched(struct mt7615_dev *dev,
- struct mt76_queue_entry *e,
- bool mcu)
+static int mt7663s_tx_pick_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
+ int buf_sz, int *pse_size, int *ple_size)
{
- struct mt76_sdio *sdio = &dev->mt76.sdio;
- struct mt76_phy *mphy = &dev->mt76.phy;
- struct ieee80211_hdr *hdr;
- int size, ret = -EBUSY;
-
- size = DIV_ROUND_UP(e->buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
+ int pse_sz;
- if (mcu) {
- if (!test_bit(MT76_STATE_MCU_RUNNING, &mphy->state))
- return 0;
+ pse_sz = DIV_ROUND_UP(buf_sz + sdio->sched.deficit, MT_PSE_PAGE_SZ);
- mutex_lock(&sdio->sched.lock);
- if (sdio->sched.pse_mcu_quota > size) {
- sdio->sched.pse_mcu_quota -= size;
- ret = 0;
- }
- mutex_unlock(&sdio->sched.lock);
+ if (qid == MT_TXQ_MCU) {
+ if (sdio->sched.pse_mcu_quota < *pse_size + pse_sz)
+ return -EBUSY;
+ } else {
+ if (sdio->sched.pse_data_quota < *pse_size + pse_sz ||
+ sdio->sched.ple_data_quota < *ple_size)
+ return -EBUSY;
- return ret;
+ *ple_size = *ple_size + 1;
}
+ *pse_size = *pse_size + pse_sz;
- hdr = (struct ieee80211_hdr *)(e->skb->data + MT_USB_TXD_SIZE);
- if (ieee80211_is_ctl(hdr->frame_control))
- return 0;
+ return 0;
+}
+static void mt7663s_tx_update_quota(struct mt76_sdio *sdio, enum mt76_txq_id qid,
+ int pse_size, int ple_size)
+{
mutex_lock(&sdio->sched.lock);
- if (sdio->sched.pse_data_quota > size &&
- sdio->sched.ple_data_quota > 0) {
- sdio->sched.pse_data_quota -= size;
- sdio->sched.ple_data_quota--;
- ret = 0;
+ if (qid == MT_TXQ_MCU) {
+ sdio->sched.pse_mcu_quota -= pse_size;
+ } else {
+ sdio->sched.pse_data_quota -= pse_size;
+ sdio->sched.ple_data_quota -= ple_size;
}
mutex_unlock(&sdio->sched.lock);
+}
+
+static int __mt7663s_xmit_queue(struct mt76_dev *dev, u8 *data, int len)
+{
+ struct mt76_sdio *sdio = &dev->sdio;
+ int err;
+
+ if (len > sdio->func->cur_blksize)
+ len = roundup(len, sdio->func->cur_blksize);
+
+ sdio_claim_host(sdio->func);
+ err = sdio_writesb(sdio->func, MCR_WTDR1, data, len);
+ sdio_release_host(sdio->func);
+
+ if (err)
+ dev_err(dev->dev, "sdio write failed: %d\n", err);
- return ret;
+ return err;
}
-static int mt7663s_tx_run_queue(struct mt7615_dev *dev, struct mt76_queue *q)
+static int mt7663s_tx_run_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
{
- bool mcu = q == dev->mt76.q_tx[MT_TXQ_MCU].q;
- struct mt76_sdio *sdio = &dev->mt76.sdio;
- int nframes = 0;
+ int err, nframes = 0, len = 0, pse_sz = 0, ple_sz = 0;
+ struct mt76_queue *q = dev->q_tx[qid];
+ struct mt76_sdio *sdio = &dev->sdio;
- while (q->first != q->tail) {
+ while (q->first != q->head) {
struct mt76_queue_entry *e = &q->entry[q->first];
- int err, len = e->skb->len;
+ struct sk_buff *iter;
- if (mt7663s_tx_update_sched(dev, e, mcu))
+ if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->phy.state)) {
+ __skb_put_zero(e->skb, 4);
+ err = __mt7663s_xmit_queue(dev, e->skb->data,
+ e->skb->len);
+ if (err)
+ return err;
+
+ goto next;
+ }
+
+ if (len + e->skb->len + 4 > MT76S_XMIT_BUF_SZ)
break;
- if (len > sdio->func->cur_blksize)
- len = roundup(len, sdio->func->cur_blksize);
+ if (mt7663s_tx_pick_quota(sdio, qid, e->buf_sz, &pse_sz,
+ &ple_sz))
+ break;
- /* TODO: skb_walk_frags and then write to SDIO port */
- err = sdio_writesb(sdio->func, MCR_WTDR1, e->skb->data, len);
- if (err) {
- dev_err(dev->mt76.dev, "sdio write failed: %d\n", err);
- return -EIO;
- }
+ memcpy(sdio->xmit_buf[qid] + len, e->skb->data,
+ skb_headlen(e->skb));
+ len += skb_headlen(e->skb);
+ nframes++;
- e->done = true;
+ skb_walk_frags(e->skb, iter) {
+ memcpy(sdio->xmit_buf[qid] + len, iter->data,
+ iter->len);
+ len += iter->len;
+ nframes++;
+ }
+next:
q->first = (q->first + 1) % q->ndesc;
- nframes++;
+ e->done = true;
+ }
+
+ if (nframes) {
+ memset(sdio->xmit_buf[qid] + len, 0, 4);
+ err = __mt7663s_xmit_queue(dev, sdio->xmit_buf[qid], len + 4);
+ if (err)
+ return err;
}
+ mt7663s_tx_update_quota(sdio, qid, pse_sz, ple_sz);
return nframes;
}
-static int mt7663s_tx_run_queues(struct mt7615_dev *dev)
+void mt7663s_tx_work(struct work_struct *work)
{
+ struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
+ tx.xmit_work);
+ struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
int i, nframes = 0;
for (i = 0; i < MT_TXQ_MCU_WA; i++) {
int ret;
- ret = mt7663s_tx_run_queue(dev, dev->mt76.q_tx[i].q);
+ ret = mt7663s_tx_run_queue(dev, i);
if (ret < 0)
- return ret;
+ break;
nframes += ret;
}
+ if (nframes)
+ queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
- return nframes;
+ queue_work(sdio->txrx_wq, &sdio->tx.status_work);
}
-int mt7663s_kthread_run(void *data)
+void mt7663s_rx_work(struct work_struct *work)
{
- struct mt7615_dev *dev = data;
- struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
+ rx.recv_work);
+ struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
+ struct mt76s_intr *intr = sdio->intr_data;
+ int nframes = 0, ret;
- while (!kthread_should_stop()) {
- int ret;
+ /* disable interrupt */
+ sdio_claim_host(sdio->func);
+ sdio_writel(sdio->func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, NULL);
+ ret = sdio_readsb(sdio->func, intr, MCR_WHISR, sizeof(*intr));
+ sdio_release_host(sdio->func);
- cond_resched();
+ if (ret < 0)
+ goto out;
- sdio_claim_host(dev->mt76.sdio.func);
- ret = mt7663s_tx_run_queues(dev);
- sdio_release_host(dev->mt76.sdio.func);
+ trace_dev_irq(dev, intr->isr, 0);
- if (ret <= 0 || !test_bit(MT76_STATE_RUNNING, &mphy->state)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- } else {
- wake_up_process(dev->mt76.sdio.kthread);
+ if (intr->isr & WHIER_RX0_DONE_INT_EN) {
+ ret = mt7663s_rx_run_queue(dev, 0, intr);
+ if (ret > 0) {
+ queue_work(sdio->txrx_wq, &sdio->rx.net_work);
+ nframes += ret;
}
}
- return 0;
+ if (intr->isr & WHIER_RX1_DONE_INT_EN) {
+ ret = mt7663s_rx_run_queue(dev, 1, intr);
+ if (ret > 0) {
+ queue_work(sdio->txrx_wq, &sdio->rx.net_work);
+ nframes += ret;
+ }
+ }
+
+ if (mt7663s_refill_sched_quota(dev, intr->tx.wtqcr))
+ queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
+
+ if (nframes) {
+ queue_work(sdio->txrx_wq, &sdio->rx.recv_work);
+ return;
+ }
+out:
+ /* enable interrupt */
+ sdio_claim_host(sdio->func);
+ sdio_writel(sdio->func, WHLPCR_INT_EN_SET, MCR_WHLPCR, NULL);
+ sdio_release_host(sdio->func);
}
void mt7663s_sdio_irq(struct sdio_func *func)
{
struct mt7615_dev *dev = sdio_get_drvdata(func);
struct mt76_sdio *sdio = &dev->mt76.sdio;
- struct mt76s_intr intr;
-
- /* disable interrupt */
- sdio_writel(func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, 0);
-
- do {
- sdio_readsb(func, &intr, MCR_WHISR, sizeof(struct mt76s_intr));
- trace_dev_irq(&dev->mt76, intr.isr, 0);
- if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
- goto out;
+ if (!test_bit(MT76_STATE_INITIALIZED, &dev->mt76.phy.state))
+ return;
- if (intr.isr & WHIER_RX0_DONE_INT_EN) {
- mt7663s_rx_run_queue(dev, 0, &intr);
- wake_up_process(sdio->kthread);
- }
-
- if (intr.isr & WHIER_RX1_DONE_INT_EN) {
- mt7663s_rx_run_queue(dev, 1, &intr);
- wake_up_process(sdio->kthread);
- }
-
- if (intr.isr & WHIER_TX_DONE_INT_EN) {
- mt7663s_refill_sched_quota(dev, intr.tx.wtqcr);
- mt7663s_tx_run_queues(dev);
- wake_up_process(sdio->kthread);
- }
- } while (intr.isr);
-out:
- /* enable interrupt */
- sdio_writel(func, WHLPCR_INT_EN_SET, MCR_WHLPCR, 0);
+ queue_work(sdio->txrx_wq, &sdio->rx.recv_work);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c
index 1730751133aa..e4dc62314bae 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/testmode.c
@@ -70,7 +70,7 @@ mt7615_tm_set_tx_power(struct mt7615_phy *phy)
if (dev->mt76.test.state != MT76_TM_STATE_OFF)
tx_power = dev->mt76.test.tx_power;
- len = sizeof(req_hdr) + MT7615_EE_MAX - MT_EE_NIC_CONF_0;
+ len = MT7615_EE_MAX - MT_EE_NIC_CONF_0;
skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(req_hdr) + len);
if (!skb)
return -ENOMEM;
@@ -80,13 +80,12 @@ mt7615_tm_set_tx_power(struct mt7615_phy *phy)
target_chains = mt7615_ext_pa_enabled(dev, band) ? 1 : n_chains;
for (i = 0; i < target_chains; i++) {
- int index;
-
ret = mt7615_eeprom_get_target_power_index(dev, chandef->chan, i);
- if (ret < 0)
+ if (ret < 0) {
+ dev_kfree_skb(skb);
return -EINVAL;
+ }
- index = ret - MT_EE_NIC_CONF_0;
if (tx_power && tx_power[i])
data[ret - MT_EE_NIC_CONF_0] = tx_power[i];
}
@@ -191,7 +190,7 @@ mt7615_tm_set_tx_antenna(struct mt7615_dev *dev, bool en)
for (i = 0; i < 4; i++) {
mt76_rmw_field(dev, MT_WF_PHY_RFINTF3_0(i),
MT_WF_PHY_RFINTF3_0_ANT,
- td->tx_antenna_mask & BIT(i) ? 0 : 0xa);
+ (td->tx_antenna_mask & BIT(i)) ? 0 : 0xa);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
index 23a21338c46e..f0ad83af9e00 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
@@ -180,9 +180,7 @@ static int mt7663u_suspend(struct usb_interface *intf, pm_message_t state)
}
mt76u_stop_rx(&dev->mt76);
-
mt76u_stop_tx(&dev->mt76);
- tasklet_kill(&dev->mt76.tx_tasklet);
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c
index 0b33df3e3bfe..4d8be366af31 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_mcu.c
@@ -18,7 +18,7 @@ mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
int cmd, bool wait_resp)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
- int ret, seq, ep;
+ int ret, seq, ep, len, pad;
mutex_lock(&mdev->mcu.mutex);
@@ -28,8 +28,10 @@ mt7663u_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
else
ep = MT_EP_OUT_AC_BE;
- put_unaligned_le32(skb->len, skb_push(skb, sizeof(skb->len)));
- ret = mt76_skb_adjust_pad(skb);
+ len = skb->len;
+ put_unaligned_le32(len, skb_push(skb, sizeof(len)));
+ pad = round_up(skb->len, 4) + 4 - skb->len;
+ ret = mt76_skb_adjust_pad(skb, pad);
if (ret < 0)
goto out;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
index 6dffdaaa9ad5..3b29a6d3dc64 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c
@@ -226,7 +226,6 @@ bool mt7663_usb_sdio_tx_status_data(struct mt76_dev *mdev, u8 *update)
EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_status_data);
void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
- enum mt76_txq_id qid,
struct mt76_queue_entry *e)
{
unsigned int headroom = MT_USB_TXD_SIZE;
@@ -235,7 +234,7 @@ void mt7663_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
headroom += MT_USB_HDR_SIZE;
skb_pull(e->skb, headroom);
- mt76_tx_complete_skb(mdev, e->skb);
+ mt76_tx_complete_skb(mdev, e->wcid, e->skb);
}
EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_complete_skb);
@@ -248,6 +247,7 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
struct sk_buff *skb = tx_info->skb;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int pad;
if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) &&
!msta->rate_probe) {
@@ -259,10 +259,16 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
}
mt7663_usb_sdio_write_txwi(dev, wcid, qid, sta, skb);
- if (mt76_is_usb(mdev))
- put_unaligned_le32(skb->len, skb_push(skb, sizeof(skb->len)));
+ if (mt76_is_usb(mdev)) {
+ u32 len = skb->len;
+
+ put_unaligned_le32(len, skb_push(skb, sizeof(len)));
+ pad = round_up(skb->len, 4) + 4 - skb->len;
+ } else {
+ pad = round_up(skb->len, 4) - skb->len;
+ }
- return mt76_skb_adjust_pad(skb);
+ return mt76_skb_adjust_pad(skb, pad);
}
EXPORT_SYMBOL_GPL(mt7663_usb_sdio_tx_prepare_skb);
@@ -359,14 +365,15 @@ int mt7663_usb_sdio_register_device(struct mt7615_dev *dev)
if (err)
return err;
- /* check hw sg support in order to enable AMSDU */
- if (dev->mt76.usb.sg_en || mt76_is_sdio(&dev->mt76))
- hw->max_tx_fragments = MT_HW_TXP_MAX_BUF_NUM;
- else
- hw->max_tx_fragments = 1;
hw->extra_tx_headroom += MT_USB_TXD_SIZE;
- if (mt76_is_usb(&dev->mt76))
+ if (mt76_is_usb(&dev->mt76)) {
hw->extra_tx_headroom += MT_USB_HDR_SIZE;
+ /* check hw sg support in order to enable AMSDU */
+ if (dev->mt76.usb.sg_en)
+ hw->max_tx_fragments = MT_HW_TXP_MAX_BUF_NUM;
+ else
+ hw->max_tx_fragments = 1;
+ }
err = mt76_register_device(&dev->mt76, true, mt7615_rates,
ARRAY_SIZE(mt7615_rates));
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
index dc8bf4c6969a..d78866bf41ba 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/init.c
@@ -10,6 +10,7 @@
#include "eeprom.h"
#include "mcu.h"
#include "initvals.h"
+#include "initvals_init.h"
#include "../mt76x02_phy.h"
static void
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h
index 3dcd9620a126..99808ed0c6cb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals.h
@@ -11,139 +11,6 @@
#include "phy.h"
-static const struct mt76_reg_pair common_mac_reg_table[] = {
- { MT_BCN_OFFSET(0), 0xf8f0e8e0 },
- { MT_BCN_OFFSET(1), 0x6f77d0c8 },
- { MT_LEGACY_BASIC_RATE, 0x0000013f },
- { MT_HT_BASIC_RATE, 0x00008003 },
- { MT_MAC_SYS_CTRL, 0x00000000 },
- { MT_RX_FILTR_CFG, 0x00017f97 },
- { MT_BKOFF_SLOT_CFG, 0x00000209 },
- { MT_TX_SW_CFG0, 0x00000000 },
- { MT_TX_SW_CFG1, 0x00080606 },
- { MT_TX_LINK_CFG, 0x00001020 },
- { MT_TX_TIMEOUT_CFG, 0x000a2090 },
- { MT_MAX_LEN_CFG, 0xa0fff | 0x00001000 },
- { MT_LED_CFG, 0x7f031e46 },
- { MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f },
- { MT_PBF_RX_MAX_PCNT, 0x0000fe9f },
- { MT_TX_RETRY_CFG, 0x47d01f0f },
- { MT_AUTO_RSP_CFG, 0x00000013 },
- { MT_CCK_PROT_CFG, 0x07f40003 },
- { MT_OFDM_PROT_CFG, 0x07f42004 },
- { MT_PBF_CFG, 0x00f40006 },
- { MT_WPDMA_GLO_CFG, 0x00000030 },
- { MT_GF20_PROT_CFG, 0x01742004 },
- { MT_GF40_PROT_CFG, 0x03f42084 },
- { MT_MM20_PROT_CFG, 0x01742004 },
- { MT_MM40_PROT_CFG, 0x03f42084 },
- { MT_TXOP_CTRL_CFG, 0x0000583f },
- { MT_TX_RTS_CFG, 0x00ffff20 },
- { MT_EXP_ACK_TIME, 0x002400ca },
- { MT_TXOP_HLDR_ET, 0x00000002 },
- { MT_XIFS_TIME_CFG, 0x33a41010 },
- { MT_PWR_PIN_CFG, 0x00000000 },
-};
-
-static const struct mt76_reg_pair mt76x0_mac_reg_table[] = {
- { MT_IOCFG_6, 0xa0040080 },
- { MT_PBF_SYS_CTRL, 0x00080c00 },
- { MT_PBF_CFG, 0x77723c1f },
- { MT_FCE_PSE_CTRL, 0x00000001 },
- { MT_AMPDU_MAX_LEN_20M1S, 0xAAA99887 },
- { MT_TX_SW_CFG0, 0x00000601 },
- { MT_TX_SW_CFG1, 0x00040000 },
- { MT_TX_SW_CFG2, 0x00000000 },
- { 0xa44, 0x00000000 },
- { MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
- { MT_TSO_CTRL, 0x00000000 },
- { MT_BB_PA_MODE_CFG1, 0x00500055 },
- { MT_RF_PA_MODE_CFG1, 0x00500055 },
- { MT_TX_ALC_CFG_0, 0x2F2F000C },
- { MT_TX0_BB_GAIN_ATTEN, 0x00000000 },
- { MT_TX_PWR_CFG_0, 0x3A3A3A3A },
- { MT_TX_PWR_CFG_1, 0x3A3A3A3A },
- { MT_TX_PWR_CFG_2, 0x3A3A3A3A },
- { MT_TX_PWR_CFG_3, 0x3A3A3A3A },
- { MT_TX_PWR_CFG_4, 0x3A3A3A3A },
- { MT_TX_PWR_CFG_7, 0x3A3A3A3A },
- { MT_TX_PWR_CFG_8, 0x0000003A },
- { MT_TX_PWR_CFG_9, 0x0000003A },
- { 0x150C, 0x00000002 },
- { 0x1238, 0x001700C8 },
- { MT_LDO_CTRL_0, 0x00A647B6 },
- { MT_LDO_CTRL_1, 0x6B006464 },
- { MT_HT_BASIC_RATE, 0x00004003 },
- { MT_HT_CTRL_CFG, 0x000001FF },
- { MT_TXOP_HLDR_ET, 0x00000000 },
- { MT_PN_PAD_MODE, 0x00000003 },
- { MT_TX_PROT_CFG6, 0xe3f42004 },
- { MT_TX_PROT_CFG7, 0xe3f42084 },
- { MT_TX_PROT_CFG8, 0xe3f42104 },
- { MT_VHT_HT_FBK_CFG1, 0xedcba980 },
-};
-
-static const struct mt76_reg_pair mt76x0_bbp_init_tab[] = {
- { MT_BBP(CORE, 1), 0x00000002 },
- { MT_BBP(CORE, 4), 0x00000000 },
- { MT_BBP(CORE, 24), 0x00000000 },
- { MT_BBP(CORE, 32), 0x4003000a },
- { MT_BBP(CORE, 42), 0x00000000 },
- { MT_BBP(CORE, 44), 0x00000000 },
- { MT_BBP(IBI, 11), 0x0FDE8081 },
- { MT_BBP(AGC, 0), 0x00021400 },
- { MT_BBP(AGC, 1), 0x00000003 },
- { MT_BBP(AGC, 2), 0x003A6464 },
- { MT_BBP(AGC, 15), 0x88A28CB8 },
- { MT_BBP(AGC, 22), 0x00001E21 },
- { MT_BBP(AGC, 23), 0x0000272C },
- { MT_BBP(AGC, 24), 0x00002F3A },
- { MT_BBP(AGC, 25), 0x8000005A },
- { MT_BBP(AGC, 26), 0x007C2005 },
- { MT_BBP(AGC, 33), 0x00003238 },
- { MT_BBP(AGC, 34), 0x000A0C0C },
- { MT_BBP(AGC, 37), 0x2121262C },
- { MT_BBP(AGC, 41), 0x38383E45 },
- { MT_BBP(AGC, 57), 0x00001010 },
- { MT_BBP(AGC, 59), 0xBAA20E96 },
- { MT_BBP(AGC, 63), 0x00000001 },
- { MT_BBP(TXC, 0), 0x00280403 },
- { MT_BBP(TXC, 1), 0x00000000 },
- { MT_BBP(RXC, 1), 0x00000012 },
- { MT_BBP(RXC, 2), 0x00000011 },
- { MT_BBP(RXC, 3), 0x00000005 },
- { MT_BBP(RXC, 4), 0x00000000 },
- { MT_BBP(RXC, 5), 0xF977C4EC },
- { MT_BBP(RXC, 7), 0x00000090 },
- { MT_BBP(TXO, 8), 0x00000000 },
- { MT_BBP(TXBE, 0), 0x00000000 },
- { MT_BBP(TXBE, 4), 0x00000004 },
- { MT_BBP(TXBE, 6), 0x00000000 },
- { MT_BBP(TXBE, 8), 0x00000014 },
- { MT_BBP(TXBE, 9), 0x20000000 },
- { MT_BBP(TXBE, 10), 0x00000000 },
- { MT_BBP(TXBE, 12), 0x00000000 },
- { MT_BBP(TXBE, 13), 0x00000000 },
- { MT_BBP(TXBE, 14), 0x00000000 },
- { MT_BBP(TXBE, 15), 0x00000000 },
- { MT_BBP(TXBE, 16), 0x00000000 },
- { MT_BBP(TXBE, 17), 0x00000000 },
- { MT_BBP(RXFE, 1), 0x00008800 },
- { MT_BBP(RXFE, 3), 0x00000000 },
- { MT_BBP(RXFE, 4), 0x00000000 },
- { MT_BBP(RXO, 13), 0x00000192 },
- { MT_BBP(RXO, 14), 0x00060612 },
- { MT_BBP(RXO, 15), 0xC8321B18 },
- { MT_BBP(RXO, 16), 0x0000001E },
- { MT_BBP(RXO, 17), 0x00000000 },
- { MT_BBP(RXO, 18), 0xCC00A993 },
- { MT_BBP(RXO, 19), 0xB9CB9CB9 },
- { MT_BBP(RXO, 20), 0x26c00057 },
- { MT_BBP(RXO, 21), 0x00000001 },
- { MT_BBP(RXO, 24), 0x00000006 },
- { MT_BBP(RXO, 28), 0x0000003F },
-};
-
static const struct mt76x0_bbp_switch_item mt76x0_bbp_switch_tab[] = {
{ RF_G_BAND | RF_BW_20 | RF_BW_40, { MT_BBP(AGC, 4), 0x1FEDA049 } },
{ RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(AGC, 4), 0x1FECA054 } },
@@ -215,16 +82,4 @@ static const struct mt76x0_bbp_switch_item mt76x0_bbp_switch_tab[] = {
{ RF_A_BAND | RF_BW_20 | RF_BW_40 | RF_BW_80, { MT_BBP(RXFE, 0), 0x895000E0 } },
};
-static const struct mt76_reg_pair mt76x0_dcoc_tab[] = {
- { MT_BBP(CAL, 47), 0x000010F0 },
- { MT_BBP(CAL, 48), 0x00008080 },
- { MT_BBP(CAL, 49), 0x00000F07 },
- { MT_BBP(CAL, 50), 0x00000040 },
- { MT_BBP(CAL, 51), 0x00000404 },
- { MT_BBP(CAL, 52), 0x00080803 },
- { MT_BBP(CAL, 53), 0x00000704 },
- { MT_BBP(CAL, 54), 0x00002828 },
- { MT_BBP(CAL, 55), 0x00005050 },
-};
-
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/initvals_init.h b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals_init.h
new file mode 100644
index 000000000000..9e99ba75f490
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/initvals_init.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * (c) Copyright 2002-2010, Ralink Technology, Inc.
+ * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl>
+ * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl>
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ */
+
+#ifndef __MT76X0U_INITVALS_INIT_H
+#define __MT76X0U_INITVALS_INIT_H
+
+#include "phy.h"
+
+static const struct mt76_reg_pair common_mac_reg_table[] = {
+ { MT_BCN_OFFSET(0), 0xf8f0e8e0 },
+ { MT_BCN_OFFSET(1), 0x6f77d0c8 },
+ { MT_LEGACY_BASIC_RATE, 0x0000013f },
+ { MT_HT_BASIC_RATE, 0x00008003 },
+ { MT_MAC_SYS_CTRL, 0x00000000 },
+ { MT_RX_FILTR_CFG, 0x00017f97 },
+ { MT_BKOFF_SLOT_CFG, 0x00000209 },
+ { MT_TX_SW_CFG0, 0x00000000 },
+ { MT_TX_SW_CFG1, 0x00080606 },
+ { MT_TX_LINK_CFG, 0x00001020 },
+ { MT_TX_TIMEOUT_CFG, 0x000a2090 },
+ { MT_MAX_LEN_CFG, 0xa0fff | 0x00001000 },
+ { MT_LED_CFG, 0x7f031e46 },
+ { MT_PBF_TX_MAX_PCNT, 0x1fbf1f1f },
+ { MT_PBF_RX_MAX_PCNT, 0x0000fe9f },
+ { MT_TX_RETRY_CFG, 0x47d01f0f },
+ { MT_AUTO_RSP_CFG, 0x00000013 },
+ { MT_CCK_PROT_CFG, 0x07f40003 },
+ { MT_OFDM_PROT_CFG, 0x07f42004 },
+ { MT_PBF_CFG, 0x00f40006 },
+ { MT_WPDMA_GLO_CFG, 0x00000030 },
+ { MT_GF20_PROT_CFG, 0x01742004 },
+ { MT_GF40_PROT_CFG, 0x03f42084 },
+ { MT_MM20_PROT_CFG, 0x01742004 },
+ { MT_MM40_PROT_CFG, 0x03f42084 },
+ { MT_TXOP_CTRL_CFG, 0x0000583f },
+ { MT_TX_RTS_CFG, 0x00ffff20 },
+ { MT_EXP_ACK_TIME, 0x002400ca },
+ { MT_TXOP_HLDR_ET, 0x00000002 },
+ { MT_XIFS_TIME_CFG, 0x33a41010 },
+ { MT_PWR_PIN_CFG, 0x00000000 },
+};
+
+static const struct mt76_reg_pair mt76x0_mac_reg_table[] = {
+ { MT_IOCFG_6, 0xa0040080 },
+ { MT_PBF_SYS_CTRL, 0x00080c00 },
+ { MT_PBF_CFG, 0x77723c1f },
+ { MT_FCE_PSE_CTRL, 0x00000001 },
+ { MT_AMPDU_MAX_LEN_20M1S, 0xAAA99887 },
+ { MT_TX_SW_CFG0, 0x00000601 },
+ { MT_TX_SW_CFG1, 0x00040000 },
+ { MT_TX_SW_CFG2, 0x00000000 },
+ { 0xa44, 0x00000000 },
+ { MT_HEADER_TRANS_CTRL_REG, 0x00000000 },
+ { MT_TSO_CTRL, 0x00000000 },
+ { MT_BB_PA_MODE_CFG1, 0x00500055 },
+ { MT_RF_PA_MODE_CFG1, 0x00500055 },
+ { MT_TX_ALC_CFG_0, 0x2F2F000C },
+ { MT_TX0_BB_GAIN_ATTEN, 0x00000000 },
+ { MT_TX_PWR_CFG_0, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_1, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_2, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_3, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_4, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_7, 0x3A3A3A3A },
+ { MT_TX_PWR_CFG_8, 0x0000003A },
+ { MT_TX_PWR_CFG_9, 0x0000003A },
+ { 0x150C, 0x00000002 },
+ { 0x1238, 0x001700C8 },
+ { MT_LDO_CTRL_0, 0x00A647B6 },
+ { MT_LDO_CTRL_1, 0x6B006464 },
+ { MT_HT_BASIC_RATE, 0x00004003 },
+ { MT_HT_CTRL_CFG, 0x000001FF },
+ { MT_TXOP_HLDR_ET, 0x00000000 },
+ { MT_PN_PAD_MODE, 0x00000003 },
+ { MT_TX_PROT_CFG6, 0xe3f42004 },
+ { MT_TX_PROT_CFG7, 0xe3f42084 },
+ { MT_TX_PROT_CFG8, 0xe3f42104 },
+ { MT_VHT_HT_FBK_CFG1, 0xedcba980 },
+};
+
+static const struct mt76_reg_pair mt76x0_bbp_init_tab[] = {
+ { MT_BBP(CORE, 1), 0x00000002 },
+ { MT_BBP(CORE, 4), 0x00000000 },
+ { MT_BBP(CORE, 24), 0x00000000 },
+ { MT_BBP(CORE, 32), 0x4003000a },
+ { MT_BBP(CORE, 42), 0x00000000 },
+ { MT_BBP(CORE, 44), 0x00000000 },
+ { MT_BBP(IBI, 11), 0x0FDE8081 },
+ { MT_BBP(AGC, 0), 0x00021400 },
+ { MT_BBP(AGC, 1), 0x00000003 },
+ { MT_BBP(AGC, 2), 0x003A6464 },
+ { MT_BBP(AGC, 15), 0x88A28CB8 },
+ { MT_BBP(AGC, 22), 0x00001E21 },
+ { MT_BBP(AGC, 23), 0x0000272C },
+ { MT_BBP(AGC, 24), 0x00002F3A },
+ { MT_BBP(AGC, 25), 0x8000005A },
+ { MT_BBP(AGC, 26), 0x007C2005 },
+ { MT_BBP(AGC, 33), 0x00003238 },
+ { MT_BBP(AGC, 34), 0x000A0C0C },
+ { MT_BBP(AGC, 37), 0x2121262C },
+ { MT_BBP(AGC, 41), 0x38383E45 },
+ { MT_BBP(AGC, 57), 0x00001010 },
+ { MT_BBP(AGC, 59), 0xBAA20E96 },
+ { MT_BBP(AGC, 63), 0x00000001 },
+ { MT_BBP(TXC, 0), 0x00280403 },
+ { MT_BBP(TXC, 1), 0x00000000 },
+ { MT_BBP(RXC, 1), 0x00000012 },
+ { MT_BBP(RXC, 2), 0x00000011 },
+ { MT_BBP(RXC, 3), 0x00000005 },
+ { MT_BBP(RXC, 4), 0x00000000 },
+ { MT_BBP(RXC, 5), 0xF977C4EC },
+ { MT_BBP(RXC, 7), 0x00000090 },
+ { MT_BBP(TXO, 8), 0x00000000 },
+ { MT_BBP(TXBE, 0), 0x00000000 },
+ { MT_BBP(TXBE, 4), 0x00000004 },
+ { MT_BBP(TXBE, 6), 0x00000000 },
+ { MT_BBP(TXBE, 8), 0x00000014 },
+ { MT_BBP(TXBE, 9), 0x20000000 },
+ { MT_BBP(TXBE, 10), 0x00000000 },
+ { MT_BBP(TXBE, 12), 0x00000000 },
+ { MT_BBP(TXBE, 13), 0x00000000 },
+ { MT_BBP(TXBE, 14), 0x00000000 },
+ { MT_BBP(TXBE, 15), 0x00000000 },
+ { MT_BBP(TXBE, 16), 0x00000000 },
+ { MT_BBP(TXBE, 17), 0x00000000 },
+ { MT_BBP(RXFE, 1), 0x00008800 },
+ { MT_BBP(RXFE, 3), 0x00000000 },
+ { MT_BBP(RXFE, 4), 0x00000000 },
+ { MT_BBP(RXO, 13), 0x00000192 },
+ { MT_BBP(RXO, 14), 0x00060612 },
+ { MT_BBP(RXO, 15), 0xC8321B18 },
+ { MT_BBP(RXO, 16), 0x0000001E },
+ { MT_BBP(RXO, 17), 0x00000000 },
+ { MT_BBP(RXO, 18), 0xCC00A993 },
+ { MT_BBP(RXO, 19), 0xB9CB9CB9 },
+ { MT_BBP(RXO, 20), 0x26c00057 },
+ { MT_BBP(RXO, 21), 0x00000001 },
+ { MT_BBP(RXO, 24), 0x00000006 },
+ { MT_BBP(RXO, 28), 0x0000003F },
+};
+
+static const struct mt76_reg_pair mt76x0_dcoc_tab[] = {
+ { MT_BBP(CAL, 47), 0x000010F0 },
+ { MT_BBP(CAL, 48), 0x00008080 },
+ { MT_BBP(CAL, 49), 0x00000F07 },
+ { MT_BBP(CAL, 50), 0x00000040 },
+ { MT_BBP(CAL, 51), 0x00000404 },
+ { MT_BBP(CAL, 52), 0x00080803 },
+ { MT_BBP(CAL, 53), 0x00000704 },
+ { MT_BBP(CAL, 54), 0x00002828 },
+ { MT_BBP(CAL, 55), 0x00005050 },
+};
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
index f7ec3400e368..dda11c704aba 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
@@ -180,6 +180,8 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mdev->rev = mt76_rr(dev, MT_ASIC_VERSION);
dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev);
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+
ret = devm_request_irq(mdev->dev, pdev->irq, mt76x02_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret)
@@ -202,7 +204,7 @@ static void mt76x0e_cleanup(struct mt76x02_dev *dev)
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
mt76x0_chip_onoff(dev, false, false);
mt76x0e_stop_hw(dev);
- mt76x02_dma_cleanup(dev);
+ mt76_dma_cleanup(&dev->mt76);
mt76x02_mcu_cleanup(dev);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
index 09f34deb6ba1..3de33aadf794 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
@@ -734,7 +734,7 @@ mt76x0_phy_get_delta_power(struct mt76x02_dev *dev, u8 tx_mode,
case 1:
if (chan->band == NL80211_BAND_2GHZ)
tssi_target += 29491; /* 3.6 * 8192 */
- /* fall through */
+ fallthrough;
case 0:
break;
default:
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h
index 4660b9691ec3..d626817a2103 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h
@@ -15,6 +15,8 @@
#include "mt76x02_dfs.h"
#include "mt76x02_dma.h"
+#define MT76x02_TX_RING_SIZE 512
+#define MT76x02_PSD_RING_SIZE 128
#define MT76x02_N_WCIDS 128
#define MT_CALIBRATE_INTERVAL HZ
#define MT_MAC_WORK_INTERVAL (HZ / 10)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c
index ff448a1ad4e3..c4fe1c436aaa 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_debugfs.c
@@ -7,7 +7,7 @@
#include "mt76x02.h"
static int
-mt76x02_ampdu_stat_read(struct seq_file *file, void *data)
+mt76x02_ampdu_stat_show(struct seq_file *file, void *data)
{
struct mt76x02_dev *dev = file->private;
int i, j;
@@ -31,11 +31,7 @@ mt76x02_ampdu_stat_read(struct seq_file *file, void *data)
return 0;
}
-static int
-mt76x02_ampdu_stat_open(struct inode *inode, struct file *f)
-{
- return single_open(f, mt76x02_ampdu_stat_read, inode->i_private);
-}
+DEFINE_SHOW_ATTRIBUTE(mt76x02_ampdu_stat);
static int read_txpower(struct seq_file *file, void *data)
{
@@ -48,15 +44,8 @@ static int read_txpower(struct seq_file *file, void *data)
return 0;
}
-static const struct file_operations fops_ampdu_stat = {
- .open = mt76x02_ampdu_stat_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static int
-mt76x02_dfs_stat_read(struct seq_file *file, void *data)
+mt76x02_dfs_stat_show(struct seq_file *file, void *data)
{
struct mt76x02_dev *dev = file->private;
struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
@@ -81,18 +70,7 @@ mt76x02_dfs_stat_read(struct seq_file *file, void *data)
return 0;
}
-static int
-mt76x02_dfs_stat_open(struct inode *inode, struct file *f)
-{
- return single_open(f, mt76x02_dfs_stat_read, inode->i_private);
-}
-
-static const struct file_operations fops_dfs_stat = {
- .open = mt76x02_dfs_stat_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mt76x02_dfs_stat);
static int read_agc(struct seq_file *file, void *data)
{
@@ -150,8 +128,8 @@ void mt76x02_init_debugfs(struct mt76x02_dev *dev)
debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc);
debugfs_create_file("edcca", 0600, dir, dev, &fops_edcca);
- debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
- debugfs_create_file("dfs_stats", 0400, dir, dev, &fops_dfs_stat);
+ debugfs_create_file("ampdu_stat", 0400, dir, dev, &mt76x02_ampdu_stat_fops);
+ debugfs_create_file("dfs_stats", 0400, dir, dev, &mt76x02_dfs_stat_fops);
debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir,
read_txpower);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
index ff6a9e4daac0..b29cd39dc176 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c
@@ -429,11 +429,11 @@ static int mt76x02_dfs_create_sequence(struct mt76x02_dev *dev,
{
struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
struct mt76x02_dfs_sw_detector_params *sw_params;
- u32 width_delta, with_sum, factor, cur_pri;
+ u32 width_delta, with_sum;
struct mt76x02_dfs_sequence seq, *seq_p;
struct mt76x02_dfs_event_rb *event_rb;
struct mt76x02_dfs_event *cur_event;
- int i, j, end, pri;
+ int i, j, end, pri, factor, cur_pri;
event_rb = event->engine == 2 ? &dfs_pd->event_rb[1]
: &dfs_pd->event_rb[0];
@@ -517,7 +517,7 @@ static u16 mt76x02_dfs_add_event_to_sequence(struct mt76x02_dev *dev,
struct mt76x02_dfs_sw_detector_params *sw_params;
struct mt76x02_dfs_sequence *seq, *tmp_seq;
u16 max_seq_len = 0;
- u32 factor, pri;
+ int factor, pri;
sw_params = &dfs_pd->sw_dpd_params;
list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h
index 4aff4f8e87b6..23b0e7d10d57 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_dma.h
@@ -61,6 +61,5 @@ mt76x02_wait_for_wpdma(struct mt76_dev *dev, int timeout)
int mt76x02_dma_init(struct mt76x02_dev *dev);
void mt76x02_dma_disable(struct mt76x02_dev *dev);
-void mt76x02_dma_cleanup(struct mt76x02_dev *dev);
#endif /* __MT76x02_DMA_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
index e4e03beabe43..da6d3f51f6d4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c
@@ -300,7 +300,7 @@ mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
return 0;
case MT_PHY_TYPE_HT_GF:
txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
- /* fall through */
+ fallthrough;
case MT_PHY_TYPE_HT:
txrate->flags |= IEEE80211_TX_RC_MCS;
txrate->idx = idx;
@@ -349,6 +349,8 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
memset(txwi, 0, sizeof(*txwi));
+ mt76_tx_check_agg_ssn(sta, skb);
+
if (!info->control.hw_key && wcid && wcid->hw_key_idx != 0xff &&
ieee80211_has_protected(hdr->frame_control)) {
wcid = NULL;
@@ -462,7 +464,7 @@ mt76x02_tx_rate_fallback(struct ieee80211_tx_rate *rates, int idx, int phy)
rates[1].idx = 0;
break;
}
- /* fall through */
+ fallthrough;
default:
rates[1].idx = max_t(int, rates[0].idx - 1, 0);
break;
@@ -677,7 +679,7 @@ mt76x02_mac_process_rate(struct mt76x02_dev *dev,
return 0;
case MT_PHY_TYPE_HT_GF:
status->enc_flags |= RX_ENC_FLAG_HT_GF;
- /* fall through */
+ fallthrough;
case MT_PHY_TYPE_HT:
status->encoding = RX_ENC_HT;
status->rate_idx = idx;
@@ -898,8 +900,7 @@ void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq)
}
}
-void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
- struct mt76_queue_entry *e)
+void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
{
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
struct mt76x02_txwi *txwi;
@@ -916,7 +917,7 @@ void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
txwi = (struct mt76x02_txwi *)txwi_ptr;
trace_mac_txdone(mdev, txwi->wcid, txwi->pktid);
- mt76_tx_complete_skb(mdev, e->skb);
+ mt76_tx_complete_skb(mdev, e->wcid, e->skb);
}
EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
index c70d17b2290c..0cfbaca50210 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.h
@@ -194,8 +194,7 @@ void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta, int len);
void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq);
-void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
- struct mt76_queue_entry *e);
+void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
void mt76x02_update_channel(struct mt76_dev *mdev);
void mt76x02_mac_work(struct work_struct *work);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index bacb1f10a699..cf68731bd094 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -14,7 +14,7 @@
static void mt76x02_pre_tbtt_tasklet(unsigned long arg)
{
struct mt76x02_dev *dev = (struct mt76x02_dev *)arg;
- struct mt76_queue *q = dev->mt76.q_tx[MT_TXQ_PSD].q;
+ struct mt76_queue *q = dev->mt76.q_tx[MT_TXQ_PSD];
struct beacon_bc_data data = {};
struct sk_buff *skb;
int i;
@@ -104,8 +104,7 @@ void mt76x02e_init_beacon_config(struct mt76x02_dev *dev)
EXPORT_SYMBOL_GPL(mt76x02e_init_beacon_config);
static int
-mt76x02_init_tx_queue(struct mt76x02_dev *dev, struct mt76_sw_queue *q,
- int idx, int n_desc)
+mt76x02_init_tx_queue(struct mt76x02_dev *dev, int qid, int idx, int n_desc)
{
struct mt76_queue *hwq;
int err;
@@ -118,8 +117,7 @@ mt76x02_init_tx_queue(struct mt76x02_dev *dev, struct mt76_sw_queue *q,
if (err < 0)
return err;
- INIT_LIST_HEAD(&q->swq);
- q->q = hwq;
+ dev->mt76.q_tx[qid] = hwq;
mt76x02_irq_enable(dev, MT_INT_TX_DONE(idx));
@@ -151,9 +149,11 @@ static void mt76x02_process_tx_status_fifo(struct mt76x02_dev *dev)
mt76x02_send_tx_status(dev, &stat, &update);
}
-static void mt76x02_tx_tasklet(unsigned long data)
+static void mt76x02_tx_worker(struct mt76_worker *w)
{
- struct mt76x02_dev *dev = (struct mt76x02_dev *)data;
+ struct mt76x02_dev *dev;
+
+ dev = container_of(w, struct mt76x02_dev, mt76.tx_worker);
mt76x02_mac_poll_tx_status(dev, false);
mt76x02_process_tx_status_fifo(dev);
@@ -178,7 +178,7 @@ static int mt76x02_poll_tx(struct napi_struct *napi, int budget)
for (i = MT_TXQ_MCU; i >= 0; i--)
mt76_queue_tx_cleanup(dev, i, false);
- tasklet_schedule(&dev->mt76.tx_tasklet);
+ mt76_worker_schedule(&dev->mt76.tx_worker);
return 0;
}
@@ -197,8 +197,7 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
if (!status_fifo)
return -ENOMEM;
- tasklet_init(&dev->mt76.tx_tasklet, mt76x02_tx_tasklet,
- (unsigned long)dev);
+ dev->mt76.tx_worker.fn = mt76x02_tx_worker;
tasklet_init(&dev->mt76.pre_tbtt_tasklet, mt76x02_pre_tbtt_tasklet,
(unsigned long)dev);
@@ -210,19 +209,18 @@ int mt76x02_dma_init(struct mt76x02_dev *dev)
mt76_wr(dev, MT_WPDMA_RST_IDX, ~0);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[i],
- mt76_ac_to_hwq(i),
- MT_TX_RING_SIZE);
+ ret = mt76x02_init_tx_queue(dev, i, mt76_ac_to_hwq(i),
+ MT76x02_TX_RING_SIZE);
if (ret)
return ret;
}
- ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_PSD],
- MT_TX_HW_QUEUE_MGMT, MT_TX_RING_SIZE);
+ ret = mt76x02_init_tx_queue(dev, MT_TXQ_PSD,
+ MT_TX_HW_QUEUE_MGMT, MT76x02_PSD_RING_SIZE);
if (ret)
return ret;
- ret = mt76x02_init_tx_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
+ ret = mt76x02_init_tx_queue(dev, MT_TXQ_MCU,
MT_TX_HW_QUEUE_MCU, MT_MCU_RING_SIZE);
if (ret)
return ret;
@@ -263,9 +261,10 @@ EXPORT_SYMBOL_GPL(mt76x02_rx_poll_complete);
irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance)
{
struct mt76x02_dev *dev = dev_instance;
- u32 intr;
+ u32 intr, mask;
intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
+ intr &= dev->mt76.mmio.irqmask;
mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
@@ -273,17 +272,17 @@ irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance)
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
- intr &= dev->mt76.mmio.irqmask;
+ mask = intr & (MT_INT_RX_DONE_ALL | MT_INT_GPTIMER);
+ if (intr & (MT_INT_TX_DONE_ALL | MT_INT_TX_STAT))
+ mask |= MT_INT_TX_DONE_ALL;
+
+ mt76x02_irq_disable(dev, mask);
- if (intr & MT_INT_RX_DONE(0)) {
- mt76x02_irq_disable(dev, MT_INT_RX_DONE(0));
+ if (intr & MT_INT_RX_DONE(0))
napi_schedule(&dev->mt76.napi[0]);
- }
- if (intr & MT_INT_RX_DONE(1)) {
- mt76x02_irq_disable(dev, MT_INT_RX_DONE(1));
+ if (intr & MT_INT_RX_DONE(1))
napi_schedule(&dev->mt76.napi[1]);
- }
if (intr & MT_INT_PRE_TBTT)
tasklet_schedule(&dev->mt76.pre_tbtt_tasklet);
@@ -293,21 +292,17 @@ irqreturn_t mt76x02_irq_handler(int irq, void *dev_instance)
if (dev->mt76.csa_complete)
mt76_csa_finish(&dev->mt76);
else
- mt76_queue_kick(dev, dev->mt76.q_tx[MT_TXQ_PSD].q);
+ mt76_queue_kick(dev, dev->mt76.q_tx[MT_TXQ_PSD]);
}
if (intr & MT_INT_TX_STAT)
mt76x02_mac_poll_tx_status(dev, true);
- if (intr & (MT_INT_TX_STAT | MT_INT_TX_DONE_ALL)) {
- mt76x02_irq_disable(dev, MT_INT_TX_DONE_ALL);
+ if (intr & (MT_INT_TX_STAT | MT_INT_TX_DONE_ALL))
napi_schedule(&dev->mt76.tx_napi);
- }
- if (intr & MT_INT_GPTIMER) {
- mt76x02_irq_disable(dev, MT_INT_GPTIMER);
+ if (intr & MT_INT_GPTIMER)
tasklet_schedule(&dev->dfs_pd.dfs_tasklet);
- }
return IRQ_HANDLED;
}
@@ -329,13 +324,6 @@ static void mt76x02_dma_enable(struct mt76x02_dev *dev)
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE);
}
-void mt76x02_dma_cleanup(struct mt76x02_dev *dev)
-{
- tasklet_kill(&dev->mt76.tx_tasklet);
- mt76_dma_cleanup(&dev->mt76);
-}
-EXPORT_SYMBOL_GPL(mt76x02_dma_cleanup);
-
void mt76x02_dma_disable(struct mt76x02_dev *dev)
{
u32 val = mt76_rr(dev, MT_WPDMA_GLO_CFG);
@@ -369,7 +357,7 @@ static bool mt76x02_tx_hang(struct mt76x02_dev *dev)
int i;
for (i = 0; i < 4; i++) {
- q = dev->mt76.q_tx[i].q;
+ q = dev->mt76.q_tx[i];
if (!q->queued)
continue;
@@ -453,7 +441,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
set_bit(MT76_RESET, &dev->mphy.state);
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
- tasklet_disable(&dev->mt76.tx_tasklet);
+ mt76_worker_disable(&dev->mt76.tx_worker);
napi_disable(&dev->mt76.tx_napi);
mt76_for_each_q_rx(&dev->mt76, i) {
@@ -510,7 +498,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
clear_bit(MT76_RESET, &dev->mphy.state);
- tasklet_enable(&dev->mt76.tx_tasklet);
+ mt76_worker_enable(&dev->mt76.tx_worker);
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
index a57dcc8820aa..b5be884b3549 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb.h
@@ -19,8 +19,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
-void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
- struct mt76_queue_entry *e);
+void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
void mt76x02u_init_beacon_config(struct mt76x02_dev *dev);
void mt76x02u_exit_beacon_config(struct mt76x02_dev *dev);
#endif /* __MT76x02_USB_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
index 37321e656776..2c2f56112b57 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_core.c
@@ -15,11 +15,10 @@ static void mt76x02u_remove_dma_hdr(struct sk_buff *skb)
mt76x02_remove_hdr_pad(skb, 2);
}
-void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
- struct mt76_queue_entry *e)
+void mt76x02u_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
{
mt76x02u_remove_dma_hdr(e->skb);
- mt76_tx_complete_skb(mdev, e->skb);
+ mt76_tx_complete_skb(mdev, e->wcid, e->skb);
}
EXPORT_SYMBOL_GPL(mt76x02u_tx_complete_skb);
@@ -46,7 +45,7 @@ EXPORT_SYMBOL_GPL(mt76x02u_mac_start);
int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
{
- u32 info;
+ u32 info, pad;
/* Buffer layout:
* | 4B | xfer len | pad | 4B |
@@ -58,7 +57,8 @@ int mt76x02u_skb_dma_info(struct sk_buff *skb, int port, u32 flags)
FIELD_PREP(MT_TXD_INFO_DPORT, port) | flags;
put_unaligned_le32(info, skb_push(skb, sizeof(info)));
- return mt76_skb_adjust_pad(skb);
+ pad = round_up(skb->len, 4) + 4 - skb->len;
+ return mt76_skb_adjust_pad(skb, pad);
}
int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
@@ -67,7 +67,7 @@ int mt76x02u_tx_prepare_skb(struct mt76_dev *mdev, void *data,
struct mt76_tx_info *tx_info)
{
struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76);
- int pid, len = tx_info->skb->len, ep = q2ep(mdev->q_tx[qid].q->hw_idx);
+ int pid, len = tx_info->skb->len, ep = q2ep(mdev->q_tx[qid]->hw_idx);
struct mt76x02_txwi *txwi;
bool ampdu = IEEE80211_SKB_CB(tx_info->skb)->flags & IEEE80211_TX_CTL_AMPDU;
enum mt76_qsel qsel;
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index dbd4077ea283..11b769af2f8f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -294,8 +294,6 @@ mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif,
mvif->group_wcid.hw_key_idx = -1;
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
mtxq->wcid = &mvif->group_wcid;
-
- mt76_txq_init(&dev->mt76, vif->txq);
}
int
@@ -347,7 +345,6 @@ void mt76x02_remove_interface(struct ieee80211_hw *hw,
struct mt76x02_dev *dev = hw->priv;
struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
- mt76_txq_remove(&dev->mt76, vif->txq);
dev->mphy.vif_mask &= ~BIT(mvif->idx);
}
EXPORT_SYMBOL_GPL(mt76x02_remove_interface);
@@ -490,7 +487,7 @@ int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u8 cw_min = 5, cw_max = 10, qid;
u32 val;
- qid = dev->mt76.q_tx[queue].q->hw_idx;
+ qid = dev->mt76.q_tx[queue]->hw_idx;
if (params->cw_min)
cw_min = fls(params->cw_min);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
index 6dfb0df8ec8a..4d50dad29ddf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
@@ -63,6 +63,8 @@ mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mdev->rev = mt76_rr(dev, MT_ASIC_VERSION);
dev_info(mdev->dev, "ASIC revision: %08x\n", mdev->rev);
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+
ret = devm_request_irq(mdev->dev, pdev->irq, mt76x02_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret)
@@ -111,7 +113,7 @@ mt76x2e_suspend(struct pci_dev *pdev, pm_message_t state)
napi_disable(&mdev->tx_napi);
tasklet_kill(&mdev->pre_tbtt_tasklet);
- tasklet_kill(&mdev->tx_tasklet);
+ mt76_worker_disable(&mdev->tx_worker);
mt76_for_each_q_rx(mdev, i)
napi_disable(&mdev->napi[i]);
@@ -145,6 +147,7 @@ mt76x2e_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
+ mt76_worker_enable(&mdev->tx_worker);
mt76_for_each_q_rx(mdev, i) {
napi_enable(&mdev->napi[i]);
napi_schedule(&mdev->napi[i]);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
index 101a0fe00ef3..48a3ebc9892a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_init.c
@@ -283,7 +283,7 @@ void mt76x2_cleanup(struct mt76x02_dev *dev)
tasklet_disable(&dev->dfs_pd.dfs_tasklet);
tasklet_disable(&dev->mt76.pre_tbtt_tasklet);
mt76x2_stop_hardware(dev);
- mt76x02_dma_cleanup(dev);
+ mt76_dma_cleanup(&dev->mt76);
mt76x02_mcu_cleanup(dev);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
index 38f473d587c9..1049927faf24 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
@@ -21,7 +21,6 @@ static int mt7915_ser_trigger_set(void *data, u64 val)
switch (val) {
case SER_SET_RECOVER_L1:
case SER_SET_RECOVER_L2:
- /* fall through */
ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), 0);
if (ret)
return ret;
@@ -292,15 +291,15 @@ mt7915_queues_read(struct seq_file *s, void *data)
int i;
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
- struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id];
+ struct mt76_queue *q = dev->mt76.q_tx[queue_map[i].id];
- if (!q->q)
+ if (!q)
continue;
seq_printf(s,
"%s: queued=%d head=%d tail=%d\n",
- queue_map[i].queue, q->q->queued, q->q->head,
- q->q->tail);
+ queue_map[i].queue, q->queued, q->head,
+ q->tail);
}
return 0;
@@ -400,7 +399,7 @@ static int mt7915_sta_fixed_rate_set(void *data, u64 rate)
struct ieee80211_sta *sta = data;
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
- return mt7915_mcu_set_fixed_rate(msta->vif->dev, sta, rate);
+ return mt7915_mcu_set_fixed_rate(msta->vif->phy->dev, sta, rate);
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_fixed_rate, NULL,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
index a8832c5e6004..cfa12c4c671f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c
@@ -8,7 +8,6 @@
static int
mt7915_init_tx_queues(struct mt7915_dev *dev, int n_desc)
{
- struct mt76_sw_queue *q;
struct mt76_queue *hwq;
int err, i;
@@ -21,18 +20,14 @@ mt7915_init_tx_queues(struct mt7915_dev *dev, int n_desc)
if (err < 0)
return err;
- for (i = 0; i < MT_TXQ_MCU; i++) {
- q = &dev->mt76.q_tx[i];
- INIT_LIST_HEAD(&q->swq);
- q->q = hwq;
- }
+ for (i = 0; i < MT_TXQ_MCU; i++)
+ dev->mt76.q_tx[i] = hwq;
return 0;
}
static int
-mt7915_init_mcu_queue(struct mt7915_dev *dev, struct mt76_sw_queue *q,
- int idx, int n_desc)
+mt7915_init_mcu_queue(struct mt7915_dev *dev, int qid, int idx, int n_desc)
{
struct mt76_queue *hwq;
int err;
@@ -45,8 +40,7 @@ mt7915_init_mcu_queue(struct mt7915_dev *dev, struct mt76_sw_queue *q,
if (err < 0)
return err;
- INIT_LIST_HEAD(&q->swq);
- q->q = hwq;
+ dev->mt76.q_tx[qid] = hwq;
return 0;
}
@@ -72,7 +66,7 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
mt76_rx(&dev->mt76, q, skb);
return;
}
- /* fall through */
+ fallthrough;
default:
dev_kfree_skb(skb);
break;
@@ -84,8 +78,6 @@ mt7915_tx_cleanup(struct mt7915_dev *dev)
{
mt76_queue_tx_cleanup(dev, MT_TXQ_MCU, false);
mt76_queue_tx_cleanup(dev, MT_TXQ_MCU_WA, false);
- mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
- mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
}
static int mt7915_poll_tx(struct napi_struct *napi, int budget)
@@ -97,13 +89,7 @@ static int mt7915_poll_tx(struct napi_struct *napi, int budget)
mt7915_tx_cleanup(dev);
if (napi_complete_done(napi, 0))
- mt7915_irq_enable(dev, MT_INT_TX_DONE_ALL);
-
- mt7915_tx_cleanup(dev);
-
- mt7915_mac_sta_poll(dev);
-
- tasklet_schedule(&dev->mt76.tx_tasklet);
+ mt7915_irq_enable(dev, MT_INT_TX_DONE_MCU);
return 0;
}
@@ -138,12 +124,120 @@ void mt7915_dma_prefetch(struct mt7915_dev *dev)
mt76_wr(dev, MT_WFDMA1_RX_RING3_EXT_CTRL, PREFETCH(0x480, 0x0));
}
+static u32 __mt7915_reg_addr(struct mt7915_dev *dev, u32 addr)
+{
+ static const struct {
+ u32 phys;
+ u32 mapped;
+ u32 size;
+ } fixed_map[] = {
+ { 0x54000000, 0x02000, 0x1000 }, /* WFDMA PCIE0 MCU DMA0 */
+ { 0x55000000, 0x03000, 0x1000 }, /* WFDMA PCIE0 MCU DMA1 */
+ { 0x58000000, 0x06000, 0x1000 }, /* WFDMA PCIE1 MCU DMA0 (MEM_DMA) */
+ { 0x59000000, 0x07000, 0x1000 }, /* WFDMA PCIE1 MCU DMA1 */
+ { 0x7c000000, 0xf0000, 0x10000 }, /* CONN_INFRA */
+ { 0x7c020000, 0xd0000, 0x10000 }, /* CONN_INFRA, WFDMA */
+ { 0x80020000, 0xb0000, 0x10000 }, /* WF_TOP_MISC_OFF */
+ { 0x81020000, 0xc0000, 0x10000 }, /* WF_TOP_MISC_ON */
+ { 0x820c0000, 0x08000, 0x4000 }, /* WF_UMAC_TOP (PLE) */
+ { 0x820c8000, 0x0c000, 0x2000 }, /* WF_UMAC_TOP (PSE) */
+ { 0x820cc000, 0x0e000, 0x2000 }, /* WF_UMAC_TOP (PP) */
+ { 0x820ce000, 0x21c00, 0x0200 }, /* WF_LMAC_TOP (WF_SEC) */
+ { 0x820cf000, 0x22000, 0x1000 }, /* WF_LMAC_TOP (WF_PF) */
+ { 0x820d0000, 0x30000, 0x10000 }, /* WF_LMAC_TOP (WF_WTBLON) */
+ { 0x820e0000, 0x20000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_CFG) */
+ { 0x820e1000, 0x20400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_TRB) */
+ { 0x820e2000, 0x20800, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_AGG) */
+ { 0x820e3000, 0x20c00, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_ARB) */
+ { 0x820e4000, 0x21000, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_TMAC) */
+ { 0x820e5000, 0x21400, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_RMAC) */
+ { 0x820e7000, 0x21e00, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_DMA) */
+ { 0x820e9000, 0x23400, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_WTBLOFF) */
+ { 0x820ea000, 0x24000, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_ETBF) */
+ { 0x820eb000, 0x24200, 0x0400 }, /* WF_LMAC_TOP BN0 (WF_LPON) */
+ { 0x820ec000, 0x24600, 0x0200 }, /* WF_LMAC_TOP BN0 (WF_INT) */
+ { 0x820ed000, 0x24800, 0x0800 }, /* WF_LMAC_TOP BN0 (WF_MIB) */
+ { 0x820f0000, 0xa0000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_CFG) */
+ { 0x820f1000, 0xa0600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_TRB) */
+ { 0x820f2000, 0xa0800, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_AGG) */
+ { 0x820f3000, 0xa0c00, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_ARB) */
+ { 0x820f4000, 0xa1000, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_TMAC) */
+ { 0x820f5000, 0xa1400, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_RMAC) */
+ { 0x820f7000, 0xa1e00, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_DMA) */
+ { 0x820f9000, 0xa3400, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_WTBLOFF) */
+ { 0x820fa000, 0xa4000, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_ETBF) */
+ { 0x820fb000, 0xa4200, 0x0400 }, /* WF_LMAC_TOP BN1 (WF_LPON) */
+ { 0x820fc000, 0xa4600, 0x0200 }, /* WF_LMAC_TOP BN1 (WF_INT) */
+ { 0x820fd000, 0xa4800, 0x0800 }, /* WF_LMAC_TOP BN1 (WF_MIB) */
+ };
+ int i;
+
+ if (addr < 0x100000)
+ return addr;
+
+ for (i = 0; i < ARRAY_SIZE(fixed_map); i++) {
+ u32 ofs;
+
+ if (addr < fixed_map[i].phys)
+ continue;
+
+ ofs = addr - fixed_map[i].phys;
+ if (ofs > fixed_map[i].size)
+ continue;
+
+ return fixed_map[i].mapped + ofs;
+ }
+
+ if ((addr >= 0x18000000 && addr < 0x18c00000) ||
+ (addr >= 0x70000000 && addr < 0x78000000) ||
+ (addr >= 0x7c000000 && addr < 0x7c400000))
+ return mt7915_reg_map_l1(dev, addr);
+
+ return mt7915_reg_map_l2(dev, addr);
+}
+
+static u32 mt7915_rr(struct mt76_dev *mdev, u32 offset)
+{
+ struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
+ u32 addr = __mt7915_reg_addr(dev, offset);
+
+ return dev->bus_ops->rr(mdev, addr);
+}
+
+static void mt7915_wr(struct mt76_dev *mdev, u32 offset, u32 val)
+{
+ struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
+ u32 addr = __mt7915_reg_addr(dev, offset);
+
+ dev->bus_ops->wr(mdev, addr, val);
+}
+
+static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
+{
+ struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
+ u32 addr = __mt7915_reg_addr(dev, offset);
+
+ return dev->bus_ops->rmw(mdev, addr, mask, val);
+}
+
int mt7915_dma_init(struct mt7915_dev *dev)
{
/* Increase buffer size to receive large VHT/HE MPDUs */
+ struct mt76_bus_ops *bus_ops;
int rx_buf_size = MT_RX_BUF_SIZE * 2;
int ret;
+ dev->bus_ops = dev->mt76.bus;
+ bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops),
+ GFP_KERNEL);
+ if (!bus_ops)
+ return -ENOMEM;
+
+ bus_ops->rr = mt7915_rr;
+ bus_ops->wr = mt7915_wr;
+ bus_ops->rmw = mt7915_rmw;
+ dev->mt76.bus = bus_ops;
+
mt76_dma_attach(&dev->mt76);
/* configure global setting */
@@ -168,22 +262,19 @@ int mt7915_dma_init(struct mt7915_dev *dev)
return ret;
/* command to WM */
- ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
- MT7915_TXQ_MCU_WM,
+ ret = mt7915_init_mcu_queue(dev, MT_TXQ_MCU, MT7915_TXQ_MCU_WM,
MT7915_TX_MCU_RING_SIZE);
if (ret)
return ret;
/* command to WA */
- ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU_WA],
- MT7915_TXQ_MCU_WA,
+ ret = mt7915_init_mcu_queue(dev, MT_TXQ_MCU_WA, MT7915_TXQ_MCU_WA,
MT7915_TX_MCU_RING_SIZE);
if (ret)
return ret;
/* firmware download */
- ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_FWDL],
- MT7915_TXQ_FWDL,
+ ret = mt7915_init_mcu_queue(dev, MT_TXQ_FWDL, MT7915_TXQ_FWDL,
MT7915_TX_FWDL_RING_SIZE);
if (ret)
return ret;
@@ -248,7 +339,7 @@ int mt7915_dma_init(struct mt7915_dev *dev)
MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN);
/* enable interrupts for TX/RX rings */
- mt7915_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
+ mt7915_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_MCU |
MT_INT_MCU_CMD);
return 0;
@@ -281,6 +372,5 @@ void mt7915_dma_cleanup(struct mt7915_dev *dev)
MT_WFDMA0_RST_DMASHDL_ALL_RST |
MT_WFDMA0_RST_LOGIC_RST);
- tasklet_kill(&dev->mt76.tx_tasklet);
mt76_dma_cleanup(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index 8d6ceb3b67b4..0232b66acb4f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -135,6 +135,12 @@ static int mt7915_init_hardware(struct mt7915_dev *dev)
set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
+ /*
+ * force firmware operation mode into normal state,
+ * which should be set before firmware download stage.
+ */
+ mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
+
ret = mt7915_mcu_init(dev);
if (ret)
return ret;
@@ -612,6 +618,7 @@ int mt7915_register_ext_phy(struct mt7915_dev *dev)
mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1;
mt7915_init_wiphy(mphy->hw);
+ INIT_LIST_HEAD(&phy->stats_list);
INIT_DELAYED_WORK(&phy->mac_work, mt7915_mac_work);
/*
@@ -652,7 +659,10 @@ int mt7915_register_device(struct mt7915_dev *dev)
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
dev->mt76.phy.priv = &dev->phy;
+ INIT_LIST_HEAD(&dev->phy.stats_list);
+ INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
INIT_DELAYED_WORK(&dev->phy.mac_work, mt7915_mac_work);
+ INIT_LIST_HEAD(&dev->sta_rc_list);
INIT_LIST_HEAD(&dev->sta_poll_list);
spin_lock_init(&dev->sta_poll_lock);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 036207f828f3..6f159d99a596 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -88,17 +88,16 @@ bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask)
0, 5000);
}
-static u32 mt7915_mac_wtbl_lmac_read(struct mt7915_dev *dev, u16 wcid,
- u16 addr)
+static u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid)
{
mt76_wr(dev, MT_WTBLON_TOP_WDUCR,
FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7)));
- return mt76_rr(dev, MT_WTBL_LMAC_OFFS(wcid, addr));
+ return MT_WTBL_LMAC_OFFS(wcid, 0);
}
/* TODO: use txfree airtime info to avoid runtime accessing in the long run */
-void mt7915_mac_sta_poll(struct mt7915_dev *dev)
+static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
{
static const u8 ac_to_tid[] = {
[IEEE80211_AC_BE] = 0,
@@ -106,47 +105,50 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev)
[IEEE80211_AC_VI] = 4,
[IEEE80211_AC_VO] = 6
};
- static const u8 hw_queue_map[] = {
- [IEEE80211_AC_BK] = 0,
- [IEEE80211_AC_BE] = 1,
- [IEEE80211_AC_VI] = 2,
- [IEEE80211_AC_VO] = 3,
- };
struct ieee80211_sta *sta;
struct mt7915_sta *msta;
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
+ LIST_HEAD(sta_poll_list);
int i;
+ spin_lock_bh(&dev->sta_poll_lock);
+ list_splice_init(&dev->sta_poll_list, &sta_poll_list);
+ spin_unlock_bh(&dev->sta_poll_lock);
+
rcu_read_lock();
while (true) {
bool clear = false;
+ u32 addr;
u16 idx;
spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&dev->sta_poll_list)) {
+ if (list_empty(&sta_poll_list)) {
spin_unlock_bh(&dev->sta_poll_lock);
break;
}
- msta = list_first_entry(&dev->sta_poll_list,
+ msta = list_first_entry(&sta_poll_list,
struct mt7915_sta, poll_list);
list_del_init(&msta->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
- for (i = 0, idx = msta->wcid.idx; i < IEEE80211_NUM_ACS; i++) {
+ idx = msta->wcid.idx;
+ addr = mt7915_mac_wtbl_lmac_addr(dev, idx) + 20 * 4;
+
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
u32 tx_last = msta->airtime_ac[i];
- u32 rx_last = msta->airtime_ac[i + IEEE80211_NUM_ACS];
+ u32 rx_last = msta->airtime_ac[i + 4];
+
+ msta->airtime_ac[i] = mt76_rr(dev, addr);
+ msta->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
- msta->airtime_ac[i] =
- mt7915_mac_wtbl_lmac_read(dev, idx, 20 + i);
- msta->airtime_ac[i + IEEE80211_NUM_ACS] =
- mt7915_mac_wtbl_lmac_read(dev, idx, 21 + i);
tx_time[i] = msta->airtime_ac[i] - tx_last;
- rx_time[i] = msta->airtime_ac[i + IEEE80211_NUM_ACS] -
- rx_last;
+ rx_time[i] = msta->airtime_ac[i + 4] - rx_last;
if ((tx_last | rx_last) & BIT(30))
clear = true;
+
+ addr += 8;
}
if (clear) {
@@ -161,8 +163,9 @@ void mt7915_mac_sta_poll(struct mt7915_dev *dev)
sta = container_of((void *)msta, struct ieee80211_sta,
drv_priv);
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- u32 tx_cur = tx_time[i];
- u32 rx_cur = rx_time[hw_queue_map[i]];
+ u8 q = mt7915_lmac_mapping(dev, i);
+ u32 tx_cur = tx_time[q];
+ u32 rx_cur = rx_time[q];
u8 tid = ac_to_tid[i];
if (!tx_cur && !rx_cur)
@@ -468,7 +471,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
switch (mode) {
case MT_PHY_TYPE_CCK:
cck = true;
- /* fall through */
+ fallthrough;
case MT_PHY_TYPE_OFDM:
i = mt76_get_rate(&dev->mt76, sband, i, cck);
break;
@@ -487,7 +490,7 @@ int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
break;
case MT_PHY_TYPE_HE_MU:
status->flag |= RX_FLAG_RADIOTAP_HE_MU;
- /* fall through */
+ fallthrough;
case MT_PHY_TYPE_HE_SU:
case MT_PHY_TYPE_HE_EXT_SU:
case MT_PHY_TYPE_HE_TB:
@@ -565,13 +568,15 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
bool multicast = is_multicast_ether_addr(hdr->addr1);
struct ieee80211_vif *vif = info->control.vif;
struct mt76_phy *mphy = &dev->mphy;
bool ext_phy = info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY;
u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
__le16 fc = hdr->frame_control;
- u16 tx_count = 4, seqno = 0;
+ u16 tx_count = 15, seqno = 0;
+ u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
u32 val;
if (vif) {
@@ -587,6 +592,10 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
+ txwi[4] = 0;
+ txwi[5] = 0;
+ txwi[6] = 0;
+
if (beacon) {
p_fmt = MT_TX_TYPE_FW;
q_idx = MT_LMAC_BCN0;
@@ -599,6 +608,20 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
mt7915_lmac_mapping(dev, skb_get_queue_mapping(skb));
}
+ if (ieee80211_is_action(fc) &&
+ mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+ mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
+ u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+
+ txwi[5] |= cpu_to_le32(MT_TXD5_ADD_BA);
+ tid = (capab >> 2) & IEEE80211_QOS_CTL_TID_MASK;
+ } else if (ieee80211_is_back_req(hdr->frame_control)) {
+ struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr;
+ u16 control = le16_to_cpu(bar->control);
+
+ tid = FIELD_GET(IEEE80211_BAR_CTRL_TID_INFO_MASK, control);
+ }
+
val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + MT_TXD_SIZE) |
FIELD_PREP(MT_TXD0_PKT_FMT, p_fmt) |
FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
@@ -609,8 +632,7 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_11) |
FIELD_PREP(MT_TXD1_HDR_INFO,
ieee80211_get_hdrlen_from_skb(skb) / 2) |
- FIELD_PREP(MT_TXD1_TID,
- skb->priority & IEEE80211_QOS_CTL_TID_MASK) |
+ FIELD_PREP(MT_TXD1_TID, tid) |
FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx);
if (ext_phy && q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)
@@ -634,10 +656,6 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
}
txwi[2] = cpu_to_le32(val);
- txwi[4] = 0;
- txwi[5] = 0;
- txwi[6] = 0;
-
if (!ieee80211_is_data(fc) || multicast) {
u16 rate;
@@ -665,20 +683,24 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
val = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
+ if (wcid->amsdu)
+ val |= MT_TXD7_HW_AMSDU;
txwi[7] = cpu_to_le32(val);
val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, tx_count);
- if (ieee80211_is_data_qos(fc)) {
- seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
- val |= MT_TXD3_SN_VALID;
- } else if (ieee80211_is_back_req(fc)) {
- struct ieee80211_bar *bar;
-
- bar = (struct ieee80211_bar *)skb->data;
- seqno = IEEE80211_SEQ_TO_SN(le16_to_cpu(bar->start_seq_num));
- val |= MT_TXD3_SN_VALID;
+ if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+ seqno = le16_to_cpu(hdr->seq_ctrl);
+
+ if (ieee80211_is_back_req(hdr->frame_control)) {
+ struct ieee80211_bar *bar;
+
+ bar = (struct ieee80211_bar *)skb->data;
+ seqno = le16_to_cpu(bar->start_seq_num);
+ }
+
+ val |= MT_TXD3_SN_VALID |
+ FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
}
- val |= FIELD_PREP(MT_TXD3_SEQ, seqno);
txwi[3] |= cpu_to_le32(val);
}
@@ -715,6 +737,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
/* pass partial skb header to fw */
tx_info->buf[1].len = MT_CT_PARSE_LEN;
+ tx_info->buf[1].skip_unmap = true;
tx_info->nbuf = MT_CT_DMA_BUF_NUM;
txp->flags = cpu_to_le16(MT_CT_INFO_APPLY_TXD);
@@ -747,45 +770,29 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
return 0;
}
-static inline bool
-mt7915_tx_check_aggr_tid(struct mt7915_sta *msta, u8 tid)
-{
- bool ret = false;
-
- spin_lock_bh(&msta->ampdu_lock);
- if (msta->ampdu_state[tid] == MT7915_AGGR_STOP)
- ret = true;
- spin_unlock_bh(&msta->ampdu_lock);
-
- return ret;
-}
-
static void
-mt7915_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
+mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct mt7915_sta *msta;
- u16 tid;
-
- if (!sta->ht_cap.ht_supported)
- return;
+ u16 fc, tid;
+ u32 val;
- if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
+ if (!sta || !sta->ht_cap.ht_supported)
return;
- if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
+ tid = FIELD_GET(MT_TXD1_TID, le32_to_cpu(txwi[1]));
+ if (tid >= 6) /* skip VO queue */
return;
- if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
+ val = le32_to_cpu(txwi[2]);
+ fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
+ FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
+ if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
return;
msta = (struct mt7915_sta *)sta->drv_priv;
- tid = ieee80211_get_tid(hdr);
-
- if (mt7915_tx_check_aggr_tid(msta, tid)) {
+ if (!test_and_set_bit(tid, &msta->ampdu_state))
ieee80211_start_tx_ba_session(sta, tid, 0);
- mt7915_set_aggr_state(msta, tid, MT7915_AGGR_PROGRESS);
- }
}
static inline void
@@ -822,8 +829,6 @@ mt7915_tx_complete_status(struct mt76_dev *mdev, struct sk_buff *skb,
if (info->flags & IEEE80211_TX_CTL_AMPDU)
info->flags |= IEEE80211_TX_STAT_AMPDU;
- else if (sta)
- mt7915_tx_check_aggr(sta, skb);
if (stat)
ieee80211_tx_info_clear_status(info);
@@ -864,6 +869,10 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
struct ieee80211_sta *sta = NULL;
u8 i, count;
+ /* clean DMA queues and unmap buffers first */
+ mt76_queue_tx_cleanup(dev, MT_TXQ_PSD, false);
+ mt76_queue_tx_cleanup(dev, MT_TXQ_BE, false);
+
/*
* TODO: MT_TX_FREE_LATENCY is msdu time from the TXD is queued into PLE,
* to the time ack is received or dropped by hw (air + hw queue time).
@@ -880,6 +889,7 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
*/
if (info & MT_TX_FREE_PAIR) {
struct mt7915_sta *msta;
+ struct mt7915_phy *phy;
struct mt76_wcid *wcid;
u16 idx;
@@ -891,8 +901,13 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
continue;
msta = container_of(wcid, struct mt7915_sta, wcid);
- ieee80211_queue_work(mt76_hw(dev), &msta->stats_work);
- continue;
+ phy = msta->vif->phy;
+ spin_lock_bh(&dev->sta_poll_lock);
+ if (list_empty(&msta->stats_list))
+ list_add_tail(&msta->stats_list, &phy->stats_list);
+ if (list_empty(&msta->poll_list))
+ list_add_tail(&msta->poll_list, &dev->sta_poll_list);
+ spin_unlock_bh(&dev->sta_poll_lock);
}
msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
@@ -907,6 +922,21 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
mt7915_txp_skb_unmap(mdev, txwi);
if (txwi->skb) {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txwi->skb);
+ void *txwi_ptr = mt76_get_txwi_ptr(mdev, txwi);
+
+ if (likely(txwi->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ mt7915_tx_check_aggr(sta, txwi_ptr);
+
+ if (sta && !info->tx_time_est) {
+ struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
+ int pending;
+
+ pending = atomic_dec_return(&wcid->non_aql_packets);
+ if (pending < 0)
+ atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
+ }
+
mt7915_tx_complete_status(mdev, txwi->skb, sta, stat);
txwi->skb = NULL;
}
@@ -914,10 +944,12 @@ void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb)
mt76_put_txwi(mdev, txwi);
}
dev_kfree_skb(skb);
+
+ mt7915_mac_sta_poll(dev);
+ mt76_worker_schedule(&dev->mt76.tx_worker);
}
-void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
- struct mt76_queue_entry *e)
+void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
{
struct mt7915_dev *dev;
@@ -1186,7 +1218,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
if (ext_phy)
mt76_txq_schedule_all(ext_phy);
- tasklet_disable(&dev->mt76.tx_tasklet);
+ mt76_worker_disable(&dev->mt76.tx_worker);
napi_disable(&dev->mt76.napi[0]);
napi_disable(&dev->mt76.napi[1]);
napi_disable(&dev->mt76.napi[2]);
@@ -1206,7 +1238,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_RESET, &dev->mphy.state);
- tasklet_enable(&dev->mt76.tx_tasklet);
+ mt76_worker_enable(&dev->mt76.tx_worker);
napi_enable(&dev->mt76.tx_napi);
napi_schedule(&dev->mt76.tx_napi);
@@ -1281,39 +1313,63 @@ mt7915_mac_update_mib_stats(struct mt7915_phy *phy)
}
}
-void mt7915_mac_sta_stats_work(struct work_struct *work)
+static void
+mt7915_mac_sta_stats_work(struct mt7915_phy *phy)
{
+ struct mt7915_dev *dev = phy->dev;
+ struct mt7915_sta *msta;
+ LIST_HEAD(list);
+
+ spin_lock_bh(&dev->sta_poll_lock);
+ list_splice_init(&phy->stats_list, &list);
+
+ while (!list_empty(&list)) {
+ msta = list_first_entry(&list, struct mt7915_sta, stats_list);
+ list_del_init(&msta->stats_list);
+ spin_unlock_bh(&dev->sta_poll_lock);
+
+ /* use MT_TX_FREE_RATE to report Tx rate for further devices */
+ mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO, msta->wcid.idx);
+
+ spin_lock_bh(&dev->sta_poll_lock);
+ }
+
+ spin_unlock_bh(&dev->sta_poll_lock);
+}
+
+void mt7915_mac_sta_rc_work(struct work_struct *work)
+{
+ struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work);
struct ieee80211_sta *sta;
struct ieee80211_vif *vif;
- struct mt7915_sta_stats *stats;
struct mt7915_sta *msta;
- struct mt7915_dev *dev;
+ u32 changed;
+ LIST_HEAD(list);
- msta = container_of(work, struct mt7915_sta, stats_work);
- sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
- vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
- dev = msta->vif->dev;
- stats = &msta->stats;
+ spin_lock_bh(&dev->sta_poll_lock);
+ list_splice_init(&dev->sta_rc_list, &list);
- /* use MT_TX_FREE_RATE to report Tx rate for further devices */
- if (time_after(jiffies, stats->jiffies + HZ)) {
- mt7915_mcu_get_rate_info(dev, RATE_CTRL_RU_INFO,
- msta->wcid.idx);
+ while (!list_empty(&list)) {
+ msta = list_first_entry(&list, struct mt7915_sta, rc_list);
+ list_del_init(&msta->rc_list);
+ changed = msta->stats.changed;
+ msta->stats.changed = 0;
+ spin_unlock_bh(&dev->sta_poll_lock);
- stats->jiffies = jiffies;
- }
+ sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
+ vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
- if (test_and_clear_bit(IEEE80211_RC_SUPP_RATES_CHANGED |
+ if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
IEEE80211_RC_NSS_CHANGED |
- IEEE80211_RC_BW_CHANGED, &stats->changed))
- mt7915_mcu_add_rate_ctrl(dev, vif, sta);
+ IEEE80211_RC_BW_CHANGED))
+ mt7915_mcu_add_rate_ctrl(dev, vif, sta);
- if (test_and_clear_bit(IEEE80211_RC_SMPS_CHANGED, &stats->changed))
- mt7915_mcu_add_smps(dev, vif, sta);
+ if (changed & IEEE80211_RC_SMPS_CHANGED)
+ mt7915_mcu_add_smps(dev, vif, sta);
+
+ spin_lock_bh(&dev->sta_poll_lock);
+ }
- spin_lock_bh(&dev->sta_poll_lock);
- if (list_empty(&msta->poll_list))
- list_add_tail(&msta->poll_list, &dev->sta_poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
}
@@ -1335,6 +1391,11 @@ void mt7915_mac_work(struct work_struct *work)
mt7915_mac_update_mib_stats(phy);
}
+ if (++phy->sta_work_count == 10) {
+ phy->sta_work_count = 0;
+ mt7915_mac_sta_stats_work(phy);
+ };
+
mutex_unlock(&mdev->mutex);
ieee80211_queue_delayed_work(phy->mt76->hw, &phy->mac_work,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index f95a0b55c4a2..c48158392057 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -137,7 +137,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
goto out;
}
mvif->omac_idx = idx;
- mvif->dev = dev;
+ mvif->phy = phy;
mvif->band_idx = ext_phy;
if (ext_phy)
@@ -155,6 +155,8 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
idx = MT7915_WTBL_RESERVED - mvif->idx;
+ INIT_LIST_HEAD(&mvif->sta.rc_list);
+ INIT_LIST_HEAD(&mvif->sta.stats_list);
INIT_LIST_HEAD(&mvif->sta.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.ext_phy = mvif->band_idx;
@@ -167,7 +169,6 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
if (vif->txq) {
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
mtxq->wcid = &mvif->sta.wcid;
- mt76_txq_init(&dev->mt76, vif->txq);
}
out:
@@ -190,8 +191,6 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw,
mt7915_mcu_add_dev_info(dev, vif, false);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
- if (vif->txq)
- mt76_txq_remove(&dev->mt76, vif->txq);
mutex_lock(&dev->mt76.mutex);
phy->mt76->vif_mask &= ~BIT(mvif->idx);
@@ -493,9 +492,9 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (idx < 0)
return -ENOSPC;
+ INIT_LIST_HEAD(&msta->rc_list);
+ INIT_LIST_HEAD(&msta->stats_list);
INIT_LIST_HEAD(&msta->poll_list);
- INIT_WORK(&msta->stats_work, mt7915_mac_sta_stats_work);
- spin_lock_init(&msta->ampdu_lock);
msta->vif = mvif;
msta->wcid.sta = 1;
msta->wcid.idx = idx;
@@ -528,6 +527,10 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
spin_lock_bh(&dev->sta_poll_lock);
if (!list_empty(&msta->poll_list))
list_del_init(&msta->poll_list);
+ if (!list_empty(&msta->stats_list))
+ list_del_init(&msta->stats_list);
+ if (!list_empty(&msta->rc_list))
+ list_del_init(&msta->rc_list);
spin_unlock_bh(&dev->sta_poll_lock);
}
@@ -603,23 +606,21 @@ mt7915_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_OPERATIONAL:
mtxq->aggr = true;
mtxq->send_bar = false;
- mt7915_set_aggr_state(msta, tid, MT7915_AGGR_OPERATIONAL);
mt7915_mcu_add_tx_ba(dev, params, true);
break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
mtxq->aggr = false;
- mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP);
+ clear_bit(tid, &msta->ampdu_state);
mt7915_mcu_add_tx_ba(dev, params, false);
break;
case IEEE80211_AMPDU_TX_START:
- mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
- mt7915_set_aggr_state(msta, tid, MT7915_AGGR_START);
+ set_bit(tid, &msta->ampdu_state);
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
- mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP);
+ clear_bit(tid, &msta->ampdu_state);
mt7915_mcu_add_tx_ba(dev, params, false);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
@@ -789,18 +790,16 @@ mt7915_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u32 changed)
{
+ struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
- rcu_read_lock();
- sta = ieee80211_find_sta(vif, sta->addr);
- if (!sta) {
- rcu_read_unlock();
- return;
- }
- rcu_read_unlock();
+ spin_lock_bh(&dev->sta_poll_lock);
+ msta->stats.changed |= changed;
+ if (list_empty(&msta->rc_list))
+ list_add_tail(&msta->rc_list, &dev->sta_rc_list);
+ spin_unlock_bh(&dev->sta_poll_lock);
- set_bit(changed, &msta->stats.changed);
- ieee80211_queue_work(hw, &msta->stats_work);
+ ieee80211_queue_work(hw, &dev->rc_work);
}
const struct ieee80211_ops mt7915_ops = {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index ac8ec257da03..a3ccc1785661 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -522,6 +522,9 @@ mt7915_mcu_tx_rate_report(struct mt7915_dev *dev, struct sk_buff *skb)
return;
wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
+ if (!wcid)
+ return;
+
msta = container_of(wcid, struct mt7915_sta, wcid);
stats = &msta->stats;
@@ -714,8 +717,8 @@ mt7915_mcu_add_nested_subtlv(struct sk_buff *skb, int sub_tag, int sub_len,
ptlv = skb_put(skb, sub_len);
memcpy(ptlv, &tlv, sizeof(tlv));
- *sub_ntlv = cpu_to_le16(le16_to_cpu(*sub_ntlv) + 1);
- *len = cpu_to_le16(le16_to_cpu(*len) + sub_len);
+ le16_add_cpu(sub_ntlv, 1);
+ le16_add_cpu(len, sub_len);
return ptlv;
}
@@ -933,11 +936,11 @@ mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he));
he = (struct bss_info_he *)tlv;
- he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext * 4;
+ he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;
if (!he->he_pe_duration)
he->he_pe_duration = DEFAULT_HE_PE_DURATION;
- he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th * 32);
+ he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
if (!he->he_rts_thres)
he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
@@ -947,6 +950,23 @@ mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
}
static void
+mt7915_mcu_bss_hw_amsdu_tlv(struct sk_buff *skb)
+{
+#define TXD_CMP_MAP1 GENMASK(15, 0)
+#define TXD_CMP_MAP2 (GENMASK(31, 0) & ~BIT(23))
+ struct bss_info_hw_amsdu *amsdu;
+ struct tlv *tlv;
+
+ tlv = mt7915_mcu_add_tlv(skb, BSS_INFO_HW_AMSDU, sizeof(*amsdu));
+
+ amsdu = (struct bss_info_hw_amsdu *)tlv;
+ amsdu->cmp_bitmap_0 = cpu_to_le32(TXD_CMP_MAP1);
+ amsdu->cmp_bitmap_1 = cpu_to_le32(TXD_CMP_MAP2);
+ amsdu->trig_thres = cpu_to_le16(2);
+ amsdu->enable = true;
+}
+
+static void
mt7915_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt7915_vif *mvif)
{
/* SIFS 20us + 512 byte beacon tranmitted by 1Mbps (3906us) */
@@ -1020,6 +1040,7 @@ int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
mt7915_mcu_bss_rfch_tlv(skb, vif, phy);
mt7915_mcu_bss_bmc_tlv(skb, phy);
mt7915_mcu_bss_ra_tlv(skb, vif, phy);
+ mt7915_mcu_bss_hw_amsdu_tlv(skb);
if (vif->bss_conf.he_support)
mt7915_mcu_bss_he_tlv(skb, vif, phy);
@@ -1178,6 +1199,9 @@ mt7915_mcu_sta_ba(struct mt7915_dev *dev,
struct sk_buff *skb;
int ret;
+ if (enable && tx && !params->amsdu)
+ msta->wcid.amsdu = false;
+
skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta,
MT7915_STA_UPDATE_MAX_SIZE);
if (IS_ERR(skb))
@@ -1407,7 +1431,7 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
he->max_nss_mcs[CMD_HE_MCS_BW160] =
he_cap->he_mcs_nss_supp.rx_mcs_160;
- /* fall through */
+ fallthrough;
default:
he->max_nss_mcs[CMD_HE_MCS_BW80] =
he_cap->he_mcs_nss_supp.rx_mcs_80;
@@ -1441,6 +1465,38 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
}
static void
+mt7915_mcu_sta_uapsd_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
+ struct ieee80211_vif *vif)
+{
+ struct sta_rec_uapsd *uapsd;
+ struct tlv *tlv;
+
+ if (vif->type != NL80211_IFTYPE_AP || !sta->wme)
+ return;
+
+ tlv = mt7915_mcu_add_tlv(skb, STA_REC_APPS, sizeof(*uapsd));
+ uapsd = (struct sta_rec_uapsd *)tlv;
+
+ if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) {
+ uapsd->dac_map |= BIT(3);
+ uapsd->tac_map |= BIT(3);
+ }
+ if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) {
+ uapsd->dac_map |= BIT(2);
+ uapsd->tac_map |= BIT(2);
+ }
+ if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) {
+ uapsd->dac_map |= BIT(1);
+ uapsd->tac_map |= BIT(1);
+ }
+ if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) {
+ uapsd->dac_map |= BIT(0);
+ uapsd->tac_map |= BIT(0);
+ }
+ uapsd->max_sp = sta->max_sp;
+}
+
+static void
mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
{
struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
@@ -1512,8 +1568,39 @@ mt7915_mcu_add_mu(struct mt7915_dev *dev, struct ieee80211_vif *vif,
}
static void
+mt7915_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+{
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ struct sta_rec_amsdu *amsdu;
+ struct tlv *tlv;
+
+ if (!sta->max_amsdu_len)
+ return;
+
+ tlv = mt7915_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));
+ amsdu = (struct sta_rec_amsdu *)tlv;
+ amsdu->max_amsdu_num = 8;
+ amsdu->amsdu_en = true;
+ amsdu->max_mpdu_size = sta->max_amsdu_len >=
+ IEEE80211_MAX_MPDU_LEN_VHT_7991;
+ msta->wcid.amsdu = true;
+}
+
+static bool
+mt7915_hw_amsdu_supported(struct ieee80211_vif *vif)
+{
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_STATION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void
mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
- struct ieee80211_sta *sta)
+ struct ieee80211_sta *sta, struct ieee80211_vif *vif)
{
struct tlv *tlv;
@@ -1524,6 +1611,9 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
tlv = mt7915_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
ht = (struct sta_rec_ht *)tlv;
ht->ht_cap = cpu_to_le16(sta->ht_cap.cap);
+
+ if (mt7915_hw_amsdu_supported(vif))
+ mt7915_mcu_sta_amsdu_tlv(skb, sta);
}
/* starec vht */
@@ -1540,6 +1630,9 @@ mt7915_mcu_sta_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
/* starec he */
if (sta->he_cap.has_he)
mt7915_mcu_sta_he_tlv(skb, sta);
+
+ /* starec uapsd */
+ mt7915_mcu_sta_uapsd_tlv(skb, sta, vif);
}
static void
@@ -2176,7 +2269,7 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
mt7915_mcu_sta_basic_tlv(skb, vif, sta, enable);
if (enable && sta)
- mt7915_mcu_sta_tlv(dev, skb, sta);
+ mt7915_mcu_sta_tlv(dev, skb, sta, vif);
sta_wtbl = mt7915_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
@@ -2335,14 +2428,6 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw,
struct bss_info_bcn *bcn;
int len = MT7915_BEACON_UPDATE_SIZE + MAX_BEACON_SIZE;
- rskb = mt7915_mcu_alloc_sta_req(dev, mvif, NULL, len);
- if (IS_ERR(rskb))
- return PTR_ERR(rskb);
-
- tlv = mt7915_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
- bcn = (struct bss_info_bcn *)tlv;
- bcn->enable = en;
-
skb = ieee80211_beacon_get_template(hw, vif, &offs);
if (!skb)
return -EINVAL;
@@ -2353,6 +2438,16 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw,
return -EINVAL;
}
+ rskb = mt7915_mcu_alloc_sta_req(dev, mvif, NULL, len);
+ if (IS_ERR(rskb)) {
+ dev_kfree_skb(skb);
+ return PTR_ERR(rskb);
+ }
+
+ tlv = mt7915_mcu_add_tlv(rskb, BSS_INFO_OFFLOAD, sizeof(*bcn));
+ bcn = (struct bss_info_bcn *)tlv;
+ bcn->enable = en;
+
if (mvif->band_idx) {
info = IEEE80211_SKB_CB(skb);
info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
@@ -2901,6 +2996,7 @@ int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif)
struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
struct edca *e = &req.edca[ac];
+ e->set = WMM_PARAM_SET;
e->queue = ac + mvif->wmm_idx * MT7915_MAX_WMM_SETS;
e->aifs = q->aifs;
e->txop = cpu_to_le16(q->txop);
@@ -3052,8 +3148,10 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd)
.channel_band = chandef->chan->band,
};
- if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
- chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
+ if (dev->mt76.hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
+ req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
+ else if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
+ chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
req.switch_reason = CH_SWITCH_DFS;
else
req.switch_reason = CH_SWITCH_NORMAL;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index cb35e718409a..c656d66385c4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -402,6 +402,16 @@ struct bss_info_ra {
__le32 fast_interval;
} __packed;
+struct bss_info_hw_amsdu {
+ __le16 tag;
+ __le16 len;
+ __le32 cmp_bitmap_0;
+ __le32 cmp_bitmap_1;
+ __le16 trig_thres;
+ u8 enable;
+ u8 rsv;
+} __packed;
+
struct bss_info_he {
__le16 tag;
__le16 len;
@@ -645,6 +655,17 @@ struct sta_rec_vht {
u8 rsv[3];
} __packed;
+struct sta_rec_uapsd {
+ __le16 tag;
+ __le16 len;
+ u8 dac_map;
+ u8 tac_map;
+ u8 max_sp;
+ u8 rsv0;
+ __le16 listen_interval;
+ u8 rsv1[2];
+} __packed;
+
struct sta_rec_muru {
__le16 tag;
__le16 len;
@@ -725,6 +746,15 @@ struct sta_rec_ba {
__le16 winsize;
} __packed;
+struct sta_rec_amsdu {
+ __le16 tag;
+ __le16 len;
+ u8 max_amsdu_num;
+ u8 max_mpdu_size;
+ u8 amsdu_en;
+ u8 rsv;
+} __packed;
+
struct sec_key {
u8 cipher_id;
u8 cipher_len;
@@ -951,6 +981,8 @@ enum {
sizeof(struct sta_rec_he) + \
sizeof(struct sta_rec_ba) + \
sizeof(struct sta_rec_vht) + \
+ sizeof(struct sta_rec_uapsd) + \
+ sizeof(struct sta_rec_amsdu) + \
sizeof(struct tlv) + \
MT7915_WTBL_UPDATE_MAX_SIZE)
@@ -962,6 +994,7 @@ enum {
sizeof(struct bss_info_basic) +\
sizeof(struct bss_info_rf_ch) +\
sizeof(struct bss_info_ra) + \
+ sizeof(struct bss_info_hw_amsdu) +\
sizeof(struct bss_info_he) + \
sizeof(struct bss_info_bmc_rate) +\
sizeof(struct bss_info_ext_bss) +\
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index d8a13b4a2359..4b8908fa7eda 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -62,13 +62,6 @@ enum mt7915_rxq_id {
MT7915_RXQ_MCU_WA,
};
-enum mt7915_ampdu_state {
- MT7915_AGGR_STOP,
- MT7915_AGGR_PROGRESS,
- MT7915_AGGR_START,
- MT7915_AGGR_OPERATIONAL
-};
-
struct mt7915_sta_stats {
struct rate_info prob_rate;
struct rate_info tx_rate;
@@ -83,14 +76,14 @@ struct mt7915_sta {
struct mt7915_vif *vif;
+ struct list_head stats_list;
struct list_head poll_list;
+ struct list_head rc_list;
u32 airtime_ac[8];
struct mt7915_sta_stats stats;
- struct work_struct stats_work;
- spinlock_t ampdu_lock;
- enum mt7915_ampdu_state ampdu_state[IEEE80211_NUM_TIDS];
+ unsigned long ampdu_state;
};
struct mt7915_vif {
@@ -100,7 +93,7 @@ struct mt7915_vif {
u8 wmm_idx;
struct mt7915_sta sta;
- struct mt7915_dev *dev;
+ struct mt7915_phy *phy;
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
};
@@ -135,9 +128,11 @@ struct mt7915_phy {
u32 ampdu_ref;
struct mib_stats mib;
+ struct list_head stats_list;
struct delayed_work mac_work;
u8 mac_work_count;
+ u8 sta_work_count;
};
struct mt7915_dev {
@@ -146,15 +141,18 @@ struct mt7915_dev {
struct mt76_phy mphy;
};
+ const struct mt76_bus_ops *bus_ops;
struct mt7915_phy phy;
u16 chainmask;
struct work_struct init_work;
+ struct work_struct rc_work;
struct work_struct reset_work;
wait_queue_head_t reset_wait;
u32 reset_state;
+ struct list_head sta_rc_list;
struct list_head sta_poll_list;
spinlock_t sta_poll_lock;
@@ -260,26 +258,8 @@ mt7915_ext_phy(struct mt7915_dev *dev)
static inline u8 mt7915_lmac_mapping(struct mt7915_dev *dev, u8 ac)
{
- static const u8 lmac_queue_map[] = {
- [IEEE80211_AC_BK] = MT_LMAC_AC00,
- [IEEE80211_AC_BE] = MT_LMAC_AC01,
- [IEEE80211_AC_VI] = MT_LMAC_AC02,
- [IEEE80211_AC_VO] = MT_LMAC_AC03,
- };
-
- if (WARN_ON_ONCE(ac >= ARRAY_SIZE(lmac_queue_map)))
- return MT_LMAC_AC01; /* BE */
-
- return lmac_queue_map[ac];
-}
-
-static inline void
-mt7915_set_aggr_state(struct mt7915_sta *msta, u8 tid,
- enum mt7915_ampdu_state state)
-{
- spin_lock_bh(&msta->ampdu_lock);
- msta->ampdu_state[tid] = state;
- spin_unlock_bh(&msta->ampdu_lock);
+ /* LMAC uses the reverse order of mac80211 AC indexes */
+ return 3 - ac;
}
extern const struct ieee80211_ops mt7915_ops;
@@ -448,7 +428,6 @@ mt7915_l2_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val)
bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask);
void mt7915_mac_reset_counters(struct mt7915_phy *phy);
void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy);
-void mt7915_mac_sta_poll(struct mt7915_dev *dev);
void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, bool beacon);
@@ -461,13 +440,12 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7915_mac_work(struct work_struct *work);
void mt7915_mac_reset_work(struct work_struct *work);
-void mt7915_mac_sta_stats_work(struct work_struct *work);
+void mt7915_mac_sta_rc_work(struct work_struct *work);
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,
struct mt76_tx_info *tx_info);
-void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
- struct mt76_queue_entry *e);
+void mt7915_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
index 0ec4e184b889..fe62b4d853e4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
@@ -29,9 +29,10 @@ mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
{
struct mt7915_dev *dev = dev_instance;
- u32 intr;
+ u32 intr, mask;
intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
+ intr &= dev->mt76.mmio.irqmask;
mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
@@ -39,27 +40,23 @@ static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
- intr &= dev->mt76.mmio.irqmask;
+ mask = intr & MT_INT_RX_DONE_ALL;
+ if (intr & MT_INT_TX_DONE_MCU)
+ mask |= MT_INT_TX_DONE_MCU;
- if (intr & MT_INT_TX_DONE_ALL) {
- mt7915_irq_disable(dev, MT_INT_TX_DONE_ALL);
+ mt7915_irq_disable(dev, mask);
+
+ if (intr & MT_INT_TX_DONE_MCU)
napi_schedule(&dev->mt76.tx_napi);
- }
- if (intr & MT_INT_RX_DONE_DATA) {
- mt7915_irq_disable(dev, MT_INT_RX_DONE_DATA);
+ if (intr & MT_INT_RX_DONE_DATA)
napi_schedule(&dev->mt76.napi[0]);
- }
- if (intr & MT_INT_RX_DONE_WM) {
- mt7915_irq_disable(dev, MT_INT_RX_DONE_WM);
+ if (intr & MT_INT_RX_DONE_WM)
napi_schedule(&dev->mt76.napi[1]);
- }
- if (intr & MT_INT_RX_DONE_WA) {
- mt7915_irq_disable(dev, MT_INT_RX_DONE_WA);
+ if (intr & MT_INT_RX_DONE_WA)
napi_schedule(&dev->mt76.napi[2]);
- }
if (intr & MT_INT_MCU_CMD) {
u32 val = mt76_rr(dev, MT_MCU_CMD);
@@ -103,7 +100,8 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
static const struct mt76_driver_ops drv_ops = {
/* txwi_size = txd size + txp size */
.txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp),
- .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ,
+ .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ |
+ MT_DRV_AMSDU_OFFLOAD,
.survey_flags = SURVEY_INFO_TIME_TX |
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_BSS_RX,
@@ -149,6 +147,8 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
(mt7915_l1_rr(dev, MT_HW_REV) & 0xff);
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+
/* master switch of PCIe tnterrupt enable */
mt7915_l1_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
index e0989141d9da..64327153b7fa 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h
@@ -313,9 +313,17 @@
#define MT_INT_RX_DONE_WA BIT(1)
#define MT_INT_RX_DONE(_n) ((_n) ? BIT((_n) - 1) : BIT(16))
#define MT_INT_RX_DONE_ALL (BIT(0) | BIT(1) | BIT(16))
-#define MT_INT_TX_DONE_ALL (BIT(15) | GENMASK(27, 26) | BIT(30))
+#define MT_INT_TX_DONE_MCU_WA BIT(15)
+#define MT_INT_TX_DONE_FWDL BIT(26)
+#define MT_INT_TX_DONE_MCU_WM BIT(27)
+#define MT_INT_TX_DONE_BAND0 BIT(30)
+#define MT_INT_TX_DONE_BAND1 BIT(31)
#define MT_INT_MCU_CMD BIT(29)
+#define MT_INT_TX_DONE_MCU (MT_INT_TX_DONE_MCU_WA | \
+ MT_INT_TX_DONE_MCU_WM | \
+ MT_INT_TX_DONE_FWDL)
+
#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44)
#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0)
@@ -352,6 +360,13 @@
#define MT_HIF_REMAP_L2_BASE GENMASK(31, 12)
#define MT_HIF_REMAP_BASE_L2 0x00000
+#define MT_SWDEF_BASE 0x41f200
+#define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs))
+#define MT_SWDEF_MODE MT_SWDEF(0x3c)
+#define MT_SWDEF_NORMAL_MODE 0
+#define MT_SWDEF_ICAP_MODE 1
+#define MT_SWDEF_SPECTRUM_MODE 2
+
#define MT_TOP_BASE 0x18060000
#define MT_TOP(ofs) (MT_TOP_BASE + (ofs))
diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c
index d2b38ed7f3b4..9a4d95a2a707 100644
--- a/drivers/net/wireless/mediatek/mt76/sdio.c
+++ b/drivers/net/wireless/mediatek/mt76/sdio.c
@@ -42,15 +42,13 @@ static int mt76s_alloc_tx(struct mt76_dev *dev)
int i;
for (i = 0; i < MT_TXQ_MCU_WA; i++) {
- INIT_LIST_HEAD(&dev->q_tx[i].swq);
-
q = devm_kzalloc(dev->dev, sizeof(*q), GFP_KERNEL);
if (!q)
return -ENOMEM;
spin_lock_init(&q->lock);
q->hw_idx = i;
- dev->q_tx[i].q = q;
+ dev->q_tx[i] = q;
q->entry = devm_kcalloc(dev->dev,
MT_NUM_TX_ENTRIES, sizeof(*q->entry),
@@ -68,6 +66,10 @@ void mt76s_stop_txrx(struct mt76_dev *dev)
{
struct mt76_sdio *sdio = &dev->sdio;
+ cancel_work_sync(&sdio->tx.xmit_work);
+ cancel_work_sync(&sdio->tx.status_work);
+ cancel_work_sync(&sdio->rx.recv_work);
+ cancel_work_sync(&sdio->rx.net_work);
cancel_work_sync(&sdio->stat_work);
clear_bit(MT76_READING_STATS, &dev->phy.state);
@@ -94,8 +96,8 @@ mt76s_get_next_rx_entry(struct mt76_queue *q)
spin_lock_bh(&q->lock);
if (q->queued > 0) {
- e = &q->entry[q->head];
- q->head = (q->head + 1) % q->ndesc;
+ e = &q->entry[q->tail];
+ q->tail = (q->tail + 1) % q->ndesc;
q->queued--;
}
spin_unlock_bh(&q->lock);
@@ -129,38 +131,26 @@ mt76s_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
return nframes;
}
-static int mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
+static void mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
{
- struct mt76_sw_queue *sq = &dev->q_tx[qid];
- u32 n_dequeued = 0, n_sw_dequeued = 0;
+ struct mt76_queue *q = dev->q_tx[qid];
struct mt76_queue_entry entry;
- struct mt76_queue *q = sq->q;
bool wake;
- while (q->queued > n_dequeued) {
- if (!q->entry[q->head].done)
+ while (q->queued > 0) {
+ if (!q->entry[q->tail].done)
break;
- if (q->entry[q->head].schedule) {
- q->entry[q->head].schedule = false;
- n_sw_dequeued++;
- }
-
- entry = q->entry[q->head];
- q->entry[q->head].done = false;
- q->head = (q->head + 1) % q->ndesc;
- n_dequeued++;
+ entry = q->entry[q->tail];
+ q->entry[q->tail].done = false;
- if (qid == MT_TXQ_MCU)
+ if (qid == MT_TXQ_MCU) {
dev_kfree_skb(entry.skb);
- else
- dev->drv->tx_complete_skb(dev, qid, &entry);
- }
-
- spin_lock_bh(&q->lock);
+ entry.skb = NULL;
+ }
- sq->swq_queued -= n_sw_dequeued;
- q->queued -= n_dequeued;
+ mt76_queue_tx_complete(dev, q, &entry);
+ }
wake = q->stopped && q->queued < q->ndesc - 8;
if (wake)
@@ -169,19 +159,13 @@ static int mt76s_process_tx_queue(struct mt76_dev *dev, enum mt76_txq_id qid)
if (!q->queued)
wake_up(&dev->tx_wait);
- spin_unlock_bh(&q->lock);
-
if (qid == MT_TXQ_MCU)
- goto out;
+ return;
mt76_txq_schedule(&dev->phy, qid);
if (wake)
ieee80211_wake_queue(dev->hw, qid);
-
- wake_up_process(dev->sdio.tx_kthread);
-out:
- return n_dequeued;
}
static void mt76s_tx_status_data(struct work_struct *work)
@@ -214,12 +198,12 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta)
{
- struct mt76_queue *q = dev->q_tx[qid].q;
+ struct mt76_queue *q = dev->q_tx[qid];
struct mt76_tx_info tx_info = {
.skb = skb,
};
int err, len = skb->len;
- u16 idx = q->tail;
+ u16 idx = q->head;
if (q->queued == q->ndesc)
return -ENOSPC;
@@ -229,9 +213,9 @@ mt76s_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
if (err < 0)
return err;
- q->entry[q->tail].skb = tx_info.skb;
- q->entry[q->tail].buf_sz = len;
- q->tail = (q->tail + 1) % q->ndesc;
+ q->entry[q->head].skb = tx_info.skb;
+ q->entry[q->head].buf_sz = len;
+ q->head = (q->head + 1) % q->ndesc;
q->queued++;
return idx;
@@ -241,25 +225,31 @@ static int
mt76s_tx_queue_skb_raw(struct mt76_dev *dev, enum mt76_txq_id qid,
struct sk_buff *skb, u32 tx_info)
{
- struct mt76_queue *q = dev->q_tx[qid].q;
- int ret = -ENOSPC, len = skb->len;
+ struct mt76_queue *q = dev->q_tx[qid];
+ int ret = -ENOSPC, len = skb->len, pad;
- spin_lock_bh(&q->lock);
if (q->queued == q->ndesc)
- goto out;
+ goto error;
- ret = mt76_skb_adjust_pad(skb);
+ pad = round_up(skb->len, 4) - skb->len;
+ ret = mt76_skb_adjust_pad(skb, pad);
if (ret)
- goto out;
+ goto error;
- q->entry[q->tail].buf_sz = len;
- q->entry[q->tail].skb = skb;
- q->tail = (q->tail + 1) % q->ndesc;
+ spin_lock_bh(&q->lock);
+
+ q->entry[q->head].buf_sz = len;
+ q->entry[q->head].skb = skb;
+ q->head = (q->head + 1) % q->ndesc;
q->queued++;
-out:
spin_unlock_bh(&q->lock);
+ return 0;
+
+error:
+ dev_kfree_skb(skb);
+
return ret;
}
@@ -267,7 +257,7 @@ static void mt76s_tx_kick(struct mt76_dev *dev, struct mt76_queue *q)
{
struct mt76_sdio *sdio = &dev->sdio;
- wake_up_process(sdio->tx_kthread);
+ queue_work(sdio->txrx_wq, &sdio->tx.xmit_work);
}
static const struct mt76_queue_ops sdio_queue_ops = {
@@ -276,41 +266,37 @@ static const struct mt76_queue_ops sdio_queue_ops = {
.tx_queue_skb_raw = mt76s_tx_queue_skb_raw,
};
-static int mt76s_kthread_run(void *data)
+static void mt76s_tx_work(struct work_struct *work)
{
- struct mt76_dev *dev = data;
- struct mt76_phy *mphy = &dev->phy;
-
- while (!kthread_should_stop()) {
- int i, nframes = 0;
-
- cond_resched();
-
- /* rx processing */
- local_bh_disable();
- rcu_read_lock();
+ struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
+ tx.status_work);
+ struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
+ int i;
- mt76_for_each_q_rx(dev, i)
- nframes += mt76s_process_rx_queue(dev, &dev->q_rx[i]);
+ for (i = 0; i < MT_TXQ_MCU_WA; i++)
+ mt76s_process_tx_queue(dev, i);
- rcu_read_unlock();
- local_bh_enable();
+ if (dev->drv->tx_status_data &&
+ !test_and_set_bit(MT76_READING_STATS, &dev->phy.state))
+ queue_work(dev->wq, &dev->sdio.stat_work);
+}
- /* tx processing */
- for (i = 0; i < MT_TXQ_MCU_WA; i++)
- nframes += mt76s_process_tx_queue(dev, i);
+static void mt76s_rx_work(struct work_struct *work)
+{
+ struct mt76_sdio *sdio = container_of(work, struct mt76_sdio,
+ rx.net_work);
+ struct mt76_dev *dev = container_of(sdio, struct mt76_dev, sdio);
+ int i;
- if (dev->drv->tx_status_data &&
- !test_and_set_bit(MT76_READING_STATS, &mphy->state))
- queue_work(dev->wq, &dev->sdio.stat_work);
+ /* rx processing */
+ local_bh_disable();
+ rcu_read_lock();
- if (!nframes || !test_bit(MT76_STATE_RUNNING, &mphy->state)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- }
- }
+ mt76_for_each_q_rx(dev, i)
+ mt76s_process_rx_queue(dev, &dev->q_rx[i]);
- return 0;
+ rcu_read_unlock();
+ local_bh_enable();
}
void mt76s_deinit(struct mt76_dev *dev)
@@ -318,9 +304,11 @@ void mt76s_deinit(struct mt76_dev *dev)
struct mt76_sdio *sdio = &dev->sdio;
int i;
- kthread_stop(sdio->kthread);
- kthread_stop(sdio->tx_kthread);
mt76s_stop_txrx(dev);
+ if (sdio->txrx_wq) {
+ destroy_workqueue(sdio->txrx_wq);
+ sdio->txrx_wq = NULL;
+ }
sdio_claim_host(sdio->func);
sdio_release_irq(sdio->func);
@@ -348,11 +336,15 @@ int mt76s_init(struct mt76_dev *dev, struct sdio_func *func,
{
struct mt76_sdio *sdio = &dev->sdio;
- sdio->kthread = kthread_create(mt76s_kthread_run, dev, "mt76s");
- if (IS_ERR(sdio->kthread))
- return PTR_ERR(sdio->kthread);
+ sdio->txrx_wq = alloc_workqueue("mt76s_txrx_wq",
+ WQ_UNBOUND | WQ_HIGHPRI,
+ WQ_UNBOUND_MAX_ACTIVE);
+ if (!sdio->txrx_wq)
+ return -ENOMEM;
INIT_WORK(&sdio->stat_work, mt76s_tx_status_data);
+ INIT_WORK(&sdio->tx.status_work, mt76s_tx_work);
+ INIT_WORK(&sdio->rx.net_work, mt76s_rx_work);
mutex_init(&sdio->sched.lock);
dev->queue_ops = &sdio_queue_ops;
diff --git a/drivers/net/wireless/mediatek/mt76/testmode.c b/drivers/net/wireless/mediatek/mt76/testmode.c
index 75bb02cdfdae..883f59c7a7e4 100644
--- a/drivers/net/wireless/mediatek/mt76/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/testmode.c
@@ -29,11 +29,12 @@ void mt76_testmode_tx_pending(struct mt76_dev *dev)
return;
qid = skb_get_queue_mapping(skb);
- q = dev->q_tx[qid].q;
+ q = dev->q_tx[qid];
spin_lock_bh(&q->lock);
- while (td->tx_pending > 0 && q->queued < q->ndesc / 2) {
+ while (td->tx_pending > 0 && td->tx_queued - td->tx_done < 1000 &&
+ q->queued < q->ndesc / 2) {
int ret;
ret = dev->queue_ops->tx_queue_skb(dev, qid, skb_get(skb), wcid, NULL);
@@ -160,7 +161,7 @@ mt76_testmode_tx_start(struct mt76_dev *dev)
td->tx_queued = 0;
td->tx_done = 0;
td->tx_pending = td->tx_count;
- tasklet_schedule(&dev->tx_tasklet);
+ mt76_worker_schedule(&dev->tx_worker);
}
static void
@@ -168,11 +169,11 @@ mt76_testmode_tx_stop(struct mt76_dev *dev)
{
struct mt76_testmode_data *td = &dev->test;
- tasklet_disable(&dev->tx_tasklet);
+ mt76_worker_disable(&dev->tx_worker);
td->tx_pending = 0;
- tasklet_enable(&dev->tx_tasklet);
+ mt76_worker_enable(&dev->tx_worker);
wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued, 10 * HZ);
@@ -442,9 +443,13 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
mutex_lock(&dev->mutex);
if (tb[MT76_TM_ATTR_STATS]) {
+ err = -EINVAL;
+
a = nla_nest_start(msg, MT76_TM_ATTR_STATS);
- err = mt76_testmode_dump_stats(dev, msg);
- nla_nest_end(msg, a);
+ if (a) {
+ err = mt76_testmode_dump_stats(dev, msg);
+ nla_nest_end(msg, a);
+ }
goto out;
}
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 3afd89ecd6c9..44ef4bc7a46e 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -5,75 +5,6 @@
#include "mt76.h"
-static struct mt76_txwi_cache *
-mt76_alloc_txwi(struct mt76_dev *dev)
-{
- struct mt76_txwi_cache *t;
- dma_addr_t addr;
- u8 *txwi;
- int size;
-
- size = L1_CACHE_ALIGN(dev->drv->txwi_size + sizeof(*t));
- txwi = devm_kzalloc(dev->dev, size, GFP_ATOMIC);
- if (!txwi)
- return NULL;
-
- addr = dma_map_single(dev->dev, txwi, dev->drv->txwi_size,
- DMA_TO_DEVICE);
- t = (struct mt76_txwi_cache *)(txwi + dev->drv->txwi_size);
- t->dma_addr = addr;
-
- return t;
-}
-
-static struct mt76_txwi_cache *
-__mt76_get_txwi(struct mt76_dev *dev)
-{
- struct mt76_txwi_cache *t = NULL;
-
- spin_lock_bh(&dev->lock);
- if (!list_empty(&dev->txwi_cache)) {
- t = list_first_entry(&dev->txwi_cache, struct mt76_txwi_cache,
- list);
- list_del(&t->list);
- }
- spin_unlock_bh(&dev->lock);
-
- return t;
-}
-
-struct mt76_txwi_cache *
-mt76_get_txwi(struct mt76_dev *dev)
-{
- struct mt76_txwi_cache *t = __mt76_get_txwi(dev);
-
- if (t)
- return t;
-
- return mt76_alloc_txwi(dev);
-}
-
-void
-mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t)
-{
- if (!t)
- return;
-
- spin_lock_bh(&dev->lock);
- list_add(&t->list, &dev->txwi_cache);
- spin_unlock_bh(&dev->lock);
-}
-EXPORT_SYMBOL_GPL(mt76_put_txwi);
-
-void mt76_tx_free(struct mt76_dev *dev)
-{
- struct mt76_txwi_cache *t;
-
- while ((t = __mt76_get_txwi(dev)) != NULL)
- dma_unmap_single(dev->dev, t->dma_addr, dev->drv->txwi_size,
- DMA_TO_DEVICE);
-}
-
static int
mt76_txq_get_qid(struct ieee80211_txq *txq)
{
@@ -83,17 +14,27 @@ mt76_txq_get_qid(struct ieee80211_txq *txq)
return txq->ac;
}
-static void
-mt76_check_agg_ssn(struct mt76_txq *mtxq, struct sk_buff *skb)
+void
+mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_txq *txq;
+ struct mt76_txq *mtxq;
+ u8 tid;
- if (!ieee80211_is_data_qos(hdr->frame_control) ||
+ if (!sta || !ieee80211_is_data_qos(hdr->frame_control) ||
!ieee80211_is_data_present(hdr->frame_control))
return;
+ tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+ txq = sta->txq[tid];
+ mtxq = (struct mt76_txq *)txq->drv_priv;
+ if (!mtxq->aggr)
+ return;
+
mtxq->agg_ssn = le16_to_cpu(hdr->seq_ctrl) + 0x10;
}
+EXPORT_SYMBOL_GPL(mt76_tx_check_agg_ssn);
void
mt76_tx_status_lock(struct mt76_dev *dev, struct sk_buff_head *list)
@@ -231,7 +172,32 @@ mt76_tx_status_check(struct mt76_dev *dev, struct mt76_wcid *wcid, bool flush)
}
EXPORT_SYMBOL_GPL(mt76_tx_status_check);
-void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb)
+static void
+mt76_tx_check_non_aql(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct mt76_wcid *wcid;
+ int pending;
+
+ if (info->tx_time_est)
+ return;
+
+ if (wcid_idx >= ARRAY_SIZE(dev->wcid))
+ return;
+
+ rcu_read_lock();
+
+ wcid = rcu_dereference(dev->wcid[wcid_idx]);
+ if (wcid) {
+ pending = atomic_dec_return(&wcid->non_aql_packets);
+ if (pending < 0)
+ atomic_cmpxchg(&wcid->non_aql_packets, pending, 0);
+ }
+
+ rcu_read_unlock();
+}
+
+void mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb)
{
struct ieee80211_hw *hw;
struct sk_buff_head list;
@@ -244,6 +210,8 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb)
}
#endif
+ mt76_tx_check_non_aql(dev, wcid_idx, skb);
+
if (!skb->prev) {
hw = mt76_tx_status_get_hw(dev, skb);
ieee80211_free_txskb(hw, skb);
@@ -256,6 +224,32 @@ void mt76_tx_complete_skb(struct mt76_dev *dev, struct sk_buff *skb)
}
EXPORT_SYMBOL_GPL(mt76_tx_complete_skb);
+static int
+__mt76_tx_queue_skb(struct mt76_dev *dev, int qid, struct sk_buff *skb,
+ struct mt76_wcid *wcid, struct ieee80211_sta *sta,
+ bool *stop)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct mt76_queue *q;
+ bool non_aql;
+ int pending;
+ int idx;
+
+ non_aql = !info->tx_time_est;
+ idx = dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid, sta);
+ if (idx < 0 || !sta || !non_aql)
+ return idx;
+
+ wcid = (struct mt76_wcid *)sta->drv_priv;
+ q = dev->q_tx[qid];
+ q->entry[idx].wcid = wcid->idx;
+ pending = atomic_inc_return(&wcid->non_aql_packets);
+ if (stop && pending >= MT_MAX_NON_AQL_PKT)
+ *stop = true;
+
+ return idx;
+}
+
void
mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
struct mt76_wcid *wcid, struct sk_buff *skb)
@@ -288,26 +282,13 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
ieee80211_get_tx_rates(info->control.vif, sta, skb,
info->control.rates, 1);
- if (sta && ieee80211_is_data_qos(hdr->frame_control)) {
- struct ieee80211_txq *txq;
- struct mt76_txq *mtxq;
- u8 tid;
-
- tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
- txq = sta->txq[tid];
- mtxq = (struct mt76_txq *)txq->drv_priv;
-
- if (mtxq->aggr)
- mt76_check_agg_ssn(mtxq, skb);
- }
-
if (ext_phy)
info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
- q = dev->q_tx[qid].q;
+ q = dev->q_tx[qid];
spin_lock_bh(&q->lock);
- dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid, sta);
+ __mt76_tx_queue_skb(dev, qid, skb, wcid, sta, NULL);
dev->queue_ops->kick(dev, q);
if (q->queued > q->ndesc - 8 && !q->stopped) {
@@ -320,23 +301,13 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
EXPORT_SYMBOL_GPL(mt76_tx);
static struct sk_buff *
-mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq, bool ps)
+mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq)
{
struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
struct ieee80211_tx_info *info;
bool ext_phy = phy != &phy->dev->phy;
struct sk_buff *skb;
- skb = skb_dequeue(&mtxq->retry_q);
- if (skb) {
- u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
-
- if (ps && skb_queue_empty(&mtxq->retry_q))
- ieee80211_sta_set_buffered(txq->sta, tid, false);
-
- return skb;
- }
-
skb = ieee80211_tx_dequeue(phy->hw, txq);
if (!skb)
return NULL;
@@ -361,7 +332,7 @@ mt76_queue_ps_skb(struct mt76_dev *dev, struct ieee80211_sta *sta,
IEEE80211_TX_CTL_REQ_TX_STATUS;
mt76_skb_set_moredata(skb, !last);
- dev->queue_ops->tx_queue_skb(dev, MT_TXQ_PSD, skb, wcid, sta);
+ __mt76_tx_queue_skb(dev, MT_TXQ_PSD, skb, wcid, sta, NULL);
}
void
@@ -373,7 +344,7 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
struct mt76_phy *phy = hw->priv;
struct mt76_dev *dev = phy->dev;
struct sk_buff *last_skb = NULL;
- struct mt76_queue *hwq = dev->q_tx[MT_TXQ_PSD].q;
+ struct mt76_queue *hwq = dev->q_tx[MT_TXQ_PSD];
int i;
spin_lock_bh(&hwq->lock);
@@ -386,13 +357,10 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
continue;
do {
- skb = mt76_txq_dequeue(phy, mtxq, true);
+ skb = mt76_txq_dequeue(phy, mtxq);
if (!skb)
break;
- if (mtxq->aggr)
- mt76_check_agg_ssn(mtxq, skb);
-
nframes--;
if (last_skb)
mt76_queue_ps_skb(dev, sta, last_skb, false);
@@ -413,26 +381,26 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
EXPORT_SYMBOL_GPL(mt76_release_buffered_frames);
static int
-mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_sw_queue *sq,
+mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q,
struct mt76_txq *mtxq)
{
struct mt76_dev *dev = phy->dev;
struct ieee80211_txq *txq = mtxq_to_txq(mtxq);
enum mt76_txq_id qid = mt76_txq_get_qid(txq);
struct mt76_wcid *wcid = mtxq->wcid;
- struct mt76_queue *hwq = sq->q;
struct ieee80211_tx_info *info;
struct sk_buff *skb;
- int n_frames = 1, limit;
- struct ieee80211_tx_rate tx_rate;
- bool ampdu;
- bool probe;
+ int n_frames = 1;
+ bool stop = false;
int idx;
if (test_bit(MT_WCID_FLAG_PS, &wcid->flags))
return 0;
- skb = mt76_txq_dequeue(phy, mtxq, false);
+ if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT)
+ return 0;
+
+ skb = mt76_txq_dequeue(phy, mtxq);
if (!skb)
return 0;
@@ -440,62 +408,39 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_sw_queue *sq,
if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
info->control.rates, 1);
- tx_rate = info->control.rates[0];
-
- probe = (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
- ampdu = IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_AMPDU;
- limit = ampdu ? 16 : 3;
-
- if (ampdu)
- mt76_check_agg_ssn(mtxq, skb);
-
- idx = dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid, txq->sta);
+ idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop);
if (idx < 0)
return idx;
do {
- bool cur_ampdu;
+ if (test_bit(MT76_STATE_PM, &phy->state) ||
+ test_bit(MT76_RESET, &phy->state))
+ return -EBUSY;
- if (probe)
+ if (stop)
break;
- if (test_bit(MT76_RESET, &phy->state))
- return -EBUSY;
+ if (q->queued + MT_TXQ_FREE_THR >= q->ndesc)
+ break;
- skb = mt76_txq_dequeue(phy, mtxq, false);
+ skb = mt76_txq_dequeue(phy, mtxq);
if (!skb)
break;
info = IEEE80211_SKB_CB(skb);
- cur_ampdu = info->flags & IEEE80211_TX_CTL_AMPDU;
-
- if (ampdu != cur_ampdu ||
- (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) {
- skb_queue_tail(&mtxq->retry_q, skb);
- break;
- }
+ if (!(wcid->tx_info & MT_WCID_TX_INFO_SET))
+ ieee80211_get_tx_rates(txq->vif, txq->sta, skb,
+ info->control.rates, 1);
- info->control.rates[0] = tx_rate;
-
- if (cur_ampdu)
- mt76_check_agg_ssn(mtxq, skb);
-
- idx = dev->queue_ops->tx_queue_skb(dev, qid, skb, wcid,
- txq->sta);
+ idx = __mt76_tx_queue_skb(dev, qid, skb, wcid, txq->sta, &stop);
if (idx < 0)
- return idx;
+ break;
n_frames++;
- } while (n_frames < limit);
-
- if (!probe) {
- hwq->entry[idx].qid = sq - dev->q_tx;
- hwq->entry[idx].schedule = true;
- sq->swq_queued++;
- }
+ } while (1);
- dev->queue_ops->kick(dev, hwq);
+ dev->queue_ops->kick(dev, q);
return n_frames;
}
@@ -504,23 +449,23 @@ static int
mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
{
struct mt76_dev *dev = phy->dev;
- struct mt76_sw_queue *sq = &dev->q_tx[qid];
- struct mt76_queue *hwq = sq->q;
+ struct mt76_queue *q = dev->q_tx[qid];
struct ieee80211_txq *txq;
struct mt76_txq *mtxq;
struct mt76_wcid *wcid;
int ret = 0;
- spin_lock_bh(&hwq->lock);
+ spin_lock_bh(&q->lock);
while (1) {
- if (sq->swq_queued >= 4)
- break;
-
- if (test_bit(MT76_RESET, &phy->state)) {
+ if (test_bit(MT76_STATE_PM, &phy->state) ||
+ test_bit(MT76_RESET, &phy->state)) {
ret = -EBUSY;
break;
}
+ if (q->queued + MT_TXQ_FREE_THR >= q->ndesc)
+ break;
+
txq = ieee80211_next_txq(phy->hw, qid);
if (!txq)
break;
@@ -538,32 +483,26 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid)
u8 tid = txq->tid;
mtxq->send_bar = false;
- spin_unlock_bh(&hwq->lock);
+ spin_unlock_bh(&q->lock);
ieee80211_send_bar(vif, sta->addr, tid, agg_ssn);
- spin_lock_bh(&hwq->lock);
+ spin_lock_bh(&q->lock);
}
- ret += mt76_txq_send_burst(phy, sq, mtxq);
- ieee80211_return_txq(phy->hw, txq,
- !skb_queue_empty(&mtxq->retry_q));
+ ret += mt76_txq_send_burst(phy, q, mtxq);
+ ieee80211_return_txq(phy->hw, txq, false);
}
- spin_unlock_bh(&hwq->lock);
+ spin_unlock_bh(&q->lock);
return ret;
}
void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid)
{
- struct mt76_dev *dev = phy->dev;
- struct mt76_sw_queue *sq = &dev->q_tx[qid];
int len;
if (qid >= 4)
return;
- if (sq->swq_queued >= 4)
- return;
-
rcu_read_lock();
do {
@@ -585,9 +524,9 @@ void mt76_txq_schedule_all(struct mt76_phy *phy)
}
EXPORT_SYMBOL_GPL(mt76_txq_schedule_all);
-void mt76_tx_tasklet(unsigned long data)
+void mt76_tx_worker(struct mt76_worker *w)
{
- struct mt76_dev *dev = (struct mt76_dev *)data;
+ struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
mt76_txq_schedule_all(&dev->phy);
if (dev->phy2)
@@ -612,8 +551,8 @@ void mt76_stop_tx_queues(struct mt76_dev *dev, struct ieee80211_sta *sta,
if (!txq)
continue;
+ hwq = dev->q_tx[mt76_txq_get_qid(txq)];
mtxq = (struct mt76_txq *)txq->drv_priv;
- hwq = mtxq->swq->q;
spin_lock_bh(&hwq->lock);
mtxq->send_bar = mtxq->aggr && send_bar;
@@ -630,38 +569,10 @@ void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
if (!test_bit(MT76_STATE_RUNNING, &phy->state))
return;
- tasklet_schedule(&dev->tx_tasklet);
+ mt76_worker_schedule(&dev->tx_worker);
}
EXPORT_SYMBOL_GPL(mt76_wake_tx_queue);
-void mt76_txq_remove(struct mt76_dev *dev, struct ieee80211_txq *txq)
-{
- struct ieee80211_hw *hw;
- struct mt76_txq *mtxq;
- struct sk_buff *skb;
-
- if (!txq)
- return;
-
- mtxq = (struct mt76_txq *)txq->drv_priv;
-
- while ((skb = skb_dequeue(&mtxq->retry_q)) != NULL) {
- hw = mt76_tx_status_get_hw(dev, skb);
- ieee80211_free_txskb(hw, skb);
- }
-}
-EXPORT_SYMBOL_GPL(mt76_txq_remove);
-
-void mt76_txq_init(struct mt76_dev *dev, struct ieee80211_txq *txq)
-{
- struct mt76_txq *mtxq = (struct mt76_txq *)txq->drv_priv;
-
- skb_queue_head_init(&mtxq->retry_q);
-
- mtxq->swq = &dev->q_tx[mt76_txq_get_qid(txq)];
-}
-EXPORT_SYMBOL_GPL(mt76_txq_init);
-
u8 mt76_ac_to_hwq(u8 ac)
{
static const u8 wmm_queue_map[] = {
@@ -678,13 +589,9 @@ u8 mt76_ac_to_hwq(u8 ac)
}
EXPORT_SYMBOL_GPL(mt76_ac_to_hwq);
-int mt76_skb_adjust_pad(struct sk_buff *skb)
+int mt76_skb_adjust_pad(struct sk_buff *skb, int pad)
{
struct sk_buff *iter, *last = skb;
- u32 pad;
-
- /* Add zero pad of 4 - 7 bytes */
- pad = round_up(skb->len, 4) + 4 - skb->len;
/* First packet of a A-MSDU burst keeps track of the whole burst
* length, need to update length of it and the last packet.
@@ -706,3 +613,16 @@ int mt76_skb_adjust_pad(struct sk_buff *skb)
return 0;
}
EXPORT_SYMBOL_GPL(mt76_skb_adjust_pad);
+
+void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q,
+ struct mt76_queue_entry *e)
+{
+ if (e->skb)
+ dev->drv->tx_complete_skb(dev, e);
+
+ spin_lock_bh(&q->lock);
+ q->tail = (q->tail + 1) % q->ndesc;
+ q->queued--;
+ spin_unlock_bh(&q->lock);
+}
+EXPORT_SYMBOL_GPL(mt76_queue_tx_complete);
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index dcab5993763a..7d3f0a2e5fa0 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -497,8 +497,8 @@ mt76u_get_next_rx_entry(struct mt76_queue *q)
spin_lock_irqsave(&q->lock, flags);
if (q->queued > 0) {
- urb = q->entry[q->head].urb;
- q->head = (q->head + 1) % q->ndesc;
+ urb = q->entry[q->tail].urb;
+ q->tail = (q->tail + 1) % q->ndesc;
q->queued--;
}
spin_unlock_irqrestore(&q->lock, flags);
@@ -616,16 +616,16 @@ static void mt76u_complete_rx(struct urb *urb)
default:
dev_err_ratelimited(dev->dev, "rx urb failed: %d\n",
urb->status);
- /* fall through */
+ fallthrough;
case 0:
break;
}
spin_lock_irqsave(&q->lock, flags);
- if (WARN_ONCE(q->entry[q->tail].urb != urb, "rx urb mismatch"))
+ if (WARN_ONCE(q->entry[q->head].urb != urb, "rx urb mismatch"))
goto out;
- q->tail = (q->tail + 1) % q->ndesc;
+ q->head = (q->head + 1) % q->ndesc;
q->queued++;
tasklet_schedule(&dev->usb.rx_tasklet);
out:
@@ -792,43 +792,27 @@ int mt76u_resume_rx(struct mt76_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76u_resume_rx);
-static void mt76u_tx_tasklet(unsigned long data)
+static void mt76u_tx_worker(struct mt76_worker *w)
{
- struct mt76_dev *dev = (struct mt76_dev *)data;
+ struct mt76_dev *dev = container_of(w, struct mt76_dev, tx_worker);
struct mt76_queue_entry entry;
- struct mt76_sw_queue *sq;
struct mt76_queue *q;
bool wake;
int i;
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- u32 n_dequeued = 0, n_sw_dequeued = 0;
-
- sq = &dev->q_tx[i];
- q = sq->q;
+ q = dev->q_tx[i];
- while (q->queued > n_dequeued) {
- if (!q->entry[q->head].done)
+ while (q->queued > 0) {
+ if (!q->entry[q->tail].done)
break;
- if (q->entry[q->head].schedule) {
- q->entry[q->head].schedule = false;
- n_sw_dequeued++;
- }
-
- entry = q->entry[q->head];
- q->entry[q->head].done = false;
- q->head = (q->head + 1) % q->ndesc;
- n_dequeued++;
+ entry = q->entry[q->tail];
+ q->entry[q->tail].done = false;
- dev->drv->tx_complete_skb(dev, i, &entry);
+ mt76_queue_tx_complete(dev, q, &entry);
}
- spin_lock_bh(&q->lock);
-
- sq->swq_queued -= n_sw_dequeued;
- q->queued -= n_dequeued;
-
wake = q->stopped && q->queued < q->ndesc - 8;
if (wake)
q->stopped = false;
@@ -836,8 +820,6 @@ static void mt76u_tx_tasklet(unsigned long data)
if (!q->queued)
wake_up(&dev->tx_wait);
- spin_unlock_bh(&q->lock);
-
mt76_txq_schedule(&dev->phy, i);
if (dev->drv->tx_status_data &&
@@ -882,7 +864,7 @@ static void mt76u_complete_tx(struct urb *urb)
dev_err(dev->dev, "tx urb failed: %d\n", urb->status);
e->done = true;
- tasklet_schedule(&dev->tx_tasklet);
+ mt76_worker_schedule(&dev->tx_worker);
}
static int
@@ -909,11 +891,11 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta)
{
- struct mt76_queue *q = dev->q_tx[qid].q;
+ struct mt76_queue *q = dev->q_tx[qid];
struct mt76_tx_info tx_info = {
.skb = skb,
};
- u16 idx = q->tail;
+ u16 idx = q->head;
int err;
if (q->queued == q->ndesc)
@@ -932,7 +914,7 @@ mt76u_tx_queue_skb(struct mt76_dev *dev, enum mt76_txq_id qid,
q->entry[idx].urb, mt76u_complete_tx,
&q->entry[idx]);
- q->tail = (q->tail + 1) % q->ndesc;
+ q->head = (q->head + 1) % q->ndesc;
q->entry[idx].skb = tx_info.skb;
q->queued++;
@@ -944,7 +926,7 @@ static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q)
struct urb *urb;
int err;
- while (q->first != q->tail) {
+ while (q->first != q->head) {
urb = q->entry[q->first].urb;
trace_submit_urb(dev, urb);
@@ -987,10 +969,8 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
int i, j, err;
for (i = 0; i <= MT_TXQ_PSD; i++) {
- INIT_LIST_HEAD(&dev->q_tx[i].swq);
-
if (i >= IEEE80211_NUM_ACS) {
- dev->q_tx[i].q = dev->q_tx[0].q;
+ dev->q_tx[i] = dev->q_tx[0];
continue;
}
@@ -1000,7 +980,7 @@ static int mt76u_alloc_tx(struct mt76_dev *dev)
spin_lock_init(&q->lock);
q->hw_idx = mt76u_ac_to_hwq(dev, i);
- dev->q_tx[i].q = q;
+ dev->q_tx[i] = q;
q->entry = devm_kcalloc(dev->dev,
MT_NUM_TX_ENTRIES, sizeof(*q->entry),
@@ -1027,7 +1007,7 @@ static void mt76u_free_tx(struct mt76_dev *dev)
struct mt76_queue *q;
int j;
- q = dev->q_tx[i].q;
+ q = dev->q_tx[i];
if (!q)
continue;
@@ -1040,6 +1020,8 @@ void mt76u_stop_tx(struct mt76_dev *dev)
{
int ret;
+ mt76_worker_disable(&dev->tx_worker);
+
ret = wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(&dev->phy),
HZ / 5);
if (!ret) {
@@ -1050,7 +1032,7 @@ void mt76u_stop_tx(struct mt76_dev *dev)
dev_err(dev->dev, "timed out waiting for pending tx\n");
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- q = dev->q_tx[i].q;
+ q = dev->q_tx[i];
if (!q)
continue;
@@ -1058,32 +1040,26 @@ void mt76u_stop_tx(struct mt76_dev *dev)
usb_kill_urb(q->entry[j].urb);
}
- tasklet_kill(&dev->tx_tasklet);
-
/* On device removal we maight queue skb's, but mt76u_tx_kick()
* will fail to submit urb, cleanup those skb's manually.
*/
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- q = dev->q_tx[i].q;
+ q = dev->q_tx[i];
if (!q)
continue;
- /* Assure we are in sync with killed tasklet. */
- spin_lock_bh(&q->lock);
- while (q->queued) {
- entry = q->entry[q->head];
- q->head = (q->head + 1) % q->ndesc;
- q->queued--;
+ entry = q->entry[q->tail];
+ q->entry[q->tail].done = false;
- dev->drv->tx_complete_skb(dev, i, &entry);
- }
- spin_unlock_bh(&q->lock);
+ mt76_queue_tx_complete(dev, q, &entry);
}
}
cancel_work_sync(&dev->usb.stat_work);
clear_bit(MT76_READING_STATS, &dev->phy.state);
+ mt76_worker_enable(&dev->tx_worker);
+
mt76_tx_status_check(dev, NULL, true);
}
EXPORT_SYMBOL_GPL(mt76u_stop_tx);
@@ -1133,8 +1109,8 @@ int mt76u_init(struct mt76_dev *dev,
mt76u_ops.rmw = ext ? mt76u_rmw_ext : mt76u_rmw;
mt76u_ops.write_copy = ext ? mt76u_copy_ext : mt76u_copy;
+ dev->tx_worker.fn = mt76u_tx_worker;
tasklet_init(&usb->rx_tasklet, mt76u_rx_tasklet, (unsigned long)dev);
- tasklet_init(&dev->tx_tasklet, mt76u_tx_tasklet, (unsigned long)dev);
INIT_WORK(&usb->stat_work, mt76u_tx_status_data);
usb->data_len = usb_maxpacket(udev, usb_sndctrlpipe(udev, 0), 1);
diff --git a/drivers/net/wireless/mediatek/mt76/util.c b/drivers/net/wireless/mediatek/mt76/util.c
index f53bb4ae5001..581964425468 100644
--- a/drivers/net/wireless/mediatek/mt76/util.c
+++ b/drivers/net/wireless/mediatek/mt76/util.c
@@ -110,4 +110,32 @@ int mt76_get_min_avg_rssi(struct mt76_dev *dev, bool ext_phy)
}
EXPORT_SYMBOL_GPL(mt76_get_min_avg_rssi);
+int __mt76_worker_fn(void *ptr)
+{
+ struct mt76_worker *w = ptr;
+
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (kthread_should_park()) {
+ kthread_parkme();
+ continue;
+ }
+
+ if (!test_and_clear_bit(MT76_WORKER_SCHEDULED, &w->state)) {
+ schedule();
+ continue;
+ }
+
+ set_bit(MT76_WORKER_RUNNING, &w->state);
+ set_current_state(TASK_RUNNING);
+ w->fn(w);
+ cond_resched();
+ clear_bit(MT76_WORKER_RUNNING, &w->state);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__mt76_worker_fn);
+
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/util.h b/drivers/net/wireless/mediatek/mt76/util.h
index fd1a68820e0a..1c363ea9ab9c 100644
--- a/drivers/net/wireless/mediatek/mt76/util.h
+++ b/drivers/net/wireless/mediatek/mt76/util.h
@@ -10,6 +10,19 @@
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <linux/bitfield.h>
+#include <net/mac80211.h>
+
+struct mt76_worker
+{
+ struct task_struct *task;
+ void (*fn)(struct mt76_worker *);
+ unsigned long state;
+};
+
+enum {
+ MT76_WORKER_SCHEDULED,
+ MT76_WORKER_RUNNING,
+};
#define MT76_INCR(_var, _size) \
(_var = (((_var) + 1) % (_size)))
@@ -45,4 +58,67 @@ mt76_skb_set_moredata(struct sk_buff *skb, bool enable)
hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA);
}
+int __mt76_worker_fn(void *ptr);
+
+static inline int
+mt76_worker_setup(struct ieee80211_hw *hw, struct mt76_worker *w,
+ void (*fn)(struct mt76_worker *),
+ const char *name)
+{
+ const char *dev_name = wiphy_name(hw->wiphy);
+ int ret;
+
+ if (fn)
+ w->fn = fn;
+ w->task = kthread_create(__mt76_worker_fn, w, "mt76-%s %s",
+ name, dev_name);
+
+ ret = PTR_ERR_OR_ZERO(w->task);
+ if (ret) {
+ w->task = NULL;
+ return ret;
+ }
+
+ wake_up_process(w->task);
+
+ return 0;
+}
+
+static inline void mt76_worker_schedule(struct mt76_worker *w)
+{
+ if (!w->task)
+ return;
+
+ if (!test_and_set_bit(MT76_WORKER_SCHEDULED, &w->state) &&
+ !test_bit(MT76_WORKER_RUNNING, &w->state))
+ wake_up_process(w->task);
+}
+
+static inline void mt76_worker_disable(struct mt76_worker *w)
+{
+ if (!w->task)
+ return;
+
+ kthread_park(w->task);
+ WRITE_ONCE(w->state, 0);
+}
+
+static inline void mt76_worker_enable(struct mt76_worker *w)
+{
+ if (!w->task)
+ return;
+
+ kthread_unpark(w->task);
+ mt76_worker_schedule(w);
+}
+
+static inline void mt76_worker_teardown(struct mt76_worker *w)
+{
+ if (!w->task)
+ return;
+
+ kthread_stop(w->task);
+ w->task = NULL;
+}
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt7601u/debugfs.c b/drivers/net/wireless/mediatek/mt7601u/debugfs.c
index 300242bce799..20669eacb66e 100644
--- a/drivers/net/wireless/mediatek/mt7601u/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt7601u/debugfs.c
@@ -30,7 +30,7 @@ mt76_reg_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mt76_reg_get, mt76_reg_set, "0x%08llx\n");
static int
-mt7601u_ampdu_stat_read(struct seq_file *file, void *data)
+mt7601u_ampdu_stat_show(struct seq_file *file, void *data)
{
struct mt7601u_dev *dev = file->private;
int i, j;
@@ -73,21 +73,10 @@ mt7601u_ampdu_stat_read(struct seq_file *file, void *data)
return 0;
}
-static int
-mt7601u_ampdu_stat_open(struct inode *inode, struct file *f)
-{
- return single_open(f, mt7601u_ampdu_stat_read, inode->i_private);
-}
-
-static const struct file_operations fops_ampdu_stat = {
- .open = mt7601u_ampdu_stat_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mt7601u_ampdu_stat);
static int
-mt7601u_eeprom_param_read(struct seq_file *file, void *data)
+mt7601u_eeprom_param_show(struct seq_file *file, void *data)
{
struct mt7601u_dev *dev = file->private;
struct mt7601u_rate_power *rp = &dev->ee->power_rate_table;
@@ -131,18 +120,7 @@ mt7601u_eeprom_param_read(struct seq_file *file, void *data)
return 0;
}
-static int
-mt7601u_eeprom_param_open(struct inode *inode, struct file *f)
-{
- return single_open(f, mt7601u_eeprom_param_read, inode->i_private);
-}
-
-static const struct file_operations fops_eeprom_param = {
- .open = mt7601u_eeprom_param_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mt7601u_eeprom_param);
void mt7601u_init_debugfs(struct mt7601u_dev *dev)
{
@@ -157,6 +135,6 @@ void mt7601u_init_debugfs(struct mt7601u_dev *dev)
debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg);
debugfs_create_file("regval", 0600, dir, dev, &fops_regval);
- debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat);
- debugfs_create_file("eeprom_param", 0400, dir, dev, &fops_eeprom_param);
+ debugfs_create_file("ampdu_stat", 0400, dir, dev, &mt7601u_ampdu_stat_fops);
+ debugfs_create_file("eeprom_param", 0400, dir, dev, &mt7601u_eeprom_param_fops);
}
diff --git a/drivers/net/wireless/microchip/wilc1000/mon.c b/drivers/net/wireless/microchip/wilc1000/mon.c
index 358ac8601333..b5a1b65c087c 100644
--- a/drivers/net/wireless/microchip/wilc1000/mon.c
+++ b/drivers/net/wireless/microchip/wilc1000/mon.c
@@ -235,11 +235,10 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl,
if (register_netdevice(wl->monitor_dev)) {
netdev_err(real_dev, "register_netdevice failed\n");
+ free_netdev(wl->monitor_dev);
return NULL;
}
priv = netdev_priv(wl->monitor_dev);
- if (!priv)
- return NULL;
priv->real_ndev = real_dev;
diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c
index 6aafff9d4231..a36d5ec297ab 100644
--- a/drivers/net/wireless/quantenna/qtnfmac/core.c
+++ b/drivers/net/wireless/quantenna/qtnfmac/core.c
@@ -15,7 +15,6 @@
#include "util.h"
#include "switchdev.h"
-#define QTNF_DMP_MAX_LEN 48
#define QTNF_PRIMARY_VIF_IDX 0
static bool slave_radar = true;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
index 4c8d71fbdd7a..63f9ea21962f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
@@ -774,22 +774,22 @@ static bool _rtl88ee_llt_table_init(struct ieee80211_hw *hw)
for (i = 0; i < (txpktbuf_bndy - 1); i++) {
status = _rtl88ee_llt_write(hw, i, i + 1);
- if (true != status)
+ if (!status)
return status;
}
status = _rtl88ee_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
- if (true != status)
+ if (!status)
return status;
for (i = txpktbuf_bndy; i < maxpage; i++) {
status = _rtl88ee_llt_write(hw, i, (i + 1));
- if (true != status)
+ if (!status)
return status;
}
status = _rtl88ee_llt_write(hw, maxpage, txpktbuf_bndy);
- if (true != status)
+ if (!status)
return status;
return true;
@@ -868,7 +868,7 @@ static bool _rtl88ee_init_mac(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, MSR, 0x00);
if (!rtlhal->mac_func_enable) {
- if (_rtl88ee_llt_table_init(hw) == false) {
+ if (!_rtl88ee_llt_table_init(hw)) {
rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
"LLT table init fail\n");
return false;
@@ -1067,7 +1067,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
}
rtstatus = _rtl88ee_init_mac(hw);
- if (rtstatus != true) {
+ if (!rtstatus) {
pr_info("Init MAC failed\n");
err = 1;
goto exit;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
index 63ec5a20b67b..9be032e8ec95 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
@@ -16,7 +16,12 @@ static u32 _rtl88e_phy_rf_serial_read(struct ieee80211_hw *hw,
static void _rtl88e_phy_rf_serial_write(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 offset,
u32 data);
-static u32 _rtl88e_phy_calculate_bit_shift(u32 bitmask);
+static u32 _rtl88e_phy_calculate_bit_shift(u32 bitmask)
+{
+ u32 i = ffs(bitmask);
+
+ return i ? i - 1 : 32;
+}
static bool _rtl88e_phy_bb8188e_config_parafile(struct ieee80211_hw *hw);
static bool _rtl88e_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
static bool phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
@@ -208,17 +213,6 @@ static void _rtl88e_phy_rf_serial_write(struct ieee80211_hw *hw,
rfpath, pphyreg->rf3wire_offset, data_and_addr);
}
-static u32 _rtl88e_phy_calculate_bit_shift(u32 bitmask)
-{
- u32 i;
-
- for (i = 0; i <= 31; i++) {
- if (((bitmask >> i) & 0x1) == 1)
- break;
- }
- return i;
-}
-
bool rtl88e_phy_mac_config(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1581,7 +1575,7 @@ static void _rtl88e_phy_path_adda_on(struct ieee80211_hw *hw,
u32 i;
pathon = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
- if (false == is2t) {
+ if (!is2t) {
pathon = 0x0bdb25a0;
rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
} else {
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c
index 8f7689225393..b9775eec4c54 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/trx.c
@@ -732,7 +732,7 @@ void rtl88ee_set_desc(struct ieee80211_hw *hw, u8 *pdesc8,
{
__le32 *pdesc = (__le32 *)pdesc8;
- if (istx == true) {
+ if (istx) {
switch (desc_name) {
case HW_DESC_OWN:
set_tx_desc_own(pdesc, 1);
@@ -773,7 +773,7 @@ u64 rtl88ee_get_desc(struct ieee80211_hw *hw,
u32 ret = 0;
__le32 *pdesc = (__le32 *)pdesc8;
- if (istx == true) {
+ if (istx) {
switch (desc_name) {
case HW_DESC_OWN:
ret = get_tx_desc_own(pdesc);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c
index fc6c81291cf5..3d29c8dbb255 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c
@@ -145,13 +145,9 @@ EXPORT_SYMBOL(_rtl92c_phy_rf_serial_write);
u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask)
{
- u32 i;
+ u32 i = ffs(bitmask);
- for (i = 0; i <= 31; i++) {
- if (((bitmask >> i) & 0x1) == 1)
- break;
- }
- return i;
+ return i ? i - 1 : 32;
}
EXPORT_SYMBOL(_rtl92c_phy_calculate_bit_shift);
@@ -1103,7 +1099,7 @@ static void _rtl92c_phy_path_adda_on(struct ieee80211_hw *hw,
u32 i;
pathon = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
- if (false == is2t) {
+ if (!is2t) {
pathon = 0x0bdb25a0;
rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
} else {
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c
index d4cd186036fd..bb5a0c4aec93 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c
@@ -613,22 +613,22 @@ static bool _rtl92ce_llt_table_init(struct ieee80211_hw *hw)
for (i = 0; i < (txpktbuf_bndy - 1); i++) {
status = _rtl92ce_llt_write(hw, i, i + 1);
- if (true != status)
+ if (!status)
return status;
}
status = _rtl92ce_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
- if (true != status)
+ if (!status)
return status;
for (i = txpktbuf_bndy; i < maxpage; i++) {
status = _rtl92ce_llt_write(hw, i, (i + 1));
- if (true != status)
+ if (!status)
return status;
}
status = _rtl92ce_llt_write(hw, maxpage, txpktbuf_bndy);
- if (true != status)
+ if (!status)
return status;
return true;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c
index 3061bd81f39e..6312fddd9c00 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c
@@ -828,7 +828,7 @@ static int _rtl92cu_init_mac(struct ieee80211_hw *hw)
? WMM_CHIP_B_TX_PAGE_BOUNDARY
: WMM_CHIP_A_TX_PAGE_BOUNDARY;
}
- if (false == rtl92c_init_llt_table(hw, boundary)) {
+ if (!rtl92c_init_llt_table(hw, boundary)) {
pr_err("Failed to init LLT Table!\n");
return -EINVAL;
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c
index d7afb6a186df..2890a495a23e 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/mac.c
@@ -158,14 +158,14 @@ bool rtl92c_init_llt_table(struct ieee80211_hw *hw, u32 boundary)
for (i = 0; i < (boundary - 1); i++) {
rst = rtl92c_llt_write(hw, i , i + 1);
- if (true != rst) {
+ if (!rst) {
pr_err("===> %s #1 fail\n", __func__);
return rst;
}
}
/* end of list */
rst = rtl92c_llt_write(hw, (boundary - 1), 0xFF);
- if (true != rst) {
+ if (!rst) {
pr_err("===> %s #2 fail\n", __func__);
return rst;
}
@@ -176,14 +176,14 @@ bool rtl92c_init_llt_table(struct ieee80211_hw *hw, u32 boundary)
*/
for (i = boundary; i < LLT_LAST_ENTRY_OF_TX_PKT_BUFFER; i++) {
rst = rtl92c_llt_write(hw, i, (i + 1));
- if (true != rst) {
+ if (!rst) {
pr_err("===> %s #3 fail\n", __func__);
return rst;
}
}
/* Let last entry point to the start entry of ring buffer */
rst = rtl92c_llt_write(hw, LLT_LAST_ENTRY_OF_TX_PKT_BUFFER, boundary);
- if (true != rst) {
+ if (!rst) {
pr_err("===> %s #4 fail\n", __func__);
return rst;
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c
index 2deadc7339ce..f849291cc587 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/hw.c
@@ -563,13 +563,13 @@ static bool _rtl92de_llt_table_init(struct ieee80211_hw *hw)
/* 18. LLT_table_init(Adapter); */
for (i = 0; i < (txpktbuf_bndy - 1); i++) {
status = _rtl92de_llt_write(hw, i, i + 1);
- if (true != status)
+ if (!status)
return status;
}
/* end of list */
status = _rtl92de_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
- if (true != status)
+ if (!status)
return status;
/* Make the other pages as ring buffer */
@@ -578,13 +578,13 @@ static bool _rtl92de_llt_table_init(struct ieee80211_hw *hw)
/* Otherwise used as local loopback buffer. */
for (i = txpktbuf_bndy; i < maxpage; i++) {
status = _rtl92de_llt_write(hw, i, (i + 1));
- if (true != status)
+ if (!status)
return status;
}
/* Let last entry point to the start entry of ring buffer */
status = _rtl92de_llt_write(hw, maxpage, txpktbuf_bndy);
- if (true != status)
+ if (!status)
return status;
return true;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
index 87804325928a..e34d33e73e52 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/phy.c
@@ -162,14 +162,9 @@ static u32 targetchnl_2g[TARGET_CHNL_NUM_2G] = {
static u32 _rtl92d_phy_calculate_bit_shift(u32 bitmask)
{
- u32 i;
-
- for (i = 0; i <= 31; i++) {
- if (((bitmask >> i) & 0x1) == 1)
- break;
- }
+ u32 i = ffs(bitmask);
- return i;
+ return i ? i - 1 : 32;
}
u32 rtl92d_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c
index 140f33089c4d..997ff115b9ab 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c
@@ -718,11 +718,11 @@ static void rtl92ee_dm_dynamic_atc_switch(struct ieee80211_hw *hw)
(rtldm->cfo_ave_pre - cfo_ave) :
(cfo_ave - rtldm->cfo_ave_pre);
- if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0) {
- rtldm->large_cfo_hit = 1;
+ if (cfo_ave_diff > 20 && !rtldm->large_cfo_hit) {
+ rtldm->large_cfo_hit = true;
return;
}
- rtldm->large_cfo_hit = 0;
+ rtldm->large_cfo_hit = false;
rtldm->cfo_ave_pre = cfo_ave;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
index 473296e808ba..88fa2e593fef 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c
@@ -794,7 +794,7 @@ static bool _rtl92ee_init_mac(struct ieee80211_hw *hw)
rtl_write_word(rtlpriv, REG_CR, 0x2ff);
if (!rtlhal->mac_func_enable) {
- if (_rtl92ee_llt_table_init(hw) == false) {
+ if (!_rtl92ee_llt_table_init(hw)) {
rtl_dbg(rtlpriv, COMP_INIT, DBG_LOUD,
"LLT table init fail\n");
return false;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c
index f107a30a96f0..cc0bcaf13e96 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/phy.c
@@ -203,13 +203,9 @@ static void _rtl92ee_phy_rf_serial_write(struct ieee80211_hw *hw,
static u32 _rtl92ee_phy_calculate_bit_shift(u32 bitmask)
{
- u32 i;
+ u32 i = ffs(bitmask);
- for (i = 0; i <= 31; i++) {
- if (((bitmask >> i) & 0x1) == 1)
- break;
- }
- return i;
+ return i ? i - 1 : 32;
}
bool rtl92ee_phy_mac_config(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c
index 3d482b8675e2..63283d9e7485 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/phy.c
@@ -16,14 +16,9 @@
static u32 _rtl92s_phy_calculate_bit_shift(u32 bitmask)
{
- u32 i;
-
- for (i = 0; i <= 31; i++) {
- if (((bitmask >> i) & 0x1) == 1)
- break;
- }
+ u32 i = ffs(bitmask);
- return i;
+ return i ? i - 1 : 32;
}
u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c
index 5ba645bc46dc..fa0eed434d4f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/phy.c
@@ -188,7 +188,7 @@ static bool _rtl8723e_phy_bb8192c_config_parafile(struct ieee80211_hw *hw)
rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE, "\n");
rtstatus = _rtl8723e_phy_config_bb_with_headerfile(hw,
BASEBAND_CONFIG_PHY_REG);
- if (rtstatus != true) {
+ if (!rtstatus) {
pr_err("Write BB Reg Fail!!\n");
return false;
}
@@ -202,13 +202,13 @@ static bool _rtl8723e_phy_bb8192c_config_parafile(struct ieee80211_hw *hw)
rtstatus = _rtl8723e_phy_config_bb_with_pgheaderfile(hw,
BASEBAND_CONFIG_PHY_REG);
}
- if (rtstatus != true) {
+ if (!rtstatus) {
pr_err("BB_PG Reg Fail!!\n");
return false;
}
rtstatus =
_rtl8723e_phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_AGC_TAB);
- if (rtstatus != true) {
+ if (!rtstatus) {
pr_err("AGC Table Fail\n");
return false;
}
@@ -622,7 +622,7 @@ void rtl8723e_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
u8 cckpowerlevel[2], ofdmpowerlevel[2];
- if (rtlefuse->txpwr_fromeprom == false)
+ if (!rtlefuse->txpwr_fromeprom)
return;
_rtl8723e_get_txpower_index(hw, channel,
&cckpowerlevel[0], &ofdmpowerlevel[0]);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/rf.c
index ecec8c9f0992..b8ed80c84266 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/rf.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/rf.c
@@ -49,7 +49,7 @@ void rtl8723e_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
if (rtlefuse->eeprom_regulatory != 0)
turbo_scanoff = true;
- if (mac->act_scanning == true) {
+ if (mac->act_scanning) {
tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
@@ -479,7 +479,7 @@ static bool _rtl8723e_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
break;
}
- if (rtstatus != true) {
+ if (!rtstatus) {
rtl_dbg(rtlpriv, COMP_INIT, DBG_TRACE,
"Radio[%d] Fail!!\n", rfpath);
return false;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c
index 159f86e665f9..e3ee91b7ea8d 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c
@@ -589,7 +589,7 @@ void rtl8723e_set_desc(struct ieee80211_hw *hw, u8 *pdesc8,
{
__le32 *pdesc = (__le32 *)pdesc8;
- if (istx == true) {
+ if (istx) {
switch (desc_name) {
case HW_DESC_OWN:
set_tx_desc_own(pdesc, 1);
@@ -630,7 +630,7 @@ u64 rtl8723e_get_desc(struct ieee80211_hw *hw,
u32 ret = 0;
__le32 *pdesc = (__le32 *)pdesc8;
- if (istx == true) {
+ if (istx) {
switch (desc_name) {
case HW_DESC_OWN:
ret = get_tx_desc_own(pdesc);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c
index fbcff23eb058..c3c990cc032f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c
@@ -1152,11 +1152,11 @@ static void rtl8723be_dm_dynamic_atc_switch(struct ieee80211_hw *hw)
(rtldm->cfo_ave_pre - cfo_ave) :
(cfo_ave - rtldm->cfo_ave_pre);
- if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0) {
- rtldm->large_cfo_hit = 1;
+ if (cfo_ave_diff > 20 && !rtldm->large_cfo_hit) {
+ rtldm->large_cfo_hit = true;
return;
} else
- rtldm->large_cfo_hit = 0;
+ rtldm->large_cfo_hit = false;
rtldm->cfo_ave_pre = cfo_ave;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c
index 3c7ba8214daf..0748aedce2ad 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c
@@ -858,7 +858,7 @@ static bool _rtl8723be_init_mac(struct ieee80211_hw *hw)
rtl_write_word(rtlpriv, REG_CR, 0x2ff);
if (!rtlhal->mac_func_enable) {
- if (_rtl8723be_llt_table_init(hw) == false)
+ if (!_rtl8723be_llt_table_init(hw))
return false;
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c
index 097f21f6d35b..47b6c1aa36b0 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/phy_common.c
@@ -53,13 +53,9 @@ EXPORT_SYMBOL_GPL(rtl8723_phy_set_bb_reg);
u32 rtl8723_phy_calculate_bit_shift(u32 bitmask)
{
- u32 i;
+ u32 i = ffs(bitmask);
- for (i = 0; i <= 31; i++) {
- if (((bitmask >> i) & 0x1) == 1)
- break;
- }
- return i;
+ return i ? i - 1 : 32;
}
EXPORT_SYMBOL_GPL(rtl8723_phy_calculate_bit_shift);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
index 93893825e6d6..f6bff0ebd6b0 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c
@@ -2677,13 +2677,13 @@ static void rtl8821ae_dm_dynamic_atc_switch(struct ieee80211_hw *hw)
(rtldm->cfo_ave_pre - cfo_ave) :
(cfo_ave - rtldm->cfo_ave_pre);
- if (cfo_ave_diff > 20 && rtldm->large_cfo_hit == 0) {
+ if (cfo_ave_diff > 20 && !rtldm->large_cfo_hit) {
rtl_dbg(rtlpriv, COMP_DIG, DBG_LOUD,
"first large CFO hit\n");
- rtldm->large_cfo_hit = 1;
+ rtldm->large_cfo_hit = true;
return;
} else
- rtldm->large_cfo_hit = 0;
+ rtldm->large_cfo_hit = false;
rtldm->cfo_ave_pre = cfo_ave;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
index b2e5b9fda669..33ffc24d3675 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
@@ -1894,7 +1894,7 @@ int rtl8821ae_hw_init(struct ieee80211_hw *hw)
}
rtstatus = _rtl8821ae_init_mac(hw);
- if (rtstatus != true) {
+ if (!rtstatus) {
pr_err("Init MAC failed\n");
err = 1;
return err;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c
index 7832fae3d00f..f41a7643b9c4 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c
@@ -27,7 +27,12 @@ static u32 _rtl8821ae_phy_rf_serial_read(struct ieee80211_hw *hw,
static void _rtl8821ae_phy_rf_serial_write(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 offset,
u32 data);
-static u32 _rtl8821ae_phy_calculate_bit_shift(u32 bitmask);
+static u32 _rtl8821ae_phy_calculate_bit_shift(u32 bitmask)
+{
+ u32 i = ffs(bitmask);
+
+ return i ? i - 1 : 32;
+}
static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw);
/*static bool _rtl8812ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);*/
static bool _rtl8821ae_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
@@ -272,17 +277,6 @@ static void _rtl8821ae_phy_rf_serial_write(struct ieee80211_hw *hw,
rfpath, pphyreg->rf3wire_offset, data_and_addr);
}
-static u32 _rtl8821ae_phy_calculate_bit_shift(u32 bitmask)
-{
- u32 i;
-
- for (i = 0; i <= 31; i++) {
- if (((bitmask >> i) & 0x1) == 1)
- break;
- }
- return i;
-}
-
bool rtl8821ae_phy_mac_config(struct ieee80211_hw *hw)
{
bool rtstatus = 0;
@@ -1813,7 +1807,7 @@ static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw)
rtstatus = _rtl8821ae_phy_config_bb_with_headerfile(hw,
BASEBAND_CONFIG_PHY_REG);
- if (rtstatus != true) {
+ if (!rtstatus) {
pr_err("Write BB Reg Fail!!\n");
return false;
}
@@ -1822,7 +1816,7 @@ static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw)
rtstatus = _rtl8821ae_phy_config_bb_with_pgheaderfile(hw,
BASEBAND_CONFIG_PHY_REG);
}
- if (rtstatus != true) {
+ if (!rtstatus) {
pr_err("BB_PG Reg Fail!!\n");
return false;
}
@@ -1836,7 +1830,7 @@ static bool _rtl8821ae_phy_bb8821a_config_parafile(struct ieee80211_hw *hw)
rtstatus = _rtl8821ae_phy_config_bb_with_headerfile(hw,
BASEBAND_CONFIG_AGC_TAB);
- if (rtstatus != true) {
+ if (!rtstatus) {
pr_err("AGC Table Fail\n");
return false;
}
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index 9770982b2f14..cc82c80f0433 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -1472,6 +1472,9 @@ int rtw_core_init(struct rtw_dev *rtwdev)
ret = rtw_load_firmware(rtwdev, RTW_WOWLAN_FW);
if (ret) {
rtw_warn(rtwdev, "no wow firmware loaded\n");
+ wait_for_completion(&rtwdev->fw.completion);
+ if (rtwdev->fw.firmware)
+ release_firmware(rtwdev->fw.firmware);
return ret;
}
}
@@ -1486,6 +1489,8 @@ void rtw_core_deinit(struct rtw_dev *rtwdev)
struct rtw_rsvd_page *rsvd_pkt, *tmp;
unsigned long flags;
+ rtw_wait_firmware_completion(rtwdev);
+
if (fw->firmware)
release_firmware(fw->firmware);
diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
index ed1c14af082b..dd216a23fc99 100644
--- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c
+++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c
@@ -154,25 +154,16 @@ static void rtw8822c_rf_minmax_cmp(struct rtw_dev *rtwdev, u32 value,
}
}
-static void swap_u32(u32 *v1, u32 *v2)
-{
- u32 tmp;
-
- tmp = *v1;
- *v1 = *v2;
- *v2 = tmp;
-}
-
static void __rtw8822c_dac_iq_sort(struct rtw_dev *rtwdev, u32 *v1, u32 *v2)
{
if (*v1 >= 0x200 && *v2 >= 0x200) {
if (*v1 > *v2)
- swap_u32(v1, v2);
+ swap(*v1, *v2);
} else if (*v1 < 0x200 && *v2 < 0x200) {
if (*v1 > *v2)
- swap_u32(v1, v2);
+ swap(*v1, *v2);
} else if (*v1 < 0x200 && *v2 >= 0x200) {
- swap_u32(v1, v2);
+ swap(*v1, *v2);
}
}
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index 48adb1876ab9..cce8d75d8b81 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -122,13 +122,6 @@ static void chip_op_handler(struct wl1271 *wl, unsigned long value,
pm_runtime_put_autosuspend(wl->dev);
}
-
-static inline void no_write_handler(struct wl1271 *wl,
- unsigned long value,
- unsigned long param)
-{
-}
-
#define WL12XX_CONF_DEBUGFS(param, conf_sub_struct, \
min_val, max_val, write_handler_locked, \
write_handler_arg) \
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index d2bbd5108f7e..6863fd552d5e 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -30,7 +30,6 @@
#include "sysfs.h"
#define WL1271_BOOT_RETRIES 3
-#define WL1271_SUSPEND_SLEEP 100
#define WL1271_WAKEUP_TIMEOUT 500
static char *fwlog_param;
diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c
index 41641fc2be74..718c4ee865ba 100644
--- a/drivers/net/wireless/zydas/zd1201.c
+++ b/drivers/net/wireless/zydas/zd1201.c
@@ -1652,15 +1652,11 @@ static int zd1201_set_maxassoc(struct net_device *dev,
struct iw_request_info *info, struct iw_param *rrq, char *extra)
{
struct zd1201 *zd = netdev_priv(dev);
- int err;
if (!zd->ap)
return -EOPNOTSUPP;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value);
- if (err)
- return err;
- return 0;
+ return zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value);
}
static int zd1201_get_maxassoc(struct net_device *dev,
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 7c3ae52f2b15..dac54041ad8d 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -1164,17 +1164,12 @@ void ssb_pci_exit(struct ssb_bus *bus)
int ssb_pci_init(struct ssb_bus *bus)
{
struct pci_dev *pdev;
- int err;
if (bus->bustype != SSB_BUSTYPE_PCI)
return 0;
pdev = bus->host_pci;
mutex_init(&bus->sprom_mutex);
- err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
- if (err)
- goto out;
-out:
- return err;
+ return device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
}