diff options
Diffstat (limited to 'drivers/net')
139 files changed, 4175 insertions, 3422 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, ®ister_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, ®isters_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, |