diff options
Diffstat (limited to 'drivers/net/wireless/ath')
99 files changed, 3601 insertions, 1111 deletions
diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 815f8f599f..5a55db349c 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1594,6 +1594,20 @@ static int ar5523_probe(struct usb_interface *intf, struct ar5523 *ar; int error = -ENOMEM; + static const u8 bulk_ep_addr[] = { + AR5523_CMD_TX_PIPE | USB_DIR_OUT, + AR5523_DATA_TX_PIPE | USB_DIR_OUT, + AR5523_CMD_RX_PIPE | USB_DIR_IN, + AR5523_DATA_RX_PIPE | USB_DIR_IN, + 0}; + + if (!usb_check_bulk_endpoints(intf, bulk_ep_addr)) { + dev_err(&dev->dev, + "Could not find all expected endpoints\n"); + error = -ENODEV; + goto out; + } + /* * Load firmware if the device requires it. This will return * -ENXIO on success and we'll get called back afer the usb diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index f02a308a9f..34654f710d 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -171,8 +171,10 @@ struct ath_common { unsigned int clockrate; spinlock_t cc_lock; - struct ath_cycle_counters cc_ani; - struct ath_cycle_counters cc_survey; + struct_group(cc, + struct ath_cycle_counters cc_ani; + struct ath_cycle_counters cc_survey; + ); struct ath_regulatory regulatory; struct ath_regulatory reg_world_copy; diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig index e6ea884caf..4f385f4a8c 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig @@ -45,6 +45,7 @@ config ATH10K_SNOC depends on ATH10K depends on ARCH_QCOM || COMPILE_TEST depends on QCOM_SMEM + depends on QCOM_RPROC_COMMON || QCOM_RPROC_COMMON=n select QCOM_SCM select QCOM_QMI_HELPERS help diff --git a/drivers/net/wireless/ath/ath10k/ahb.c b/drivers/net/wireless/ath/ath10k/ahb.c index a378bc48b1..f0441b3d7d 100644 --- a/drivers/net/wireless/ath/ath10k/ahb.c +++ b/drivers/net/wireless/ath/ath10k/ahb.c @@ -394,14 +394,14 @@ static irqreturn_t ath10k_ahb_interrupt_handler(int irq, void *arg) if (!ath10k_pci_irq_pending(ar)) return IRQ_NONE; - ath10k_pci_disable_and_clear_legacy_irq(ar); + ath10k_pci_disable_and_clear_intx_irq(ar); ath10k_pci_irq_msi_fw_mask(ar); napi_schedule(&ar->napi); return IRQ_HANDLED; } -static int ath10k_ahb_request_irq_legacy(struct ath10k *ar) +static int ath10k_ahb_request_irq_intx(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); @@ -415,12 +415,12 @@ static int ath10k_ahb_request_irq_legacy(struct ath10k *ar) ar_ahb->irq, ret); return ret; } - ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY; + ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_INTX; return 0; } -static void ath10k_ahb_release_irq_legacy(struct ath10k *ar) +static void ath10k_ahb_release_irq_intx(struct ath10k *ar) { struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); @@ -430,7 +430,7 @@ static void ath10k_ahb_release_irq_legacy(struct ath10k *ar) static void ath10k_ahb_irq_disable(struct ath10k *ar) { ath10k_ce_disable_interrupts(ar); - ath10k_pci_disable_and_clear_legacy_irq(ar); + ath10k_pci_disable_and_clear_intx_irq(ar); } static int ath10k_ahb_resource_init(struct ath10k *ar) @@ -621,7 +621,7 @@ static int ath10k_ahb_hif_start(struct ath10k *ar) ath10k_core_napi_enable(ar); ath10k_ce_enable_interrupts(ar); - ath10k_pci_enable_legacy_irq(ar); + ath10k_pci_enable_intx_irq(ar); ath10k_pci_rx_post(ar); @@ -775,7 +775,7 @@ static int ath10k_ahb_probe(struct platform_device *pdev) ath10k_pci_init_napi(ar); - ret = ath10k_ahb_request_irq_legacy(ar); + ret = ath10k_ahb_request_irq_intx(ar); if (ret) goto err_free_pipes; @@ -806,7 +806,7 @@ err_halt_device: ath10k_ahb_clock_disable(ar); err_free_irq: - ath10k_ahb_release_irq_legacy(ar); + ath10k_ahb_release_irq_intx(ar); err_free_pipes: ath10k_pci_release_resource(ar); @@ -828,7 +828,7 @@ static void ath10k_ahb_remove(struct platform_device *pdev) ath10k_core_unregister(ar); ath10k_ahb_irq_disable(ar); - ath10k_ahb_release_irq_legacy(ar); + ath10k_ahb_release_irq_intx(ar); ath10k_pci_release_resource(ar); ath10k_ahb_halt_chip(ar); ath10k_ahb_clock_disable(ar); diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 9ce6f49ab2..bdf0552cd1 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -75,7 +75,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 2116, .fw = { .dir = QCA988X_HW_2_0_FW_DIR, - .board = QCA988X_HW_2_0_BOARD_DATA_FILE, .board_size = QCA988X_BOARD_DATA_SZ, .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ, }, @@ -116,7 +115,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 2116, .fw = { .dir = QCA988X_HW_2_0_FW_DIR, - .board = QCA988X_HW_2_0_BOARD_DATA_FILE, .board_size = QCA988X_BOARD_DATA_SZ, .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ, }, @@ -158,7 +156,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 2116, .fw = { .dir = QCA9887_HW_1_0_FW_DIR, - .board = QCA9887_HW_1_0_BOARD_DATA_FILE, .board_size = QCA9887_BOARD_DATA_SZ, .board_ext_size = QCA9887_BOARD_EXT_DATA_SZ, }, @@ -199,7 +196,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 0, .fw = { .dir = QCA6174_HW_3_0_FW_DIR, - .board = QCA6174_HW_3_0_BOARD_DATA_FILE, .board_size = QCA6174_BOARD_DATA_SZ, .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, }, @@ -236,7 +232,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 8124, .fw = { .dir = QCA6174_HW_2_1_FW_DIR, - .board = QCA6174_HW_2_1_BOARD_DATA_FILE, .board_size = QCA6174_BOARD_DATA_SZ, .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, }, @@ -277,7 +272,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 8124, .fw = { .dir = QCA6174_HW_2_1_FW_DIR, - .board = QCA6174_HW_2_1_BOARD_DATA_FILE, .board_size = QCA6174_BOARD_DATA_SZ, .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, }, @@ -318,7 +312,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 8124, .fw = { .dir = QCA6174_HW_3_0_FW_DIR, - .board = QCA6174_HW_3_0_BOARD_DATA_FILE, .board_size = QCA6174_BOARD_DATA_SZ, .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, }, @@ -360,7 +353,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .fw = { /* uses same binaries as hw3.0 */ .dir = QCA6174_HW_3_0_FW_DIR, - .board = QCA6174_HW_3_0_BOARD_DATA_FILE, .board_size = QCA6174_BOARD_DATA_SZ, .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, }, @@ -409,7 +401,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 12064, .fw = { .dir = QCA99X0_HW_2_0_FW_DIR, - .board = QCA99X0_HW_2_0_BOARD_DATA_FILE, .board_size = QCA99X0_BOARD_DATA_SZ, .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, }, @@ -457,8 +448,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 12064, .fw = { .dir = QCA9984_HW_1_0_FW_DIR, - .board = QCA9984_HW_1_0_BOARD_DATA_FILE, - .eboard = QCA9984_HW_1_0_EBOARD_DATA_FILE, .board_size = QCA99X0_BOARD_DATA_SZ, .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, .ext_board_size = QCA99X0_EXT_BOARD_DATA_SZ, @@ -510,7 +499,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 12064, .fw = { .dir = QCA9888_HW_2_0_FW_DIR, - .board = QCA9888_HW_2_0_BOARD_DATA_FILE, .board_size = QCA99X0_BOARD_DATA_SZ, .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, }, @@ -556,7 +544,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 8124, .fw = { .dir = QCA9377_HW_1_0_FW_DIR, - .board = QCA9377_HW_1_0_BOARD_DATA_FILE, .board_size = QCA9377_BOARD_DATA_SZ, .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ, }, @@ -597,7 +584,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 8124, .fw = { .dir = QCA9377_HW_1_0_FW_DIR, - .board = QCA9377_HW_1_0_BOARD_DATA_FILE, .board_size = QCA9377_BOARD_DATA_SZ, .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ, }, @@ -640,7 +626,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 8124, .fw = { .dir = QCA9377_HW_1_0_FW_DIR, - .board = QCA9377_HW_1_0_BOARD_DATA_FILE, .board_size = QCA9377_BOARD_DATA_SZ, .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ, }, @@ -680,7 +665,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .cal_data_len = 12064, .fw = { .dir = QCA4019_HW_1_0_FW_DIR, - .board = QCA4019_HW_1_0_BOARD_DATA_FILE, .board_size = QCA4019_BOARD_DATA_SZ, .board_ext_size = QCA4019_BOARD_EXT_DATA_SZ, }, @@ -720,6 +704,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .max_spatial_stream = 4, .fw = { .dir = WCN3990_HW_1_0_FW_DIR, + .board_size = WCN3990_BOARD_DATA_SZ, + .board_ext_size = WCN3990_BOARD_EXT_DATA_SZ, }, .sw_decrypt_mcast_mgmt = true, .rx_desc_ops = &wcn3990_rx_desc_ops, @@ -942,11 +928,20 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, if (dir == NULL) dir = "."; + if (ar->board_name) { + snprintf(filename, sizeof(filename), "%s/%s/%s", + dir, ar->board_name, file); + ret = firmware_request_nowarn(&fw, filename, ar->dev); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n", + filename, ret); + if (!ret) + return fw; + } + snprintf(filename, sizeof(filename), "%s/%s", dir, file); ret = firmware_request_nowarn(&fw, filename, ar->dev); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n", filename, ret); - if (ret) return ERR_PTR(ret); @@ -1288,11 +1283,6 @@ static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type) char boardname[100]; if (bd_ie_type == ATH10K_BD_IE_BOARD) { - if (!ar->hw_params.fw.board) { - ath10k_err(ar, "failed to find board file fw entry\n"); - return -EINVAL; - } - scnprintf(boardname, sizeof(boardname), "board-%s-%s.bin", ath10k_bus_str(ar->hif.bus), dev_name(ar->dev)); @@ -1302,7 +1292,7 @@ static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type) if (IS_ERR(ar->normal_mode_fw.board)) { fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, - ar->hw_params.fw.board); + ATH10K_BOARD_DATA_FILE); ar->normal_mode_fw.board = fw; } @@ -1312,13 +1302,8 @@ static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type) ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data; ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size; } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) { - if (!ar->hw_params.fw.eboard) { - ath10k_err(ar, "failed to find eboard file fw entry\n"); - return -EINVAL; - } - fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, - ar->hw_params.fw.eboard); + ATH10K_EBOARD_DATA_FILE); ar->normal_mode_fw.ext_board = fw; if (IS_ERR(ar->normal_mode_fw.ext_board)) return PTR_ERR(ar->normal_mode_fw.ext_board); @@ -3673,11 +3658,13 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, INIT_WORK(&ar->set_coverage_class_work, ath10k_core_set_coverage_class_work); - init_dummy_netdev(&ar->napi_dev); + ar->napi_dev = alloc_netdev_dummy(0); + if (!ar->napi_dev) + goto err_free_tx_complete; ret = ath10k_coredump_create(ar); if (ret) - goto err_free_tx_complete; + goto err_free_netdev; ret = ath10k_debug_create(ar); if (ret) @@ -3687,6 +3674,8 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, err_free_coredump: ath10k_coredump_destroy(ar); +err_free_netdev: + free_netdev(ar->napi_dev); err_free_tx_complete: destroy_workqueue(ar->workqueue_tx_complete); err_free_aux_wq: @@ -3708,6 +3697,7 @@ void ath10k_core_destroy(struct ath10k *ar) destroy_workqueue(ar->workqueue_tx_complete); + free_netdev(ar->napi_dev); ath10k_debug_destroy(ar); ath10k_coredump_destroy(ar); ath10k_htt_tx_destroy(&ar->htt); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index c110d15528..b00099f0b2 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -1081,6 +1081,8 @@ struct ath10k { */ const struct ath10k_fw_components *running_fw; + const char *board_name; + const struct firmware *pre_cal_file; const struct firmware *cal_file; @@ -1269,7 +1271,7 @@ struct ath10k { struct ath10k_per_peer_tx_stats peer_tx_stats; /* NAPI */ - struct net_device napi_dev; + struct net_device *napi_dev; struct napi_struct napi; struct work_struct set_coverage_class_work; diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 394bf3c32a..0f6de862c3 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -439,7 +439,7 @@ ath10k_dbg_sta_write_peer_debug_trigger(struct file *file, } out: mutex_unlock(&ar->conf_mutex); - return count; + return ret ?: count; } static const struct file_operations fops_peer_debug_trigger = { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 93c0730919..48897e5eca 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -39,14 +39,12 @@ enum ath10k_bus { #define QCA988X_HW_2_0_VERSION 0x4100016c #define QCA988X_HW_2_0_CHIP_ID_REV 0x2 #define QCA988X_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA988X/hw2.0" -#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234 /* QCA9887 1.0 definitions */ #define QCA9887_HW_1_0_VERSION 0x4100016d #define QCA9887_HW_1_0_CHIP_ID_REV 0 #define QCA9887_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9887/hw1.0" -#define QCA9887_HW_1_0_BOARD_DATA_FILE "board.bin" #define QCA9887_HW_1_0_PATCH_LOAD_ADDR 0x1234 /* QCA6174 target BMI version signatures */ @@ -85,11 +83,9 @@ enum qca9377_chip_id_rev { }; #define QCA6174_HW_2_1_FW_DIR ATH10K_FW_DIR "/QCA6174/hw2.1" -#define QCA6174_HW_2_1_BOARD_DATA_FILE "board.bin" #define QCA6174_HW_2_1_PATCH_LOAD_ADDR 0x1234 #define QCA6174_HW_3_0_FW_DIR ATH10K_FW_DIR "/QCA6174/hw3.0" -#define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin" #define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234 /* QCA99X0 1.0 definitions (unsupported) */ @@ -99,7 +95,6 @@ enum qca9377_chip_id_rev { #define QCA99X0_HW_2_0_DEV_VERSION 0x01000000 #define QCA99X0_HW_2_0_CHIP_ID_REV 0x1 #define QCA99X0_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA99X0/hw2.0" -#define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234 /* QCA9984 1.0 defines */ @@ -107,8 +102,6 @@ enum qca9377_chip_id_rev { #define QCA9984_HW_DEV_TYPE 0xa #define QCA9984_HW_1_0_CHIP_ID_REV 0x0 #define QCA9984_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9984/hw1.0" -#define QCA9984_HW_1_0_BOARD_DATA_FILE "board.bin" -#define QCA9984_HW_1_0_EBOARD_DATA_FILE "eboard.bin" #define QCA9984_HW_1_0_PATCH_LOAD_ADDR 0x1234 /* QCA9888 2.0 defines */ @@ -116,18 +109,15 @@ enum qca9377_chip_id_rev { #define QCA9888_HW_DEV_TYPE 0xc #define QCA9888_HW_2_0_CHIP_ID_REV 0x0 #define QCA9888_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA9888/hw2.0" -#define QCA9888_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA9888_HW_2_0_PATCH_LOAD_ADDR 0x1234 /* QCA9377 1.0 definitions */ #define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0" -#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin" #define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234 /* QCA4019 1.0 definitions */ #define QCA4019_HW_1_0_DEV_VERSION 0x01000000 #define QCA4019_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA4019/hw1.0" -#define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin" #define QCA4019_HW_1_0_PATCH_LOAD_ADDR 0x1234 /* WCN3990 1.0 definitions */ @@ -159,7 +149,9 @@ enum qca9377_chip_id_rev { #define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K" #define ATH10K_BOARD_MAGIC "QCA-ATH10K-BOARD" +#define ATH10K_BOARD_DATA_FILE "board.bin" #define ATH10K_BOARD_API2_FILE "board-2.bin" +#define ATH10K_EBOARD_DATA_FILE "eboard.bin" #define REG_DUMP_COUNT_QCA988X 60 @@ -553,9 +545,7 @@ struct ath10k_hw_params { struct ath10k_hw_params_fw { const char *dir; - const char *board; size_t board_size; - const char *eboard; size_t ext_board_size; size_t board_ext_size; } fw; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 5c34b156b4..c52a16f807 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -721,7 +721,7 @@ bool ath10k_pci_irq_pending(struct ath10k *ar) return false; } -void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar) +void ath10k_pci_disable_and_clear_intx_irq(struct ath10k *ar) { /* IMPORTANT: INTR_CLR register has to be set after * INTR_ENABLE is set to 0, otherwise interrupt can not be @@ -739,7 +739,7 @@ void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar) PCIE_INTR_ENABLE_ADDRESS); } -void ath10k_pci_enable_legacy_irq(struct ath10k *ar) +void ath10k_pci_enable_intx_irq(struct ath10k *ar) { ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, @@ -1935,7 +1935,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) static void ath10k_pci_irq_disable(struct ath10k *ar) { ath10k_ce_disable_interrupts(ar); - ath10k_pci_disable_and_clear_legacy_irq(ar); + ath10k_pci_disable_and_clear_intx_irq(ar); ath10k_pci_irq_msi_fw_mask(ar); } @@ -1949,7 +1949,7 @@ static void ath10k_pci_irq_sync(struct ath10k *ar) static void ath10k_pci_irq_enable(struct ath10k *ar) { ath10k_ce_enable_interrupts(ar); - ath10k_pci_enable_legacy_irq(ar); + ath10k_pci_enable_intx_irq(ar); ath10k_pci_irq_msi_fw_unmask(ar); } @@ -3111,11 +3111,11 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) return IRQ_NONE; } - if ((ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) && + if ((ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_INTX) && !ath10k_pci_irq_pending(ar)) return IRQ_NONE; - ath10k_pci_disable_and_clear_legacy_irq(ar); + ath10k_pci_disable_and_clear_intx_irq(ar); ath10k_pci_irq_msi_fw_mask(ar); napi_schedule(&ar->napi); @@ -3152,7 +3152,7 @@ static int ath10k_pci_napi_poll(struct napi_struct *ctx, int budget) napi_schedule(ctx); goto out; } - ath10k_pci_enable_legacy_irq(ar); + ath10k_pci_enable_intx_irq(ar); ath10k_pci_irq_msi_fw_unmask(ar); } @@ -3177,7 +3177,7 @@ static int ath10k_pci_request_irq_msi(struct ath10k *ar) return 0; } -static int ath10k_pci_request_irq_legacy(struct ath10k *ar) +static int ath10k_pci_request_irq_intx(struct ath10k *ar) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; @@ -3199,8 +3199,8 @@ static int ath10k_pci_request_irq(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); switch (ar_pci->oper_irq_mode) { - case ATH10K_PCI_IRQ_LEGACY: - return ath10k_pci_request_irq_legacy(ar); + case ATH10K_PCI_IRQ_INTX: + return ath10k_pci_request_irq_intx(ar); case ATH10K_PCI_IRQ_MSI: return ath10k_pci_request_irq_msi(ar); default: @@ -3217,7 +3217,7 @@ static void ath10k_pci_free_irq(struct ath10k *ar) void ath10k_pci_init_napi(struct ath10k *ar) { - netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_pci_napi_poll); + netif_napi_add(ar->napi_dev, &ar->napi, ath10k_pci_napi_poll); } static int ath10k_pci_init_irq(struct ath10k *ar) @@ -3232,7 +3232,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar) ath10k_pci_irq_mode); /* Try MSI */ - if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_LEGACY) { + if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_INTX) { ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_MSI; ret = pci_enable_msi(ar_pci->pdev); if (ret == 0) @@ -3250,7 +3250,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar) * For now, fix the race by repeating the write in below * synchronization checking. */ - ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY; + ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_INTX; ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); @@ -3258,7 +3258,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar) return 0; } -static void ath10k_pci_deinit_irq_legacy(struct ath10k *ar) +static void ath10k_pci_deinit_irq_intx(struct ath10k *ar) { ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, 0); @@ -3269,8 +3269,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); switch (ar_pci->oper_irq_mode) { - case ATH10K_PCI_IRQ_LEGACY: - ath10k_pci_deinit_irq_legacy(ar); + case ATH10K_PCI_IRQ_INTX: + ath10k_pci_deinit_irq_intx(ar); break; default: pci_disable_msi(ar_pci->pdev); @@ -3307,14 +3307,14 @@ int ath10k_pci_wait_for_target_init(struct ath10k *ar) if (val & FW_IND_INITIALIZED) break; - if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) + if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_INTX) /* Fix potential race by repeating CORE_BASE writes */ - ath10k_pci_enable_legacy_irq(ar); + ath10k_pci_enable_intx_irq(ar); mdelay(10); } while (time_before(jiffies, timeout)); - ath10k_pci_disable_and_clear_legacy_irq(ar); + ath10k_pci_disable_and_clear_intx_irq(ar); ath10k_pci_irq_msi_fw_mask(ar); if (val == 0xffffffff) { @@ -3826,28 +3826,28 @@ MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE); MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE); MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API4_FILE); MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API5_FILE); -MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); +MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_BOARD_DATA_FILE); MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); /* QCA9887 1.0 firmware files */ MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE); -MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" QCA9887_HW_1_0_BOARD_DATA_FILE); +MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_BOARD_DATA_FILE); MODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); /* QCA6174 2.1 firmware files */ MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE); MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE); -MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE); +MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_BOARD_DATA_FILE); MODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_BOARD_API2_FILE); /* QCA6174 3.1 firmware files */ MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API6_FILE); -MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE); +MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_DATA_FILE); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); /* QCA9377 1.0 firmware files */ MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API6_FILE); MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE); -MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" QCA9377_HW_1_0_BOARD_DATA_FILE); +MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index 27bb4cf2df..4c3f536f2e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -101,7 +101,7 @@ struct ath10k_pci_supp_chip { enum ath10k_pci_irq_mode { ATH10K_PCI_IRQ_AUTO = 0, - ATH10K_PCI_IRQ_LEGACY = 1, + ATH10K_PCI_IRQ_INTX = 1, ATH10K_PCI_IRQ_MSI = 2, }; @@ -243,9 +243,9 @@ int ath10k_pci_init_pipes(struct ath10k *ar); int ath10k_pci_init_config(struct ath10k *ar); void ath10k_pci_rx_post(struct ath10k *ar); void ath10k_pci_flush(struct ath10k *ar); -void ath10k_pci_enable_legacy_irq(struct ath10k *ar); +void ath10k_pci_enable_intx_irq(struct ath10k *ar); bool ath10k_pci_irq_pending(struct ath10k *ar); -void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar); +void ath10k_pci_disable_and_clear_intx_irq(struct ath10k *ar); void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar); int ath10k_pci_wait_for_target_init(struct ath10k *ar); int ath10k_pci_setup_resource(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 0ab5433f6c..08a6f36a6b 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -2532,7 +2532,7 @@ static int ath10k_sdio_probe(struct sdio_func *func, return -ENOMEM; } - netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_sdio_napi_poll); + netif_napi_add(ar->napi_dev, &ar->napi, ath10k_sdio_napi_poll); ath10k_dbg(ar, ATH10K_DBG_BOOT, "sdio new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n", @@ -2667,29 +2667,10 @@ static struct sdio_driver ath10k_sdio_driver = { .probe = ath10k_sdio_probe, .remove = ath10k_sdio_remove, .drv = { - .owner = THIS_MODULE, .pm = ATH10K_SDIO_PM_OPS, }, }; - -static int __init ath10k_sdio_init(void) -{ - int ret; - - ret = sdio_register_driver(&ath10k_sdio_driver); - if (ret) - pr_err("sdio driver registration failed: %d\n", ret); - - return ret; -} - -static void __exit ath10k_sdio_exit(void) -{ - sdio_unregister_driver(&ath10k_sdio_driver); -} - -module_init(ath10k_sdio_init); -module_exit(ath10k_sdio_exit); +module_sdio_driver(ath10k_sdio_driver); MODULE_AUTHOR("Qualcomm Atheros"); MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN SDIO devices"); diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index 2c39bad7eb..8530550cf5 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -935,7 +935,7 @@ static int ath10k_snoc_hif_start(struct ath10k *ar) bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX); - dev_set_threaded(&ar->napi_dev, true); + dev_set_threaded(ar->napi_dev, true); ath10k_core_napi_enable(ar); ath10k_snoc_irq_enable(ar); ath10k_snoc_rx_post(ar); @@ -1253,7 +1253,7 @@ static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget) static void ath10k_snoc_init_napi(struct ath10k *ar) { - netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll); + netif_napi_add(ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll); } static int ath10k_snoc_request_irq(struct ath10k *ar) @@ -1338,6 +1338,9 @@ static void ath10k_snoc_quirks_init(struct ath10k *ar) struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar); struct device *dev = &ar_snoc->dev->dev; + /* ignore errors, keep NULL if there is no property */ + of_property_read_string(dev->of_node, "firmware-name", &ar->board_name); + if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk")) set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags); } diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index ec556bb88d..ba37e6c7ce 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -491,4 +491,7 @@ struct host_interest { #define QCA4019_BOARD_DATA_SZ 12064 #define QCA4019_BOARD_EXT_DATA_SZ 0 +#define WCN3990_BOARD_DATA_SZ 26328 +#define WCN3990_BOARD_EXT_DATA_SZ 0 + #endif /* __TARGADDRS_H__ */ diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index 31c8d7fbb0..8b15ec07b1 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -100,7 +100,7 @@ static ssize_t ath10k_thermal_show_temp(struct device *dev, spin_unlock_bh(&ar->data_lock); /* display in millidegree celsius */ - ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000); + ret = sysfs_emit(buf, "%d\n", temperature * 1000); out: mutex_unlock(&ar->conf_mutex); return ret; diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index 64e7a767d9..68b78ca17e 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h @@ -55,8 +55,8 @@ DECLARE_EVENT_CLASS(ath10k_log_event, __vstring(msg, vaf->fmt, vaf->va) ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __assign_vstr(msg, vaf->fmt, vaf->va); ), TP_printk( @@ -92,8 +92,8 @@ TRACE_EVENT(ath10k_log_dbg, __vstring(msg, vaf->fmt, vaf->va) ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->level = level; __assign_vstr(msg, vaf->fmt, vaf->va); ), @@ -121,10 +121,10 @@ TRACE_EVENT(ath10k_log_dbg_dump, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); - __assign_str(msg, msg); - __assign_str(prefix, prefix); + __assign_str(device); + __assign_str(driver); + __assign_str(msg); + __assign_str(prefix); __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); ), @@ -152,8 +152,8 @@ TRACE_EVENT(ath10k_wmi_cmd, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->id = id; __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); @@ -182,8 +182,8 @@ TRACE_EVENT(ath10k_wmi_event, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->id = id; __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); @@ -211,8 +211,8 @@ TRACE_EVENT(ath10k_htt_stats, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); ), @@ -239,8 +239,8 @@ TRACE_EVENT(ath10k_wmi_dbglog, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->hw_type = ar->hw_rev; __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); @@ -269,8 +269,8 @@ TRACE_EVENT(ath10k_htt_pktlog, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->hw_type = ar->hw_rev; __entry->buf_len = buf_len; memcpy(__get_dynamic_array(pktlog), buf, buf_len); @@ -301,8 +301,8 @@ TRACE_EVENT(ath10k_htt_tx, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->msdu_id = msdu_id; __entry->msdu_len = msdu_len; __entry->vdev_id = vdev_id; @@ -332,8 +332,8 @@ TRACE_EVENT(ath10k_txrx_tx_unref, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->msdu_id = msdu_id; ), @@ -358,8 +358,8 @@ DECLARE_EVENT_CLASS(ath10k_hdr_event, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = ath10k_frm_hdr_len(data, len); memcpy(__get_dynamic_array(data), data, __entry->len); ), @@ -386,8 +386,8 @@ DECLARE_EVENT_CLASS(ath10k_payload_event, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = len - ath10k_frm_hdr_len(data, len); memcpy(__get_dynamic_array(payload), data + ath10k_frm_hdr_len(data, len), __entry->len); @@ -435,8 +435,8 @@ TRACE_EVENT(ath10k_htt_rx_desc, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->hw_type = ar->hw_rev; __entry->len = len; memcpy(__get_dynamic_array(rxdesc), data, len); @@ -472,8 +472,8 @@ TRACE_EVENT(ath10k_wmi_diag_container, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->type = type; __entry->timestamp = timestamp; __entry->code = code; @@ -505,8 +505,8 @@ TRACE_EVENT(ath10k_wmi_diag, ), TP_fast_assign( - __assign_str(device, dev_name(ar->dev)); - __assign_str(driver, dev_driver_string(ar->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = len; memcpy(__get_dynamic_array(data), data, len); ), diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index 3c482baace..3b51b7f521 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -1014,7 +1014,7 @@ static int ath10k_usb_probe(struct usb_interface *interface, return -ENOMEM; } - netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_usb_napi_poll); + netif_napi_add(ar->napi_dev, &ar->napi, ath10k_usb_napi_poll); usb_get_dev(dev); vendor_id = le16_to_cpu(dev->descriptor.idVendor); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 2e9661f4be..80d255aaff 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1763,12 +1763,32 @@ void ath10k_wmi_put_wmi_channel(struct ath10k *ar, struct wmi_channel *ch, int ath10k_wmi_wait_for_service_ready(struct ath10k *ar) { - unsigned long time_left; + unsigned long time_left, i; time_left = wait_for_completion_timeout(&ar->wmi.service_ready, WMI_SERVICE_READY_TIMEOUT_HZ); - if (!time_left) - return -ETIMEDOUT; + if (!time_left) { + /* Sometimes the PCI HIF doesn't receive interrupt + * for the service ready message even if the buffer + * was completed. PCIe sniffer shows that it's + * because the corresponding CE ring doesn't fires + * it. Workaround here by polling CE rings once. + */ + ath10k_warn(ar, "failed to receive service ready completion, polling..\n"); + + for (i = 0; i < CE_COUNT; i++) + ath10k_hif_send_complete_check(ar, i, 1); + + time_left = wait_for_completion_timeout(&ar->wmi.service_ready, + WMI_SERVICE_READY_TIMEOUT_HZ); + if (!time_left) { + ath10k_warn(ar, "polling timed out\n"); + return -ETIMEDOUT; + } + + ath10k_warn(ar, "service ready completion received, continuing normally\n"); + } + return 0; } diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile index 2c94d50ae3..43d2d8ddcd 100644 --- a/drivers/net/wireless/ath/ath11k/Makefile +++ b/drivers/net/wireless/ath/ath11k/Makefile @@ -18,7 +18,8 @@ ath11k-y += core.o \ dbring.o \ hw.o \ pcic.o \ - fw.o + fw.o \ + p2p.o ath11k-$(CONFIG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 7c0a235179..ca0f17ddeb 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/module.h> @@ -413,7 +413,7 @@ static int ath11k_ahb_power_up(struct ath11k_base *ab) return ret; } -static void ath11k_ahb_power_down(struct ath11k_base *ab) +static void ath11k_ahb_power_down(struct ath11k_base *ab, bool is_suspend) { struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab); @@ -442,6 +442,7 @@ static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab) free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); netif_napi_del(&irq_grp->napi); + free_netdev(irq_grp->napi_ndev); } } @@ -533,8 +534,12 @@ static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab) irq_grp->ab = ab; irq_grp->grp_id = i; - init_dummy_netdev(&irq_grp->napi_ndev); - netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, + + irq_grp->napi_ndev = alloc_netdev_dummy(0); + if (!irq_grp->napi_ndev) + return -ENOMEM; + + netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi, ath11k_ahb_ext_grp_napi_poll); for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) { @@ -1256,7 +1261,7 @@ static void ath11k_ahb_remove(struct platform_device *pdev) struct ath11k_base *ab = platform_get_drvdata(pdev); if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { - ath11k_ahb_power_down(ab); + ath11k_ahb_power_down(ab, false); ath11k_debugfs_soc_destroy(ab); ath11k_qmi_deinit_service(ab); goto qmi_fail; diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h index 69946fc700..bcde2fcf02 100644 --- a/drivers/net/wireless/ath/ath11k/ce.h +++ b/drivers/net/wireless/ath/ath11k/ce.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_CE_H @@ -146,7 +146,7 @@ struct ath11k_ce_ring { /* Host address space */ void *base_addr_owner_space_unaligned; /* CE address space */ - u32 base_addr_ce_space_unaligned; + dma_addr_t base_addr_ce_space_unaligned; /* Actual start of descriptors. * Aligned to descriptor-size boundary. @@ -156,7 +156,7 @@ struct ath11k_ce_ring { void *base_addr_owner_space; /* CE address space */ - u32 base_addr_ce_space; + dma_addr_t base_addr_ce_space; /* HAL ring id */ u32 hal_ring_id; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index c78bce19bd..47554c3619 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -247,7 +247,10 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { }, .interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), .supports_monitor = false, .full_monitor_mode = false, .supports_shadow_regs = true, @@ -416,7 +419,10 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { }, .interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), .supports_monitor = false, .full_monitor_mode = false, .supports_shadow_regs = true, @@ -501,7 +507,10 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { }, .interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), .supports_monitor = false, .supports_shadow_regs = true, .idle_ps = true, @@ -595,7 +604,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .coldboot_cal_ftm = true, .cbcal_restart_fw = false, .fw_mem_mode = 0, - .num_vdevs = 16 + 1, + .num_vdevs = 3, .num_peers = 512, .supports_suspend = false, .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074), @@ -750,7 +759,10 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { }, .interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), .supports_monitor = false, .full_monitor_mode = false, .supports_shadow_regs = true, @@ -894,12 +906,6 @@ int ath11k_core_suspend(struct ath11k_base *ab) return ret; } - ret = ath11k_wow_enable(ab); - if (ret) { - ath11k_warn(ab, "failed to enable wow during suspend: %d\n", ret); - return ret; - } - ret = ath11k_dp_rx_pktlog_stop(ab, false); if (ret) { ath11k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n", @@ -910,29 +916,85 @@ int ath11k_core_suspend(struct ath11k_base *ab) ath11k_ce_stop_shadow_timers(ab); ath11k_dp_stop_shadow_timers(ab); + /* PM framework skips suspend_late/resume_early callbacks + * if other devices report errors in their suspend callbacks. + * However ath11k_core_resume() would still be called because + * here we return success thus kernel put us on dpm_suspended_list. + * Since we won't go through a power down/up cycle, there is + * no chance to call complete(&ab->restart_completed) in + * ath11k_core_restart(), making ath11k_core_resume() timeout. + * So call it here to avoid this issue. This also works in case + * no error happens thus suspend_late/resume_early get called, + * because it will be reinitialized in ath11k_core_resume_early(). + */ + complete(&ab->restart_completed); + + return 0; +} +EXPORT_SYMBOL(ath11k_core_suspend); + +int ath11k_core_suspend_late(struct ath11k_base *ab) +{ + struct ath11k_pdev *pdev; + struct ath11k *ar; + + if (!ab->hw_params.supports_suspend) + return -EOPNOTSUPP; + + /* so far single_pdev_only chips have supports_suspend as true + * and only the first pdev is valid. + */ + pdev = ath11k_core_get_single_pdev(ab); + ar = pdev->ar; + if (!ar || ar->state != ATH11K_STATE_OFF) + return 0; + ath11k_hif_irq_disable(ab); ath11k_hif_ce_irq_disable(ab); - ret = ath11k_hif_suspend(ab); - if (ret) { - ath11k_warn(ab, "failed to suspend hif: %d\n", ret); - return ret; - } + ath11k_hif_power_down(ab, true); return 0; } -EXPORT_SYMBOL(ath11k_core_suspend); +EXPORT_SYMBOL(ath11k_core_suspend_late); + +int ath11k_core_resume_early(struct ath11k_base *ab) +{ + int ret; + struct ath11k_pdev *pdev; + struct ath11k *ar; + + if (!ab->hw_params.supports_suspend) + return -EOPNOTSUPP; + + /* so far single_pdev_only chips have supports_suspend as true + * and only the first pdev is valid. + */ + pdev = ath11k_core_get_single_pdev(ab); + ar = pdev->ar; + if (!ar || ar->state != ATH11K_STATE_OFF) + return 0; + + reinit_completion(&ab->restart_completed); + ret = ath11k_hif_power_up(ab); + if (ret) + ath11k_warn(ab, "failed to power up hif during resume: %d\n", ret); + + return ret; +} +EXPORT_SYMBOL(ath11k_core_resume_early); int ath11k_core_resume(struct ath11k_base *ab) { int ret; struct ath11k_pdev *pdev; struct ath11k *ar; + long time_left; if (!ab->hw_params.supports_suspend) return -EOPNOTSUPP; - /* so far signle_pdev_only chips have supports_suspend as true + /* so far single_pdev_only chips have supports_suspend as true * and only the first pdev is valid. */ pdev = ath11k_core_get_single_pdev(ab); @@ -940,29 +1002,29 @@ int ath11k_core_resume(struct ath11k_base *ab) if (!ar || ar->state != ATH11K_STATE_OFF) return 0; - ret = ath11k_hif_resume(ab); - if (ret) { - ath11k_warn(ab, "failed to resume hif during resume: %d\n", ret); - return ret; + time_left = wait_for_completion_timeout(&ab->restart_completed, + ATH11K_RESET_TIMEOUT_HZ); + if (time_left == 0) { + ath11k_warn(ab, "timeout while waiting for restart complete"); + return -ETIMEDOUT; } - ath11k_hif_ce_irq_enable(ab); - ath11k_hif_irq_enable(ab); + if (ab->hw_params.current_cc_support && + ar->alpha2[0] != 0 && ar->alpha2[1] != 0) { + ret = ath11k_reg_set_cc(ar); + if (ret) { + ath11k_warn(ab, "failed to set country code during resume: %d\n", + ret); + return ret; + } + } ret = ath11k_dp_rx_pktlog_start(ab); - if (ret) { + if (ret) ath11k_warn(ab, "failed to start rx pktlog during resume: %d\n", ret); - return ret; - } - ret = ath11k_wow_wakeup(ab); - if (ret) { - ath11k_warn(ab, "failed to wakeup wow during resume: %d\n", ret); - return ret; - } - - return 0; + return ret; } EXPORT_SYMBOL(ath11k_core_resume); @@ -1926,23 +1988,20 @@ static void ath11k_update_11d(struct work_struct *work) struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work); struct ath11k *ar; struct ath11k_pdev *pdev; - struct wmi_set_current_country_params set_current_param = {}; int ret, i; - spin_lock_bh(&ab->base_lock); - memcpy(&set_current_param.alpha2, &ab->new_alpha2, 2); - spin_unlock_bh(&ab->base_lock); - - ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c\n", - set_current_param.alpha2[0], - set_current_param.alpha2[1]); - for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; ar = pdev->ar; - memcpy(&ar->alpha2, &set_current_param.alpha2, 2); - ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + spin_lock_bh(&ab->base_lock); + memcpy(&ar->alpha2, &ab->new_alpha2, 2); + spin_unlock_bh(&ab->base_lock); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c for pdev %d\n", + ar->alpha2[0], ar->alpha2[1], i); + + ret = ath11k_reg_set_cc(ar); if (ret) ath11k_warn(ar->ab, "pdev id %d failed set current country code: %d\n", @@ -2060,6 +2119,8 @@ static void ath11k_core_restart(struct work_struct *work) if (!ab->is_reset) ath11k_core_post_reconfigure_recovery(ab); + + complete(&ab->restart_completed); } static void ath11k_core_reset(struct work_struct *work) @@ -2129,7 +2190,7 @@ static void ath11k_core_reset(struct work_struct *work) ath11k_hif_irq_disable(ab); ath11k_hif_ce_irq_disable(ab); - ath11k_hif_power_down(ab); + ath11k_hif_power_down(ab, false); ath11k_hif_power_up(ab); ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset started\n"); @@ -2202,7 +2263,7 @@ void ath11k_core_deinit(struct ath11k_base *ab) mutex_unlock(&ab->core_lock); - ath11k_hif_power_down(ab); + ath11k_hif_power_down(ab, false); ath11k_mac_destroy(ab); ath11k_core_soc_destroy(ab); ath11k_fw_destroy(ab); @@ -2255,6 +2316,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); init_completion(&ab->htc_suspend); init_completion(&ab->wow.wakeup_completed); + init_completion(&ab->restart_completed); ab->dev = dev; ab->hif.bus = bus; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index b3fb74a226..205f40ee6b 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_CORE_H @@ -174,7 +174,7 @@ struct ath11k_ext_irq_grp { u64 timestamp; bool napi_enabled; struct napi_struct napi; - struct net_device napi_ndev; + struct net_device *napi_ndev; }; enum ath11k_smbios_cc_type { @@ -1033,6 +1033,8 @@ struct ath11k_base { DECLARE_BITMAP(fw_features, ATH11K_FW_FEATURE_COUNT); } fw; + struct completion restart_completed; + #ifdef CONFIG_NL80211_TESTMODE struct { u32 data_pos; @@ -1232,8 +1234,10 @@ void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); int ath11k_core_check_dt(struct ath11k_base *ath11k); int ath11k_core_check_smbios(struct ath11k_base *ab); void ath11k_core_halt(struct ath11k *ar); +int ath11k_core_resume_early(struct ath11k_base *ab); int ath11k_core_resume(struct ath11k_base *ab); int ath11k_core_suspend(struct ath11k_base *ab); +int ath11k_core_suspend_late(struct ath11k_base *ab); void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab); bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab); diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index a48e737ef3..414a5ce279 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/vmalloc.h> @@ -980,7 +980,7 @@ int ath11k_debugfs_pdev_create(struct ath11k_base *ab) 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, + debugfs_create_file("soc_dp_stats", 0400, ab->debugfs_soc, ab, &fops_soc_dp_stats); if (ab->hw_params.sram_dump.start != 0) diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index afd481f585..aabde24d87 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1877,8 +1877,7 @@ static void ath11k_dp_rx_h_csum_offload(struct ath11k *ar, struct sk_buff *msdu) CHECKSUM_NONE : CHECKSUM_UNNECESSARY; } -static int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar, - enum hal_encrypt_type enctype) +int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar, enum hal_encrypt_type enctype) { switch (enctype) { case HAL_ENCRYPT_TYPE_OPEN: diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.h b/drivers/net/wireless/ath/ath11k/dp_rx.h index 623da3bf9d..c322e30caa 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.h +++ b/drivers/net/wireless/ath/ath11k/dp_rx.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_DP_RX_H #define ATH11K_DP_RX_H @@ -95,4 +96,6 @@ int ath11k_peer_rx_frag_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id int ath11k_dp_rx_pktlog_start(struct ath11k_base *ab); int ath11k_dp_rx_pktlog_stop(struct ath11k_base *ab, bool stop_timer); +int ath11k_dp_rx_crypto_mic_len(struct ath11k *ar, enum hal_encrypt_type enctype); + #endif /* ATH11K_DP_RX_H */ diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 65e8f244eb..e453c13738 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -664,7 +664,7 @@ struct hal_srng_config { }; /** - * enum hal_rx_buf_return_buf_manager + * enum hal_rx_buf_return_buf_manager - manager for returned rx buffers * * @HAL_RX_BUF_RBM_WBM_IDLE_BUF_LIST: Buffer returned to WBM idle buffer list * @HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST: Descriptor returned to WBM idle diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h index 877a4073fe..c4c6cc09c7 100644 --- a/drivers/net/wireless/ath/ath11k/hif.h +++ b/drivers/net/wireless/ath/ath11k/hif.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _HIF_H_ @@ -18,7 +18,7 @@ struct ath11k_hif_ops { int (*start)(struct ath11k_base *ab); void (*stop)(struct ath11k_base *ab); int (*power_up)(struct ath11k_base *ab); - void (*power_down)(struct ath11k_base *ab); + void (*power_down)(struct ath11k_base *ab, bool is_suspend); int (*suspend)(struct ath11k_base *ab); int (*resume)(struct ath11k_base *ab); int (*map_service_to_pipe)(struct ath11k_base *ab, u16 service_id, @@ -67,12 +67,18 @@ static inline void ath11k_hif_irq_disable(struct ath11k_base *ab) static inline int ath11k_hif_power_up(struct ath11k_base *ab) { + if (!ab->hif.ops->power_up) + return -EOPNOTSUPP; + return ab->hif.ops->power_up(ab); } -static inline void ath11k_hif_power_down(struct ath11k_base *ab) +static inline void ath11k_hif_power_down(struct ath11k_base *ab, bool is_suspend) { - ab->hif.ops->power_down(ab); + if (!ab->hif.ops->power_down) + return; + + ab->hif.ops->power_down(ab, is_suspend); } static inline int ath11k_hif_suspend(struct ath11k_base *ab) diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 9f4bf41a3d..eaa53bc39a 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1231,14 +1231,7 @@ static int ath11k_mac_vif_setup_ps(struct ath11k_vif *arvif) enable_ps = arvif->ps; - if (!arvif->is_started) { - /* mac80211 can update vif powersave state while disconnected. - * Firmware doesn't behave nicely and consumes more power than - * necessary if PS is disabled on a non-started vdev. Hence - * force-enable PS for non-running vdevs. - */ - psmode = WMI_STA_PS_MODE_ENABLED; - } else if (enable_ps) { + if (enable_ps) { psmode = WMI_STA_PS_MODE_ENABLED; param = WMI_STA_PS_PARAM_INACTIVITY_TIME; @@ -1430,10 +1423,67 @@ static bool ath11k_mac_set_nontx_vif_params(struct ath11k_vif *tx_arvif, return false; } -static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif, - struct sk_buff *bcn) +static int ath11k_mac_setup_bcn_p2p_ie(struct ath11k_vif *arvif, + struct sk_buff *bcn) +{ + struct ath11k *ar = arvif->ar; + struct ieee80211_mgmt *mgmt; + const u8 *p2p_ie; + int ret; + + mgmt = (void *)bcn->data; + p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, + mgmt->u.beacon.variable, + bcn->len - (mgmt->u.beacon.variable - + bcn->data)); + if (!p2p_ie) + return -ENOENT; + + ret = ath11k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie); + if (ret) { + ath11k_warn(ar->ab, "failed to submit P2P GO bcn ie for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return ret; +} + +static int ath11k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, + u8 oui_type, size_t ie_offset) +{ + size_t len; + const u8 *next, *end; + u8 *ie; + + if (WARN_ON(skb->len < ie_offset)) + return -EINVAL; + + ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, + skb->data + ie_offset, + skb->len - ie_offset); + if (!ie) + return -ENOENT; + + len = ie[1] + 2; + end = skb->data + skb->len; + next = ie + len; + + if (WARN_ON(next > end)) + return -EINVAL; + + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); + + return 0; +} + +static int ath11k_mac_set_vif_params(struct ath11k_vif *arvif, + struct sk_buff *bcn) { + struct ath11k_base *ab = arvif->ar->ab; struct ieee80211_mgmt *mgmt; + int ret = 0; u8 *ies; ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn); @@ -1451,6 +1501,32 @@ static void ath11k_mac_set_vif_params(struct ath11k_vif *arvif, arvif->wpaie_present = true; else arvif->wpaie_present = false; + + if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO) + return ret; + + ret = ath11k_mac_setup_bcn_p2p_ie(arvif, bcn); + if (ret) { + ath11k_warn(ab, "failed to setup P2P GO bcn ie: %d\n", + ret); + return ret; + } + + /* P2P IE is inserted by firmware automatically (as + * configured above) so remove it from the base beacon + * template to avoid duplicate P2P IEs in beacon frames. + */ + ret = ath11k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, + WLAN_OUI_TYPE_WFA_P2P, + offsetof(struct ieee80211_mgmt, + u.beacon.variable)); + if (ret) { + ath11k_warn(ab, "failed to remove P2P vendor ie: %d\n", + ret); + return ret; + } + + return ret; } static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif) @@ -1472,10 +1548,12 @@ static int ath11k_mac_setup_bcn_tmpl_ema(struct ath11k_vif *arvif) return -EPERM; } - if (tx_arvif == arvif) - ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb); - else + if (tx_arvif == arvif) { + if (ath11k_mac_set_vif_params(tx_arvif, beacons->bcn[0].skb)) + return -EINVAL; + } else { arvif->wpaie_present = tx_arvif->wpaie_present; + } for (i = 0; i < beacons->cnt; i++) { if (tx_arvif != arvif && !nontx_vif_params_set) @@ -1534,10 +1612,12 @@ static int ath11k_mac_setup_bcn_tmpl_mbssid(struct ath11k_vif *arvif) return -EPERM; } - if (tx_arvif == arvif) - ath11k_mac_set_vif_params(tx_arvif, bcn); - else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn)) + if (tx_arvif == arvif) { + if (ath11k_mac_set_vif_params(tx_arvif, bcn)) + return -EINVAL; + } else if (!ath11k_mac_set_nontx_vif_params(tx_arvif, arvif, bcn)) { return -EINVAL; + } ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn, 0); kfree_skb(bcn); @@ -1579,7 +1659,7 @@ void ath11k_mac_bcn_tx_event(struct ath11k_vif *arvif) if (vif->bss_conf.color_change_active && ieee80211_beacon_cntdwn_is_complete(vif, 0)) { arvif->bcca_zero_sent = true; - ieee80211_color_change_finish(vif); + ieee80211_color_change_finish(vif, 0); return; } @@ -3996,6 +4076,9 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, arg->vdev_id = arvif->vdev_id; arg->scan_id = ATH11K_SCAN_ID; + if (ar->ab->hw_params.single_pdev_only) + arg->scan_f_filter_prb_req = 1; + if (req->ie_len) { arg->extraie.ptr = kmemdup(req->ie, req->ie_len, GFP_KERNEL); if (!arg->extraie.ptr) { @@ -4146,6 +4229,7 @@ static int ath11k_install_key(struct ath11k_vif *arvif, switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: arg.key_cipher = WMI_CIPHER_AES_CCM; /* TODO: Re-check if flag is valid */ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; @@ -4155,12 +4239,10 @@ static int ath11k_install_key(struct ath11k_vif *arvif, arg.key_txmic_len = 8; arg.key_rxmic_len = 8; break; - case WLAN_CIPHER_SUITE_CCMP_256: - arg.key_cipher = WMI_CIPHER_AES_CCM; - break; case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: arg.key_cipher = WMI_CIPHER_AES_GCM; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; break; default: ath11k_warn(ar->ab, "cipher %d is not supported\n", key->cipher); @@ -5820,7 +5902,10 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, { struct ath11k_base *ab = ar->ab; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb); struct ieee80211_tx_info *info; + enum hal_encrypt_type enctype; + unsigned int mic_len; dma_addr_t paddr; int buf_id; int ret; @@ -5844,7 +5929,12 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, ieee80211_is_deauth(hdr->frame_control) || ieee80211_is_disassoc(hdr->frame_control)) && ieee80211_has_protected(hdr->frame_control)) { - skb_put(skb, IEEE80211_CCMP_MIC_LEN); + if (!(skb_cb->flags & ATH11K_SKB_CIPHER_SET)) + ath11k_warn(ab, "WMI management tx frame without ATH11K_SKB_CIPHER_SET"); + + enctype = ath11k_dp_tx_get_encrypt_type(skb_cb->cipher); + mic_len = ath11k_dp_rx_crypto_mic_len(ar, enctype); + skb_put(skb, mic_len); } } @@ -6570,17 +6660,26 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: arvif->vdev_type = WMI_VDEV_TYPE_STA; + if (vif->p2p) + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT; break; case NL80211_IFTYPE_MESH_POINT: arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; fallthrough; case NL80211_IFTYPE_AP: arvif->vdev_type = WMI_VDEV_TYPE_AP; + if (vif->p2p) + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO; break; case NL80211_IFTYPE_MONITOR: arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; ar->monitor_vdev_id = bit; break; + case NL80211_IFTYPE_P2P_DEVICE: + arvif->vdev_type = WMI_VDEV_TYPE_STA; + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; + break; + default: WARN_ON(1); break; @@ -7896,8 +7995,6 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ath11k_base *ab = ar->ab; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); int ret; - struct cur_regulatory_info *reg_info; - enum ieee80211_ap_reg_power power_type; mutex_lock(&ar->conf_mutex); @@ -7908,17 +8005,6 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, if (ath11k_wmi_supports_6ghz_cc_ext(ar) && ctx->def.chan->band == NL80211_BAND_6GHZ && arvif->vdev_type == WMI_VDEV_TYPE_STA) { - reg_info = &ab->reg_info_store[ar->pdev_idx]; - power_type = vif->bss_conf.power_type; - - ath11k_dbg(ab, ATH11K_DBG_MAC, "chanctx power type %d\n", power_type); - - if (power_type == IEEE80211_REG_UNSET_AP) { - ret = -EINVAL; - goto out; - } - - ath11k_reg_handle_chan_list(ab, reg_info, power_type); arvif->chanctx = *ctx; ath11k_mac_parse_tx_pwr_env(ar, vif, ctx); } @@ -8772,12 +8858,8 @@ ath11k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ieee80211_wake_queues(ar->hw); if (ar->ab->hw_params.current_cc_support && - ar->alpha2[0] != 0 && ar->alpha2[1] != 0) { - struct wmi_set_current_country_params set_current_param = {}; - - memcpy(&set_current_param.alpha2, ar->alpha2, 2); - ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); - } + ar->alpha2[0] != 0 && ar->alpha2[1] != 0) + ath11k_reg_set_cc(ar); if (ab->is_reset) { recovery_count = atomic_inc_return(&ab->recovery_count); @@ -9255,9 +9337,11 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw, arg->dwell_time_passive = scan_time_msec; arg->max_scan_time = scan_time_msec; arg->scan_f_passive = 1; - arg->scan_f_filter_prb_req = 1; arg->burst_duration = duration; + if (!ar->ab->hw_params.single_pdev_only) + arg->scan_f_filter_prb_req = 1; + ret = ath11k_start_scan(ar, arg); if (ret) { ath11k_warn(ar->ab, "failed to start roc scan: %d\n", ret); @@ -9532,6 +9616,8 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, struct ath11k *ar = hw->priv; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); + enum ieee80211_ap_reg_power power_type; + struct cur_regulatory_info *reg_info; struct ath11k_peer *peer; int ret = 0; @@ -9611,6 +9697,29 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw, ath11k_warn(ar->ab, "Unable to authorize peer %pM vdev %d: %d\n", sta->addr, arvif->vdev_id, ret); } + + if (!ret && + ath11k_wmi_supports_6ghz_cc_ext(ar) && + arvif->vdev_type == WMI_VDEV_TYPE_STA && + arvif->chanctx.def.chan && + arvif->chanctx.def.chan->band == NL80211_BAND_6GHZ) { + reg_info = &ar->ab->reg_info_store[ar->pdev_idx]; + power_type = vif->bss_conf.power_type; + + if (power_type == IEEE80211_REG_UNSET_AP) { + ath11k_warn(ar->ab, "invalid power type %d\n", + power_type); + ret = -EINVAL; + } else { + ret = ath11k_reg_handle_chan_list(ar->ab, + reg_info, + power_type); + if (ret) + ath11k_warn(ar->ab, + "failed to handle chan list with power type %d\n", + power_type); + } + } } else if (old_state == IEEE80211_STA_AUTHORIZED && new_state == IEEE80211_STA_ASSOC) { spin_lock_bh(&ar->ab->base_lock); @@ -9859,12 +9968,18 @@ static int ath11k_mac_setup_iface_combinations(struct ath11k *ar) struct ieee80211_iface_combination *combinations; struct ieee80211_iface_limit *limits; int n_limits; + bool p2p; + + p2p = ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_P2P_DEVICE); combinations = kzalloc(sizeof(*combinations), GFP_KERNEL); if (!combinations) return -ENOMEM; - n_limits = 2; + if (p2p) + n_limits = 3; + else + n_limits = 2; limits = kcalloc(n_limits, sizeof(*limits), GFP_KERNEL); if (!limits) { @@ -9872,39 +9987,29 @@ static int ath11k_mac_setup_iface_combinations(struct ath11k *ar) return -ENOMEM; } + limits[0].types |= BIT(NL80211_IFTYPE_STATION); + limits[1].types |= BIT(NL80211_IFTYPE_AP); + if (IS_ENABLED(CONFIG_MAC80211_MESH) && + ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) + limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); + + combinations[0].limits = limits; + combinations[0].n_limits = n_limits; + combinations[0].beacon_int_infra_match = true; + combinations[0].beacon_int_min_gcd = 100; + if (ab->hw_params.support_dual_stations) { limits[0].max = 2; - limits[0].types |= BIT(NL80211_IFTYPE_STATION); - limits[1].max = 1; - limits[1].types |= BIT(NL80211_IFTYPE_AP); - if (IS_ENABLED(CONFIG_MAC80211_MESH) && - ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) - limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); - combinations[0].limits = limits; - combinations[0].n_limits = 2; combinations[0].max_interfaces = ab->hw_params.num_vdevs; combinations[0].num_different_channels = 2; - combinations[0].beacon_int_infra_match = true; - combinations[0].beacon_int_min_gcd = 100; } else { limits[0].max = 1; - limits[0].types |= BIT(NL80211_IFTYPE_STATION); - limits[1].max = 16; - limits[1].types |= BIT(NL80211_IFTYPE_AP); - - if (IS_ENABLED(CONFIG_MAC80211_MESH) && - ab->hw_params.interface_modes & BIT(NL80211_IFTYPE_MESH_POINT)) - limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); - combinations[0].limits = limits; - combinations[0].n_limits = 2; combinations[0].max_interfaces = 16; combinations[0].num_different_channels = 1; - combinations[0].beacon_int_infra_match = true; - combinations[0].beacon_int_min_gcd = 100; combinations[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | BIT(NL80211_CHAN_WIDTH_40) | @@ -9913,6 +10018,13 @@ static int ath11k_mac_setup_iface_combinations(struct ath11k *ar) BIT(NL80211_CHAN_WIDTH_160); } + if (p2p) { + limits[1].types |= BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); + limits[2].max = 1; + limits[2].types |= BIT(NL80211_IFTYPE_P2P_DEVICE); + } + ar->hw->wiphy->iface_combinations = combinations; ar->hw->wiphy->n_iface_combinations = 1; @@ -10029,6 +10141,7 @@ static int __ath11k_mac_register(struct ath11k *ar) if (ret) goto err; + wiphy_read_of_freq_limits(ar->hw->wiphy); ath11k_mac_setup_ht_vht_cap(ar, cap, &ht_cap); ath11k_mac_setup_he_cap(ar, cap); @@ -10215,11 +10328,8 @@ static int __ath11k_mac_register(struct ath11k *ar) } if (ab->hw_params.current_cc_support && ab->new_alpha2[0]) { - struct wmi_set_current_country_params set_current_param = {}; - - memcpy(&set_current_param.alpha2, ab->new_alpha2, 2); memcpy(&ar->alpha2, ab->new_alpha2, 2); - ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + ret = ath11k_reg_set_cc(ar); if (ret) ath11k_warn(ar->ab, "failed set cc code for mac register: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index fb4ecf9a10..ab182690ae 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -19,6 +19,7 @@ #define MHI_TIMEOUT_DEFAULT_MS 20000 #define RDDM_DUMP_SIZE 0x420000 +#define MHI_CB_INVALID 0xff static const struct mhi_channel_config ath11k_mhi_channels_qca6390[] = { { @@ -158,9 +159,8 @@ void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab) ath11k_dbg(ab, ATH11K_DBG_PCI, "mhistatus 0x%x\n", val); - /* Observed on QCA6390 that after SOC_GLOBAL_RESET, MHISTATUS - * has SYSERR bit set and thus need to set MHICTRL_RESET - * to clear SYSERR. + /* After SOC_GLOBAL_RESET, MHISTATUS may still have SYSERR bit set + * and thus need to set MHICTRL_RESET to clear SYSERR. */ ath11k_pcic_write32(ab, MHICTRL, MHICTRL_RESET_MASK); @@ -269,6 +269,7 @@ static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, enum mhi_callback cb) { struct ath11k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev); + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ath11k_dbg(ab, ATH11K_DBG_BOOT, "notify status reason %s\n", ath11k_mhi_op_callback_to_str(cb)); @@ -279,12 +280,21 @@ static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl, break; case MHI_CB_EE_RDDM: ath11k_warn(ab, "firmware crashed: MHI_CB_EE_RDDM\n"); + if (ab_pci->mhi_pre_cb == MHI_CB_EE_RDDM) { + ath11k_dbg(ab, ATH11K_DBG_BOOT, + "do not queue again for consecutive RDDM event\n"); + break; + } + if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags))) queue_work(ab->workqueue_aux, &ab->reset_work); + break; default: break; } + + ab_pci->mhi_pre_cb = cb; } static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl, @@ -397,6 +407,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) goto free_controller; } + ab_pci->mhi_pre_cb = MHI_CB_INVALID; ret = mhi_register_controller(mhi_ctrl, ath11k_mhi_config); if (ret) { ath11k_err(ab, "failed to register to mhi bus, err = %d\n", ret); @@ -442,9 +453,17 @@ int ath11k_mhi_start(struct ath11k_pci *ab_pci) return 0; } -void ath11k_mhi_stop(struct ath11k_pci *ab_pci) +void ath11k_mhi_stop(struct ath11k_pci *ab_pci, bool is_suspend) { - mhi_power_down(ab_pci->mhi_ctrl, true); + /* During suspend we need to use mhi_power_down_keep_dev() + * workaround, otherwise ath11k_core_resume() will timeout + * during resume. + */ + if (is_suspend) + mhi_power_down_keep_dev(ab_pci->mhi_ctrl, true); + else + mhi_power_down(ab_pci->mhi_ctrl, true); + mhi_unprepare_after_power_down(ab_pci->mhi_ctrl); } diff --git a/drivers/net/wireless/ath/ath11k/mhi.h b/drivers/net/wireless/ath/ath11k/mhi.h index f81fba2644..2d567705e7 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.h +++ b/drivers/net/wireless/ath/ath11k/mhi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH11K_MHI_H #define _ATH11K_MHI_H @@ -18,7 +18,7 @@ #define MHICTRL_RESET_MASK 0x2 int ath11k_mhi_start(struct ath11k_pci *ar_pci); -void ath11k_mhi_stop(struct ath11k_pci *ar_pci); +void ath11k_mhi_stop(struct ath11k_pci *ar_pci, bool is_suspend); int ath11k_mhi_register(struct ath11k_pci *ar_pci); void ath11k_mhi_unregister(struct ath11k_pci *ar_pci); void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab); @@ -26,5 +26,4 @@ void ath11k_mhi_clear_vector(struct ath11k_base *ab); int ath11k_mhi_suspend(struct ath11k_pci *ar_pci); int ath11k_mhi_resume(struct ath11k_pci *ar_pci); - #endif diff --git a/drivers/net/wireless/ath/ath11k/p2p.c b/drivers/net/wireless/ath/ath11k/p2p.c new file mode 100644 index 0000000000..01e14523f1 --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/p2p.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "core.h" +#include "wmi.h" +#include "mac.h" +#include "p2p.h" + +static void ath11k_p2p_noa_ie_fill(u8 *data, size_t len, + const struct ath11k_wmi_p2p_noa_info *noa) +{ + struct ieee80211_p2p_noa_attr *noa_attr; + u8 noa_descriptors, ctwindow; + bool oppps; + __le16 *noa_attr_len; + u16 attr_len; + int i; + + ctwindow = u32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_CTWIN_TU); + oppps = u32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS); + noa_descriptors = u32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_DESC_NUM); + + /* P2P IE */ + data[0] = WLAN_EID_VENDOR_SPECIFIC; + data[1] = len - 2; + data[2] = (WLAN_OUI_WFA >> 16) & 0xff; + data[3] = (WLAN_OUI_WFA >> 8) & 0xff; + data[4] = (WLAN_OUI_WFA >> 0) & 0xff; + data[5] = WLAN_OUI_TYPE_WFA_P2P; + + /* NOA ATTR */ + data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE; + noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */ + noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9]; + + noa_attr->index = u32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_INDEX); + noa_attr->oppps_ctwindow = ctwindow; + if (oppps) + noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT; + + for (i = 0; i < noa_descriptors; i++) { + noa_attr->desc[i].count = noa->descriptors[i].type_count; + noa_attr->desc[i].duration = + cpu_to_le32(noa->descriptors[i].duration); + noa_attr->desc[i].interval = + cpu_to_le32(noa->descriptors[i].interval); + noa_attr->desc[i].start_time = + cpu_to_le32(noa->descriptors[i].start_time); + } + + attr_len = 2; /* index + oppps_ctwindow */ + attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc); + *noa_attr_len = __cpu_to_le16(attr_len); +} + +static size_t +ath11k_p2p_noa_ie_len_compute(const struct ath11k_wmi_p2p_noa_info *noa) +{ + size_t len = 0; + u8 noa_descriptors = u32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_DESC_NUM); + + if (!(noa_descriptors) && + !(u32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS))) + return 0; + + len += 1 + 1 + 4; /* EID + len + OUI */ + len += 1 + 2; /* noa attr + attr len */ + len += 1 + 1; /* index + oppps_ctwindow */ + len += noa_descriptors * + sizeof(struct ieee80211_p2p_noa_desc); + + return len; +} + +static void ath11k_p2p_noa_ie_assign(struct ath11k_vif *arvif, void *ie, + size_t len) +{ + struct ath11k *ar = arvif->ar; + + lockdep_assert_held(&ar->data_lock); + + kfree(arvif->u.ap.noa_data); + + arvif->u.ap.noa_data = ie; + arvif->u.ap.noa_len = len; +} + +static void __ath11k_p2p_noa_update(struct ath11k_vif *arvif, + const struct ath11k_wmi_p2p_noa_info *noa) +{ + struct ath11k *ar = arvif->ar; + void *ie; + size_t len; + + lockdep_assert_held(&ar->data_lock); + + ath11k_p2p_noa_ie_assign(arvif, NULL, 0); + + len = ath11k_p2p_noa_ie_len_compute(noa); + if (!len) + return; + + ie = kmalloc(len, GFP_ATOMIC); + if (!ie) + return; + + ath11k_p2p_noa_ie_fill(ie, len, noa); + ath11k_p2p_noa_ie_assign(arvif, ie, len); } + +void ath11k_p2p_noa_update(struct ath11k_vif *arvif, + const struct ath11k_wmi_p2p_noa_info *noa) +{ + struct ath11k *ar = arvif->ar; + + spin_lock_bh(&ar->data_lock); + __ath11k_p2p_noa_update(arvif, noa); + spin_unlock_bh(&ar->data_lock); +} + +static void ath11k_p2p_noa_update_vdev_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); + struct ath11k_p2p_noa_arg *arg = data; + + if (arvif->vdev_id != arg->vdev_id) + return; + + ath11k_p2p_noa_update(arvif, arg->noa); +} + +void ath11k_p2p_noa_update_by_vdev_id(struct ath11k *ar, u32 vdev_id, + const struct ath11k_wmi_p2p_noa_info *noa) +{ + struct ath11k_p2p_noa_arg arg = { + .vdev_id = vdev_id, + .noa = noa, + }; + + ieee80211_iterate_active_interfaces_atomic(ar->hw, + IEEE80211_IFACE_ITER_NORMAL, + ath11k_p2p_noa_update_vdev_iter, + &arg); +} diff --git a/drivers/net/wireless/ath/ath11k/p2p.h b/drivers/net/wireless/ath/ath11k/p2p.h new file mode 100644 index 0000000000..d907940a9b --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/p2p.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef ATH11K_P2P_H +#define ATH11K_P2P_H + +#include "wmi.h" + +struct ath11k_wmi_p2p_noa_info; + +struct ath11k_p2p_noa_arg { + u32 vdev_id; + const struct ath11k_wmi_p2p_noa_info *noa; +}; + +void ath11k_p2p_noa_update(struct ath11k_vif *arvif, + const struct ath11k_wmi_p2p_noa_info *noa); +void ath11k_p2p_noa_update_by_vdev_id(struct ath11k *ar, u32 vdev_id, + const struct ath11k_wmi_p2p_noa_info *noa); +#endif diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index be9d2c69cc..8d63b84d12 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -638,7 +638,7 @@ static int ath11k_pci_power_up(struct ath11k_base *ab) return 0; } -static void ath11k_pci_power_down(struct ath11k_base *ab) +static void ath11k_pci_power_down(struct ath11k_base *ab, bool is_suspend) { struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); @@ -649,7 +649,7 @@ static void ath11k_pci_power_down(struct ath11k_base *ab) ath11k_pci_msi_disable(ab_pci); - ath11k_mhi_stop(ab_pci); + ath11k_mhi_stop(ab_pci, is_suspend); clear_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags); ath11k_pci_sw_reset(ab_pci->ab, false); } @@ -970,7 +970,7 @@ static void ath11k_pci_remove(struct pci_dev *pdev) ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { - ath11k_pci_power_down(ab); + ath11k_pci_power_down(ab, false); ath11k_debugfs_soc_destroy(ab); ath11k_qmi_deinit_service(ab); goto qmi_fail; @@ -998,7 +998,7 @@ static void ath11k_pci_shutdown(struct pci_dev *pdev) struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); ath11k_pci_set_irq_affinity_hint(ab_pci, NULL); - ath11k_pci_power_down(ab); + ath11k_pci_power_down(ab, false); } static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev) @@ -1035,9 +1035,39 @@ static __maybe_unused int ath11k_pci_pm_resume(struct device *dev) return ret; } -static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops, - ath11k_pci_pm_suspend, - ath11k_pci_pm_resume); +static __maybe_unused int ath11k_pci_pm_suspend_late(struct device *dev) +{ + struct ath11k_base *ab = dev_get_drvdata(dev); + int ret; + + ret = ath11k_core_suspend_late(ab); + if (ret) + ath11k_warn(ab, "failed to late suspend core: %d\n", ret); + + /* Similar to ath11k_pci_pm_suspend(), we return success here + * even error happens, to allow system suspend/hibernation survive. + */ + return 0; +} + +static __maybe_unused int ath11k_pci_pm_resume_early(struct device *dev) +{ + struct ath11k_base *ab = dev_get_drvdata(dev); + int ret; + + ret = ath11k_core_resume_early(ab); + if (ret) + ath11k_warn(ab, "failed to early resume core: %d\n", ret); + + return ret; +} + +static const struct dev_pm_ops __maybe_unused ath11k_pci_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ath11k_pci_pm_suspend, + ath11k_pci_pm_resume) + SET_LATE_SYSTEM_SLEEP_PM_OPS(ath11k_pci_pm_suspend_late, + ath11k_pci_pm_resume_early) +}; static struct pci_driver ath11k_pci_driver = { .name = "ath11k_pci", diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h index 6be73333d9..c33c786514 100644 --- a/drivers/net/wireless/ath/ath11k/pci.h +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -64,6 +64,7 @@ struct ath11k_pci { char amss_path[100]; struct mhi_controller *mhi_ctrl; const struct ath11k_msi_config *msi_config; + enum mhi_callback mhi_pre_cb; u32 register_window; /* protects register_window above */ diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c index add4db4c50..debe7c5919 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.c +++ b/drivers/net/wireless/ath/ath11k/pcic.c @@ -316,6 +316,7 @@ static void ath11k_pcic_free_ext_irq(struct ath11k_base *ab) free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); netif_napi_del(&irq_grp->napi); + free_netdev(irq_grp->napi_ndev); } } @@ -558,8 +559,9 @@ ath11k_pcic_get_msi_irq(struct ath11k_base *ab, unsigned int vector) static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) { - int i, j, ret, num_vectors = 0; + int i, j, n, ret, num_vectors = 0; u32 user_base_data = 0, base_vector = 0; + struct ath11k_ext_irq_grp *irq_grp; unsigned long irq_flags; ret = ath11k_pcic_get_user_msi_assignment(ab, "DP", &num_vectors, @@ -573,13 +575,18 @@ static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) irq_flags |= IRQF_NOBALANCING; for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { - struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; + irq_grp = &ab->ext_irq_grp[i]; u32 num_irq = 0; irq_grp->ab = ab; irq_grp->grp_id = i; - init_dummy_netdev(&irq_grp->napi_ndev); - netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, + irq_grp->napi_ndev = alloc_netdev_dummy(0); + if (!irq_grp->napi_ndev) { + ret = -ENOMEM; + goto fail_allocate; + } + + netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi, ath11k_pcic_ext_grp_napi_poll); if (ab->hw_params.ring_mask->tx[i] || @@ -601,8 +608,10 @@ static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) int vector = (i % num_vectors) + base_vector; int irq = ath11k_pcic_get_msi_irq(ab, vector); - if (irq < 0) - return irq; + if (irq < 0) { + ret = irq; + goto fail_irq; + } ab->irq_num[irq_idx] = irq; @@ -615,6 +624,10 @@ static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) if (ret) { ath11k_err(ab, "failed request irq %d: %d\n", vector, ret); + for (n = 0; n <= i; n++) { + irq_grp = &ab->ext_irq_grp[n]; + free_netdev(irq_grp->napi_ndev); + } return ret; } } @@ -622,6 +635,15 @@ static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) } return 0; +fail_irq: + /* i ->napi_ndev was properly allocated. Free it also */ + i += 1; +fail_allocate: + for (n = 0; n < i; n++) { + irq_grp = &ab->ext_irq_grp[n]; + free_netdev(irq_grp->napi_ndev); + } + return ret; } int ath11k_pcic_config_irq(struct ath11k_base *ab) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 5006f81f77..d4a243b64f 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2877,7 +2877,7 @@ int ath11k_qmi_fwreset_from_cold_boot(struct ath11k_base *ab) } /* reset the firmware */ - ath11k_hif_power_down(ab); + ath11k_hif_power_down(ab, false); ath11k_hif_power_up(ab); ath11k_dbg(ab, ATH11K_DBG_QMI, "exit wait for cold boot done\n"); return 0; diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index 737fcd450d..39232b8f52 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -49,7 +49,6 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct wmi_init_country_params init_country_param; - struct wmi_set_current_country_params set_current_param = {}; struct ath11k *ar = hw->priv; int ret; @@ -83,9 +82,8 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) * reg info */ if (ar->ab->hw_params.current_cc_support) { - memcpy(&set_current_param.alpha2, request->alpha2, 2); - memcpy(&ar->alpha2, &set_current_param.alpha2, 2); - ret = ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); + memcpy(&ar->alpha2, request->alpha2, 2); + ret = ath11k_reg_set_cc(ar); if (ret) ath11k_warn(ar->ab, "failed set current country code: %d\n", ret); @@ -1017,3 +1015,11 @@ void ath11k_reg_free(struct ath11k_base *ab) kfree(ab->new_regd[i]); } } + +int ath11k_reg_set_cc(struct ath11k *ar) +{ + struct wmi_set_current_country_params set_current_param = {}; + + memcpy(&set_current_param.alpha2, ar->alpha2, 2); + return ath11k_wmi_send_set_current_country_cmd(ar, &set_current_param); +} diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h index 64edb79426..263ea90619 100644 --- a/drivers/net/wireless/ath/ath11k/reg.h +++ b/drivers/net/wireless/ath/ath11k/reg.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_REG_H @@ -45,5 +45,5 @@ ath11k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type); int ath11k_reg_handle_chan_list(struct ath11k_base *ab, struct cur_regulatory_info *reg_info, enum ieee80211_ap_reg_power power_type); - +int ath11k_reg_set_cc(struct ath11k *ar); #endif diff --git a/drivers/net/wireless/ath/ath11k/thermal.c b/drivers/net/wireless/ath/ath11k/thermal.c index 41e7499f07..18d6eab5cc 100644 --- a/drivers/net/wireless/ath/ath11k/thermal.c +++ b/drivers/net/wireless/ath/ath11k/thermal.c @@ -101,7 +101,7 @@ static ssize_t ath11k_thermal_show_temp(struct device *dev, spin_unlock_bh(&ar->data_lock); /* display in millidegree Celsius */ - ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000); + ret = sysfs_emit(buf, "%d\n", temperature * 1000); out: mutex_unlock(&ar->conf_mutex); return ret; diff --git a/drivers/net/wireless/ath/ath11k/trace.h b/drivers/net/wireless/ath/ath11k/trace.h index 235ab8ea71..75246b0a82 100644 --- a/drivers/net/wireless/ath/ath11k/trace.h +++ b/drivers/net/wireless/ath/ath11k/trace.h @@ -48,8 +48,8 @@ TRACE_EVENT(ath11k_htt_pktlog, ), TP_fast_assign( - __assign_str(device, dev_name(ar->ab->dev)); - __assign_str(driver, dev_driver_string(ar->ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->buf_len = buf_len; __entry->pktlog_checksum = pktlog_checksum; memcpy(__get_dynamic_array(pktlog), buf, buf_len); @@ -77,8 +77,8 @@ TRACE_EVENT(ath11k_htt_ppdu_stats, ), TP_fast_assign( - __assign_str(device, dev_name(ar->ab->dev)); - __assign_str(driver, dev_driver_string(ar->ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = len; memcpy(__get_dynamic_array(ppdu), data, len); ), @@ -105,8 +105,8 @@ TRACE_EVENT(ath11k_htt_rxdesc, ), TP_fast_assign( - __assign_str(device, dev_name(ar->ab->dev)); - __assign_str(driver, dev_driver_string(ar->ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = len; __entry->log_type = log_type; memcpy(__get_dynamic_array(rxdesc), data, len); @@ -130,8 +130,8 @@ DECLARE_EVENT_CLASS(ath11k_log_event, __vstring(msg, vaf->fmt, vaf->va) ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(device); + __assign_str(driver); __assign_vstr(msg, vaf->fmt, vaf->va); ), TP_printk( @@ -171,8 +171,8 @@ TRACE_EVENT(ath11k_wmi_cmd, ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->id = id; __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); @@ -201,8 +201,8 @@ TRACE_EVENT(ath11k_wmi_event, ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->id = id; __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); @@ -230,8 +230,8 @@ TRACE_EVENT(ath11k_log_dbg, ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->level = level; WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), ATH11K_MSG_MAX, vaf->fmt, @@ -262,10 +262,10 @@ TRACE_EVENT(ath11k_log_dbg_dump, ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); - __assign_str(msg, msg); - __assign_str(prefix, prefix); + __assign_str(device); + __assign_str(driver); + __assign_str(msg); + __assign_str(prefix); __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); ), @@ -292,8 +292,8 @@ TRACE_EVENT(ath11k_wmi_diag, ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = len; memcpy(__get_dynamic_array(data), data, len); ), @@ -318,8 +318,8 @@ TRACE_EVENT(ath11k_ps_timekeeper, __field(u32, peer_ps_timestamp) ), - TP_fast_assign(__assign_str(device, dev_name(ar->ab->dev)); - __assign_str(driver, dev_driver_string(ar->ab->dev)); + TP_fast_assign(__assign_str(device); + __assign_str(driver); memcpy(__get_dynamic_array(peer_addr), peer_addr, ETH_ALEN); __entry->peer_ps_state = peer_ps_state; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 34ab9631ff..6ff01c45f1 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -20,6 +20,7 @@ #include "hw.h" #include "peer.h" #include "testmode.h" +#include "p2p.h" struct wmi_tlv_policy { size_t min_len; @@ -154,6 +155,10 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_per_chain_rssi_stats) }, [WMI_TAG_TWT_ADD_DIALOG_COMPLETE_EVENT] = { .min_len = sizeof(struct wmi_twt_add_dialog_event) }, + [WMI_TAG_P2P_NOA_INFO] = { + .min_len = sizeof(struct ath11k_wmi_p2p_noa_info) }, + [WMI_TAG_P2P_NOA_EVENT] = { + .min_len = sizeof(struct wmi_p2p_noa_event) }, }; #define PRIMAP(_hw_mode_) \ @@ -981,7 +986,7 @@ int ath11k_wmi_vdev_start(struct ath11k *ar, struct wmi_vdev_start_req_arg *arg, FIELD_PREP(WMI_TLV_LEN, 0); /* Note: This is a nested TLV containing: - * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv].. + * [wmi_tlv][ath11k_wmi_p2p_noa_descriptor][wmi_tlv].. */ ptr += sizeof(*tlv); @@ -1704,6 +1709,45 @@ int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, return ret; } +int ath11k_wmi_p2p_go_bcn_ie(struct ath11k *ar, u32 vdev_id, + const u8 *p2p_ie) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_p2p_go_set_beacon_ie_cmd *cmd; + size_t p2p_ie_len, aligned_len; + struct wmi_tlv *tlv; + struct sk_buff *skb; + int ret, len; + + p2p_ie_len = p2p_ie[1] + 2; + aligned_len = roundup(p2p_ie_len, 4); + + len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_p2p_go_set_beacon_ie_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_P2P_GO_SET_BEACON_IE) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; + cmd->ie_buf_len = p2p_ie_len; + + tlv = (struct wmi_tlv *)cmd->tlv; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | + FIELD_PREP(WMI_TLV_LEN, aligned_len); + memcpy(tlv->value, p2p_ie, p2p_ie_len); + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_P2P_GO_SET_BEACON_IE); + if (ret) { + ath11k_warn(ar->ab, "failed to send WMI_P2P_GO_SET_BEACON_IE\n"); + dev_kfree_skb(skb); + } + + return ret; +} + int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, struct sk_buff *bcn, u32 ema_params) @@ -4020,7 +4064,8 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk switch (ev->evt_type) { case WMI_BSS_COLOR_COLLISION_DETECTION: - ieee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap); + ieee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap, + 0); ath11k_dbg(ab, ATH11K_DBG_WMI, "OBSS color collision detected vdev:%d, event:%d, bitmap:%08llx\n", ev->vdev_id, ev->evt_type, ev->obss_color_bitmap); @@ -8606,6 +8651,58 @@ exit: kfree(tb); } +static void ath11k_wmi_p2p_noa_event(struct ath11k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_p2p_noa_event *ev; + const struct ath11k_wmi_p2p_noa_info *noa; + struct ath11k *ar; + int vdev_id; + u8 noa_descriptors; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ath11k_warn(ab, "failed to parse tlv: %ld\n", PTR_ERR(tb)); + return; + } + + ev = tb[WMI_TAG_P2P_NOA_EVENT]; + noa = tb[WMI_TAG_P2P_NOA_INFO]; + + if (!ev || !noa) + goto out; + + vdev_id = ev->vdev_id; + noa_descriptors = u32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_DESC_NUM); + + if (noa_descriptors > WMI_P2P_MAX_NOA_DESCRIPTORS) { + ath11k_warn(ab, "invalid descriptor num %d in P2P NoA event\n", + noa_descriptors); + goto out; + } + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "wmi tlv p2p noa vdev_id %i descriptors %u\n", + vdev_id, noa_descriptors); + + rcu_read_lock(); + ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id); + if (!ar) { + ath11k_warn(ab, "invalid vdev id %d in P2P NoA event\n", + vdev_id); + goto unlock; + } + + ath11k_p2p_noa_update_by_vdev_id(ar, vdev_id, noa); + +unlock: + rcu_read_unlock(); +out: + kfree(tb); +} + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -8733,6 +8830,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_GTK_OFFLOAD_STATUS_EVENTID: ath11k_wmi_gtk_offload_status_event(ab, skb); break; + case WMI_P2P_NOA_EVENTID: + ath11k_wmi_p2p_noa_event(ab, skb); + break; default: ath11k_dbg(ab, ATH11K_DBG_WMI, "unsupported event id 0x%x\n", id); break; diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index bb419e3abb..8982b909c8 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH11K_WMI_H @@ -60,13 +60,9 @@ struct wmi_tlv { #define WLAN_SCAN_MAX_HINT_BSSID 10 #define MAX_RNR_BSS 5 -#define WLAN_SCAN_MAX_HINT_S_SSID 10 -#define WLAN_SCAN_MAX_HINT_BSSID 10 -#define MAX_RNR_BSS 5 - #define WLAN_SCAN_PARAMS_MAX_SSID 16 #define WLAN_SCAN_PARAMS_MAX_BSSID 4 -#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 +#define WLAN_SCAN_PARAMS_MAX_IE_LEN 512 #define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1 @@ -3444,34 +3440,6 @@ struct wmi_bssid_arg { const u8 *bssid; }; -struct wmi_start_scan_arg { - u32 scan_id; - u32 scan_req_id; - u32 vdev_id; - u32 scan_priority; - u32 notify_scan_events; - u32 dwell_time_active; - u32 dwell_time_passive; - u32 min_rest_time; - u32 max_rest_time; - u32 repeat_probe_time; - u32 probe_spacing_time; - u32 idle_time; - u32 max_scan_time; - u32 probe_delay; - u32 scan_ctrl_flags; - - u32 ie_len; - u32 n_channels; - u32 n_ssids; - u32 n_bssids; - - u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN]; - u32 channels[64]; - struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID]; - struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID]; -}; - #define WMI_SCAN_STOP_ONE 0x00000000 #define WMI_SCN_STOP_VAP_ALL 0x01000000 #define WMI_SCAN_STOP_ALL 0x04000000 @@ -3630,6 +3598,37 @@ struct wmi_ftm_event_msg { u8 data[]; } __packed; +#define WMI_P2P_MAX_NOA_DESCRIPTORS 4 + +struct wmi_p2p_noa_event { + u32 vdev_id; +} __packed; + +struct ath11k_wmi_p2p_noa_descriptor { + u32 type_count; /* 255: continuous schedule, 0: reserved */ + u32 duration; /* Absent period duration in micro seconds */ + u32 interval; /* Absent period interval in micro seconds */ + u32 start_time; /* 32 bit tsf time when in starts */ +} __packed; + +#define WMI_P2P_NOA_INFO_CHANGED_FLAG BIT(0) +#define WMI_P2P_NOA_INFO_INDEX GENMASK(15, 8) +#define WMI_P2P_NOA_INFO_OPP_PS BIT(16) +#define WMI_P2P_NOA_INFO_CTWIN_TU GENMASK(23, 17) +#define WMI_P2P_NOA_INFO_DESC_NUM GENMASK(31, 24) + +struct ath11k_wmi_p2p_noa_info { + /* Bit 0 - Flag to indicate an update in NOA schedule + * Bits 7-1 - Reserved + * Bits 15-8 - Index (identifies the instance of NOA sub element) + * Bit 16 - Opp PS state of the AP + * Bits 23-17 - Ctwindow in TUs + * Bits 31-24 - Number of NOA descriptors + */ + u32 noa_attr; + struct ath11k_wmi_p2p_noa_descriptor descriptors[WMI_P2P_MAX_NOA_DESCRIPTORS]; +} __packed; + #define WMI_BEACON_TX_BUFFER_SIZE 512 #define WMI_EMA_TMPL_IDX_SHIFT 8 @@ -3653,6 +3652,13 @@ struct wmi_bcn_tmpl_cmd { u32 ema_params; } __packed; +struct wmi_p2p_go_set_beacon_ie_cmd { + u32 tlv_header; + u32 vdev_id; + u32 ie_buf_len; + u8 tlv[]; +} __packed; + struct wmi_key_seq_counter { u32 key_seq_counter_l; u32 key_seq_counter_h; @@ -5740,8 +5746,6 @@ struct wmi_debug_log_config_cmd_fixed_param { u32 value; } __packed; -#define WMI_MAX_MEM_REQS 32 - #define MAX_RADIOS 3 #define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ) @@ -6349,6 +6353,8 @@ int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len); int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, struct sk_buff *frame); +int ath11k_wmi_p2p_go_bcn_ie(struct ath11k *ar, u32 vdev_id, + const u8 *p2p_ie); int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, struct sk_buff *bcn, u32 ema_param); diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig index e135d2b1b6..eceab9153e 100644 --- a/drivers/net/wireless/ath/ath12k/Kconfig +++ b/drivers/net/wireless/ath/ath12k/Kconfig @@ -24,6 +24,15 @@ config ATH12K_DEBUG If unsure, say Y to make it easier to debug problems. But if you want optimal performance choose N. +config ATH12K_DEBUGFS + bool "QTI ath12k debugfs support" + depends on ATH12K && MAC80211_DEBUGFS + help + Enable ath12k debugfs support + + If unsure, say Y to make it easier to debug problems. But if + you want optimal performance choose N. + config ATH12K_TRACING bool "ath12k tracing support" depends on ATH12K && EVENT_TRACING diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile index 71669f94ff..d42480db74 100644 --- a/drivers/net/wireless/ath/ath12k/Makefile +++ b/drivers/net/wireless/ath/ath12k/Makefile @@ -23,6 +23,8 @@ ath12k-y += core.o \ fw.o \ p2p.o +ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o +ath12k-$(CONFIG_ACPI) += acpi.o ath12k-$(CONFIG_ATH12K_TRACING) += trace.o # for tracing framework to find trace.h diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c new file mode 100644 index 0000000000..0555d35aab --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/acpi.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "core.h" +#include "acpi.h" +#include "debug.h" + +static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func) +{ + union acpi_object *obj; + acpi_handle root_handle; + int ret; + + root_handle = ACPI_HANDLE(ab->dev); + if (!root_handle) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, "invalid acpi handler\n"); + return -EOPNOTSUPP; + } + + obj = acpi_evaluate_dsm(root_handle, ab->hw_params->acpi_guid, 0, func, + NULL); + + if (!obj) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi_evaluate_dsm() failed\n"); + return -ENOENT; + } + + if (obj->type == ACPI_TYPE_INTEGER) { + ab->acpi.func_bit = obj->integer.value; + } else if (obj->type == ACPI_TYPE_BUFFER) { + switch (func) { + case ATH12K_ACPI_DSM_FUNC_TAS_CFG: + if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) { + ath12k_warn(ab, "invalid ACPI DSM TAS config size: %d\n", + obj->buffer.length); + ret = -EINVAL; + goto out; + } + + memcpy(&ab->acpi.tas_cfg, obj->buffer.pointer, + obj->buffer.length); + + break; + case ATH12K_ACPI_DSM_FUNC_TAS_DATA: + if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_DATA_SIZE) { + ath12k_warn(ab, "invalid ACPI DSM TAS data size: %d\n", + obj->buffer.length); + ret = -EINVAL; + goto out; + } + + memcpy(&ab->acpi.tas_sar_power_table, obj->buffer.pointer, + obj->buffer.length); + + break; + case ATH12K_ACPI_DSM_FUNC_BIOS_SAR: + if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) { + ath12k_warn(ab, "invalid ACPI BIOS SAR data size: %d\n", + obj->buffer.length); + ret = -EINVAL; + goto out; + } + + memcpy(&ab->acpi.bios_sar_data, obj->buffer.pointer, + obj->buffer.length); + + break; + case ATH12K_ACPI_DSM_FUNC_GEO_OFFSET: + if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) { + ath12k_warn(ab, "invalid ACPI GEO OFFSET data size: %d\n", + obj->buffer.length); + ret = -EINVAL; + goto out; + } + + memcpy(&ab->acpi.geo_offset_data, obj->buffer.pointer, + obj->buffer.length); + + break; + case ATH12K_ACPI_DSM_FUNC_INDEX_CCA: + if (obj->buffer.length != ATH12K_ACPI_DSM_CCA_DATA_SIZE) { + ath12k_warn(ab, "invalid ACPI DSM CCA data size: %d\n", + obj->buffer.length); + ret = -EINVAL; + goto out; + } + + memcpy(&ab->acpi.cca_data, obj->buffer.pointer, + obj->buffer.length); + + break; + case ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE: + if (obj->buffer.length != ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE) { + ath12k_warn(ab, "invalid ACPI DSM band edge data size: %d\n", + obj->buffer.length); + ret = -EINVAL; + goto out; + } + + memcpy(&ab->acpi.band_edge_power, obj->buffer.pointer, + obj->buffer.length); + + break; + } + } else { + ath12k_warn(ab, "ACPI DSM method returned an unsupported object type: %d\n", + obj->type); + ret = -EINVAL; + goto out; + } + + ret = 0; + +out: + ACPI_FREE(obj); + return ret; +} + +static int ath12k_acpi_set_power_limit(struct ath12k_base *ab) +{ + const u8 *tas_sar_power_table = ab->acpi.tas_sar_power_table; + int ret; + + if (tas_sar_power_table[0] != ATH12K_ACPI_TAS_DATA_VERSION || + tas_sar_power_table[1] != ATH12K_ACPI_TAS_DATA_ENABLE) { + ath12k_warn(ab, "latest ACPI TAS data is invalid\n"); + return -EINVAL; + } + + ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE, + tas_sar_power_table, + ATH12K_ACPI_DSM_TAS_DATA_SIZE); + if (ret) { + ath12k_warn(ab, "failed to send ACPI TAS data table: %d\n", ret); + return ret; + } + + return ret; +} + +static int ath12k_acpi_set_bios_sar_power(struct ath12k_base *ab) +{ + int ret; + + if (ab->acpi.bios_sar_data[0] != ATH12K_ACPI_POWER_LIMIT_VERSION || + ab->acpi.bios_sar_data[1] != ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) { + ath12k_warn(ab, "invalid latest ACPI BIOS SAR data\n"); + return -EINVAL; + } + + ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data); + if (ret) { + ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret); + return ret; + } + + return 0; +} + +static void ath12k_acpi_dsm_notify(acpi_handle handle, u32 event, void *data) +{ + int ret; + struct ath12k_base *ab = data; + + if (event == ATH12K_ACPI_NOTIFY_EVENT) { + ath12k_warn(ab, "unknown acpi notify %u\n", event); + return; + } + + if (!ab->acpi.acpi_tas_enable) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi_tas_enable is false\n"); + return; + } + + ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA); + if (ret) { + ath12k_warn(ab, "failed to update ACPI TAS data table: %d\n", ret); + return; + } + + ret = ath12k_acpi_set_power_limit(ab); + if (ret) { + ath12k_warn(ab, "failed to set ACPI TAS power limit data: %d", ret); + return; + } + + if (!ab->acpi.acpi_bios_sar_enable) + return; + + ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR); + if (ret) { + ath12k_warn(ab, "failed to update BIOS SAR: %d\n", ret); + return; + } + + ret = ath12k_acpi_set_bios_sar_power(ab); + if (ret) { + ath12k_warn(ab, "failed to set BIOS SAR power limit: %d\n", ret); + return; + } +} + +static int ath12k_acpi_set_bios_sar_params(struct ath12k_base *ab) +{ + int ret; + + ret = ath12k_wmi_set_bios_sar_cmd(ab, ab->acpi.bios_sar_data); + if (ret) { + ath12k_warn(ab, "failed to set ACPI BIOS SAR table: %d\n", ret); + return ret; + } + + ret = ath12k_wmi_set_bios_geo_cmd(ab, ab->acpi.geo_offset_data); + if (ret) { + ath12k_warn(ab, "failed to set ACPI BIOS GEO table: %d\n", ret); + return ret; + } + + return 0; +} + +static int ath12k_acpi_set_tas_params(struct ath12k_base *ab) +{ + int ret; + + ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_CONFIG_TYPE, + ab->acpi.tas_cfg, + ATH12K_ACPI_DSM_TAS_CFG_SIZE); + if (ret) { + ath12k_warn(ab, "failed to send ACPI TAS config table parameter: %d\n", + ret); + return ret; + } + + ret = ath12k_wmi_set_bios_cmd(ab, WMI_BIOS_PARAM_TAS_DATA_TYPE, + ab->acpi.tas_sar_power_table, + ATH12K_ACPI_DSM_TAS_DATA_SIZE); + if (ret) { + ath12k_warn(ab, "failed to send ACPI TAS data table parameter: %d\n", + ret); + return ret; + } + + return 0; +} + +int ath12k_acpi_start(struct ath12k_base *ab) +{ + acpi_status status; + u8 *buf; + int ret; + + if (!ab->hw_params->acpi_guid) + /* not supported with this hardware */ + return 0; + + ab->acpi.acpi_tas_enable = false; + + ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS); + if (ret) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to get ACPI DSM data: %d\n", ret); + return ret; + } + + if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) { + ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_CFG); + if (ret) { + ath12k_warn(ab, "failed to get ACPI TAS config table: %d\n", ret); + return ret; + } + } + + if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_DATA)) { + ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_TAS_DATA); + if (ret) { + ath12k_warn(ab, "failed to get ACPI TAS data table: %d\n", ret); + return ret; + } + + if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_TAS_CFG) && + ab->acpi.tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION && + ab->acpi.tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE) + ab->acpi.acpi_tas_enable = true; + } + + if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) { + ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_BIOS_SAR); + if (ret) { + ath12k_warn(ab, "failed to get ACPI bios sar data: %d\n", ret); + return ret; + } + } + + if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) { + ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_GEO_OFFSET); + if (ret) { + ath12k_warn(ab, "failed to get ACPI geo offset data: %d\n", ret); + return ret; + } + + if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) && + ab->acpi.bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION && + ab->acpi.bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG && + !ab->acpi.acpi_tas_enable) + ab->acpi.acpi_bios_sar_enable = true; + } + + if (ab->acpi.acpi_tas_enable) { + ret = ath12k_acpi_set_tas_params(ab); + if (ret) { + ath12k_warn(ab, "failed to send ACPI parameters: %d\n", ret); + return ret; + } + } + + if (ab->acpi.acpi_bios_sar_enable) { + ret = ath12k_acpi_set_bios_sar_params(ab); + if (ret) + return ret; + } + + if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, ATH12K_ACPI_FUNC_BIT_CCA)) { + ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_CCA); + if (ret) { + ath12k_warn(ab, "failed to get ACPI DSM CCA threshold configuration: %d\n", + ret); + return ret; + } + + if (ab->acpi.cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION && + ab->acpi.cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] == + ATH12K_ACPI_CCA_THR_ENABLE_FLAG) { + buf = ab->acpi.cca_data + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET; + ret = ath12k_wmi_set_bios_cmd(ab, + WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE, + buf, + ATH12K_ACPI_CCA_THR_OFFSET_LEN); + if (ret) { + ath12k_warn(ab, "failed to set ACPI DSM CCA threshold: %d\n", + ret); + return ret; + } + } + } + + if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acpi, + ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER)) { + ret = ath12k_acpi_dsm_get_data(ab, ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE); + if (ret) { + ath12k_warn(ab, "failed to get ACPI DSM band edge channel power: %d\n", + ret); + return ret; + } + + if (ab->acpi.band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION && + ab->acpi.band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG) { + ret = ath12k_wmi_set_bios_cmd(ab, + WMI_BIOS_PARAM_TYPE_BANDEDGE, + ab->acpi.band_edge_power, + sizeof(ab->acpi.band_edge_power)); + if (ret) { + ath12k_warn(ab, + "failed to set ACPI DSM band edge channel power: %d\n", + ret); + return ret; + } + } + } + + status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev), + ACPI_DEVICE_NOTIFY, + ath12k_acpi_dsm_notify, ab); + if (ACPI_FAILURE(status)) { + ath12k_warn(ab, "failed to install DSM notify callback: %d\n", status); + return -EIO; + } + + ab->acpi.started = true; + + return 0; +} + +void ath12k_acpi_stop(struct ath12k_base *ab) +{ + if (!ab->acpi.started) + return; + + acpi_remove_notify_handler(ACPI_HANDLE(ab->dev), + ACPI_DEVICE_NOTIFY, + ath12k_acpi_dsm_notify); + + memset(&ab->acpi, 0, sizeof(ab->acpi)); +} diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h new file mode 100644 index 0000000000..39e003d86a --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/acpi.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#ifndef ATH12K_ACPI_H +#define ATH12K_ACPI_H + +#include <linux/acpi.h> + +#define ATH12K_ACPI_DSM_FUNC_SUPPORT_FUNCS 0 +#define ATH12K_ACPI_DSM_FUNC_BIOS_SAR 4 +#define ATH12K_ACPI_DSM_FUNC_GEO_OFFSET 5 +#define ATH12K_ACPI_DSM_FUNC_INDEX_CCA 6 +#define ATH12K_ACPI_DSM_FUNC_TAS_CFG 8 +#define ATH12K_ACPI_DSM_FUNC_TAS_DATA 9 +#define ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE 10 + +#define ATH12K_ACPI_FUNC_BIT_BIOS_SAR BIT(3) +#define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET BIT(4) +#define ATH12K_ACPI_FUNC_BIT_CCA BIT(5) +#define ATH12K_ACPI_FUNC_BIT_TAS_CFG BIT(7) +#define ATH12K_ACPI_FUNC_BIT_TAS_DATA BIT(8) +#define ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER BIT(9) + +#define ATH12K_ACPI_NOTIFY_EVENT 0x86 +#define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func) (((_acdata).func_bit) & (_func)) + +#define ATH12K_ACPI_TAS_DATA_VERSION 0x1 +#define ATH12K_ACPI_TAS_DATA_ENABLE 0x1 +#define ATH12K_ACPI_POWER_LIMIT_VERSION 0x1 +#define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG 0x1 +#define ATH12K_ACPI_CCA_THR_VERSION 0x1 +#define ATH12K_ACPI_CCA_THR_ENABLE_FLAG 0x1 +#define ATH12K_ACPI_BAND_EDGE_VERSION 0x1 +#define ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG 0x1 + +#define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET 1 +#define ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET 2 +#define ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET 5 +#define ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN 10 +#define ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET 12 +#define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN 18 +#define ATH12K_ACPI_BIOS_SAR_TABLE_LEN 22 +#define ATH12K_ACPI_CCA_THR_OFFSET_LEN 36 + +#define ATH12K_ACPI_DSM_TAS_DATA_SIZE 69 +#define ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE 100 +#define ATH12K_ACPI_DSM_TAS_CFG_SIZE 108 + +#define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE (ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET + \ + ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN) +#define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE (ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET + \ + ATH12K_ACPI_BIOS_SAR_TABLE_LEN) +#define ATH12K_ACPI_DSM_CCA_DATA_SIZE (ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET + \ + ATH12K_ACPI_CCA_THR_OFFSET_LEN) + +#ifdef CONFIG_ACPI + +int ath12k_acpi_start(struct ath12k_base *ab); +void ath12k_acpi_stop(struct ath12k_base *ab); + +#else + +static inline int ath12k_acpi_start(struct ath12k_base *ab) +{ + return 0; +} + +static inline void ath12k_acpi_stop(struct ath12k_base *ab) +{ +} + +#endif /* CONFIG_ACPI */ + +#endif /* ATH12K_ACPI_H */ diff --git a/drivers/net/wireless/ath/ath12k/ce.h b/drivers/net/wireless/ath/ath12k/ce.h index 79af3b6159..857bc5f9e9 100644 --- a/drivers/net/wireless/ath/ath12k/ce.h +++ b/drivers/net/wireless/ath/ath12k/ce.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_CE_H @@ -119,7 +119,7 @@ struct ath12k_ce_ring { /* Host address space */ void *base_addr_owner_space_unaligned; /* CE address space */ - u32 base_addr_ce_space_unaligned; + dma_addr_t base_addr_ce_space_unaligned; /* Actual start of descriptors. * Aligned to descriptor-size boundary. @@ -129,7 +129,7 @@ struct ath12k_ce_ring { void *base_addr_owner_space; /* CE address space */ - u32 base_addr_ce_space; + dma_addr_t base_addr_ce_space; /* HAL ring id */ u32 hal_ring_id; diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 391b6fb2bd..52969a1bb5 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -15,6 +15,7 @@ #include "debug.h" #include "hif.h" #include "fw.h" +#include "debugfs.h" unsigned int ath12k_debug_mask; module_param_named(debug_mask, ath12k_debug_mask, uint, 0644); @@ -43,67 +44,89 @@ static int ath12k_core_rfkill_config(struct ath12k_base *ab) int ath12k_core_suspend(struct ath12k_base *ab) { - int ret; + struct ath12k *ar; + int ret, i; if (!ab->hw_params->supports_suspend) return -EOPNOTSUPP; - /* TODO: there can frames in queues so for now add delay as a hack. - * Need to implement to handle and remove this delay. + for (i = 0; i < ab->num_radios; i++) { + ar = ab->pdevs[i].ar; + if (!ar) + continue; + ret = ath12k_mac_wait_tx_complete(ar); + if (ret) { + ath12k_warn(ab, "failed to wait tx complete: %d\n", ret); + return ret; + } + } + + /* PM framework skips suspend_late/resume_early callbacks + * if other devices report errors in their suspend callbacks. + * However ath12k_core_resume() would still be called because + * here we return success thus kernel put us on dpm_suspended_list. + * Since we won't go through a power down/up cycle, there is + * no chance to call complete(&ab->restart_completed) in + * ath12k_core_restart(), making ath12k_core_resume() timeout. + * So call it here to avoid this issue. This also works in case + * no error happens thus suspend_late/resume_early get called, + * because it will be reinitialized in ath12k_core_resume_early(). */ - msleep(500); + complete(&ab->restart_completed); - ret = ath12k_dp_rx_pktlog_stop(ab, true); - if (ret) { - ath12k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n", - ret); - return ret; - } + return 0; +} +EXPORT_SYMBOL(ath12k_core_suspend); - ret = ath12k_dp_rx_pktlog_stop(ab, false); - if (ret) { - ath12k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n", - ret); - return ret; - } +int ath12k_core_suspend_late(struct ath12k_base *ab) +{ + if (!ab->hw_params->supports_suspend) + return -EOPNOTSUPP; + + ath12k_acpi_stop(ab); ath12k_hif_irq_disable(ab); ath12k_hif_ce_irq_disable(ab); - ret = ath12k_hif_suspend(ab); - if (ret) { - ath12k_warn(ab, "failed to suspend hif: %d\n", ret); - return ret; - } + ath12k_hif_power_down(ab, true); return 0; } +EXPORT_SYMBOL(ath12k_core_suspend_late); -int ath12k_core_resume(struct ath12k_base *ab) +int ath12k_core_resume_early(struct ath12k_base *ab) { int ret; if (!ab->hw_params->supports_suspend) return -EOPNOTSUPP; - ret = ath12k_hif_resume(ab); - if (ret) { - ath12k_warn(ab, "failed to resume hif during resume: %d\n", ret); - return ret; - } + reinit_completion(&ab->restart_completed); + ret = ath12k_hif_power_up(ab); + if (ret) + ath12k_warn(ab, "failed to power up hif during resume: %d\n", ret); - ath12k_hif_ce_irq_enable(ab); - ath12k_hif_irq_enable(ab); + return ret; +} +EXPORT_SYMBOL(ath12k_core_resume_early); - ret = ath12k_dp_rx_pktlog_start(ab); - if (ret) { - ath12k_warn(ab, "failed to start rx pktlog during resume: %d\n", - ret); - return ret; +int ath12k_core_resume(struct ath12k_base *ab) +{ + long time_left; + + if (!ab->hw_params->supports_suspend) + return -EOPNOTSUPP; + + time_left = wait_for_completion_timeout(&ab->restart_completed, + ATH12K_RESET_TIMEOUT_HZ); + if (time_left == 0) { + ath12k_warn(ab, "timeout while waiting for restart complete"); + return -ETIMEDOUT; } return 0; } +EXPORT_SYMBOL(ath12k_core_resume); static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, size_t name_len, bool with_variant, @@ -542,6 +565,8 @@ static void ath12k_core_stop(struct ath12k_base *ab) if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags)) ath12k_qmi_firmware_stop(ab); + ath12k_acpi_stop(ab); + ath12k_hif_stop(ab); ath12k_wmi_detach(ab); ath12k_dp_rx_pdev_reo_cleanup(ab); @@ -628,6 +653,8 @@ static int ath12k_core_soc_create(struct ath12k_base *ab) return ret; } + ath12k_debugfs_soc_create(ab); + ret = ath12k_hif_power_up(ab); if (ret) { ath12k_err(ab, "failed to power up :%d\n", ret); @@ -637,6 +664,7 @@ static int ath12k_core_soc_create(struct ath12k_base *ab) return 0; err_qmi_deinit: + ath12k_debugfs_soc_destroy(ab); ath12k_qmi_deinit_service(ab); return ret; } @@ -645,6 +673,7 @@ static void ath12k_core_soc_destroy(struct ath12k_base *ab) { ath12k_dp_free(ab); ath12k_reg_free(ab); + ath12k_debugfs_soc_destroy(ab); ath12k_qmi_deinit_service(ab); } @@ -779,6 +808,11 @@ static int ath12k_core_start(struct ath12k_base *ab, goto err_reo_cleanup; } + ret = ath12k_acpi_start(ab); + if (ret) + /* ACPI is optional so continue in case of an error */ + ath12k_dbg(ab, ATH12K_DBG_BOOT, "acpi failed: %d\n", ret); + return 0; err_reo_cleanup: @@ -874,9 +908,8 @@ static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab) int ret; mutex_lock(&ab->core_lock); - ath12k_hif_irq_disable(ab); ath12k_dp_pdev_free(ab); - ath12k_hif_stop(ab); + ath12k_ce_cleanup_pipes(ab); ath12k_wmi_detach(ab); ath12k_dp_rx_pdev_reo_cleanup(ab); mutex_unlock(&ab->core_lock); @@ -1052,9 +1085,6 @@ static void ath12k_core_restart(struct work_struct *work) struct ath12k_base *ab = container_of(work, struct ath12k_base, restart_work); int ret; - if (!ab->is_reset) - ath12k_core_pre_reconfigure_recovery(ab); - ret = ath12k_core_reconfigure_on_crash(ab); if (ret) { ath12k_err(ab, "failed to reconfigure driver on crash recovery\n"); @@ -1064,8 +1094,7 @@ static void ath12k_core_restart(struct work_struct *work) if (ab->is_reset) complete_all(&ab->reconfigure_complete); - if (!ab->is_reset) - ath12k_core_post_reconfigure_recovery(ab); + complete(&ab->restart_completed); } static void ath12k_core_reset(struct work_struct *work) @@ -1131,8 +1160,10 @@ static void ath12k_core_reset(struct work_struct *work) time_left = wait_for_completion_timeout(&ab->recovery_start, ATH12K_RECOVER_START_TIMEOUT_HZ); - ath12k_hif_power_down(ab); - ath12k_qmi_free_resource(ab); + ath12k_hif_irq_disable(ab); + ath12k_hif_ce_irq_disable(ab); + + ath12k_hif_power_down(ab, false); ath12k_hif_power_up(ab); ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset started\n"); @@ -1175,7 +1206,7 @@ void ath12k_core_deinit(struct ath12k_base *ab) mutex_unlock(&ab->core_lock); - ath12k_hif_power_down(ab); + ath12k_hif_power_down(ab, false); ath12k_mac_destroy(ab); ath12k_core_soc_destroy(ab); ath12k_fw_unmap(ab); @@ -1223,11 +1254,12 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0); init_completion(&ab->htc_suspend); + init_completion(&ab->restart_completed); ab->dev = dev; ab->hif.bus = bus; ab->qmi.num_radios = U8_MAX; - ab->slo_capable = true; + ab->mlo_capable_flags = ATH12K_INTRA_DEVICE_MLO_SUPPORT; return ab; diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 97e5a0ccd2..47dde44012 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -26,6 +26,7 @@ #include "reg.h" #include "dbring.h" #include "fw.h" +#include "acpi.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -46,6 +47,7 @@ #define ATH12K_SMBIOS_BDF_EXT_MAGIC "BDF_" #define ATH12K_INVALID_HW_MAC_ID 0xFF +#define ATH12K_CONNECTION_LOSS_HZ (3 * HZ) #define ATH12K_RX_RATE_TABLE_NUM 320 #define ATH12K_RX_RATE_TABLE_11AX_NUM 576 @@ -214,6 +216,24 @@ enum ath12k_monitor_flags { ATH12K_FLAG_MONITOR_ENABLED, }; +struct ath12k_tx_conf { + bool changed; + u16 ac; + struct ieee80211_tx_queue_params tx_queue_params; +}; + +struct ath12k_key_conf { + bool changed; + enum set_key_cmd cmd; + struct ieee80211_key_conf *key; +}; + +struct ath12k_vif_cache { + struct ath12k_tx_conf tx_conf; + struct ath12k_key_conf key_conf; + u32 bss_conf_changed; +}; + struct ath12k_vif { u32 vdev_id; enum wmi_vdev_type vdev_type; @@ -251,11 +271,13 @@ struct ath12k_vif { } ap; } u; + bool is_created; bool is_started; bool is_up; u32 aid; u8 bssid[ETH_ALEN]; struct cfg80211_bitrate_mask bitrate_mask; + struct delayed_work connection_loss_work; int num_legacy_stations; int rtscts_prot_mode; int txpower; @@ -267,10 +289,12 @@ struct ath12k_vif { u8 vdev_stats_id; u32 punct_bitmap; bool ps; + struct ath12k_vif_cache *cache; }; struct ath12k_vif_iter { u32 vdev_id; + struct ath12k *ar; struct ath12k_vif *arvif; }; @@ -453,6 +477,10 @@ struct ath12k_fw_stats { struct list_head bcn; }; +struct ath12k_debug { + struct dentry *debugfs_pdev; +}; + struct ath12k_per_peer_tx_stats { u32 succ_bytes; u32 retry_bytes; @@ -592,16 +620,24 @@ struct ath12k { struct ath12k_per_peer_tx_stats cached_stats; u32 last_ppdu_id; u32 cached_ppdu_id; +#ifdef CONFIG_ATH12K_DEBUGFS + struct ath12k_debug debug; +#endif bool dfs_block_radar_events; bool monitor_conf_enabled; bool monitor_vdev_created; bool monitor_started; int monitor_vdev_id; + + u32 freq_low; + u32 freq_high; }; struct ath12k_hw { struct ieee80211_hw *hw; + bool regd_updated; + bool use_6ghz_regd; u8 num_radio; struct ath12k radio[] __aligned(sizeof(void *)); @@ -688,6 +724,21 @@ struct ath12k_soc_dp_stats { struct ath12k_soc_dp_tx_err_stats tx_err; }; +/** + * enum ath12k_link_capable_flags - link capable flags + * + * Single/Multi link capability information + * + * @ATH12K_INTRA_DEVICE_MLO_SUPPORT: SLO/MLO form between the radio, where all + * the links (radios) present within a device. + * @ATH12K_INTER_DEVICE_MLO_SUPPORT: SLO/MLO form between the radio, where all + * the links (radios) present across the devices. + */ +enum ath12k_link_capable_flags { + ATH12K_INTRA_DEVICE_MLO_SUPPORT = BIT(0), + ATH12K_INTER_DEVICE_MLO_SUPPORT = BIT(1), +}; + /* Master structure to hold the hw data which may be used in core module */ struct ath12k_base { enum ath12k_hw_rev hw_rev; @@ -782,6 +833,9 @@ struct ath12k_base { /* Current DFS Regulatory */ enum ath12k_dfs_region dfs_region; struct ath12k_soc_dp_stats soc_stats; +#ifdef CONFIG_ATH12K_DEBUGFS + struct dentry *debugfs_soc; +#endif unsigned long dev_flags; struct completion driver_recovery; @@ -843,10 +897,31 @@ struct ath12k_base { const struct hal_rx_ops *hal_rx_ops; - /* slo_capable denotes if the single/multi link operation - * is supported within the same chip (SoC). + /* mlo_capable_flags denotes the single/multi link operation + * capabilities of the Device. + * + * See enum ath12k_link_capable_flags */ - bool slo_capable; + u8 mlo_capable_flags; + + struct completion restart_completed; + +#ifdef CONFIG_ACPI + + struct { + bool started; + u32 func_bit; + bool acpi_tas_enable; + bool acpi_bios_sar_enable; + u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE]; + u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE]; + u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE]; + u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE]; + u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE]; + u8 band_edge_power[ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE]; + } acpi; + +#endif /* CONFIG_ACPI */ /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); @@ -874,8 +949,10 @@ int ath12k_core_fetch_regdb(struct ath12k_base *ab, struct ath12k_board_data *bd int ath12k_core_check_dt(struct ath12k_base *ath12k); int ath12k_core_check_smbios(struct ath12k_base *ab); void ath12k_core_halt(struct ath12k *ar); +int ath12k_core_resume_early(struct ath12k_base *ab); int ath12k_core_resume(struct ath12k_base *ab); int ath12k_core_suspend(struct ath12k_base *ab); +int ath12k_core_suspend_late(struct ath12k_base *ab); const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab, const char *filename); @@ -951,13 +1028,21 @@ static inline struct ath12k_hw *ath12k_hw_to_ah(struct ieee80211_hw *hw) return hw->priv; } -static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah) +static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah, u8 hw_link_id) { - return ah->radio; + if (WARN(hw_link_id >= ah->num_radio, + "bad hw link id %d, so switch to default link\n", hw_link_id)) + hw_link_id = 0; + + return &ah->radio[hw_link_id]; } static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar) { return ar->ah->hw; } + +#define for_each_ar(ah, ar, index) \ + for ((index) = 0; ((index) < (ah)->num_radio && \ + ((ar) = &(ah)->radio[(index)])); (index)++) #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c new file mode 100644 index 0000000000..8d8ba95109 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "core.h" +#include "debugfs.h" + +static ssize_t ath12k_write_simulate_radar(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath12k *ar = file->private_data; + int ret; + + mutex_lock(&ar->conf_mutex); + ret = ath12k_wmi_simulate_radar(ar); + if (ret) + goto exit; + + ret = count; +exit: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static const struct file_operations fops_simulate_radar = { + .write = ath12k_write_simulate_radar, + .open = simple_open +}; + +void ath12k_debugfs_soc_create(struct ath12k_base *ab) +{ + bool dput_needed; + char soc_name[64] = { 0 }; + struct dentry *debugfs_ath12k; + + debugfs_ath12k = debugfs_lookup("ath12k", NULL); + if (debugfs_ath12k) { + /* a dentry from lookup() needs dput() after we don't use it */ + dput_needed = true; + } else { + debugfs_ath12k = debugfs_create_dir("ath12k", NULL); + if (IS_ERR_OR_NULL(debugfs_ath12k)) + return; + dput_needed = false; + } + + scnprintf(soc_name, sizeof(soc_name), "%s-%s", ath12k_bus_str(ab->hif.bus), + dev_name(ab->dev)); + + ab->debugfs_soc = debugfs_create_dir(soc_name, debugfs_ath12k); + + if (dput_needed) + dput(debugfs_ath12k); +} + +void ath12k_debugfs_soc_destroy(struct ath12k_base *ab) +{ + debugfs_remove_recursive(ab->debugfs_soc); + ab->debugfs_soc = NULL; + /* We are not removing ath12k directory on purpose, even if it + * would be empty. This simplifies the directory handling and it's + * a minor cosmetic issue to leave an empty ath12k directory to + * debugfs. + */ +} + +void ath12k_debugfs_register(struct ath12k *ar) +{ + struct ath12k_base *ab = ar->ab; + struct ieee80211_hw *hw = ar->ah->hw; + char pdev_name[5]; + char buf[100] = {0}; + + scnprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx); + + ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc); + + /* Create a symlink under ieee80211/phy* */ + scnprintf(buf, sizeof(buf), "../../ath12k/%pd2", ar->debug.debugfs_pdev); + debugfs_create_symlink("ath12k", hw->wiphy->debugfsdir, buf); + + if (ar->mac.sbands[NL80211_BAND_5GHZ].channels) { + debugfs_create_file("dfs_simulate_radar", 0200, + ar->debug.debugfs_pdev, ar, + &fops_simulate_radar); + } +} diff --git a/drivers/net/wireless/ath/ath12k/debugfs.h b/drivers/net/wireless/ath/ath12k/debugfs.h new file mode 100644 index 0000000000..a62f2a550b --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/debugfs.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _ATH12K_DEBUGFS_H_ +#define _ATH12K_DEBUGFS_H_ + +#ifdef CONFIG_ATH12K_DEBUGFS +void ath12k_debugfs_soc_create(struct ath12k_base *ab); +void ath12k_debugfs_soc_destroy(struct ath12k_base *ab); +void ath12k_debugfs_register(struct ath12k *ar); + +#else +static inline void ath12k_debugfs_soc_create(struct ath12k_base *ab) +{ +} + +static inline void ath12k_debugfs_soc_destroy(struct ath12k_base *ab) +{ +} + +static inline void ath12k_debugfs_register(struct ath12k *ar) +{ +} + +#endif /* CONFIG_ATH12K_DEBUGFS */ + +#endif /* _ATH12K_DEBUGFS_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index c8e1b244b6..90476f38e8 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -14,6 +14,11 @@ #include "peer.h" #include "dp_mon.h" +enum ath12k_dp_desc_type { + ATH12K_DP_TX_DESC, + ATH12K_DP_RX_DESC, +}; + static void ath12k_dp_htt_htc_tx_complete(struct ath12k_base *ab, struct sk_buff *skb) { @@ -127,7 +132,9 @@ static int ath12k_dp_srng_find_ring_in_mask(int ring_num, const u8 *grp_mask) static int ath12k_dp_srng_calculate_msi_group(struct ath12k_base *ab, enum hal_ring_type type, int ring_num) { + const struct ath12k_hal_tcl_to_wbm_rbm_map *map; const u8 *grp_mask; + int i; switch (type) { case HAL_WBM2SW_RELEASE: @@ -135,6 +142,14 @@ static int ath12k_dp_srng_calculate_msi_group(struct ath12k_base *ab, grp_mask = &ab->hw_params->ring_mask->rx_wbm_rel[0]; ring_num = 0; } else { + map = ab->hw_params->hal_ops->tcl_to_wbm_rbm_map; + for (i = 0; i < ab->hw_params->max_tx_ring; i++) { + if (ring_num == map[i].wbm_ring_num) { + ring_num = i; + break; + } + } + grp_mask = &ab->hw_params->ring_mask->tx[0]; } break; @@ -876,11 +891,9 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, enum dp_monitor_mode monitor_mode; u8 ring_mask; - while (i < ab->hw_params->max_tx_ring) { - if (ab->hw_params->ring_mask->tx[grp_id] & - BIT(ab->hw_params->hal_ops->tcl_to_wbm_rbm_map[i].wbm_ring_num)) - ath12k_dp_tx_completion_handler(ab, i); - i++; + if (ab->hw_params->ring_mask->tx[grp_id]) { + i = fls(ab->hw_params->ring_mask->tx[grp_id]) - 1; + ath12k_dp_tx_completion_handler(ab, i); } if (ab->hw_params->ring_mask->rx_err[grp_id]) { @@ -960,8 +973,9 @@ int ath12k_dp_service_srng(struct ath12k_base *ab, if (ab->hw_params->ring_mask->host2rxdma[grp_id]) { struct ath12k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; + LIST_HEAD(list); - ath12k_dp_rx_bufs_replenish(ab, rx_ring, 0); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, &list, 0); } /* TODO: Implement handler for other interrupts */ @@ -1146,11 +1160,13 @@ void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_vif *arvif) static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) { - struct ath12k_rx_desc_info *desc_info, *tmp; + struct ath12k_rx_desc_info *desc_info; struct ath12k_tx_desc_info *tx_desc_info, *tmp1; struct ath12k_dp *dp = &ab->dp; + struct ath12k_skb_cb *skb_cb; struct sk_buff *skb; - int i; + struct ath12k *ar; + int i, j; u32 pool_id, tx_spt_page; if (!dp->spt_info) @@ -1159,16 +1175,23 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) /* RX Descriptor cleanup */ spin_lock_bh(&dp->rx_desc_lock); - list_for_each_entry_safe(desc_info, tmp, &dp->rx_desc_used_list, list) { - list_del(&desc_info->list); - skb = desc_info->skb; + for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { + desc_info = dp->spt_info->rxbaddr[i]; - if (!skb) - continue; + for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { + if (!desc_info[j].in_use) { + list_del(&desc_info[j].list); + continue; + } - dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr, - skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); - dev_kfree_skb_any(skb); + skb = desc_info[j].skb; + if (!skb) + continue; + + dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr, + skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + } } for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { @@ -1193,6 +1216,11 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) if (!skb) continue; + skb_cb = ATH12K_SKB_CB(skb); + ar = skb_cb->ar; + if (atomic_dec_and_test(&ar->dp.num_tx_pending)) + wake_up(&ar->dp.tx_empty_waitq); + dma_unmap_single(ab->dev, ATH12K_SKB_CB(skb)->paddr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); @@ -1336,12 +1364,16 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab, u32 cookie) { struct ath12k_rx_desc_info **desc_addr_ptr; - u16 ppt_idx, spt_idx; + u16 start_ppt_idx, end_ppt_idx, ppt_idx, spt_idx; ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT); - spt_idx = u32_get_bits(cookie, ATH12k_DP_CC_COOKIE_SPT); + spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT); + + start_ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET; + end_ppt_idx = start_ppt_idx + ATH12K_NUM_RX_SPT_PAGES; - if (ppt_idx > ATH12K_NUM_RX_SPT_PAGES || + if (ppt_idx < start_ppt_idx || + ppt_idx >= end_ppt_idx || spt_idx > ATH12K_MAX_SPT_ENTRIES) return NULL; @@ -1354,13 +1386,17 @@ struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab, u32 cookie) { struct ath12k_tx_desc_info **desc_addr_ptr; - u16 ppt_idx, spt_idx; + u16 start_ppt_idx, end_ppt_idx, ppt_idx, spt_idx; ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT); - spt_idx = u32_get_bits(cookie, ATH12k_DP_CC_COOKIE_SPT); + spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT); - if (ppt_idx < ATH12K_NUM_RX_SPT_PAGES || - ppt_idx > ab->dp.num_spt_pages || + start_ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET; + end_ppt_idx = start_ppt_idx + + (ATH12K_TX_SPT_PAGES_PER_POOL * ATH12K_HW_MAX_QUEUES); + + if (ppt_idx < start_ppt_idx || + ppt_idx >= end_ppt_idx || spt_idx > ATH12K_MAX_SPT_ENTRIES) return NULL; @@ -1389,15 +1425,16 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) return -ENOMEM; } + ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET + i; dp->spt_info->rxbaddr[i] = &rx_descs[0]; for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { - rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(i, j); + rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(ppt_idx, j); rx_descs[j].magic = ATH12K_DP_RX_DESC_MAGIC; list_add_tail(&rx_descs[j].list, &dp->rx_desc_free_list); /* Update descriptor VA in SPT */ - rx_desc_addr = ath12k_dp_cc_get_desc_addr_ptr(ab, i, j); + rx_desc_addr = ath12k_dp_cc_get_desc_addr_ptr(ab, ppt_idx, j); *rx_desc_addr = &rx_descs[j]; } } @@ -1417,10 +1454,11 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) } tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL; + ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET + tx_spt_page; + dp->spt_info->txbaddr[tx_spt_page] = &tx_descs[0]; for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { - ppt_idx = ATH12K_NUM_RX_SPT_PAGES + tx_spt_page; tx_descs[j].desc_id = ath12k_dp_cc_cookie_gen(ppt_idx, j); tx_descs[j].pool_id = pool_id; list_add_tail(&tx_descs[j].list, @@ -1437,14 +1475,43 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) return 0; } +static int ath12k_dp_cmem_init(struct ath12k_base *ab, + struct ath12k_dp *dp, + enum ath12k_dp_desc_type type) +{ + u32 cmem_base; + int i, start, end; + + cmem_base = ab->qmi.dev_mem[ATH12K_QMI_DEVMEM_CMEM_INDEX].start; + + switch (type) { + case ATH12K_DP_TX_DESC: + start = ATH12K_TX_SPT_PAGE_OFFSET; + end = start + ATH12K_NUM_TX_SPT_PAGES; + break; + case ATH12K_DP_RX_DESC: + start = ATH12K_RX_SPT_PAGE_OFFSET; + end = start + ATH12K_NUM_RX_SPT_PAGES; + break; + default: + ath12k_err(ab, "invalid descriptor type %d in cmem init\n", type); + return -EINVAL; + } + + /* Write to PPT in CMEM */ + for (i = start; i < end; i++) + ath12k_hif_write32(ab, cmem_base + ATH12K_PPT_ADDR_OFFSET(i), + dp->spt_info[i].paddr >> ATH12K_SPT_4K_ALIGN_OFFSET); + + return 0; +} + static int ath12k_dp_cc_init(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; int i, ret = 0; - u32 cmem_base; INIT_LIST_HEAD(&dp->rx_desc_free_list); - INIT_LIST_HEAD(&dp->rx_desc_used_list); spin_lock_init(&dp->rx_desc_lock); for (i = 0; i < ATH12K_HW_MAX_QUEUES; i++) { @@ -1465,8 +1532,6 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) return -ENOMEM; } - cmem_base = ab->qmi.dev_mem[ATH12K_QMI_DEVMEM_CMEM_INDEX].start; - for (i = 0; i < dp->num_spt_pages; i++) { dp->spt_info[i].vaddr = dma_alloc_coherent(ab->dev, ATH12K_PAGE_SIZE, @@ -1483,10 +1548,18 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) ret = -EINVAL; goto free; } + } - /* Write to PPT in CMEM */ - ath12k_hif_write32(ab, cmem_base + ATH12K_PPT_ADDR_OFFSET(i), - dp->spt_info[i].paddr >> ATH12K_SPT_4K_ALIGN_OFFSET); + ret = ath12k_dp_cmem_init(ab, dp, ATH12K_DP_TX_DESC); + if (ret) { + ath12k_warn(ab, "HW CC Tx cmem init failed %d", ret); + goto free; + } + + ret = ath12k_dp_cmem_init(ab, dp, ATH12K_DP_RX_DESC); + if (ret) { + ath12k_warn(ab, "HW CC Rx cmem init failed %d", ret); + goto free; } ret = ath12k_dp_cc_desc_init(ab); diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index eb2dd408e0..4dfbff3260 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -223,6 +223,9 @@ struct ath12k_pdev_dp { #define ATH12K_NUM_TX_SPT_PAGES (ATH12K_TX_SPT_PAGES_PER_POOL * ATH12K_HW_MAX_QUEUES) #define ATH12K_NUM_SPT_PAGES (ATH12K_NUM_RX_SPT_PAGES + ATH12K_NUM_TX_SPT_PAGES) +#define ATH12K_TX_SPT_PAGE_OFFSET 0 +#define ATH12K_RX_SPT_PAGE_OFFSET ATH12K_NUM_TX_SPT_PAGES + /* The SPT pages are divided for RX and TX, first block for RX * and remaining for TX */ @@ -245,7 +248,7 @@ struct ath12k_pdev_dp { #define ATH12K_CC_SPT_MSB 8 #define ATH12K_CC_PPT_MSB 19 #define ATH12K_CC_PPT_SHIFT 9 -#define ATH12k_DP_CC_COOKIE_SPT GENMASK(8, 0) +#define ATH12K_DP_CC_COOKIE_SPT GENMASK(8, 0) #define ATH12K_DP_CC_COOKIE_PPT GENMASK(19, 9) #define DP_REO_QREF_NUM GENMASK(31, 16) @@ -282,6 +285,8 @@ struct ath12k_rx_desc_info { struct sk_buff *skb; u32 cookie; u32 magic; + u8 in_use : 1, + reserved : 7; }; struct ath12k_tx_desc_info { @@ -329,6 +334,7 @@ struct ath12k_dp { struct dp_srng reo_except_ring; struct dp_srng reo_cmd_ring; struct dp_srng reo_status_ring; + enum ath12k_peer_metadata_version peer_metadata_ver; struct dp_srng reo_dst_ring[DP_REO_DST_RING_MAX]; struct dp_tx_ring tx_ring[DP_TCL_NUM_RING_MAX]; struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX]; @@ -347,8 +353,7 @@ struct ath12k_dp { struct ath12k_spt_info *spt_info; u32 num_spt_pages; struct list_head rx_desc_free_list; - struct list_head rx_desc_used_list; - /* protects the free and used desc list */ + /* protects the free desc list */ spinlock_t rx_desc_lock; struct list_head tx_desc_free_list[ATH12K_HW_MAX_QUEUES]; @@ -377,8 +382,6 @@ struct ath12k_dp { /* peer meta data */ #define HTT_TCL_META_DATA_PEER_ID GENMASK(15, 2) -#define HTT_TX_WBM_COMP_STATUS_OFFSET 8 - /* HTT tx completion is overlaid in wbm_release_ring */ #define HTT_TX_WBM_COMP_INFO0_STATUS GENMASK(16, 13) #define HTT_TX_WBM_COMP_INFO1_REINJECT_REASON GENMASK(3, 0) diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 2d56913a75..6b0b724775 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -944,7 +944,7 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, goto err_merge_fail; ath12k_dbg(ab, ATH12K_DBG_DATA, - "mpdu_buf %pK mpdu_buf->len %u", + "mpdu_buf %p mpdu_buf->len %u", prev_buf, prev_buf->len); } else { ath12k_dbg(ab, ATH12K_DBG_DATA, @@ -958,7 +958,7 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, err_merge_fail: if (mpdu_buf && decap_format != DP_RX_DECAP_TYPE_RAW) { ath12k_dbg(ab, ATH12K_DBG_DATA, - "err_merge_fail mpdu_buf %pK", mpdu_buf); + "err_merge_fail mpdu_buf %p", mpdu_buf); /* Free the head buffer */ dev_kfree_skb_any(mpdu_buf); } @@ -1092,7 +1092,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct spin_unlock_bh(&ar->ab->base_lock); ath12k_dbg(ar->ab, ATH12K_DBG_DATA, - "rx skb %pK len %u peer %pM %u %s %s%s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", + "rx skb %p len %u peer %pM %u %s %s%s%s%s%s%s%s%s %srate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", msdu, msdu->len, peer ? peer->addr : NULL, diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index ca76c018dd..1d287ed25a 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -239,31 +239,61 @@ static inline u8 ath12k_dp_rx_get_msdu_src_link(struct ath12k_base *ab, return ab->hal_rx_ops->rx_desc_get_msdu_src_link_id(desc); } -static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab) +static void ath12k_dp_clean_up_skb_list(struct sk_buff_head *skb_list) { - int i, reaped = 0; - unsigned long timeout = jiffies + msecs_to_jiffies(DP_MON_PURGE_TIMEOUT_MS); + struct sk_buff *skb; + + while ((skb = __skb_dequeue(skb_list))) + dev_kfree_skb_any(skb); +} + +static size_t ath12k_dp_list_cut_nodes(struct list_head *list, + struct list_head *head, + size_t count) +{ + struct list_head *cur; + struct ath12k_rx_desc_info *rx_desc; + size_t nodes = 0; - do { - for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) - reaped += ath12k_dp_mon_process_ring(ab, i, NULL, - DP_MON_SERVICE_BUDGET, - ATH12K_DP_RX_MONITOR_MODE); + if (!count) { + INIT_LIST_HEAD(list); + goto out; + } + + list_for_each(cur, head) { + if (!count) + break; + + rx_desc = list_entry(cur, struct ath12k_rx_desc_info, list); + rx_desc->in_use = true; + + count--; + nodes++; + } - /* nothing more to reap */ - if (reaped < DP_MON_SERVICE_BUDGET) - return 0; + list_cut_before(list, head, cur); +out: + return nodes; +} - } while (time_before(jiffies, timeout)); +static void ath12k_dp_rx_enqueue_free(struct ath12k_dp *dp, + struct list_head *used_list) +{ + struct ath12k_rx_desc_info *rx_desc, *safe; - ath12k_warn(ab, "dp mon ring purge timeout"); + /* Reset the use flag */ + list_for_each_entry_safe(rx_desc, safe, used_list, list) + rx_desc->in_use = false; - return -ETIMEDOUT; + spin_lock_bh(&dp->rx_desc_lock); + list_splice_tail(used_list, &dp->rx_desc_free_list); + spin_unlock_bh(&dp->rx_desc_lock); } /* Returns number of Rx buffers replenished */ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring, + struct list_head *used_list, int req_entries) { struct ath12k_buffer_addr *desc; @@ -292,6 +322,19 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, req_entries = min(num_free, req_entries); num_remain = req_entries; + if (!num_remain) + goto out; + + /* Get the descriptor from free list */ + if (list_empty(used_list)) { + spin_lock_bh(&dp->rx_desc_lock); + req_entries = ath12k_dp_list_cut_nodes(used_list, + &dp->rx_desc_free_list, + num_remain); + spin_unlock_bh(&dp->rx_desc_lock); + num_remain = req_entries; + } + while (num_remain > 0) { skb = dev_alloc_skb(DP_RX_BUFFER_SIZE + DP_RX_BUFFER_ALIGN_SIZE); @@ -311,33 +354,20 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, if (dma_mapping_error(ab->dev, paddr)) goto fail_free_skb; - spin_lock_bh(&dp->rx_desc_lock); - - /* Get desc from free list and store in used list - * for cleanup purposes - * - * TODO: pass the removed descs rather than - * add/read to optimize - */ - rx_desc = list_first_entry_or_null(&dp->rx_desc_free_list, + rx_desc = list_first_entry_or_null(used_list, struct ath12k_rx_desc_info, list); - if (!rx_desc) { - spin_unlock_bh(&dp->rx_desc_lock); + if (!rx_desc) goto fail_dma_unmap; - } rx_desc->skb = skb; cookie = rx_desc->cookie; - list_del(&rx_desc->list); - list_add_tail(&rx_desc->list, &dp->rx_desc_used_list); - - spin_unlock_bh(&dp->rx_desc_lock); desc = ath12k_hal_srng_src_get_next_entry(ab, srng); if (!desc) - goto fail_buf_unassign; + goto fail_dma_unmap; + list_del(&rx_desc->list); ATH12K_SKB_RXCB(skb)->paddr = paddr; num_remain--; @@ -345,26 +375,19 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, ath12k_hal_rx_buf_addr_info_set(desc, paddr, cookie, mgr); } - ath12k_hal_srng_access_end(ab, srng); - - spin_unlock_bh(&srng->lock); + goto out; - return req_entries - num_remain; - -fail_buf_unassign: - spin_lock_bh(&dp->rx_desc_lock); - list_del(&rx_desc->list); - list_add_tail(&rx_desc->list, &dp->rx_desc_free_list); - rx_desc->skb = NULL; - spin_unlock_bh(&dp->rx_desc_lock); fail_dma_unmap: dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); fail_free_skb: dev_kfree_skb_any(skb); - +out: ath12k_hal_srng_access_end(ab, srng); + if (!list_empty(used_list)) + ath12k_dp_rx_enqueue_free(dp, used_list); + spin_unlock_bh(&srng->lock); return req_entries - num_remain; @@ -422,13 +445,12 @@ static int ath12k_dp_rxdma_mon_ring_buf_setup(struct ath12k_base *ab, static int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring) { - int num_entries; + LIST_HEAD(list); - num_entries = rx_ring->refill_buf_ring.size / - ath12k_hal_srng_get_entrysize(ab, HAL_RXDMA_BUF); + rx_ring->bufs_max = rx_ring->refill_buf_ring.size / + ath12k_hal_srng_get_entrysize(ab, HAL_RXDMA_BUF); - rx_ring->bufs_max = num_entries; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_entries); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, &list, 0); return 0; } @@ -2361,8 +2383,10 @@ void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct hal_rx_desc *rx_desc, channel_num = meta_data; center_freq = meta_data >> 16; - if (center_freq >= 5935 && center_freq <= 7105) { + if (center_freq >= ATH12K_MIN_6G_FREQ && + center_freq <= ATH12K_MAX_6G_FREQ) { rx_status->band = NL80211_BAND_6GHZ; + rx_status->freq = center_freq; } else if (channel_num >= 1 && channel_num <= 14) { rx_status->band = NL80211_BAND_2GHZ; } else if (channel_num >= 36 && channel_num <= 173) { @@ -2380,8 +2404,9 @@ void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct hal_rx_desc *rx_desc, rx_desc, sizeof(*rx_desc)); } - rx_status->freq = ieee80211_channel_to_frequency(channel_num, - rx_status->band); + if (rx_status->band != NL80211_BAND_6GHZ) + rx_status->freq = ieee80211_channel_to_frequency(channel_num, + rx_status->band); ath12k_dp_rx_h_rate(ar, rx_desc, rx_status); } @@ -2423,7 +2448,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap spin_unlock_bh(&ab->base_lock); ath12k_dbg(ab, ATH12K_DBG_DATA, - "rx skb %pK len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", + "rx skb %p len %u peer %pM %d %s sn %u %s%s%s%s%s%s%s%s%s rate_idx %u vht_nss %u freq %u band %u flag 0x%x fcs-err %i mic-err %i amsdu-more %i\n", msdu, msdu->len, peer ? peer->addr : NULL, @@ -2582,9 +2607,33 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, rcu_read_unlock(); } +static u16 ath12k_dp_rx_get_peer_id(struct ath12k_base *ab, + enum ath12k_peer_metadata_version ver, + __le32 peer_metadata) +{ + switch (ver) { + default: + ath12k_warn(ab, "Unknown peer metadata version: %d", ver); + fallthrough; + case ATH12K_PEER_METADATA_V0: + return le32_get_bits(peer_metadata, + RX_MPDU_DESC_META_DATA_V0_PEER_ID); + case ATH12K_PEER_METADATA_V1: + return le32_get_bits(peer_metadata, + RX_MPDU_DESC_META_DATA_V1_PEER_ID); + case ATH12K_PEER_METADATA_V1A: + return le32_get_bits(peer_metadata, + RX_MPDU_DESC_META_DATA_V1A_PEER_ID); + case ATH12K_PEER_METADATA_V1B: + return le32_get_bits(peer_metadata, + RX_MPDU_DESC_META_DATA_V1B_PEER_ID); + } +} + int ath12k_dp_rx_process(struct ath12k_base *ab, int ring_id, struct napi_struct *napi, int budget) { + LIST_HEAD(rx_desc_used_list); struct ath12k_rx_desc_info *desc_info; struct ath12k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring; @@ -2609,6 +2658,8 @@ try_again: ath12k_hal_srng_access_begin(ab, srng); while ((desc = ath12k_hal_srng_dst_get_next_entry(ab, srng))) { + struct rx_mpdu_desc *mpdu_info; + struct rx_msdu_desc *msdu_info; enum hal_reo_dest_ring_push_reason push_reason; u32 cookie; @@ -2637,9 +2688,7 @@ try_again: msdu = desc_info->skb; desc_info->skb = NULL; - spin_lock_bh(&dp->rx_desc_lock); - list_move_tail(&desc_info->list, &dp->rx_desc_free_list); - spin_unlock_bh(&dp->rx_desc_lock); + list_add_tail(&desc_info->list, &rx_desc_used_list); rxcb = ATH12K_SKB_RXCB(msdu); dma_unmap_single(ab->dev, rxcb->paddr, @@ -2657,16 +2706,19 @@ try_again: continue; } - rxcb->is_first_msdu = !!(le32_to_cpu(desc->rx_msdu_info.info0) & + msdu_info = &desc->rx_msdu_info; + mpdu_info = &desc->rx_mpdu_info; + + rxcb->is_first_msdu = !!(le32_to_cpu(msdu_info->info0) & RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); - rxcb->is_last_msdu = !!(le32_to_cpu(desc->rx_msdu_info.info0) & + rxcb->is_last_msdu = !!(le32_to_cpu(msdu_info->info0) & RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); - rxcb->is_continuation = !!(le32_to_cpu(desc->rx_msdu_info.info0) & + rxcb->is_continuation = !!(le32_to_cpu(msdu_info->info0) & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); rxcb->mac_id = mac_id; - rxcb->peer_id = le32_get_bits(desc->rx_mpdu_info.peer_meta_data, - RX_MPDU_DESC_META_DATA_PEER_ID); - rxcb->tid = le32_get_bits(desc->rx_mpdu_info.info0, + rxcb->peer_id = ath12k_dp_rx_get_peer_id(ab, dp->peer_metadata_ver, + mpdu_info->peer_meta_data); + rxcb->tid = le32_get_bits(mpdu_info->info0, RX_MPDU_DESC_INFO0_TID); __skb_queue_tail(&msdu_list, msdu); @@ -2700,7 +2752,8 @@ try_again: if (!total_msdu_reaped) goto exit; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, &rx_desc_used_list, + num_buffs_reaped); ath12k_dp_rx_process_received_packets(ab, napi, &msdu_list, ring_id); @@ -2740,6 +2793,7 @@ int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev peer = ath12k_peer_find(ab, vdev_id, peer_mac); if (!peer) { spin_unlock_bh(&ab->base_lock); + crypto_free_shash(tfm); ath12k_warn(ab, "failed to find the peer to set up fragment info\n"); return -ENOENT; } @@ -2969,7 +3023,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, struct hal_srng *srng; dma_addr_t link_paddr, buf_paddr; u32 desc_bank, msdu_info, msdu_ext_info, mpdu_info; - u32 cookie, hal_rx_desc_sz, dest_ring_info0; + u32 cookie, hal_rx_desc_sz, dest_ring_info0, queue_addr_hi; int ret; struct ath12k_rx_desc_info *desc_info; u8 dst_ind; @@ -3005,7 +3059,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, buf_paddr = dma_map_single(ab->dev, defrag_skb->data, defrag_skb->len + skb_tailroom(defrag_skb), - DMA_FROM_DEVICE); + DMA_TO_DEVICE); if (dma_mapping_error(ab->dev, buf_paddr)) return -ENOMEM; @@ -3021,9 +3075,9 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, } desc_info->skb = defrag_skb; + desc_info->in_use = true; list_del(&desc_info->list); - list_add_tail(&desc_info->list, &dp->rx_desc_used_list); spin_unlock_bh(&dp->rx_desc_lock); ATH12K_SKB_RXCB(defrag_skb)->paddr = buf_paddr; @@ -3061,13 +3115,11 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, reo_ent_ring->rx_mpdu_info.peer_meta_data = reo_dest_ring->rx_mpdu_info.peer_meta_data; - /* Firmware expects physical address to be filled in queue_addr_lo in - * the MLO scenario and in case of non MLO peer meta data needs to be - * filled. - * TODO: Need to handle for MLO scenario. - */ - reo_ent_ring->queue_addr_lo = reo_dest_ring->rx_mpdu_info.peer_meta_data; - reo_ent_ring->info0 = le32_encode_bits(dst_ind, + reo_ent_ring->queue_addr_lo = cpu_to_le32(lower_32_bits(rx_tid->paddr)); + queue_addr_hi = upper_32_bits(rx_tid->paddr); + reo_ent_ring->info0 = le32_encode_bits(queue_addr_hi, + HAL_REO_ENTR_RING_INFO0_QUEUE_ADDR_HI) | + le32_encode_bits(dst_ind, HAL_REO_ENTR_RING_INFO0_DEST_IND); reo_ent_ring->info1 = le32_encode_bits(rx_tid->cur_sn, @@ -3085,13 +3137,13 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, err_free_desc: spin_lock_bh(&dp->rx_desc_lock); - list_del(&desc_info->list); - list_add_tail(&desc_info->list, &dp->rx_desc_free_list); + desc_info->in_use = false; desc_info->skb = NULL; + list_add_tail(&desc_info->list, &dp->rx_desc_free_list); spin_unlock_bh(&dp->rx_desc_lock); err_unmap_dma: dma_unmap_single(ab->dev, buf_paddr, defrag_skb->len + skb_tailroom(defrag_skb), - DMA_FROM_DEVICE); + DMA_TO_DEVICE); return ret; } @@ -3304,6 +3356,7 @@ out_unlock: static int ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc, + struct list_head *used_list, bool drop, u32 cookie) { struct ath12k_base *ab = ar->ab; @@ -3333,9 +3386,8 @@ ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc, msdu = desc_info->skb; desc_info->skb = NULL; - spin_lock_bh(&ab->dp.rx_desc_lock); - list_move_tail(&desc_info->list, &ab->dp.rx_desc_free_list); - spin_unlock_bh(&ab->dp.rx_desc_lock); + + list_add_tail(&desc_info->list, used_list); rxcb = ATH12K_SKB_RXCB(msdu); dma_unmap_single(ar->ab->dev, rxcb->paddr, @@ -3391,6 +3443,7 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, struct hal_reo_dest_ring *reo_desc; struct dp_rxdma_ring *rx_ring; struct dp_srng *reo_except; + LIST_HEAD(rx_desc_used_list); u32 desc_bank, num_msdus; struct hal_srng *srng; struct ath12k_dp *dp; @@ -3458,7 +3511,9 @@ int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi, pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); ar = ab->pdevs[pdev_id].ar; - if (!ath12k_dp_process_rx_err_buf(ar, reo_desc, drop, + if (!ath12k_dp_process_rx_err_buf(ar, reo_desc, + &rx_desc_used_list, + drop, msdu_cookies[i])) tot_n_bufs_reaped++; } @@ -3478,7 +3533,8 @@ exit: rx_ring = &dp->rx_refill_buf_ring; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, tot_n_bufs_reaped); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, &rx_desc_used_list, + tot_n_bufs_reaped); return tot_n_bufs_reaped; } @@ -3695,25 +3751,27 @@ static void ath12k_dp_rx_wbm_err(struct ath12k *ar, int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, struct napi_struct *napi, int budget) { + LIST_HEAD(rx_desc_used_list); struct ath12k *ar; struct ath12k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring; struct hal_rx_wbm_rel_info err_info; struct hal_srng *srng; struct sk_buff *msdu; - struct sk_buff_head msdu_list; + struct sk_buff_head msdu_list, scatter_msdu_list; struct ath12k_skb_rxcb *rxcb; void *rx_desc; u8 mac_id; int num_buffs_reaped = 0; struct ath12k_rx_desc_info *desc_info; int ret, pdev_id; + struct hal_rx_desc *msdu_data; __skb_queue_head_init(&msdu_list); + __skb_queue_head_init(&scatter_msdu_list); srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id]; rx_ring = &dp->rx_refill_buf_ring; - spin_lock_bh(&srng->lock); ath12k_hal_srng_access_begin(ab, srng); @@ -3748,9 +3806,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, msdu = desc_info->skb; desc_info->skb = NULL; - spin_lock_bh(&dp->rx_desc_lock); - list_move_tail(&desc_info->list, &dp->rx_desc_free_list); - spin_unlock_bh(&dp->rx_desc_lock); + list_add_tail(&desc_info->list, &rx_desc_used_list); rxcb = ATH12K_SKB_RXCB(msdu); dma_unmap_single(ab->dev, rxcb->paddr, @@ -3768,17 +3824,53 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, continue; } + msdu_data = (struct hal_rx_desc *)msdu->data; rxcb->err_rel_src = err_info.err_rel_src; rxcb->err_code = err_info.err_code; - rxcb->rx_desc = (struct hal_rx_desc *)msdu->data; - - __skb_queue_tail(&msdu_list, msdu); - rxcb->is_first_msdu = err_info.first_msdu; rxcb->is_last_msdu = err_info.last_msdu; rxcb->is_continuation = err_info.continuation; + rxcb->rx_desc = msdu_data; + + if (err_info.continuation) { + __skb_queue_tail(&scatter_msdu_list, msdu); + continue; + } + + mac_id = ath12k_dp_rx_get_msdu_src_link(ab, + msdu_data); + if (mac_id >= MAX_RADIOS) { + dev_kfree_skb_any(msdu); + + /* In any case continuation bit is set + * in the previous record, cleanup scatter_msdu_list + */ + ath12k_dp_clean_up_skb_list(&scatter_msdu_list); + continue; + } + + if (!skb_queue_empty(&scatter_msdu_list)) { + struct sk_buff *msdu; + + skb_queue_walk(&scatter_msdu_list, msdu) { + rxcb = ATH12K_SKB_RXCB(msdu); + rxcb->mac_id = mac_id; + } + + skb_queue_splice_tail_init(&scatter_msdu_list, + &msdu_list); + } + + rxcb = ATH12K_SKB_RXCB(msdu); + rxcb->mac_id = mac_id; + __skb_queue_tail(&msdu_list, msdu); } + /* In any case continuation bit is set in the + * last record, cleanup scatter_msdu_list + */ + ath12k_dp_clean_up_skb_list(&scatter_msdu_list); + ath12k_hal_srng_access_end(ab, srng); spin_unlock_bh(&srng->lock); @@ -3786,12 +3878,14 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, if (!num_buffs_reaped) goto done; - ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped); + ath12k_dp_rx_bufs_replenish(ab, rx_ring, &rx_desc_used_list, + num_buffs_reaped); rcu_read_lock(); while ((msdu = __skb_dequeue(&msdu_list))) { - mac_id = ath12k_dp_rx_get_msdu_src_link(ab, - (struct hal_rx_desc *)msdu->data); + rxcb = ATH12K_SKB_RXCB(msdu); + mac_id = rxcb->mac_id; + pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); ar = ab->pdevs[pdev_id].ar; @@ -4224,29 +4318,3 @@ int ath12k_dp_rx_pdev_mon_attach(struct ath12k *ar) return 0; } - -int ath12k_dp_rx_pktlog_start(struct ath12k_base *ab) -{ - /* start reap timer */ - mod_timer(&ab->mon_reap_timer, - jiffies + msecs_to_jiffies(ATH12K_MON_TIMER_INTERVAL)); - - return 0; -} - -int ath12k_dp_rx_pktlog_stop(struct ath12k_base *ab, bool stop_timer) -{ - int ret; - - if (stop_timer) - del_timer_sync(&ab->mon_reap_timer); - - /* reap all the monitor related rings */ - ret = ath12k_dp_purge_mon_ring(ab); - if (ret) { - ath12k_warn(ab, "failed to purge dp mon ring: %d\n", ret); - return ret; - } - - return 0; -} diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index 05b3d5581d..2ff4211601 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_DP_RX_H #define ATH12K_DP_RX_H @@ -118,12 +118,11 @@ int ath12k_dp_rx_process(struct ath12k_base *ab, int mac_id, int budget); int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab, struct dp_rxdma_ring *rx_ring, + struct list_head *used_list, int req_entries); int ath12k_dp_rx_pdev_mon_attach(struct ath12k *ar); int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id); -int ath12k_dp_rx_pktlog_start(struct ath12k_base *ab); -int ath12k_dp_rx_pktlog_stop(struct ath12k_base *ab, bool stop_timer); u8 ath12k_dp_rx_h_l3pad(struct ath12k_base *ab, struct hal_rx_desc *desc); struct ath12k_peer * diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 572b871536..a7c7a868c1 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -352,15 +352,15 @@ static void ath12k_dp_tx_free_txbuf(struct ath12k_base *ab, u8 pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); skb_cb = ATH12K_SKB_CB(msdu); + ar = ab->pdevs[pdev_id].ar; dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); if (skb_cb->paddr_ext_desc) dma_unmap_single(ab->dev, skb_cb->paddr_ext_desc, sizeof(struct hal_tx_msdu_ext_desc), DMA_TO_DEVICE); - dev_kfree_skb_any(msdu); + ieee80211_free_txskb(ar->ah->hw, msdu); - ar = ab->pdevs[pdev_id].ar; if (atomic_dec_and_test(&ar->dp.num_tx_pending)) wake_up(&ar->dp.tx_empty_waitq); } @@ -414,7 +414,7 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, struct ath12k_dp_htt_wbm_tx_status ts = {0}; enum hal_wbm_htt_tx_comp_status wbm_status; - status_desc = desc + HTT_TX_WBM_COMP_STATUS_OFFSET; + status_desc = desc; wbm_status = le32_get_bits(status_desc->info0, HTT_TX_WBM_COMP_INFO0_STATUS); @@ -448,6 +448,7 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, struct hal_tx_status *ts) { struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ar->ah; struct ieee80211_tx_info *info; struct ath12k_skb_cb *skb_cb; @@ -466,12 +467,12 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, rcu_read_lock(); if (!rcu_dereference(ab->pdevs_active[ar->pdev_idx])) { - dev_kfree_skb_any(msdu); + ieee80211_free_txskb(ah->hw, msdu); goto exit; } if (!skb_cb->vif) { - dev_kfree_skb_any(msdu); + ieee80211_free_txskb(ah->hw, msdu); goto exit; } @@ -481,18 +482,36 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, /* skip tx rate update from ieee80211_status*/ info->status.rates[0].idx = -1; - if (ts->status == HAL_WBM_TQM_REL_REASON_FRAME_ACKED && - !(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - info->flags |= IEEE80211_TX_STAT_ACK; - info->status.ack_signal = ATH12K_DEFAULT_NOISE_FLOOR + - ts->ack_rssi; - info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; + switch (ts->status) { + case HAL_WBM_TQM_REL_REASON_FRAME_ACKED: + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ack_signal = ATH12K_DEFAULT_NOISE_FLOOR + + ts->ack_rssi; + info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; + } + break; + case HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX: + if (info->flags & IEEE80211_TX_CTL_NO_ACK) { + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + break; + } + fallthrough; + case HAL_WBM_TQM_REL_REASON_CMD_REMOVE_MPDU: + case HAL_WBM_TQM_REL_REASON_DROP_THRESHOLD: + case HAL_WBM_TQM_REL_REASON_CMD_REMOVE_AGED_FRAMES: + /* The failure status is due to internal firmware tx failure + * hence drop the frame; do not update the status of frame to + * the upper layer + */ + ieee80211_free_txskb(ah->hw, msdu); + goto exit; + default: + ath12k_dbg(ab, ATH12K_DBG_DP_TX, "tx frame is not acked status %d\n", + ts->status); + break; } - if (ts->status == HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX && - (info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; - /* NOTE: Tx rate status reporting. Tx completion status does not have * necessary information (for example nss) to build the tx rate. * Might end up reporting it out-of-band from HTT stats. diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index 107927d64b..dbb9205bfa 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -767,7 +767,7 @@ struct hal_srng_config { }; /** - * enum hal_rx_buf_return_buf_manager + * enum hal_rx_buf_return_buf_manager - manager for returned rx buffers * * @HAL_RX_BUF_RBM_WBM_IDLE_BUF_LIST: Buffer returned to WBM idle buffer list * @HAL_RX_BUF_RBM_WBM_CHIP0_IDLE_DESC_LIST: Descriptor returned to WBM idle diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index 63340256d3..072e363658 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" @@ -597,8 +597,30 @@ struct hal_tlv_64_hdr { #define RX_MPDU_DESC_INFO0_MPDU_QOS_CTRL_VALID BIT(27) #define RX_MPDU_DESC_INFO0_TID GENMASK(31, 28) -/* TODO revisit after meta data is concluded */ -#define RX_MPDU_DESC_META_DATA_PEER_ID GENMASK(15, 0) +/* Peer Metadata classification */ + +/* Version 0 */ +#define RX_MPDU_DESC_META_DATA_V0_PEER_ID GENMASK(15, 0) +#define RX_MPDU_DESC_META_DATA_V0_VDEV_ID GENMASK(23, 16) + +/* Version 1 */ +#define RX_MPDU_DESC_META_DATA_V1_PEER_ID GENMASK(13, 0) +#define RX_MPDU_DESC_META_DATA_V1_LOGICAL_LINK_ID GENMASK(15, 14) +#define RX_MPDU_DESC_META_DATA_V1_VDEV_ID GENMASK(23, 16) +#define RX_MPDU_DESC_META_DATA_V1_LMAC_ID GENMASK(25, 24) +#define RX_MPDU_DESC_META_DATA_V1_DEVICE_ID GENMASK(28, 26) + +/* Version 1A */ +#define RX_MPDU_DESC_META_DATA_V1A_PEER_ID GENMASK(13, 0) +#define RX_MPDU_DESC_META_DATA_V1A_VDEV_ID GENMASK(21, 14) +#define RX_MPDU_DESC_META_DATA_V1A_LOGICAL_LINK_ID GENMASK(25, 22) +#define RX_MPDU_DESC_META_DATA_V1A_DEVICE_ID GENMASK(28, 26) + +/* Version 1B */ +#define RX_MPDU_DESC_META_DATA_V1B_PEER_ID GENMASK(13, 0) +#define RX_MPDU_DESC_META_DATA_V1B_VDEV_ID GENMASK(21, 14) +#define RX_MPDU_DESC_META_DATA_V1B_HW_LINK_ID GENMASK(25, 22) +#define RX_MPDU_DESC_META_DATA_V1B_DEVICE_ID GENMASK(28, 26) struct rx_mpdu_desc { __le32 info0; /* %RX_MPDU_DESC_INFO */ @@ -2048,6 +2070,19 @@ struct hal_wbm_release_ring { * fw with fw_reason2. * @HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON3: Remove command initiated by * fw with fw_reason3. + * @HAL_WBM_TQM_REL_REASON_CMD_DISABLE_QUEUE: Remove command initiated by + * fw with disable queue. + * @HAL_WBM_TQM_REL_REASON_CMD_TILL_NONMATCHING: Remove command initiated by + * fw to remove all mpdu until 1st non-match. + * @HAL_WBM_TQM_REL_REASON_DROP_THRESHOLD: Dropped due to drop threshold + * criteria + * @HAL_WBM_TQM_REL_REASON_DROP_LINK_DESC_UNAVAIL: Dropped due to link desc + * not available + * @HAL_WBM_TQM_REL_REASON_DROP_OR_INVALID_MSDU: Dropped due drop bit set or + * null flow + * @HAL_WBM_TQM_REL_REASON_MULTICAST_DROP: Dropped due mcast drop set for VDEV + * @HAL_WBM_TQM_REL_REASON_VDEV_MISMATCH_DROP: Dropped due to being set with + * 'TCL_drop_reason' */ enum hal_wbm_tqm_rel_reason { HAL_WBM_TQM_REL_REASON_FRAME_ACKED, @@ -2058,6 +2093,13 @@ enum hal_wbm_tqm_rel_reason { HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON1, HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON2, HAL_WBM_TQM_REL_REASON_CMD_REMOVE_RESEAON3, + HAL_WBM_TQM_REL_REASON_CMD_DISABLE_QUEUE, + HAL_WBM_TQM_REL_REASON_CMD_TILL_NONMATCHING, + HAL_WBM_TQM_REL_REASON_DROP_THRESHOLD, + HAL_WBM_TQM_REL_REASON_DROP_LINK_DESC_UNAVAIL, + HAL_WBM_TQM_REL_REASON_DROP_OR_INVALID_MSDU, + HAL_WBM_TQM_REL_REASON_MULTICAST_DROP, + HAL_WBM_TQM_REL_REASON_VDEV_MISMATCH_DROP, }; struct hal_wbm_buffer_ring { diff --git a/drivers/net/wireless/ath/ath12k/hif.h b/drivers/net/wireless/ath/ath12k/hif.h index c653ca1f59..7f0926fe75 100644 --- a/drivers/net/wireless/ath/ath12k/hif.h +++ b/drivers/net/wireless/ath/ath12k/hif.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HIF_H @@ -17,7 +17,7 @@ struct ath12k_hif_ops { int (*start)(struct ath12k_base *ab); void (*stop)(struct ath12k_base *ab); int (*power_up)(struct ath12k_base *ab); - void (*power_down)(struct ath12k_base *ab); + void (*power_down)(struct ath12k_base *ab, bool is_suspend); int (*suspend)(struct ath12k_base *ab); int (*resume)(struct ath12k_base *ab); int (*map_service_to_pipe)(struct ath12k_base *ab, u16 service_id, @@ -133,12 +133,18 @@ static inline void ath12k_hif_write32(struct ath12k_base *ab, u32 address, static inline int ath12k_hif_power_up(struct ath12k_base *ab) { + if (!ab->hif.ops->power_up) + return -EOPNOTSUPP; + return ab->hif.ops->power_up(ab); } -static inline void ath12k_hif_power_down(struct ath12k_base *ab) +static inline void ath12k_hif_power_down(struct ath12k_base *ab, bool is_suspend) { - ab->hif.ops->power_down(ab); + if (!ab->hif.ops->power_down) + return; + + ab->hif.ops->power_down(ab, is_suspend); } #endif /* ATH12K_HIF_H */ diff --git a/drivers/net/wireless/ath/ath12k/htc.c b/drivers/net/wireless/ath/ath12k/htc.c index 23f7428abd..2f2230f565 100644 --- a/drivers/net/wireless/ath/ath12k/htc.c +++ b/drivers/net/wireless/ath/ath12k/htc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/skbuff.h> #include <linux/ctype.h> @@ -358,7 +358,7 @@ void ath12k_htc_rx_completion_handler(struct ath12k_base *ab, goto out; } - ath12k_dbg(ab, ATH12K_DBG_HTC, "htc rx completion ep %d skb %pK\n", + ath12k_dbg(ab, ATH12K_DBG_HTC, "htc rx completion ep %d skb %p\n", eid, skb); ep->ep_ops.ep_rx_complete(ab, skb); diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 0b17dfd478..bff8cf97a1 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -15,6 +15,10 @@ #include "mhi.h" #include "dp_rx.h" +static const guid_t wcn7850_uuid = GUID_INIT(0xf634f534, 0x6147, 0x11ec, + 0x90, 0xd6, 0x02, 0x42, + 0xac, 0x12, 0x00, 0x03); + static u8 ath12k_hw_qcn9274_mac_from_pdev_id(int pdev_idx) { return pdev_idx; @@ -540,9 +544,6 @@ static const struct ath12k_hw_ring_mask ath12k_hw_ring_mask_qcn9274 = { }, .rx_mon_dest = { 0, 0, 0, - ATH12K_RX_MON_RING_MASK_0, - ATH12K_RX_MON_RING_MASK_1, - ATH12K_RX_MON_RING_MASK_2, }, .rx = { 0, 0, 0, 0, @@ -568,16 +569,15 @@ static const struct ath12k_hw_ring_mask ath12k_hw_ring_mask_qcn9274 = { ATH12K_HOST2RXDMA_RING_MASK_0, }, .tx_mon_dest = { - ATH12K_TX_MON_RING_MASK_0, - ATH12K_TX_MON_RING_MASK_1, + 0, 0, 0, }, }; static const struct ath12k_hw_ring_mask ath12k_hw_ring_mask_wcn7850 = { .tx = { ATH12K_TX_RING_MASK_0, + ATH12K_TX_RING_MASK_1, ATH12K_TX_RING_MASK_2, - ATH12K_TX_RING_MASK_4, }, .rx_mon_dest = { }, @@ -920,6 +920,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, .supports_sta_ps = false, + + .acpi_guid = NULL, }, { .name = "wcn7850 hw2.0", @@ -964,7 +966,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .idle_ps = true, .download_calib = false, - .supports_suspend = false, + .supports_suspend = true, .tcl_ring_retry = false, .reoq_lut_support = false, .supports_shadow_regs = true, @@ -993,6 +995,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .otp_board_id_register = 0, .supports_sta_ps = true, + + .acpi_guid = &wcn7850_uuid, }, { .name = "qcn9274 hw2.0", @@ -1061,6 +1065,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, .supports_sta_ps = false, + + .acpi_guid = NULL, }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 87965980b9..2a314cfc8c 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -8,6 +8,7 @@ #define ATH12K_HW_H #include <linux/mhi.h> +#include <linux/uuid.h> #include "wmi.h" #include "hal.h" @@ -77,9 +78,9 @@ #define TARGET_NUM_WDS_ENTRIES 32 #define TARGET_DMA_BURST_SIZE 1 #define TARGET_RX_BATCHMODE 1 -#define TARGET_RX_PEER_METADATA_VER_V1A 2 -#define TARGET_RX_PEER_METADATA_VER_V1B 3 +#define TARGET_EMA_MAX_PROFILE_PERIOD 8 +#define ATH12K_HW_DEFAULT_QUEUE 0 #define ATH12K_HW_MAX_QUEUES 4 #define ATH12K_QUEUE_LEN 4096 @@ -211,6 +212,8 @@ struct ath12k_hw_params { u32 otp_board_id_register; bool supports_sta_ps; + + const guid_t *acpi_guid; }; struct ath12k_hw_ops { diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 52a5fb8b03..ead37a4e00 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -14,6 +14,7 @@ #include "dp_tx.h" #include "dp_rx.h" #include "peer.h" +#include "debugfs.h" #define CHAN2G(_channel, _freq, _flags) { \ .band = NL80211_BAND_2GHZ, \ @@ -243,6 +244,9 @@ static const u32 ath12k_smps_map[] = { static int ath12k_start_vdev_delay(struct ath12k *ar, struct ath12k_vif *arvif); +static void ath12k_mac_stop(struct ath12k *ar); +static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif); +static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif); static const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode) { @@ -530,7 +534,8 @@ static void ath12k_get_arvif_iter(void *data, u8 *mac, struct ath12k_vif_iter *arvif_iter = data; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - if (arvif->vdev_id == arvif_iter->vdev_id) + if (arvif->vdev_id == arvif_iter->vdev_id && + arvif->ar == arvif_iter->ar) arvif_iter->arvif = arvif; } @@ -540,6 +545,7 @@ struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id) u32 flags; arvif_iter.vdev_id = vdev_id; + arvif_iter.ar = ar; flags = IEEE80211_IFACE_ITER_RESUME_ALL; ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar), @@ -613,6 +619,53 @@ struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id) return NULL; } +static struct ath12k *ath12k_mac_get_ar_by_chan(struct ieee80211_hw *hw, + struct ieee80211_channel *channel) +{ + struct ath12k_hw *ah = hw->priv; + struct ath12k *ar; + int i; + + ar = ah->radio; + + if (ah->num_radio == 1) + return ar; + + for_each_ar(ah, ar, i) { + if (channel->center_freq >= ar->freq_low && + channel->center_freq <= ar->freq_high) + return ar; + } + return NULL; +} + +static struct ath12k *ath12k_get_ar_by_ctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *ctx) +{ + if (!ctx) + return NULL; + + return ath12k_mac_get_ar_by_chan(hw, ctx->def.chan); +} + +static struct ath12k *ath12k_get_ar_by_vif(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + + /* If there is one pdev within ah, then we return + * ar directly. + */ + if (ah->num_radio == 1) + return ah->radio; + + if (arvif->is_created) + return arvif->ar; + + return NULL; +} + static void ath12k_pdev_caps_update(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; @@ -1169,7 +1222,7 @@ static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) struct ath12k *ar; int ret; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_ah_to_ar(ah, 0); ret = ath12k_mac_config(ar, changed); if (ret) @@ -1345,6 +1398,75 @@ static void ath12k_control_beaconing(struct ath12k_vif *arvif, ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id); } +static void ath12k_mac_handle_beacon_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct sk_buff *skb = data; + struct ieee80211_mgmt *mgmt = (void *)skb->data; + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + if (!ether_addr_equal(mgmt->bssid, vif->bss_conf.bssid)) + return; + + cancel_delayed_work(&arvif->connection_loss_work); +} + +void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb) +{ + ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar), + IEEE80211_IFACE_ITER_NORMAL, + ath12k_mac_handle_beacon_iter, + skb); +} + +static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + u32 *vdev_id = data; + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k *ar = arvif->ar; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); + + if (arvif->vdev_id != *vdev_id) + return; + + if (!arvif->is_up) + return; + + ieee80211_beacon_loss(vif); + + /* Firmware doesn't report beacon loss events repeatedly. If AP probe + * (done by mac80211) succeeds but beacons do not resume then it + * doesn't make sense to continue operation. Queue connection loss work + * which can be cancelled when beacon is received. + */ + ieee80211_queue_delayed_work(hw, &arvif->connection_loss_work, + ATH12K_CONNECTION_LOSS_HZ); +} + +void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id) +{ + ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar), + IEEE80211_IFACE_ITER_NORMAL, + ath12k_mac_handle_beacon_miss_iter, + &vdev_id); +} + +static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work) +{ + struct ath12k_vif *arvif = container_of(work, struct ath12k_vif, + connection_loss_work.work); + struct ieee80211_vif *vif = arvif->vif; + + if (!arvif->is_up) + return; + + ieee80211_connection_loss(vif); +} + static void ath12k_peer_assoc_h_basic(struct ath12k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -2517,7 +2639,7 @@ static void ath12k_bss_disassoc(struct ath12k *ar, arvif->is_up = false; - /* TODO: cancel connection_loss_work */ + cancel_delayed_work(&arvif->connection_loss_work); } static u32 ath12k_mac_get_rate_hw_value(int bitrate) @@ -2961,16 +3083,42 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, } } +static struct ath12k_vif_cache *ath12k_arvif_get_cache(struct ath12k_vif *arvif) +{ + if (!arvif->cache) + arvif->cache = kzalloc(sizeof(*arvif->cache), GFP_KERNEL); + + return arvif->cache; +} + +static void ath12k_arvif_put_cache(struct ath12k_vif *arvif) +{ + kfree(arvif->cache); + arvif->cache = NULL; +} + static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, u64 changed) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif_cache *cache; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_get_ar_by_vif(hw, vif); + + /* if the vdev is not created on a certain radio, + * cache the info to be updated later on vdev creation + */ + + if (!ar) { + cache = ath12k_arvif_get_cache(arvif); + if (!cache) + return; + arvif->cache->bss_conf_changed |= changed; + return; + } mutex_lock(&ar->conf_mutex); @@ -2979,6 +3127,42 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); } +static struct ath12k* +ath12k_mac_select_scan_device(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_scan_request *req) +{ + struct ath12k_hw *ah = hw->priv; + enum nl80211_band band; + struct ath12k *ar; + int i; + + if (ah->num_radio == 1) + return ah->radio; + + /* Currently mac80211 supports splitting scan requests into + * multiple scan requests per band. + * Loop through first channel and determine the scan radio + * TODO: There could be 5 GHz low/high channels in that case + * split the hw request and perform multiple scans + */ + + if (req->req.channels[0]->center_freq < ATH12K_MIN_5G_FREQ) + band = NL80211_BAND_2GHZ; + else if (req->req.channels[0]->center_freq < ATH12K_MIN_6G_FREQ) + band = NL80211_BAND_5GHZ; + else + band = NL80211_BAND_6GHZ; + + for_each_ar(ah, ar, i) { + /* TODO 5 GHz low high split changes */ + if (ar->mac.sbands[band].channels) + return ar; + } + + return NULL; +} + void __ath12k_mac_scan_finish(struct ath12k *ar) { struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); @@ -3148,15 +3332,68 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_scan_request *hw_req) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k *ar; + struct ath12k *ar, *prev_ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct cfg80211_scan_request *req = &hw_req->req; struct ath12k_wmi_scan_req_arg arg = {}; int ret; int i; + bool create = true; + + if (ah->num_radio == 1) { + WARN_ON(!arvif->is_created); + ar = ath12k_ah_to_ar(ah, 0); + goto scan; + } + + /* Since the targeted scan device could depend on the frequency + * requested in the hw_req, select the corresponding radio + */ + ar = ath12k_mac_select_scan_device(hw, vif, hw_req); + if (!ar) + return -EINVAL; - ar = ath12k_ah_to_ar(ah); + /* If the vif is already assigned to a specific vdev of an ar, + * check whether its already started, vdev which is started + * are not allowed to switch to a new radio. + * If the vdev is not started, but was earlier created on a + * different ar, delete that vdev and create a new one. We don't + * delete at the scan stop as an optimization to avoid redundant + * delete-create vdev's for the same ar, in case the request is + * always on the same band for the vif + */ + if (arvif->is_created) { + if (WARN_ON(!arvif->ar)) + return -EINVAL; + if (ar != arvif->ar && arvif->is_started) + return -EINVAL; + + if (ar != arvif->ar) { + /* backup the previously used ar ptr, since the vdev delete + * would assign the arvif->ar to NULL after the call + */ + prev_ar = arvif->ar; + mutex_lock(&prev_ar->conf_mutex); + ret = ath12k_mac_vdev_delete(prev_ar, vif); + mutex_unlock(&prev_ar->conf_mutex); + if (ret) + ath12k_warn(prev_ar->ab, + "unable to delete scan vdev %d\n", ret); + } else { + create = false; + } + } + if (create) { + mutex_lock(&ar->conf_mutex); + ret = ath12k_mac_vdev_create(ar, vif); + mutex_unlock(&ar->conf_mutex); + if (ret) { + ath12k_warn(ar->ab, "unable to create scan vdev %d\n", ret); + return -EINVAL; + } + } +scan: mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); @@ -3242,10 +3479,13 @@ exit: static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k *ar; - ar = ath12k_ah_to_ar(ah); + if (!arvif->is_created) + return; + + ar = arvif->ar; mutex_lock(&ar->conf_mutex); ath12k_scan_abort(ar); @@ -3369,13 +3609,11 @@ static int ath12k_clear_peer_keys(struct ath12k_vif *arvif, return first_errno; } -static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) +static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k *ar; - struct ath12k_base *ab; + struct ath12k_base *ab = ar->ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_peer *peer; struct ath12k_sta *arsta; @@ -3383,24 +3621,11 @@ static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, int ret = 0; u32 flags = 0; - /* BIP needs to be done in software */ - if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC || - key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || - key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || - key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) - return 1; - - ar = ath12k_ah_to_ar(ah); - ab = ar->ab; + lockdep_assert_held(&ar->conf_mutex); - if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) + if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) return 1; - if (key->keyidx > WMI_MAX_KEY_INDEX) - return -ENOSPC; - - mutex_lock(&ar->conf_mutex); - if (sta) peer_addr = sta->addr; else if (arvif->vdev_type == WMI_VDEV_TYPE_STA) @@ -3492,6 +3717,47 @@ static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, spin_unlock_bh(&ab->base_lock); exit: + return ret; +} + +static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif_cache *cache; + struct ath12k *ar; + int ret; + + /* BIP needs to be done in software */ + if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC || + key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || + key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || + key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) + return 1; + + if (key->keyidx > WMI_MAX_KEY_INDEX) + return -ENOSPC; + + ar = ath12k_get_ar_by_vif(hw, vif); + if (!ar) { + /* ar is expected to be valid when sta ptr is available */ + if (sta) { + WARN_ON_ONCE(1); + return -EINVAL; + } + + cache = ath12k_arvif_get_cache(arvif); + if (!cache) + return -ENOSPC; + cache->key_conf.cmd = cmd; + cache->key_conf.key = key; + cache->key_conf.changed = true; + return 0; + } + + mutex_lock(&ar->conf_mutex); + ret = ath12k_mac_set_key(ar, cmd, vif, sta, key); mutex_unlock(&ar->conf_mutex); return ret; } @@ -3968,7 +4234,6 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); @@ -3980,7 +4245,11 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, new_state == IEEE80211_STA_NOTEXIST)) cancel_work_sync(&arsta->update_wk); - ar = ath12k_ah_to_ar(ah); + ar = ath12k_get_ar_by_vif(hw, vif); + if (!ar) { + WARN_ON_ONCE(1); + return -EINVAL; + } mutex_lock(&ar->conf_mutex); @@ -4109,7 +4378,7 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL) return -EINVAL; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_ah_to_ar(ah, 0); mutex_lock(&ar->conf_mutex); @@ -4131,14 +4400,17 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u32 changed) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_peer *peer; u32 bw, smps; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_get_ar_by_vif(hw, vif); + if (!ar) { + WARN_ON_ONCE(1); + return; + } spin_lock_bh(&ar->ab->base_lock); @@ -4314,12 +4586,22 @@ static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw, unsigned int link_id, u16 ac, const struct ieee80211_tx_queue_params *params) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif_cache *cache = arvif->cache; int ret; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_get_ar_by_vif(hw, vif); + if (!ar) { + /* cache the info and apply after vdev is created */ + cache = ath12k_arvif_get_cache(arvif); + if (!cache) + return -ENOSPC; + cache->tx_conf.changed = true; + cache->tx_conf.ac = ac; + cache->tx_conf.tx_queue_params = *params; + return 0; + } mutex_lock(&ar->conf_mutex); ret = ath12k_mac_conf_tx(arvif, link_id, ac, params); @@ -4997,6 +5279,13 @@ static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant) if (ath12k_check_chain_mask(ar, rx_ant, false)) return -EINVAL; + /* Since we advertised the max cap of all radios combined during wiphy + * registration, ensure we don't set the antenna config higher than the + * limits + */ + tx_ant = min_t(u32, tx_ant, ar->pdev->cap.tx_chain_mask); + rx_ant = min_t(u32, rx_ant, ar->pdev->cap.rx_chain_mask); + ar->cfg_tx_chainmask = tx_ant; ar->cfg_rx_chainmask = rx_ant; @@ -5443,23 +5732,39 @@ err: return ret; } +static void ath12k_drain_tx(struct ath12k_hw *ah) +{ + struct ath12k *ar; + int i; + + for_each_ar(ah, ar, i) + ath12k_mac_drain_tx(ar); +} + static int ath12k_mac_op_start(struct ieee80211_hw *hw) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k *ar = ath12k_ah_to_ar(ah); - struct ath12k_base *ab = ar->ab; - int ret; + struct ath12k *ar; + int ret, i; - ath12k_mac_drain_tx(ar); + ath12k_drain_tx(ah); - ret = ath12k_mac_start(ar); - if (ret) { - ath12k_err(ab, "fail to start mac operations in pdev idx %d ret %d\n", - ar->pdev_idx, ret); - return ret; + for_each_ar(ah, ar, i) { + ret = ath12k_mac_start(ar); + if (ret) { + ath12k_err(ar->ab, "fail to start mac operations in pdev idx %d ret %d\n", + ar->pdev_idx, ret); + goto fail_start; + } } return 0; +fail_start: + for (; i > 0; i--) { + ar = ath12k_ah_to_ar(ah, i - 1); + ath12k_mac_stop(ar); + } + return ret; } int ath12k_mac_rfkill_config(struct ath12k *ar) @@ -5555,11 +5860,13 @@ static void ath12k_mac_stop(struct ath12k *ar) static void ath12k_mac_op_stop(struct ieee80211_hw *hw) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k *ar = ath12k_ah_to_ar(ah); + struct ath12k *ar; + int i; - ath12k_mac_drain_tx(ar); + ath12k_drain_tx(ah); - ath12k_mac_stop(ar); + for_each_ar(ah, ar, i) + ath12k_mac_stop(ar); } static u8 @@ -5732,64 +6039,24 @@ static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, ath12k_mac_update_vif_offload(arvif); } -static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static int ath12k_mac_vdev_create(struct ath12k *ar, struct ieee80211_vif *vif) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k *ar; - struct ath12k_base *ab; + struct ath12k_hw *ah = ar->ah; + struct ath12k_base *ab = ar->ab; + struct ieee80211_hw *hw = ah->hw; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_wmi_vdev_create_arg vdev_arg = {0}; struct ath12k_wmi_peer_create_arg peer_param; u32 param_id, param_value; u16 nss; int i; - int ret; - int bit; + int ret, vdev_id; - vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; - - ar = ath12k_ah_to_ar(ah); - ab = ar->ab; - - mutex_lock(&ar->conf_mutex); - - if (vif->type == NL80211_IFTYPE_AP && - ar->num_peers > (ar->max_num_peers - 1)) { - ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n"); - ret = -ENOBUFS; - goto err; - } - - if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) { - ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n", - TARGET_NUM_VDEVS); - ret = -EBUSY; - goto err; - } - - memset(arvif, 0, sizeof(*arvif)); + lockdep_assert_held(&ar->conf_mutex); arvif->ar = ar; - arvif->vif = vif; - - INIT_LIST_HEAD(&arvif->list); - - /* Should we initialize any worker to handle connection loss indication - * from firmware in sta mode? - */ - - for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { - arvif->bitrate_mask.control[i].legacy = 0xffffffff; - memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff, - sizeof(arvif->bitrate_mask.control[i].ht_mcs)); - memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, - sizeof(arvif->bitrate_mask.control[i].vht_mcs)); - } - - bit = __ffs64(ab->free_vdev_map); - - arvif->vdev_id = bit; + vdev_id = __ffs64(ab->free_vdev_map); + arvif->vdev_id = vdev_id; arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; switch (vif->type) { @@ -5813,7 +6080,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, break; case NL80211_IFTYPE_MONITOR: arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; - ar->monitor_vdev_id = bit; + ar->monitor_vdev_id = vdev_id; break; case NL80211_IFTYPE_P2P_DEVICE: arvif->vdev_type = WMI_VDEV_TYPE_STA; @@ -5824,7 +6091,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, break; } - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac add interface id %d type %d subtype %d map %llx\n", + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev create id %d type %d subtype %d map %llx\n", arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, ab->free_vdev_map); @@ -5842,6 +6109,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, } ar->num_created_vdevs++; + arvif->is_created = true; ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM created, vdev_id %d\n", vif->addr, arvif->vdev_id); ar->allocated_vdev_map |= 1LL << arvif->vdev_id; @@ -5942,8 +6210,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, if (vif->type != NL80211_IFTYPE_MONITOR && ar->monitor_conf_enabled) ath12k_mac_monitor_vdev_create(ar); - mutex_unlock(&ar->conf_mutex); - + arvif->ar = ar; return ret; err_peer_del: @@ -5969,6 +6236,8 @@ err_peer_del: err_vdev_del: ath12k_wmi_vdev_delete(ar, arvif->vdev_id); ar->num_created_vdevs--; + arvif->is_created = false; + arvif->ar = NULL; ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); ab->free_vdev_map |= 1LL << arvif->vdev_id; ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id); @@ -5977,9 +6246,171 @@ err_vdev_del: spin_unlock_bh(&ar->data_lock); err: + arvif->ar = NULL; + return ret; +} + +static void ath12k_mac_vif_cache_flush(struct ath12k *ar, struct ieee80211_vif *vif) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_vif_cache *cache = arvif->cache; + struct ath12k_base *ab = ar->ab; + + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + if (!cache) + return; + + if (cache->tx_conf.changed) { + ret = ath12k_mac_conf_tx(arvif, 0, cache->tx_conf.ac, + &cache->tx_conf.tx_queue_params); + if (ret) + ath12k_warn(ab, + "unable to apply tx config parameters to vdev %d\n", + ret); + } + + if (cache->bss_conf_changed) { + ath12k_mac_bss_info_changed(ar, arvif, &vif->bss_conf, + cache->bss_conf_changed); + } + + if (cache->key_conf.changed) { + ret = ath12k_mac_set_key(ar, cache->key_conf.cmd, vif, NULL, + cache->key_conf.key); + if (ret) + ath12k_warn(ab, "unable to apply set key param to vdev %d ret %d\n", + arvif->vdev_id, ret); + } + ath12k_arvif_put_cache(arvif); +} + +static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *ctx) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_hw *ah = hw->priv; + struct ath12k *ar, *prev_ar; + struct ath12k_base *ab; + int ret; + + if (ah->num_radio == 1) + ar = ah->radio; + else if (ctx) + ar = ath12k_get_ar_by_ctx(hw, ctx); + else + return NULL; + + if (!ar) + return NULL; + + if (arvif->ar) { + /* This is not expected really */ + if (WARN_ON(!arvif->is_created)) { + arvif->ar = NULL; + return NULL; + } + + if (ah->num_radio == 1) + return arvif->ar; + + /* This can happen as scan vdev gets created during multiple scans + * across different radios before a vdev is brought up in + * a certain radio. + */ + if (ar != arvif->ar) { + if (WARN_ON(arvif->is_started)) + return NULL; + + /* backup the previously used ar ptr since arvif->ar would + * be set to NULL after vdev delete is done + */ + prev_ar = arvif->ar; + mutex_lock(&prev_ar->conf_mutex); + ret = ath12k_mac_vdev_delete(prev_ar, vif); + + if (ret) + ath12k_warn(prev_ar->ab, "unable to delete vdev %d\n", + ret); + mutex_unlock(&prev_ar->conf_mutex); + } + } + + ab = ar->ab; + + mutex_lock(&ar->conf_mutex); + + if (arvif->is_created) + goto flush; + + if (vif->type == NL80211_IFTYPE_AP && + ar->num_peers > (ar->max_num_peers - 1)) { + ath12k_warn(ab, "failed to create vdev due to insufficient peer entry resource in firmware\n"); + goto unlock; + } + + if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) { + ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n", + TARGET_NUM_VDEVS); + goto unlock; + } + + ret = ath12k_mac_vdev_create(ar, vif); + if (ret) { + ath12k_warn(ab, "failed to create vdev %pM ret %d", vif->addr, ret); + goto unlock; + } + +flush: + /* If the vdev is created during channel assign and not during + * add_interface(), Apply any parameters for the vdev which were received + * after add_interface, corresponding to this vif. + */ + ath12k_mac_vif_cache_flush(ar, vif); +unlock: mutex_unlock(&ar->conf_mutex); + return arvif->ar; +} - return ret; +static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + int i; + + memset(arvif, 0, sizeof(*arvif)); + + arvif->vif = vif; + + INIT_LIST_HEAD(&arvif->list); + INIT_DELAYED_WORK(&arvif->connection_loss_work, + ath12k_mac_vif_sta_connection_loss_work); + + for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { + arvif->bitrate_mask.control[i].legacy = 0xffffffff; + memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].ht_mcs)); + memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].vht_mcs)); + } + + /* Allocate Default Queue now and reassign during actual vdev create */ + vif->cab_queue = ATH12K_HW_DEFAULT_QUEUE; + for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++) + vif->hw_queue[i] = ATH12K_HW_DEFAULT_QUEUE; + + vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; + + /* For single radio wiphy(i.e ah->num_radio is 1), create the vdev + * during add_interface itself, for multi radio wiphy, defer the vdev + * creation until channel_assign to determine the radio on which the + * vdev needs to be created + */ + ath12k_mac_assign_vif_to_vdev(hw, vif, NULL); + return 0; } static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif) @@ -6007,31 +6438,14 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif } } -static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static int ath12k_mac_vdev_delete(struct ath12k *ar, struct ieee80211_vif *vif) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_base *ab; + struct ath12k_base *ab = ar->ab; unsigned long time_left; int ret; - ar = ath12k_ah_to_ar(ah); - ab = ar->ab; - - mutex_lock(&ar->conf_mutex); - - ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n", - arvif->vdev_id); - - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { - ret = ath12k_peer_delete(ar, arvif->vdev_id, vif->addr); - if (ret) - ath12k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n", - arvif->vdev_id, ret); - } - + lockdep_assert_held(&ar->conf_mutex); reinit_completion(&ar->vdev_delete_done); ret = ath12k_wmi_vdev_delete(ar, arvif->vdev_id); @@ -6048,6 +6462,10 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, goto err_vdev_del; } + ab->free_vdev_map |= 1LL << arvif->vdev_id; + ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); + ar->num_created_vdevs--; + if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ar->monitor_vdev_id = -1; ar->monitor_vdev_created = false; @@ -6055,11 +6473,6 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, ret = ath12k_mac_monitor_vdev_delete(ar); } - ab->free_vdev_map |= 1LL << (arvif->vdev_id); - ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); - ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id); - ar->num_created_vdevs--; - ath12k_dbg(ab, ATH12K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n", vif->addr, arvif->vdev_id); @@ -6069,6 +6482,7 @@ err_vdev_del: spin_unlock_bh(&ar->data_lock); ath12k_peer_cleanup(ar, arvif->vdev_id); + ath12k_arvif_put_cache(arvif); idr_for_each(&ar->txmgmt_idr, ath12k_mac_vif_txmgmt_idr_remove, vif); @@ -6081,6 +6495,46 @@ err_vdev_del: clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); /* TODO: recal traffic pause state based on the available vdevs */ + arvif->is_created = false; + arvif->ar = NULL; + + return ret; +} + +static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_base *ab; + struct ath12k *ar; + int ret; + + if (!arvif->is_created) { + /* if we cached some config but never received assign chanctx, + * free the allocated cache. + */ + ath12k_arvif_put_cache(arvif); + return; + } + + ar = arvif->ar; + ab = ar->ab; + + cancel_delayed_work_sync(&arvif->connection_loss_work); + + mutex_lock(&ar->conf_mutex); + + ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n", + arvif->vdev_id); + + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + ret = ath12k_peer_delete(ar, arvif->vdev_id, vif->addr); + if (ret) + ath12k_warn(ab, "failed to submit AP self-peer removal on vdev %d: %d\n", + arvif->vdev_id, ret); + } + + ath12k_mac_vdev_delete(ar, vif); mutex_unlock(&ar->conf_mutex); } @@ -6132,7 +6586,7 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_ah_to_ar(ah, 0); mutex_lock(&ar->conf_mutex); @@ -6145,16 +6599,19 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + int antennas_rx = 0, antennas_tx = 0; struct ath12k *ar; + int i; - ar = ath12k_ah_to_ar(ah); - - mutex_lock(&ar->conf_mutex); - - *tx_ant = ar->cfg_tx_chainmask; - *rx_ant = ar->cfg_rx_chainmask; + for_each_ar(ah, ar, i) { + mutex_lock(&ar->conf_mutex); + antennas_rx = max_t(u32, antennas_rx, ar->cfg_rx_chainmask); + antennas_tx = max_t(u32, antennas_tx, ar->cfg_tx_chainmask); + mutex_unlock(&ar->conf_mutex); + } - mutex_unlock(&ar->conf_mutex); + *tx_ant = antennas_tx; + *rx_ant = antennas_rx; return 0; } @@ -6163,13 +6620,16 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; - int ret; - - ar = ath12k_ah_to_ar(ah); + int ret = 0; + int i; - mutex_lock(&ar->conf_mutex); - ret = __ath12k_set_antenna(ar, tx_ant, rx_ant); - mutex_unlock(&ar->conf_mutex); + for_each_ar(ah, ar, i) { + mutex_lock(&ar->conf_mutex); + ret = __ath12k_set_antenna(ar, tx_ant, rx_ant); + mutex_unlock(&ar->conf_mutex); + if (ret) + break; + } return ret; } @@ -6213,7 +6673,11 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret = -EINVAL; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_get_ar_by_vif(hw, vif); + if (!ar) + return -EINVAL; + + ar = ath12k_ah_to_ar(ah, 0); mutex_lock(&ar->conf_mutex); ret = ath12k_mac_ampdu_action(arvif, params); @@ -6229,15 +6693,17 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_base *ab; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_get_ar_by_ctx(hw, ctx); + if (!ar) + return -EINVAL; + ab = ar->ab; ath12k_dbg(ab, ATH12K_DBG_MAC, - "mac chanctx add freq %u width %d ptr %pK\n", + "mac chanctx add freq %u width %d ptr %p\n", ctx->def.chan->center_freq, ctx->def.width, ctx); mutex_lock(&ar->conf_mutex); @@ -6257,15 +6723,17 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_base *ab; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_get_ar_by_ctx(hw, ctx); + if (!ar) + return; + ab = ar->ab; ath12k_dbg(ab, ATH12K_DBG_MAC, - "mac chanctx remove freq %u width %d ptr %pK\n", + "mac chanctx remove freq %u width %d ptr %p\n", ctx->def.chan->center_freq, ctx->def.width, ctx); mutex_lock(&ar->conf_mutex); @@ -6286,14 +6754,24 @@ ath12k_mac_check_down_grade_phy_mode(struct ath12k *ar, enum nl80211_band band, enum nl80211_iftype type) { - struct ieee80211_sta_eht_cap *eht_cap; + struct ieee80211_sta_eht_cap *eht_cap = NULL; enum wmi_phy_mode down_mode; + int n = ar->mac.sbands[band].n_iftype_data; + int i; + struct ieee80211_sband_iftype_data *data; if (mode < MODE_11BE_EHT20) return mode; - eht_cap = &ar->mac.iftype[band][type].eht_cap; - if (eht_cap->has_eht) + data = ar->mac.iftype[band]; + for (i = 0; i < n; i++) { + if (data[i].types_mask & BIT(type)) { + eht_cap = &data[i].eht_cap; + break; + } + } + + if (eht_cap && eht_cap->has_eht) return mode; switch (mode) { @@ -6468,14 +6946,19 @@ struct ath12k_mac_change_chanctx_arg { struct ieee80211_vif_chanctx_switch *vifs; int n_vifs; int next_vif; + struct ath12k *ar; }; static void ath12k_mac_change_chanctx_cnt_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_mac_change_chanctx_arg *arg = data; + if (arvif->ar != arg->ar) + return; + if (rcu_access_pointer(vif->bss_conf.chanctx_conf) != arg->ctx) return; @@ -6486,9 +6969,13 @@ static void ath12k_mac_change_chanctx_fill_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_mac_change_chanctx_arg *arg = data; struct ieee80211_chanctx_conf *ctx; + if (arvif->ar != arg->ar) + return; + ctx = rcu_access_pointer(vif->bss_conf.chanctx_conf); if (ctx != arg->ctx) return; @@ -6502,6 +6989,57 @@ ath12k_mac_change_chanctx_fill_iter(void *data, u8 *mac, arg->next_vif++; } +static u32 ath12k_mac_nlwidth_to_wmiwidth(enum nl80211_chan_width width) +{ + switch (width) { + case NL80211_CHAN_WIDTH_20: + return WMI_CHAN_WIDTH_20; + case NL80211_CHAN_WIDTH_40: + return WMI_CHAN_WIDTH_40; + case NL80211_CHAN_WIDTH_80: + return WMI_CHAN_WIDTH_80; + case NL80211_CHAN_WIDTH_160: + return WMI_CHAN_WIDTH_160; + case NL80211_CHAN_WIDTH_80P80: + return WMI_CHAN_WIDTH_80P80; + case NL80211_CHAN_WIDTH_5: + return WMI_CHAN_WIDTH_5; + case NL80211_CHAN_WIDTH_10: + return WMI_CHAN_WIDTH_10; + case NL80211_CHAN_WIDTH_320: + return WMI_CHAN_WIDTH_320; + default: + WARN_ON(1); + return WMI_CHAN_WIDTH_20; + } +} + +static int ath12k_mac_update_peer_puncturing_width(struct ath12k *ar, + struct ath12k_vif *arvif, + struct cfg80211_chan_def def) +{ + u32 param_id, param_value; + int ret; + + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) + return 0; + + param_id = WMI_PEER_CHWIDTH_PUNCTURE_20MHZ_BITMAP; + param_value = ath12k_mac_nlwidth_to_wmiwidth(def.width) | + u32_encode_bits((~def.punctured), + WMI_PEER_PUNCTURE_BITMAP); + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "punctured bitmap %02x width %d vdev %d\n", + def.punctured, def.width, arvif->vdev_id); + + ret = ath12k_wmi_set_peer_param(ar, arvif->bssid, + arvif->vdev_id, param_id, + param_value); + + return ret; +} + static void ath12k_mac_update_vif_chan(struct ath12k *ar, struct ieee80211_vif_chanctx_switch *vifs, @@ -6594,6 +7132,16 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, arvif->vdev_id, ret); continue; } + + ret = ath12k_mac_update_peer_puncturing_width(arvif->ar, arvif, + vifs[i].new_ctx->def); + if (ret) { + ath12k_warn(ar->ab, + "failed to update puncturing bitmap %02x and width %d: %d\n", + vifs[i].new_ctx->def.punctured, + vifs[i].new_ctx->def.width, ret); + continue; + } } /* Restart the internal monitor vdev on new channel */ @@ -6607,7 +7155,7 @@ static void ath12k_mac_update_active_vif_chan(struct ath12k *ar, struct ieee80211_chanctx_conf *ctx) { - struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx }; + struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx, .ar = ar }; struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); lockdep_assert_held(&ar->conf_mutex); @@ -6637,17 +7185,19 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx, u32 changed) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_base *ab; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_get_ar_by_ctx(hw, ctx); + if (!ar) + return; + ab = ar->ab; mutex_lock(&ar->conf_mutex); ath12k_dbg(ab, ATH12K_DBG_MAC, - "mac chanctx change freq %u width %d ptr %pK changed %x\n", + "mac chanctx change freq %u width %d ptr %p changed %x\n", ctx->def.chan->center_freq, ctx->def.width, ctx, changed); /* This shouldn't really happen because channel switching should use @@ -6705,20 +7255,27 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_base *ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; struct ath12k_wmi_peer_create_arg param; - ar = ath12k_ah_to_ar(ah); + /* For multi radio wiphy, the vdev was not created during add_interface + * create now since we have a channel ctx now to assign to a specific ar/fw + */ + ar = ath12k_mac_assign_vif_to_vdev(hw, vif, ctx); + if (!ar) { + WARN_ON(1); + return -EINVAL; + } + ab = ar->ab; mutex_lock(&ar->conf_mutex); ath12k_dbg(ab, ATH12K_DBG_MAC, - "mac chanctx assign ptr %pK vdev_id %i\n", + "mac chanctx assign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); arvif->punct_bitmap = ctx->def.punctured; @@ -6788,19 +7345,28 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ath12k_base *ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; - ar = ath12k_ah_to_ar(ah); + /* The vif is expected to be attached to an ar's VDEV. + * We leave the vif/vdev in this function as is + * and not delete the vdev symmetric to assign_vif_chanctx() + * the VDEV will be deleted and unassigned either during + * remove_interface() or when there is a change in channel + * that moves the vif to a new ar + */ + if (!arvif->is_created) + return; + + ar = arvif->ar; ab = ar->ab; mutex_lock(&ar->conf_mutex); ath12k_dbg(ab, ATH12K_DBG_MAC, - "mac chanctx unassign ptr %pK vdev_id %i\n", + "mac chanctx unassign ptr %p vdev_id %i\n", ctx, arvif->vdev_id); WARN_ON(!arvif->is_started); @@ -6820,7 +7386,8 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, arvif->is_started = false; } - if (arvif->vdev_type != WMI_VDEV_TYPE_STA) { + if (arvif->vdev_type != WMI_VDEV_TYPE_STA && + arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { ath12k_bss_disassoc(ar, arvif); ret = ath12k_mac_vdev_stop(arvif); if (ret) @@ -6846,13 +7413,20 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, int n_vifs, enum ieee80211_chanctx_switch_mode mode) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_get_ar_by_ctx(hw, vifs->old_ctx); + if (!ar) + return -EINVAL; mutex_lock(&ar->conf_mutex); + /* Switching channels across radio is not allowed */ + if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx)) { + mutex_unlock(&ar->conf_mutex); + return -EINVAL; + } + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac chanctx switch n_vifs %d mode %d\n", n_vifs, mode); @@ -6893,11 +7467,21 @@ static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; - int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD, ret; + int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD, ret = 0, i; - ar = ath12k_ah_to_ar(ah); - - ret = ath12k_set_vdev_param_to_all_vifs(ar, param_id, value); + /* Currently we set the rts threshold value to all the vifs across + * all radios of the single wiphy. + * TODO Once support for vif specific RTS threshold in mac80211 is + * available, ath12k can make use of it. + */ + for_each_ar(ah, ar, i) { + ret = ath12k_set_vdev_param_to_all_vifs(ar, param_id, value); + if (ret) { + ath12k_warn(ar->ab, "failed to set RTS config for all vdevs of pdev %d", + ar->pdev->pdev_id); + break; + } + } return ret; } @@ -6917,33 +7501,62 @@ static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) return -EOPNOTSUPP; } -static void ath12k_mac_flush(struct ath12k *ar) +static int ath12k_mac_flush(struct ath12k *ar) { long time_left; + int ret = 0; time_left = wait_event_timeout(ar->dp.tx_empty_waitq, (atomic_read(&ar->dp.num_tx_pending) == 0), ATH12K_FLUSH_TIMEOUT); - if (time_left == 0) - ath12k_warn(ar->ab, "failed to flush transmit queue %ld\n", time_left); + if (time_left == 0) { + ath12k_warn(ar->ab, + "failed to flush transmit queue, data pkts pending %d\n", + atomic_read(&ar->dp.num_tx_pending)); + ret = -ETIMEDOUT; + } time_left = wait_event_timeout(ar->txmgmt_empty_waitq, (atomic_read(&ar->num_pending_mgmt_tx) == 0), ATH12K_FLUSH_TIMEOUT); - if (time_left == 0) - ath12k_warn(ar->ab, "failed to flush mgmt transmit queue %ld\n", - time_left); + if (time_left == 0) { + ath12k_warn(ar->ab, + "failed to flush mgmt transmit queue, mgmt pkts pending %d\n", + atomic_read(&ar->num_pending_mgmt_tx)); + ret = -ETIMEDOUT; + } + + return ret; +} + +int ath12k_mac_wait_tx_complete(struct ath12k *ar) +{ + ath12k_mac_drain_tx(ar); + return ath12k_mac_flush(ar); } static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k *ar = ath12k_ah_to_ar(ah); + struct ath12k *ar; + int i; if (drop) return; + /* vif can be NULL when flush() is considered for hw */ + if (!vif) { + for_each_ar(ah, ar, i) + ath12k_mac_flush(ar); + return; + } + + ar = ath12k_get_ar_by_vif(hw, vif); + + if (!ar) + return; + ath12k_mac_flush(ar); } @@ -7145,6 +7758,9 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data, struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); struct ath12k *ar = arvif->ar; + if (arsta->arvif != arvif) + return; + spin_lock_bh(&ar->data_lock); arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED; spin_unlock_bh(&ar->data_lock); @@ -7155,10 +7771,14 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data, static void ath12k_mac_disable_peer_fixed_rate(void *data, struct ieee80211_sta *sta) { + struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); struct ath12k_vif *arvif = data; struct ath12k *ar = arvif->ar; int ret; + if (arsta->arvif != arvif) + return; + ret = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, WMI_PEER_PARAM_FIXED_RATE, @@ -7306,7 +7926,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) return; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_ah_to_ar(ah, 0); ab = ar->ab; mutex_lock(&ar->conf_mutex); @@ -7392,21 +8012,13 @@ ath12k_mac_update_bss_chan_survey(struct ath12k *ar, static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) { - struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; struct ieee80211_supported_band *sband; struct survey_info *ar_survey; - int ret = 0; if (idx >= ATH12K_NUM_CHANS) return -ENOENT; - ar = ath12k_ah_to_ar(ah); - - ar_survey = &ar->survey[idx]; - - mutex_lock(&ar->conf_mutex); - sband = hw->wiphy->bands[NL80211_BAND_2GHZ]; if (sband && idx >= sband->n_channels) { idx -= sband->n_channels; @@ -7416,11 +8028,22 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, if (!sband) sband = hw->wiphy->bands[NL80211_BAND_5GHZ]; - if (!sband || idx >= sband->n_channels) { - ret = -ENOENT; - goto exit; + if (!sband || idx >= sband->n_channels) + return -ENOENT; + + ar = ath12k_mac_get_ar_by_chan(hw, &sband->channels[idx]); + if (!ar) { + if (sband->channels[idx].flags & IEEE80211_CHAN_DISABLED) { + memset(survey, 0, sizeof(*survey)); + return 0; + } + return -ENOENT; } + ar_survey = &ar->survey[idx]; + + mutex_lock(&ar->conf_mutex); + ath12k_mac_update_bss_chan_survey(ar, &sband->channels[idx]); spin_lock_bh(&ar->data_lock); @@ -7432,10 +8055,8 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, if (ar->rx_channel == survey->channel) survey->filled |= SURVEY_INFO_IN_USE; -exit: mutex_unlock(&ar->conf_mutex); - - return ret; + return 0; } static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, @@ -7478,7 +8099,7 @@ static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_ah_to_ar(ah, 0); mutex_lock(&ar->conf_mutex); @@ -7508,7 +8129,7 @@ static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, u32 scan_time_msec; int ret; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_ah_to_ar(ah, 0); mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); @@ -7643,6 +8264,9 @@ static void ath12k_mac_update_ch_list(struct ath12k *ar, band->channels[i].center_freq > freq_high) band->channels[i].flags |= IEEE80211_CHAN_DISABLED; } + + ar->freq_low = freq_low; + ar->freq_high = freq_high; } static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band) @@ -7667,6 +8291,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, { struct ieee80211_supported_band *band; struct ath12k_wmi_hal_reg_capabilities_ext_arg *reg_cap; + struct ath12k_hw *ah = ar->ah; void *channels; u32 phy_id; @@ -7721,6 +8346,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, ath12k_mac_update_ch_list(ar, band, reg_cap->low_5ghz_chan, reg_cap->high_5ghz_chan); + ah->use_6ghz_regd = true; } if (reg_cap->low_5ghz_chan < ATH12K_MIN_6G_FREQ) { @@ -7757,10 +8383,12 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, static u16 ath12k_mac_get_ifmodes(struct ath12k_hw *ah) { - struct ath12k *ar = ath12k_ah_to_ar(ah); + struct ath12k *ar; + int i; u16 interface_modes = U16_MAX; - interface_modes &= ar->ab->hw_params->interface_modes; + for_each_ar(ah, ar, i) + interface_modes &= ar->ab->hw_params->interface_modes; return interface_modes == U16_MAX ? 0 : interface_modes; } @@ -7768,15 +8396,19 @@ static u16 ath12k_mac_get_ifmodes(struct ath12k_hw *ah) static bool ath12k_mac_is_iface_mode_enable(struct ath12k_hw *ah, enum nl80211_iftype type) { - struct ath12k *ar = ath12k_ah_to_ar(ah); + struct ath12k *ar; + int i; u16 interface_modes, mode; bool is_enable = true; mode = BIT(type); - - interface_modes = ar->ab->hw_params->interface_modes; - if (!(interface_modes & mode)) - is_enable = false; + for_each_ar(ah, ar, i) { + interface_modes = ar->ab->hw_params->interface_modes; + if (!(interface_modes & mode)) { + is_enable = false; + break; + } + } return is_enable; } @@ -7857,19 +8489,23 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) static const u8 ath12k_if_types_ext_capa[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, }; static const u8 ath12k_if_types_ext_capa_sta[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT, }; static const u8 ath12k_if_types_ext_capa_ap[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, [9] = WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT, + [10] = WLAN_EXT_CAPA11_EMA_SUPPORT, }; static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { @@ -7906,13 +8542,16 @@ static void ath12k_mac_hw_unregister(struct ath12k_hw *ah) { struct ieee80211_hw *hw = ah->hw; struct wiphy *wiphy = hw->wiphy; - struct ath12k *ar = ath12k_ah_to_ar(ah); + struct ath12k *ar; + int i; - cancel_work_sync(&ar->regd_update_work); + for_each_ar(ah, ar, i) + cancel_work_sync(&ar->regd_update_work); ieee80211_unregister_hw(hw); - ath12k_mac_cleanup_unregister(ar); + for_each_ar(ah, ar, i) + ath12k_mac_cleanup_unregister(ar); kfree(wiphy->iface_combinations[0].limits); kfree(wiphy->iface_combinations); @@ -7952,7 +8591,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) { struct ieee80211_hw *hw = ah->hw; struct wiphy *wiphy = hw->wiphy; - struct ath12k *ar = ath12k_ah_to_ar(ah); + struct ath12k *ar = ath12k_ah_to_ar(ah, 0); struct ath12k_base *ab = ar->ab; struct ath12k_pdev *pdev; struct ath12k_pdev_cap *cap; @@ -7967,39 +8606,74 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) WLAN_CIPHER_SUITE_GCMP_256, WLAN_CIPHER_SUITE_CCMP_256, }; - int ret; - u32 ht_cap = 0; + int ret, i, j; + u32 ht_cap = U32_MAX, antennas_rx = 0, antennas_tx = 0; + bool is_6ghz = false, is_raw_mode = false, is_monitor_disable = false; + u8 *mac_addr = NULL; + u8 mbssid_max_interfaces = 0; - pdev = ar->pdev; + wiphy->max_ap_assoc_sta = 0; - if (ab->pdevs_macaddr_valid) - ether_addr_copy(ar->mac_addr, pdev->mac_addr); - else - ether_addr_copy(ar->mac_addr, ab->mac_addr); + for_each_ar(ah, ar, i) { + u32 ht_cap_info = 0; - ret = ath12k_mac_setup_register(ar, &ht_cap, hw->wiphy->bands); - if (ret) - goto out; + pdev = ar->pdev; + if (ar->ab->pdevs_macaddr_valid) { + ether_addr_copy(ar->mac_addr, pdev->mac_addr); + } else { + ether_addr_copy(ar->mac_addr, ar->ab->mac_addr); + ar->mac_addr[4] += ar->pdev_idx; + } + + ret = ath12k_mac_setup_register(ar, &ht_cap_info, hw->wiphy->bands); + if (ret) + goto err_cleanup_unregister; + + ht_cap &= ht_cap_info; + wiphy->max_ap_assoc_sta += ar->max_num_stations; - wiphy->max_ap_assoc_sta = ar->max_num_stations; + /* Advertise the max antenna support of all radios, driver can handle + * per pdev specific antenna setting based on pdev cap when antenna + * changes are made + */ + cap = &pdev->cap; + + antennas_rx = max_t(u32, antennas_rx, cap->rx_chain_mask); + antennas_tx = max_t(u32, antennas_tx, cap->tx_chain_mask); + + if (ar->supports_6ghz) + is_6ghz = true; - cap = &pdev->cap; + if (test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) + is_raw_mode = true; - wiphy->available_antennas_rx = cap->rx_chain_mask; - wiphy->available_antennas_tx = cap->tx_chain_mask; + if (!ar->ab->hw_params->supports_monitor) + is_monitor_disable = true; + + if (i == 0) + mac_addr = ar->mac_addr; + else + mac_addr = ab->mac_addr; - SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); + mbssid_max_interfaces += TARGET_NUM_VDEVS; + } + + wiphy->available_antennas_rx = antennas_rx; + wiphy->available_antennas_tx = antennas_tx; + + SET_IEEE80211_PERM_ADDR(hw, mac_addr); SET_IEEE80211_DEV(hw, ab->dev); ret = ath12k_mac_setup_iface_combinations(ah); if (ret) { ath12k_err(ab, "failed to setup interface combinations: %d\n", ret); - goto err_cleanup_unregister; + goto err_complete_cleanup_unregister; } wiphy->interface_modes = ath12k_mac_get_ifmodes(ah); - if (wiphy->bands[NL80211_BAND_2GHZ] && + if (ah->num_radio == 1 && + wiphy->bands[NL80211_BAND_2GHZ] && wiphy->bands[NL80211_BAND_5GHZ] && wiphy->bands[NL80211_BAND_6GHZ]) ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); @@ -8050,6 +8724,12 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; + /* MLO is not yet supported so disable Wireless Extensions for now + * to make sure ath12k users don't use it. This flag can be removed + * once WIPHY_FLAG_SUPPORTS_MLO is enabled. + */ + wiphy->flags |= WIPHY_FLAG_DISABLE_WEXT; + hw->queues = ATH12K_HW_MAX_QUEUES; wiphy->tx_queue_len = ATH12K_QUEUE_LEN; hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; @@ -8067,7 +8747,10 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy->iftype_ext_capab = ath12k_iftypes_ext_capa; wiphy->num_iftype_ext_capab = ARRAY_SIZE(ath12k_iftypes_ext_capa); - if (ar->supports_6ghz) { + wiphy->mbssid_max_interfaces = mbssid_max_interfaces; + wiphy->ema_max_profile_periodicity = TARGET_EMA_MAX_PROFILE_PERIOD; + + if (is_6ghz) { wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY); wiphy_ext_feature_set(wiphy, @@ -8078,7 +8761,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ath12k_reg_init(hw); - if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) { + if (!is_raw_mode) { hw->netdev_features = NETIF_F_HW_CSUM; ieee80211_hw_set(hw, SW_CRYPTO_CONTROL); ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); @@ -8090,7 +8773,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) goto err_free_if_combs; } - if (!ab->hw_params->supports_monitor) + if (is_monitor_disable) /* There's a race between calling ieee80211_register_hw() * and here where the monitor mode is enabled for a little * while. But that time is so short and in practise it make @@ -8098,11 +8781,15 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) */ wiphy->interface_modes &= ~BIT(NL80211_IFTYPE_MONITOR); - /* Apply the regd received during initialization */ - ret = ath12k_regd_update(ar, true); - if (ret) { - ath12k_err(ar->ab, "ath12k regd update failed: %d\n", ret); - goto err_unregister_hw; + for_each_ar(ah, ar, i) { + /* Apply the regd received during initialization */ + ret = ath12k_regd_update(ar, true); + if (ret) { + ath12k_err(ar->ab, "ath12k regd update failed: %d\n", ret); + goto err_unregister_hw; + } + + ath12k_debugfs_register(ar); } return 0; @@ -8114,10 +8801,15 @@ err_free_if_combs: kfree(wiphy->iface_combinations[0].limits); kfree(wiphy->iface_combinations); +err_complete_cleanup_unregister: + i = ah->num_radio; + err_cleanup_unregister: - ath12k_mac_cleanup_unregister(ar); + for (j = 0; j < i; j++) { + ar = ath12k_ah_to_ar(ah, j); + ath12k_mac_cleanup_unregister(ar); + } -out: SET_IEEE80211_DEV(hw, NULL); return ret; @@ -8243,7 +8935,7 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab, pdev_idx = pdev_map[i].pdev_idx; pdev = &ab->pdevs[pdev_idx]; - ar = ath12k_ah_to_ar(ah); + ar = ath12k_ah_to_ar(ah, i); ar->ah = ah; ar->ab = ab; ar->hw_link_id = i; diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 3f5e1be0df..69fd282b9d 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -78,4 +78,8 @@ enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw b enum hal_encrypt_type ath12k_dp_tx_get_encrypt_type(u32 cipher); int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable); int ath12k_mac_rfkill_config(struct ath12k *ar); +int ath12k_mac_wait_tx_complete(struct ath12k *ar); +void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb); +void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id); + #endif diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index adb8c3ec19..fef2f76220 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -19,34 +19,6 @@ static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = { { - .num = 0, - .name = "LOOPBACK", - .num_elements = 32, - .event_ring = 1, - .dir = DMA_TO_DEVICE, - .ee_mask = 0x4, - .pollcfg = 0, - .doorbell = MHI_DB_BRST_DISABLE, - .lpm_notify = false, - .offload_channel = false, - .doorbell_mode_switch = false, - .auto_queue = false, - }, - { - .num = 1, - .name = "LOOPBACK", - .num_elements = 32, - .event_ring = 1, - .dir = DMA_FROM_DEVICE, - .ee_mask = 0x4, - .pollcfg = 0, - .doorbell = MHI_DB_BRST_DISABLE, - .lpm_notify = false, - .offload_channel = false, - .doorbell_mode_switch = false, - .auto_queue = false, - }, - { .num = 20, .name = "IPCR", .num_elements = 32, @@ -112,34 +84,6 @@ const struct mhi_controller_config ath12k_mhi_config_qcn9274 = { static const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = { { - .num = 0, - .name = "LOOPBACK", - .num_elements = 32, - .event_ring = 0, - .dir = DMA_TO_DEVICE, - .ee_mask = 0x4, - .pollcfg = 0, - .doorbell = MHI_DB_BRST_DISABLE, - .lpm_notify = false, - .offload_channel = false, - .doorbell_mode_switch = false, - .auto_queue = false, - }, - { - .num = 1, - .name = "LOOPBACK", - .num_elements = 32, - .event_ring = 0, - .dir = DMA_FROM_DEVICE, - .ee_mask = 0x4, - .pollcfg = 0, - .doorbell = MHI_DB_BRST_DISABLE, - .lpm_notify = false, - .offload_channel = false, - .doorbell_mode_switch = false, - .auto_queue = false, - }, - { .num = 20, .name = "IPCR", .num_elements = 64, @@ -196,7 +140,7 @@ const struct mhi_controller_config ath12k_mhi_config_wcn7850 = { .max_channels = 128, .timeout_ms = 2000, .use_bounce_buf = false, - .buf_len = 0, + .buf_len = 8192, .num_channels = ARRAY_SIZE(ath12k_mhi_channels_wcn7850), .ch_cfg = ath12k_mhi_channels_wcn7850, .num_events = ARRAY_SIZE(ath12k_mhi_events_wcn7850), @@ -385,7 +329,6 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) "failed to read board id\n"); } else if (board_id & OTP_VALID_DUALMAC_BOARD_ID_MASK) { dualmac = true; - ab->slo_capable = false; ath12k_dbg(ab, ATH12K_DBG_BOOT, "dualmac fw selected for board id: %x\n", board_id); } @@ -470,6 +413,8 @@ static char *ath12k_mhi_state_to_str(enum ath12k_mhi_state mhi_state) return "POWER_ON"; case ATH12K_MHI_POWER_OFF: return "POWER_OFF"; + case ATH12K_MHI_POWER_OFF_KEEP_DEV: + return "POWER_OFF_KEEP_DEV"; case ATH12K_MHI_FORCE_POWER_OFF: return "FORCE_POWER_OFF"; case ATH12K_MHI_SUSPEND: @@ -501,6 +446,7 @@ static void ath12k_mhi_set_state_bit(struct ath12k_pci *ab_pci, set_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state); break; case ATH12K_MHI_POWER_OFF: + case ATH12K_MHI_POWER_OFF_KEEP_DEV: case ATH12K_MHI_FORCE_POWER_OFF: clear_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state); clear_bit(ATH12K_MHI_TRIGGER_RDDM, &ab_pci->mhi_state); @@ -544,6 +490,7 @@ static int ath12k_mhi_check_state_bit(struct ath12k_pci *ab_pci, return 0; break; case ATH12K_MHI_POWER_OFF: + case ATH12K_MHI_POWER_OFF_KEEP_DEV: case ATH12K_MHI_SUSPEND: if (test_bit(ATH12K_MHI_POWER_ON, &ab_pci->mhi_state) && !test_bit(ATH12K_MHI_SUSPEND, &ab_pci->mhi_state)) @@ -594,12 +541,27 @@ static int ath12k_mhi_set_state(struct ath12k_pci *ab_pci, ret = 0; break; case ATH12K_MHI_POWER_ON: - ret = mhi_async_power_up(ab_pci->mhi_ctrl); + /* In case of resume, QRTR's resume_early() is called + * right after ath12k' resume_early(). Since QRTR requires + * MHI mission mode state when preparing IPCR channels + * (see ee_mask of that channel), we need to use the 'sync' + * version here to make sure MHI is in that state when we + * return. Or QRTR might resume before that state comes, + * and as a result it fails. + * + * The 'sync' version works for non-resume (normal power on) + * case as well. + */ + ret = mhi_sync_power_up(ab_pci->mhi_ctrl); break; case ATH12K_MHI_POWER_OFF: mhi_power_down(ab_pci->mhi_ctrl, true); ret = 0; break; + case ATH12K_MHI_POWER_OFF_KEEP_DEV: + mhi_power_down_keep_dev(ab_pci->mhi_ctrl, true); + ret = 0; + break; case ATH12K_MHI_FORCE_POWER_OFF: mhi_power_down(ab_pci->mhi_ctrl, false); ret = 0; @@ -653,9 +615,17 @@ out: return ret; } -void ath12k_mhi_stop(struct ath12k_pci *ab_pci) +void ath12k_mhi_stop(struct ath12k_pci *ab_pci, bool is_suspend) { - ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF); + /* During suspend we need to use mhi_power_down_keep_dev() + * workaround, otherwise ath12k_core_resume() will timeout + * during resume. + */ + if (is_suspend) + ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF_KEEP_DEV); + else + ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF); + ath12k_mhi_set_state(ab_pci, ATH12K_MHI_DEINIT); } diff --git a/drivers/net/wireless/ath/ath12k/mhi.h b/drivers/net/wireless/ath/ath12k/mhi.h index ebc23640ce..9362ad1958 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.h +++ b/drivers/net/wireless/ath/ath12k/mhi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _ATH12K_MHI_H #define _ATH12K_MHI_H @@ -22,6 +22,7 @@ enum ath12k_mhi_state { ATH12K_MHI_DEINIT, ATH12K_MHI_POWER_ON, ATH12K_MHI_POWER_OFF, + ATH12K_MHI_POWER_OFF_KEEP_DEV, ATH12K_MHI_FORCE_POWER_OFF, ATH12K_MHI_SUSPEND, ATH12K_MHI_RESUME, @@ -34,7 +35,7 @@ extern const struct mhi_controller_config ath12k_mhi_config_qcn9274; extern const struct mhi_controller_config ath12k_mhi_config_wcn7850; int ath12k_mhi_start(struct ath12k_pci *ar_pci); -void ath12k_mhi_stop(struct ath12k_pci *ar_pci); +void ath12k_mhi_stop(struct ath12k_pci *ar_pci, bool is_suspend); int ath12k_mhi_register(struct ath12k_pci *ar_pci); void ath12k_mhi_unregister(struct ath12k_pci *ar_pci); void ath12k_mhi_set_mhictrl_reset(struct ath12k_base *ab); diff --git a/drivers/net/wireless/ath/ath12k/p2p.c b/drivers/net/wireless/ath/ath12k/p2p.c index d334df7200..3a851ee15b 100644 --- a/drivers/net/wireless/ath/ath12k/p2p.c +++ b/drivers/net/wireless/ath/ath12k/p2p.c @@ -121,7 +121,7 @@ static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac, struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_p2p_noa_arg *arg = data; - if (arvif->vdev_id != arg->vdev_id) + if (arvif->ar != arg->ar || arvif->vdev_id != arg->vdev_id) return; ath12k_p2p_noa_update(arvif, arg->noa); @@ -132,6 +132,7 @@ void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id, { struct ath12k_p2p_noa_arg arg = { .vdev_id = vdev_id, + .ar = ar, .noa = noa, }; diff --git a/drivers/net/wireless/ath/ath12k/p2p.h b/drivers/net/wireless/ath/ath12k/p2p.h index 5768139a78..b2eec51a99 100644 --- a/drivers/net/wireless/ath/ath12k/p2p.h +++ b/drivers/net/wireless/ath/ath12k/p2p.h @@ -12,6 +12,7 @@ struct ath12k_wmi_p2p_noa_info; struct ath12k_p2p_noa_arg { u32 vdev_id; + struct ath12k *ar; const struct ath12k_wmi_p2p_noa_info *noa; }; diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 14954bc051..f92b4ce49d 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -472,7 +472,8 @@ static void __ath12k_pci_ext_irq_disable(struct ath12k_base *ab) { int i; - clear_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); + if (!test_and_clear_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) + return; for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) { struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; @@ -872,7 +873,7 @@ static int ath12k_pci_claim(struct ath12k_pci *ab_pci, struct pci_dev *pdev) goto release_region; } - ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot pci_mem 0x%pK\n", ab->mem); + ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot pci_mem 0x%p\n", ab->mem); return 0; release_region: @@ -1090,14 +1091,14 @@ void ath12k_pci_ext_irq_enable(struct ath12k_base *ab) { int i; - set_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); - for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) { struct ath12k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; napi_enable(&irq_grp->napi); ath12k_pci_ext_grp_enable(irq_grp); } + + set_bit(ATH12K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); } void ath12k_pci_ext_irq_disable(struct ath12k_base *ab) @@ -1271,7 +1272,7 @@ int ath12k_pci_power_up(struct ath12k_base *ab) return 0; } -void ath12k_pci_power_down(struct ath12k_base *ab) +void ath12k_pci_power_down(struct ath12k_base *ab, bool is_suspend) { struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); @@ -1280,7 +1281,7 @@ void ath12k_pci_power_down(struct ath12k_base *ab) ath12k_pci_force_wake(ab_pci->ab); ath12k_pci_msi_disable(ab_pci); - ath12k_mhi_stop(ab_pci); + ath12k_mhi_stop(ab_pci, is_suspend); clear_bit(ATH12K_PCI_FLAG_INIT_DONE, &ab_pci->flags); ath12k_pci_sw_reset(ab_pci->ab, false); } @@ -1503,7 +1504,7 @@ static void ath12k_pci_remove(struct pci_dev *pdev) ath12k_pci_set_irq_affinity_hint(ab_pci, NULL); if (test_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags)) { - ath12k_pci_power_down(ab); + ath12k_pci_power_down(ab, false); ath12k_qmi_deinit_service(ab); goto qmi_fail; } @@ -1531,7 +1532,7 @@ static void ath12k_pci_shutdown(struct pci_dev *pdev) struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); ath12k_pci_set_irq_affinity_hint(ab_pci, NULL); - ath12k_pci_power_down(ab); + ath12k_pci_power_down(ab, false); } static __maybe_unused int ath12k_pci_pm_suspend(struct device *dev) @@ -1558,9 +1559,36 @@ static __maybe_unused int ath12k_pci_pm_resume(struct device *dev) return ret; } -static SIMPLE_DEV_PM_OPS(ath12k_pci_pm_ops, - ath12k_pci_pm_suspend, - ath12k_pci_pm_resume); +static __maybe_unused int ath12k_pci_pm_suspend_late(struct device *dev) +{ + struct ath12k_base *ab = dev_get_drvdata(dev); + int ret; + + ret = ath12k_core_suspend_late(ab); + if (ret) + ath12k_warn(ab, "failed to late suspend core: %d\n", ret); + + return ret; +} + +static __maybe_unused int ath12k_pci_pm_resume_early(struct device *dev) +{ + struct ath12k_base *ab = dev_get_drvdata(dev); + int ret; + + ret = ath12k_core_resume_early(ab); + if (ret) + ath12k_warn(ab, "failed to early resume core: %d\n", ret); + + return ret; +} + +static const struct dev_pm_ops __maybe_unused ath12k_pci_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ath12k_pci_pm_suspend, + ath12k_pci_pm_resume) + SET_LATE_SYSTEM_SLEEP_PM_OPS(ath12k_pci_pm_suspend_late, + ath12k_pci_pm_resume_early) +}; static struct pci_driver ath12k_pci_driver = { .name = "ath12k_pci", diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index ca93693ba4..6186a78038 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -143,5 +143,5 @@ int ath12k_pci_hif_resume(struct ath12k_base *ab); void ath12k_pci_stop(struct ath12k_base *ab); int ath12k_pci_start(struct ath12k_base *ab); int ath12k_pci_power_up(struct ath12k_base *ab); -void ath12k_pci_power_down(struct ath12k_base *ab); +void ath12k_pci_power_down(struct ath12k_base *ab, bool is_suspend); #endif /* ATH12K_PCI_H */ diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 92845ffff4..5484112859 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -583,6 +583,24 @@ static const struct qmi_elem_info qmi_wlanfw_phy_cap_resp_msg_v01_ei[] = { board_id), }, { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + single_chip_mlo_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + single_chip_mlo_support), + }, + { .data_type = QMI_EOTI, .array_type = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, @@ -2005,7 +2023,15 @@ static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, u8 hw_link_id = 0; int i; + if (!(ab->mlo_capable_flags & ATH12K_INTRA_DEVICE_MLO_SUPPORT)) { + ath12k_dbg(ab, ATH12K_DBG_QMI, + "intra device MLO is disabled hence skip QMI MLO cap"); + return; + } + if (!ab->qmi.num_radios || ab->qmi.num_radios == U8_MAX) { + ab->mlo_capable_flags = 0; + ath12k_dbg(ab, ATH12K_DBG_QMI, "skip QMI MLO cap due to invalid num_radio %d\n", ab->qmi.num_radios); @@ -2124,9 +2150,6 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab) struct qmi_txn txn; int ret; - if (!ab->slo_capable) - goto out; - ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_phy_cap_resp_msg_v01_ei, &resp); if (ret < 0) @@ -2151,6 +2174,13 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab) goto out; } + if (resp.single_chip_mlo_support_valid) { + if (resp.single_chip_mlo_support) + ab->mlo_capable_flags |= ATH12K_INTRA_DEVICE_MLO_SUPPORT; + else + ab->mlo_capable_flags &= ~ATH12K_INTRA_DEVICE_MLO_SUPPORT; + } + if (!resp.num_phy_valid) { ret = -ENODATA; goto out; @@ -2158,9 +2188,11 @@ static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab) ab->qmi.num_radios = resp.num_phy; - ath12k_dbg(ab, ATH12K_DBG_QMI, "phy capability resp valid %d num_phy %d valid %d board_id %d\n", + ath12k_dbg(ab, ATH12K_DBG_QMI, + "phy capability resp valid %d num_phy %d valid %d board_id %d valid %d single_chip_mlo_support %d\n", resp.num_phy_valid, resp.num_phy, - resp.board_id_valid, resp.board_id); + resp.board_id_valid, resp.board_id, + resp.single_chip_mlo_support_valid, resp.single_chip_mlo_support); return; @@ -2325,8 +2357,9 @@ static void ath12k_qmi_free_target_mem_chunk(struct ath12k_base *ab) for (i = 0; i < ab->qmi.mem_seg_count; i++) { if (!ab->qmi.target_mem[i].v.addr) continue; + dma_free_coherent(ab->dev, - ab->qmi.target_mem[i].size, + ab->qmi.target_mem[i].prev_size, ab->qmi.target_mem[i].v.addr, ab->qmi.target_mem[i].paddr); ab->qmi.target_mem[i].v.addr = NULL; @@ -2352,6 +2385,20 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) case M3_DUMP_REGION_TYPE: case PAGEABLE_MEM_REGION_TYPE: case CALDB_MEM_REGION_TYPE: + /* Firmware reloads in recovery/resume. + * In such cases, no need to allocate memory for FW again. + */ + if (chunk->v.addr) { + if (chunk->prev_type == chunk->type && + chunk->prev_size == chunk->size) + goto this_chunk_done; + + /* cannot reuse the existing chunk */ + dma_free_coherent(ab->dev, chunk->prev_size, + chunk->v.addr, chunk->paddr); + chunk->v.addr = NULL; + } + chunk->v.addr = dma_alloc_coherent(ab->dev, chunk->size, &chunk->paddr, @@ -2370,6 +2417,10 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) chunk->type, chunk->size); return -ENOMEM; } + + chunk->prev_type = chunk->type; + chunk->prev_size = chunk->size; +this_chunk_done: break; default: ath12k_warn(ab, "memory type %u not supported\n", @@ -2666,6 +2717,19 @@ out: return ret; } +static void ath12k_qmi_m3_free(struct ath12k_base *ab) +{ + struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; + + if (!m3_mem->vaddr) + return; + + dma_free_coherent(ab->dev, m3_mem->size, + m3_mem->vaddr, m3_mem->paddr); + m3_mem->vaddr = NULL; + m3_mem->size = 0; +} + static int ath12k_qmi_m3_load(struct ath12k_base *ab) { struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; @@ -2675,10 +2739,6 @@ static int ath12k_qmi_m3_load(struct ath12k_base *ab) size_t m3_len; int ret; - if (m3_mem->vaddr) - /* m3 firmware buffer is already available in the DMA buffer */ - return 0; - if (ab->fw.m3_data && ab->fw.m3_len > 0) { /* firmware-N.bin had a m3 firmware file so use that */ m3_data = ab->fw.m3_data; @@ -2700,6 +2760,15 @@ static int ath12k_qmi_m3_load(struct ath12k_base *ab) m3_len = fw->size; } + /* In recovery/resume cases, M3 buffer is not freed, try to reuse that */ + if (m3_mem->vaddr) { + if (m3_mem->size >= m3_len) + goto skip_m3_alloc; + + /* Old buffer is too small, free and reallocate */ + ath12k_qmi_m3_free(ab); + } + m3_mem->vaddr = dma_alloc_coherent(ab->dev, m3_len, &m3_mem->paddr, GFP_KERNEL); @@ -2710,6 +2779,7 @@ static int ath12k_qmi_m3_load(struct ath12k_base *ab) goto out; } +skip_m3_alloc: memcpy(m3_mem->vaddr, m3_data, m3_len); m3_mem->size = m3_len; @@ -2721,19 +2791,6 @@ out: return ret; } -static void ath12k_qmi_m3_free(struct ath12k_base *ab) -{ - struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; - - if (!m3_mem->vaddr) - return; - - dma_free_coherent(ab->dev, m3_mem->size, - m3_mem->vaddr, m3_mem->paddr); - m3_mem->vaddr = NULL; - m3_mem->size = 0; -} - static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab) { struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; @@ -3178,6 +3235,9 @@ static const struct qmi_msg_handler ath12k_qmi_msg_handlers[] = { .decoded_size = sizeof(struct qmi_wlanfw_fw_ready_ind_msg_v01), .fn = ath12k_qmi_msg_fw_ready_cb, }, + + /* end of list */ + {}, }; static int ath12k_qmi_ops_new_server(struct qmi_handle *qmi_hdl, @@ -3261,7 +3321,8 @@ static void ath12k_qmi_driver_event_work(struct work_struct *work) case ATH12K_QMI_EVENT_FW_READY: clear_bit(ATH12K_FLAG_QMI_FAIL, &ab->dev_flags); if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) { - ath12k_hal_dump_srng_stats(ab); + if (ab->is_reset) + ath12k_hal_dump_srng_stats(ab); queue_work(ab->workqueue, &ab->restart_work); break; } diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index 6ee33c9851..0dfcbd8cb5 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -96,6 +96,8 @@ struct ath12k_qmi_event_msg { struct target_mem_chunk { u32 size; u32 type; + u32 prev_size; + u32 prev_type; dma_addr_t paddr; union { void __iomem *ioaddr; @@ -265,6 +267,8 @@ struct qmi_wlanfw_phy_cap_resp_msg_v01 { u8 num_phy; u8 board_id_valid; u32 board_id; + u8 single_chip_mlo_support_valid; + u8 single_chip_mlo_support; }; #define QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN 54 diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index f308e9a6ed..fbf3804493 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -49,8 +49,8 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath12k_wmi_init_country_arg arg; struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k *ar = ath12k_ah_to_ar(ah); - int ret; + struct ath12k *ar = ath12k_ah_to_ar(ah, 0); + int ret, i; ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Regulatory Notification received for %s\n", wiphy_name(wiphy)); @@ -85,10 +85,16 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) memcpy(&arg.cc_info.alpha2, request->alpha2, 2); arg.cc_info.alpha2[2] = 0; - ret = ath12k_wmi_send_init_country_cmd(ar, &arg); - if (ret) - ath12k_warn(ar->ab, - "INIT Country code set to fw failed : %d\n", ret); + /* Allow fresh updates to wiphy regd */ + ah->regd_updated = false; + + /* Send the reg change request to all the radios */ + for_each_ar(ah, ar, i) { + ret = ath12k_wmi_send_init_country_cmd(ar, &arg); + if (ret) + ath12k_warn(ar->ab, + "INIT Country code set to fw failed : %d\n", ret); + } } int ath12k_reg_update_chan_list(struct ath12k *ar) @@ -202,10 +208,32 @@ int ath12k_regd_update(struct ath12k *ar, bool init) { struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ieee80211_regdomain *regd, *regd_copy = NULL; + struct ath12k_hw *ah = ar->ah; int ret, regd_len, pdev_id; struct ath12k_base *ab; + int i; ab = ar->ab; + + /* If one of the radios within ah has already updated the regd for + * the wiphy, then avoid setting regd again + */ + if (ah->regd_updated) + return 0; + + /* firmware provides reg rules which are similar for 2 GHz and 5 GHz + * pdev but 6 GHz pdev has superset of all rules including rules for + * all bands, we prefer 6 GHz pdev's rules to be used for setup of + * the wiphy regd. + * If 6 GHz pdev was part of the ath12k_hw, wait for the 6 GHz pdev, + * else pick the first pdev which calls this function and use its + * regd to update global hw regd. + * The regd_updated flag set at the end will not allow any further + * updates. + */ + if (ah->use_6ghz_regd && !ar->supports_6ghz) + return 0; + pdev_id = ar->pdev_idx; spin_lock_bh(&ab->base_lock); @@ -258,10 +286,17 @@ int ath12k_regd_update(struct ath12k *ar, bool init) if (ret) goto err; - if (ar->state == ATH12K_STATE_ON) { - ret = ath12k_reg_update_chan_list(ar); - if (ret) - goto err; + ah->regd_updated = true; + /* Apply the new regd to all the radios, this is expected to be received only once + * since we check for ah->regd_updated and allow here only once. + */ + for_each_ar(ah, ar, i) { + if (ar->state == ATH12K_STATE_ON) { + ab = ar->ab; + ret = ath12k_reg_update_chan_list(ar); + if (ret) + goto err; + } } return 0; diff --git a/drivers/net/wireless/ath/ath12k/trace.h b/drivers/net/wireless/ath/ath12k/trace.h index 240737e154..253c67accb 100644 --- a/drivers/net/wireless/ath/ath12k/trace.h +++ b/drivers/net/wireless/ath/ath12k/trace.h @@ -36,8 +36,8 @@ TRACE_EVENT(ath12k_htt_pktlog, ), TP_fast_assign( - __assign_str(device, dev_name(ar->ab->dev)); - __assign_str(driver, dev_driver_string(ar->ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->buf_len = buf_len; __entry->pktlog_checksum = pktlog_checksum; memcpy(__get_dynamic_array(pktlog), buf, buf_len); @@ -73,8 +73,8 @@ TRACE_EVENT(ath12k_htt_ppdu_stats, ), TP_fast_assign( - __assign_str(device, dev_name(ar->ab->dev)); - __assign_str(driver, dev_driver_string(ar->ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = len; __entry->info = ar->pdev->timestamp.info; __entry->sync_tstmp_lo_us = ar->pdev->timestamp.sync_timestamp_hi_us; @@ -117,8 +117,8 @@ TRACE_EVENT(ath12k_htt_rxdesc, ), TP_fast_assign( - __assign_str(device, dev_name(ar->ab->dev)); - __assign_str(driver, dev_driver_string(ar->ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = len; __entry->type = type; __entry->info = ar->pdev->timestamp.info; @@ -153,8 +153,8 @@ TRACE_EVENT(ath12k_wmi_diag, ), TP_fast_assign( - __assign_str(device, dev_name(ab->dev)); - __assign_str(driver, dev_driver_string(ab->dev)); + __assign_str(device); + __assign_str(driver); __entry->len = len; memcpy(__get_dynamic_array(data), data, len); ), diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 9d69a17699..ef775af250 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -228,9 +228,12 @@ void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, config->peer_map_unmap_version = 0x32; config->twt_ap_pdev_count = ab->num_radios; config->twt_ap_sta_count = 1000; + config->ema_max_vap_cnt = ab->num_radios; + config->ema_max_profile_period = TARGET_EMA_MAX_PROFILE_PERIOD; + config->beacon_tx_offload_max_vdev += config->ema_max_vap_cnt; if (test_bit(WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT, ab->wmi_ab.svc_map)) - config->dp_peer_meta_data_ver = TARGET_RX_PEER_METADATA_VER_V1B; + config->peer_metadata_ver = ATH12K_PEER_METADATA_V1B; } void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, @@ -858,20 +861,20 @@ int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr, len = sizeof(*txrx_streams); txrx_streams->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_TXRX_STREAMS, len); - txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_2G; + txrx_streams->band = cpu_to_le32(WMI_TPC_CHAINMASK_CONFIG_BAND_2G); txrx_streams->supported_tx_streams = - args->chains[NL80211_BAND_2GHZ].tx; + cpu_to_le32(args->chains[NL80211_BAND_2GHZ].tx); txrx_streams->supported_rx_streams = - args->chains[NL80211_BAND_2GHZ].rx; + cpu_to_le32(args->chains[NL80211_BAND_2GHZ].rx); txrx_streams++; txrx_streams->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_TXRX_STREAMS, len); - txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_5G; + txrx_streams->band = cpu_to_le32(WMI_TPC_CHAINMASK_CONFIG_BAND_5G); txrx_streams->supported_tx_streams = - args->chains[NL80211_BAND_5GHZ].tx; + cpu_to_le32(args->chains[NL80211_BAND_5GHZ].tx); txrx_streams->supported_rx_streams = - args->chains[NL80211_BAND_5GHZ].rx; + cpu_to_le32(args->chains[NL80211_BAND_5GHZ].rx); ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "WMI vdev create: id %d type %d subtype %d macaddr %pM pdevid %d\n", @@ -1900,7 +1903,7 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, if (arg->bw_160) cmd->peer_flags |= cpu_to_le32(WMI_PEER_160MHZ); if (arg->bw_320) - cmd->peer_flags |= cpu_to_le32(WMI_PEER_EXT_320MHZ); + cmd->peer_flags_ext |= cpu_to_le32(WMI_PEER_EXT_320MHZ); /* Typically if STBC is enabled for VHT it should be enabled * for HT as well @@ -2723,6 +2726,149 @@ int ath12k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath12k *ar, return ret; } +int ath12k_wmi_set_bios_cmd(struct ath12k_base *ab, u32 param_id, + const u8 *buf, size_t buf_len) +{ + struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab; + struct wmi_pdev_set_bios_interface_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + u8 *ptr; + u32 len, len_aligned; + int ret; + + len_aligned = roundup(buf_len, sizeof(u32)); + len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned; + + skb = ath12k_wmi_alloc_skb(wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD, + sizeof(*cmd)); + cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC); + cmd->param_type_id = cpu_to_le32(param_id); + cmd->length = cpu_to_le32(buf_len); + + ptr = skb->data + sizeof(*cmd); + tlv = (struct wmi_tlv *)ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned); + ptr += TLV_HDR_SIZE; + memcpy(ptr, buf, buf_len); + + ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], + skb, + WMI_PDEV_SET_BIOS_INTERFACE_CMDID); + if (ret) { + ath12k_warn(ab, + "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID parameter id %d: %d\n", + param_id, ret); + dev_kfree_skb(skb); + } + + return 0; +} + +int ath12k_wmi_set_bios_sar_cmd(struct ath12k_base *ab, const u8 *psar_table) +{ + struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab; + struct wmi_pdev_set_bios_sar_table_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + int ret; + u8 *buf_ptr; + u32 len, sar_table_len_aligned, sar_dbs_backoff_len_aligned; + const u8 *psar_value = psar_table + ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET; + const u8 *pdbs_value = psar_table + ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET; + + sar_table_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_TABLE_LEN, sizeof(u32)); + sar_dbs_backoff_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN, + sizeof(u32)); + len = sizeof(*cmd) + TLV_HDR_SIZE + sar_table_len_aligned + + TLV_HDR_SIZE + sar_dbs_backoff_len_aligned; + + skb = ath12k_wmi_alloc_skb(wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_pdev_set_bios_sar_table_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD, + sizeof(*cmd)); + cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC); + cmd->sar_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_TABLE_LEN); + cmd->dbs_backoff_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN); + + buf_ptr = skb->data + sizeof(*cmd); + tlv = (struct wmi_tlv *)buf_ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, + sar_table_len_aligned); + buf_ptr += TLV_HDR_SIZE; + memcpy(buf_ptr, psar_value, ATH12K_ACPI_BIOS_SAR_TABLE_LEN); + + buf_ptr += sar_table_len_aligned; + tlv = (struct wmi_tlv *)buf_ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, + sar_dbs_backoff_len_aligned); + buf_ptr += TLV_HDR_SIZE; + memcpy(buf_ptr, pdbs_value, ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN); + + ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], + skb, + WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID); + if (ret) { + ath12k_warn(ab, + "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", + ret); + dev_kfree_skb(skb); + } + + return ret; +} + +int ath12k_wmi_set_bios_geo_cmd(struct ath12k_base *ab, const u8 *pgeo_table) +{ + struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab; + struct wmi_pdev_set_bios_geo_table_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + int ret; + u8 *buf_ptr; + u32 len, sar_geo_len_aligned; + const u8 *pgeo_value = pgeo_table + ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET; + + sar_geo_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN, sizeof(u32)); + len = sizeof(*cmd) + TLV_HDR_SIZE + sar_geo_len_aligned; + + skb = ath12k_wmi_alloc_skb(wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_pdev_set_bios_geo_table_cmd *)skb->data; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD, + sizeof(*cmd)); + cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC); + cmd->geo_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN); + + buf_ptr = skb->data + sizeof(*cmd); + tlv = (struct wmi_tlv *)buf_ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, sar_geo_len_aligned); + buf_ptr += TLV_HDR_SIZE; + memcpy(buf_ptr, pgeo_value, ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN); + + ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], + skb, + WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID); + if (ret) { + ath12k_warn(ab, + "failed to send WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID %d\n", + ret); + dev_kfree_skb(skb); + } + + return ret; +} + int ath12k_wmi_delba_send(struct ath12k *ar, u32 vdev_id, const u8 *mac, u32 tid, u32 initiator, u32 reason) { @@ -3324,16 +3470,19 @@ ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cf wmi_cfg->bpf_instruction_size = cpu_to_le32(tg_cfg->bpf_instruction_size); wmi_cfg->max_bssid_rx_filters = cpu_to_le32(tg_cfg->max_bssid_rx_filters); wmi_cfg->use_pdev_id = cpu_to_le32(tg_cfg->use_pdev_id); - wmi_cfg->flag1 = cpu_to_le32(tg_cfg->atf_config); + wmi_cfg->flag1 = cpu_to_le32(tg_cfg->atf_config | + WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64); wmi_cfg->peer_map_unmap_version = cpu_to_le32(tg_cfg->peer_map_unmap_version); wmi_cfg->sched_params = cpu_to_le32(tg_cfg->sched_params); wmi_cfg->twt_ap_pdev_count = cpu_to_le32(tg_cfg->twt_ap_pdev_count); wmi_cfg->twt_ap_sta_count = cpu_to_le32(tg_cfg->twt_ap_sta_count); - wmi_cfg->flags2 = le32_encode_bits(tg_cfg->dp_peer_meta_data_ver, + wmi_cfg->flags2 = le32_encode_bits(tg_cfg->peer_metadata_ver, WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION); - wmi_cfg->host_service_flags = cpu_to_le32(tg_cfg->is_reg_cc_ext_event_supported << WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); + wmi_cfg->ema_max_vap_cnt = cpu_to_le32(tg_cfg->ema_max_vap_cnt); + wmi_cfg->ema_max_profile_period = cpu_to_le32(tg_cfg->ema_max_profile_period); + wmi_cfg->flags2 |= cpu_to_le32(WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET); } static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi, @@ -3557,6 +3706,8 @@ int ath12k_wmi_cmd_init(struct ath12k_base *ab) arg.num_band_to_mac = ab->num_radios; ath12k_fill_band_to_mac_param(ab, arg.band_to_mac); + ab->dp.peer_metadata_ver = arg.res_cfg.peer_metadata_ver; + return ath12k_init_cmd_send(&wmi_ab->wmi[0], &arg); } @@ -4041,6 +4192,7 @@ static void ath12k_wmi_free_dbring_caps(struct ath12k_base *ab) { kfree(ab->db_caps); ab->db_caps = NULL; + ab->num_db_cap = 0; } static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab, @@ -5877,8 +6029,10 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) if (rx_ev.status & WMI_RX_STATUS_ERR_MIC) status->flag |= RX_FLAG_MMIC_ERROR; - if (rx_ev.chan_freq >= ATH12K_MIN_6G_FREQ) { + if (rx_ev.chan_freq >= ATH12K_MIN_6G_FREQ && + rx_ev.chan_freq <= ATH12K_MAX_6G_FREQ) { status->band = NL80211_BAND_6GHZ; + status->freq = rx_ev.chan_freq; } else if (rx_ev.channel >= 1 && rx_ev.channel <= 14) { status->band = NL80211_BAND_2GHZ; } else if (rx_ev.channel >= 36 && rx_ev.channel <= ATH12K_MAX_5G_CHAN) { @@ -5899,8 +6053,10 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) sband = &ar->mac.sbands[status->band]; - status->freq = ieee80211_channel_to_frequency(rx_ev.channel, - status->band); + if (status->band != NL80211_BAND_6GHZ) + status->freq = ieee80211_channel_to_frequency(rx_ev.channel, + status->band); + status->signal = rx_ev.snr + ATH12K_DEFAULT_NOISE_FLOOR; status->rate_idx = ath12k_mac_bitrate_to_idx(sband, rx_ev.rate / 100); @@ -5927,13 +6083,11 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) } } - /* TODO: Pending handle beacon implementation - *if (ieee80211_is_beacon(hdr->frame_control)) - * ath12k_mac_handle_beacon(ar, skb); - */ + if (ieee80211_is_beacon(hdr->frame_control)) + ath12k_mac_handle_beacon(ar, skb); ath12k_dbg(ab, ATH12K_DBG_MGMT, - "event mgmt rx skb %pK len %d ftype %02x stype %02x\n", + "event mgmt rx skb %p len %d ftype %02x stype %02x\n", skb, skb->len, fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE); @@ -6137,42 +6291,44 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_roam_event roam_ev = {}; struct ath12k *ar; + u32 vdev_id; + u8 roam_reason; if (ath12k_pull_roam_ev(ab, skb, &roam_ev) != 0) { ath12k_warn(ab, "failed to extract roam event"); return; } + vdev_id = le32_to_cpu(roam_ev.vdev_id); + roam_reason = u32_get_bits(le32_to_cpu(roam_ev.reason), + WMI_ROAM_REASON_MASK); + ath12k_dbg(ab, ATH12K_DBG_WMI, - "wmi roam event vdev %u reason 0x%08x rssi %d\n", - roam_ev.vdev_id, roam_ev.reason, roam_ev.rssi); + "wmi roam event vdev %u reason %d rssi %d\n", + vdev_id, roam_reason, roam_ev.rssi); rcu_read_lock(); - ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(roam_ev.vdev_id)); + ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id); if (!ar) { - ath12k_warn(ab, "invalid vdev id in roam ev %d", - roam_ev.vdev_id); + ath12k_warn(ab, "invalid vdev id in roam ev %d", vdev_id); rcu_read_unlock(); return; } - if (le32_to_cpu(roam_ev.reason) >= WMI_ROAM_REASON_MAX) + if (roam_reason >= WMI_ROAM_REASON_MAX) ath12k_warn(ab, "ignoring unknown roam event reason %d on vdev %i\n", - roam_ev.reason, roam_ev.vdev_id); + roam_reason, vdev_id); - switch (le32_to_cpu(roam_ev.reason)) { + switch (roam_reason) { case WMI_ROAM_REASON_BEACON_MISS: - /* TODO: Pending beacon miss and connection_loss_work - * implementation - * ath12k_mac_handle_beacon_miss(ar, vdev_id); - */ + ath12k_mac_handle_beacon_miss(ar, vdev_id); break; case WMI_ROAM_REASON_BETTER_AP: case WMI_ROAM_REASON_LOW_RSSI: case WMI_ROAM_REASON_SUITABLE_AP_FOUND: case WMI_ROAM_REASON_HO_FAILED: ath12k_warn(ab, "ignoring not implemented roam event reason %d on vdev %i\n", - roam_ev.reason, roam_ev.vdev_id); + roam_reason, vdev_id); break; } diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 103462feb9..742fe0b36c 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -164,10 +164,6 @@ struct wmi_tlv { #define WLAN_SCAN_MAX_HINT_BSSID 10 #define MAX_RNR_BSS 5 -#define WLAN_SCAN_MAX_HINT_S_SSID 10 -#define WLAN_SCAN_MAX_HINT_BSSID 10 -#define MAX_RNR_BSS 5 - #define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1 #define WMI_BA_MODE_BUFFER_SIZE_256 3 @@ -357,6 +353,9 @@ enum wmi_tlv_cmd_id { WMI_PDEV_DMA_RING_CFG_REQ_CMDID, WMI_PDEV_HE_TB_ACTION_FRM_CMDID, WMI_PDEV_PKTLOG_FILTER_CMDID, + WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID = 0x4044, + WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID = 0x4045, + WMI_PDEV_SET_BIOS_INTERFACE_CMDID = 0x404A, WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV), WMI_VDEV_DELETE_CMDID, WMI_VDEV_START_REQUEST_CMDID, @@ -1929,6 +1928,9 @@ enum wmi_tlv_tag { WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9, WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT, WMI_TAG_EHT_RATE_SET = 0x3C4, + WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8, + WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD = 0x3D9, + WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD = 0x3FB, WMI_TAG_MAX }; @@ -2199,8 +2201,11 @@ enum wmi_peer_param { WMI_PEER_SET_MAX_TX_RATE = 17, WMI_PEER_SET_MIN_TX_RATE = 18, WMI_PEER_SET_DEFAULT_ROUTING = 19, + WMI_PEER_CHWIDTH_PUNCTURE_20MHZ_BITMAP = 39, }; +#define WMI_PEER_PUNCTURE_BITMAP GENMASK(23, 8) + enum wmi_slot_time { WMI_VDEV_SLOT_TIME_LONG = 1, WMI_VDEV_SLOT_TIME_SHORT = 2, @@ -2287,6 +2292,13 @@ struct ath12k_wmi_host_mem_chunk_arg { u32 req_id; }; +enum ath12k_peer_metadata_version { + ATH12K_PEER_METADATA_V0, + ATH12K_PEER_METADATA_V1, + ATH12K_PEER_METADATA_V1A, + ATH12K_PEER_METADATA_V1B +}; + struct ath12k_wmi_resource_config_arg { u32 num_vdevs; u32 num_peers; @@ -2349,8 +2361,10 @@ struct ath12k_wmi_resource_config_arg { u32 sched_params; u32 twt_ap_pdev_count; u32 twt_ap_sta_count; + enum ath12k_peer_metadata_version peer_metadata_ver; + u32 ema_max_vap_cnt; + u32 ema_max_profile_period; bool is_reg_cc_ext_event_supported; - u8 dp_peer_meta_data_ver; }; struct ath12k_wmi_init_cmd_arg { @@ -2404,6 +2418,8 @@ struct wmi_init_cmd { #define WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT 4 #define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4) +#define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) +#define WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET BIT(9) struct ath12k_wmi_resource_config_params { __le32 tlv_header; @@ -2604,6 +2620,19 @@ struct ath12k_wmi_soc_hal_reg_caps_params { __le32 num_phy; } __packed; +enum wmi_channel_width { + WMI_CHAN_WIDTH_20 = 0, + WMI_CHAN_WIDTH_40 = 1, + WMI_CHAN_WIDTH_80 = 2, + WMI_CHAN_WIDTH_160 = 3, + WMI_CHAN_WIDTH_80P80 = 4, + WMI_CHAN_WIDTH_5 = 5, + WMI_CHAN_WIDTH_10 = 6, + WMI_CHAN_WIDTH_165 = 7, + WMI_CHAN_WIDTH_160P160 = 8, + WMI_CHAN_WIDTH_320 = 9, +}; + #define WMI_MAX_EHTCAP_MAC_SIZE 2 #define WMI_MAX_EHTCAP_PHY_SIZE 3 #define WMI_MAX_EHTCAP_RATE_SET 3 @@ -2728,9 +2757,9 @@ struct wmi_vdev_create_cmd { struct ath12k_wmi_vdev_txrx_streams_params { __le32 tlv_header; - u32 band; - u32 supported_tx_streams; - u32 supported_rx_streams; + __le32 band; + __le32 supported_tx_streams; + __le32 supported_rx_streams; } __packed; struct wmi_vdev_delete_cmd { @@ -3357,34 +3386,6 @@ struct wmi_bssid_arg { const u8 *bssid; }; -struct wmi_start_scan_arg { - u32 scan_id; - u32 scan_req_id; - u32 vdev_id; - u32 scan_priority; - u32 notify_scan_events; - u32 dwell_time_active; - u32 dwell_time_passive; - u32 min_rest_time; - u32 max_rest_time; - u32 repeat_probe_time; - u32 probe_spacing_time; - u32 idle_time; - u32 max_scan_time; - u32 probe_delay; - u32 scan_ctrl_flags; - - u32 ie_len; - u32 n_channels; - u32 n_ssids; - u32 n_bssids; - - u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN]; - u32 channels[64]; - struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID]; - struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID]; -}; - #define WMI_SCAN_STOP_ONE 0x00000000 #define WMI_SCAN_STOP_VAP_ALL 0x01000000 #define WMI_SCAN_STOP_ALL 0x04000000 @@ -4214,6 +4215,9 @@ struct wmi_peer_sta_kickout_event { struct ath12k_wmi_mac_addr_params peer_macaddr; } __packed; +#define WMI_ROAM_REASON_MASK GENMASK(3, 0) +#define WMI_ROAM_SUBNET_STATUS_MASK GENMASK(5, 4) + enum wmi_roam_reason { WMI_ROAM_REASON_BETTER_AP = 1, WMI_ROAM_REASON_BEACON_MISS = 2, @@ -4776,8 +4780,6 @@ struct wmi_probe_tmpl_cmd { __le32 buf_len; } __packed; -#define WMI_MAX_MEM_REQS 32 - #define MAX_RADIOS 3 #define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ) @@ -4808,6 +4810,37 @@ struct ath12k_wmi_base { struct ath12k_wmi_target_cap_arg *targ_cap; }; +struct wmi_pdev_set_bios_interface_cmd { + __le32 tlv_header; + __le32 pdev_id; + __le32 param_type_id; + __le32 length; +} __packed; + +enum wmi_bios_param_type { + WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE = 0, + WMI_BIOS_PARAM_TAS_CONFIG_TYPE = 1, + WMI_BIOS_PARAM_TAS_DATA_TYPE = 2, + + /* bandedge control power */ + WMI_BIOS_PARAM_TYPE_BANDEDGE = 3, + + WMI_BIOS_PARAM_TYPE_MAX, +}; + +struct wmi_pdev_set_bios_sar_table_cmd { + __le32 tlv_header; + __le32 pdev_id; + __le32 sar_len; + __le32 dbs_backoff_len; +} __packed; + +struct wmi_pdev_set_bios_geo_table_cmd { + __le32 tlv_header; + __le32 pdev_id; + __le32 geo_len; +} __packed; + #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024) enum wmi_sys_cap_info_flags { @@ -4966,6 +4999,10 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id, struct sk_buff *tmpl); int ath12k_wmi_set_hw_mode(struct ath12k_base *ab, enum wmi_host_hw_mode_config_type mode); +int ath12k_wmi_set_bios_cmd(struct ath12k_base *ab, u32 param_id, + const u8 *buf, size_t buf_len); +int ath12k_wmi_set_bios_sar_cmd(struct ath12k_base *ab, const u8 *psar_table); +int ath12k_wmi_set_bios_geo_cmd(struct ath12k_base *ab, const u8 *pgeo_table); static inline u32 ath12k_wmi_caps_ext_get_pdev_id(const struct ath12k_wmi_caps_ext_params *param) diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index 1963d31454..fb5144e2d8 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -364,8 +364,7 @@ static void ath6kl_htc_tx_prep_pkt(struct htc_packet *packet, u8 flags, packet->buf -= HTC_HDR_LENGTH; hdr = (struct htc_frame_hdr *)packet->buf; - /* Endianess? */ - put_unaligned((u16)packet->act_len, &hdr->payld_len); + put_unaligned_le16(packet->act_len, &hdr->payld_len); hdr->flags = flags; hdr->eid = packet->endpoint; hdr->ctrl[0] = ctrl0; diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index 9b88d96bfe..2f2edfe437 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -237,8 +237,7 @@ static int htc_issue_packets(struct htc_target *target, packet->info.tx.flags |= HTC_FLAGS_TX_FIXUP_NETBUF; - /* Endianess? */ - put_unaligned((u16) payload_len, &htc_hdr->payld_len); + put_unaligned_le16(payload_len, &htc_hdr->payld_len); htc_hdr->flags = packet->info.tx.flags; htc_hdr->eid = (u8) packet->endpoint; htc_hdr->ctrl[0] = 0; diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 8a43c48ec1..9ab0910447 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -1427,25 +1427,7 @@ static struct sdio_driver ath6kl_sdio_driver = { .remove = ath6kl_sdio_remove, .drv.pm = ATH6KL_SDIO_PM_OPS, }; - -static int __init ath6kl_sdio_init(void) -{ - int ret; - - ret = sdio_register_driver(&ath6kl_sdio_driver); - if (ret) - ath6kl_err("sdio driver registration failed: %d\n", ret); - - return ret; -} - -static void __exit ath6kl_sdio_exit(void) -{ - sdio_unregister_driver(&ath6kl_sdio_driver); -} - -module_init(ath6kl_sdio_init); -module_exit(ath6kl_sdio_exit); +module_sdio_driver(ath6kl_sdio_driver); MODULE_AUTHOR("Atheros Communications, Inc."); MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices"); diff --git a/drivers/net/wireless/ath/ath6kl/trace.h b/drivers/net/wireless/ath/ath6kl/trace.h index 231a94769d..8577aa459c 100644 --- a/drivers/net/wireless/ath/ath6kl/trace.h +++ b/drivers/net/wireless/ath/ath6kl/trace.h @@ -304,8 +304,8 @@ TRACE_EVENT(ath6kl_log_dbg_dump, ), TP_fast_assign( - __assign_str(msg, msg); - __assign_str(prefix, prefix); + __assign_str(msg); + __assign_str(prefix); __entry->buf_len = buf_len; memcpy(__get_dynamic_array(buf), buf, buf_len); ), diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 668fc07b30..29ca65a732 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -39,6 +39,7 @@ extern int ath9k_modparam_nohwcrypt; extern int ath9k_led_blink; extern bool is_ath9k_unloaded; extern int ath9k_use_chanctx; +extern int ath9k_use_msi; /*************************/ /* Descriptor Management */ diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index e8c2cc03be..27b860b0c7 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -76,7 +76,7 @@ static bool ath9k_hw_4k_fill_eeprom(struct ath_hw *ah) static u32 ath9k_dump_4k_modal_eeprom(char *buf, u32 len, u32 size, struct modal_eep_4k_header *modal_hdr) { - PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0])); + PR_EEP("Chain0 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[0])); PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon)); PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]); PR_EEP("Switch Settle", modal_hdr->switchSettling); diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index fd5312c2a7..d85472ee4d 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -79,8 +79,8 @@ static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah) static u32 ar9287_dump_modal_eeprom(char *buf, u32 len, u32 size, struct modal_eep_ar9287_header *modal_hdr) { - PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0])); - PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1])); + PR_EEP("Chain0 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[0])); + PR_EEP("Chain1 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[1])); PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon)); PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]); PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]); diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 7685f8ab37..84b31caf8c 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -135,9 +135,9 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) static u32 ath9k_def_dump_modal_eeprom(char *buf, u32 len, u32 size, struct modal_eep_header *modal_hdr) { - PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0])); - PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1])); - PR_EEP("Chain2 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[2])); + PR_EEP("Chain0 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[0])); + PR_EEP("Chain1 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[1])); + PR_EEP("Chain2 Ant. Control", le32_to_cpu(modal_hdr->antCtrlChain[2])); PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon)); PR_EEP("Chain0 Ant. Gain", modal_hdr->antennaGainCh[0]); PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a2943aaecb..01173aac30 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -135,8 +135,7 @@ void ath9k_ps_wakeup(struct ath_softc *sc) if (power_mode != ATH9K_PM_AWAKE) { spin_lock(&common->cc_lock); ath_hw_cycle_counters_update(common); - memset(&common->cc_survey, 0, sizeof(common->cc_survey)); - memset(&common->cc_ani, 0, sizeof(common->cc_ani)); + memset(&common->cc, 0, sizeof(common->cc)); spin_unlock(&common->cc_lock); } diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index e655cd8bbf..1ff53520f0 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -21,8 +21,6 @@ #include <linux/module.h> #include "ath9k.h" -extern int ath9k_use_msi; - static const struct pci_device_id ath_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */ diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index d519b676a1..35aa47a9db 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1674,8 +1674,14 @@ static void ath9k_set_moredata(struct ath_softc *sc, struct ath_buf *bf, bool val) { struct ieee80211_hdr *hdr; - u16 mask = cpu_to_le16(IEEE80211_FCTL_MOREDATA); - u16 mask_val = mask * val; + __le16 mask, mask_val; + + mask = cpu_to_le16(IEEE80211_FCTL_MOREDATA); + + if (val) + mask_val = mask; + else + mask_val = 0; hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; if ((hdr->frame_control & mask) != mask_val) { diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index e902ca80eb..0226c31a6c 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -280,7 +280,8 @@ static void carl9170_tx_release(struct kref *ref) * carl9170_tx_fill_rateinfo() has filled the rate information * before we get to this point. */ - memset_after(&txinfo->status, 0, rates); + memset(&txinfo->pad, 0, sizeof(txinfo->pad)); + memset(&txinfo->rate_driver_data, 0, sizeof(txinfo->rate_driver_data)); if (atomic_read(&ar->tx_total_queued)) ar->tx_schedule = true; diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index c4edf83559..a3e03580cd 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -1069,6 +1069,38 @@ static int carl9170_usb_probe(struct usb_interface *intf, ar->usb_ep_cmd_is_bulk = true; } + /* Verify that all expected endpoints are present */ + if (ar->usb_ep_cmd_is_bulk) { + u8 bulk_ep_addr[] = { + AR9170_USB_EP_RX | USB_DIR_IN, + AR9170_USB_EP_TX | USB_DIR_OUT, + AR9170_USB_EP_CMD | USB_DIR_OUT, + 0}; + u8 int_ep_addr[] = { + AR9170_USB_EP_IRQ | USB_DIR_IN, + 0}; + if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) || + !usb_check_int_endpoints(intf, int_ep_addr)) + err = -ENODEV; + } else { + u8 bulk_ep_addr[] = { + AR9170_USB_EP_RX | USB_DIR_IN, + AR9170_USB_EP_TX | USB_DIR_OUT, + 0}; + u8 int_ep_addr[] = { + AR9170_USB_EP_IRQ | USB_DIR_IN, + AR9170_USB_EP_CMD | USB_DIR_OUT, + 0}; + if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) || + !usb_check_int_endpoints(intf, int_ep_addr)) + err = -ENODEV; + } + + if (err) { + carl9170_free(ar); + return err; + } + usb_set_intfdata(intf, ar); SET_IEEE80211_DEV(ar->hw, &intf->dev); diff --git a/drivers/net/wireless/ath/trace.h b/drivers/net/wireless/ath/trace.h index 9935cf475b..82aac0a4ba 100644 --- a/drivers/net/wireless/ath/trace.h +++ b/drivers/net/wireless/ath/trace.h @@ -44,8 +44,8 @@ TRACE_EVENT(ath_log, ), TP_fast_assign( - __assign_str(device, wiphy_name(wiphy)); - __assign_str(driver, KBUILD_MODNAME); + __assign_str(device); + __assign_str(driver); __assign_vstr(msg, vaf->fmt, vaf->va); ), diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index bfbd3c7a70..e760d8002e 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -756,9 +756,9 @@ static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta, if (sta->deflink.vht_cap.vht_supported) { sta_priv->supported_rates.op_rate_mode = STA_11ac; sta_priv->supported_rates.vht_rx_mcs_map = - sta->deflink.vht_cap.vht_mcs.rx_mcs_map; + le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map); sta_priv->supported_rates.vht_tx_mcs_map = - sta->deflink.vht_cap.vht_mcs.tx_mcs_map; + le16_to_cpu(sta->deflink.vht_cap.vht_mcs.tx_mcs_map); } } diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 0802ed7288..8826998797 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -318,7 +318,7 @@ int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb) memset(&status, 0, sizeof(status)); bd = (struct wcn36xx_rx_bd *)skb->data; - buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32)); + buff_to_be(bd, sizeof(*bd)/sizeof(u32)); wcn36xx_dbg_dump(WCN36XX_DBG_RX_DUMP, "BD <<< ", (char *)bd, sizeof(struct wcn36xx_rx_bd)); @@ -692,7 +692,7 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, /* MGMT and CTRL frames are handeld here*/ wcn36xx_set_tx_mgmt(&bd, wcn, &vif_priv, skb, bcast); - buff_to_be((u32 *)&bd, sizeof(bd)/sizeof(u32)); + buff_to_be(&bd, sizeof(bd)/sizeof(u32)); bd.tx_bd_sign = 0xbdbdbdbd; ret = wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low); diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index ff4a8e5d72..bccc27de84 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -100,11 +100,14 @@ enum wcn36xx_ampdu_state { #define RF_IRIS_WCN3660 0x3660 #define RF_IRIS_WCN3680 0x3680 -static inline void buff_to_be(u32 *buf, size_t len) +static inline void buff_to_be(void *buf, size_t len) { + __be32 *to = buf; + u32 *from = buf; int i; + for (i = 0; i < len; i++) - buf[i] = cpu_to_be32(buf[i]); + to[i] = cpu_to_be32(from[i]); } struct nv_data { diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index dbe4b3478f..e8f1d30a8d 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -892,10 +892,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wireless_dev *wdev = request->wdev; struct wil6210_vif *vif = wdev_to_vif(wil, wdev); - struct { - struct wmi_start_scan_cmd cmd; - u16 chnl[4]; - } __packed cmd; + DEFINE_FLEX(struct wmi_start_scan_cmd, cmd, + channel_list, num_channels, 4); uint i, n; int rc; @@ -977,9 +975,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, vif->scan_request = request; mod_timer(&vif->scan_timer, jiffies + WIL6210_SCAN_TO); - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd.scan_type = WMI_ACTIVE_SCAN; - cmd.cmd.num_channels = 0; + cmd->scan_type = WMI_ACTIVE_SCAN; + cmd->num_channels = 0; n = min(request->n_channels, 4U); for (i = 0; i < n; i++) { int ch = request->channels[i]->hw_value; @@ -991,7 +988,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, continue; } /* 0-based channel indexes */ - cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1; + cmd->num_channels++; + cmd->channel_list[cmd->num_channels - 1].channel = ch - 1; wil_dbg_misc(wil, "Scan for ch %d : %d MHz\n", ch, request->channels[i]->center_freq); } @@ -1007,16 +1005,15 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, if (rc) goto out_restore; - if (wil->discovery_mode && cmd.cmd.scan_type == WMI_ACTIVE_SCAN) { - cmd.cmd.discovery_mode = 1; + if (wil->discovery_mode && cmd->scan_type == WMI_ACTIVE_SCAN) { + cmd->discovery_mode = 1; wil_dbg_misc(wil, "active scan with discovery_mode=1\n"); } if (vif->mid == 0) wil->radio_wdev = wdev; rc = wmi_send(wil, WMI_START_SCAN_CMDID, vif->mid, - &cmd, sizeof(cmd.cmd) + - cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); + cmd, struct_size(cmd, channel_list, cmd->num_channels)); out_restore: if (rc) { @@ -2735,7 +2732,7 @@ int wil_cfg80211_iface_combinations_from_fw( return 0; } - combo = conc->combos; + combo = (const struct wil_fw_concurrency_combo *)(conc + 1); n_combos = le16_to_cpu(conc->n_combos); for (i = 0; i < n_combos; i++) { total_limits += combo->n_limits; @@ -2751,7 +2748,7 @@ int wil_cfg80211_iface_combinations_from_fw( return -ENOMEM; iface_limit = (struct ieee80211_iface_limit *)(iface_combinations + n_combos); - combo = conc->combos; + combo = (const struct wil_fw_concurrency_combo *)(conc + 1); for (i = 0; i < n_combos; i++) { iface_combinations[i].max_interfaces = combo->max_interfaces; iface_combinations[i].num_different_channels = diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h index aa1620e0d2..2079a90ec2 100644 --- a/drivers/net/wireless/ath/wil6210/fw.h +++ b/drivers/net/wireless/ath/wil6210/fw.h @@ -93,7 +93,6 @@ struct wil_fw_record_concurrency { /* type == wil_fw_type_comment */ /* number of concurrency combinations that follow */ __le16 n_combos; /* keep last - combinations, variable size by n_combos */ - struct wil_fw_concurrency_combo combos[]; } __packed; /* brd file info encoded inside a comment record */ diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index fbc84c0340..c3c0b289dc 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -212,8 +212,8 @@ fw_handle_concurrency(struct wil6210_priv *wil, const void *data, } n_combos = le16_to_cpu(rec->n_combos); - remain = size - offsetof(struct wil_fw_record_concurrency, combos); - combo = rec->combos; + remain = size - sizeof(struct wil_fw_record_concurrency); + combo = (const struct wil_fw_concurrency_combo *)(rec + 1); for (i = 0; i < n_combos; i++) { if (remain < sizeof(*combo)) goto out_short; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 6fdb77d4c5..8ff69dc72f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -4015,27 +4015,22 @@ int wmi_set_cqm_rssi_config(struct wil6210_priv *wil, struct wil6210_vif *vif = ndev_to_vif(ndev); int rc; struct { - struct wmi_set_link_monitor_cmd cmd; - s8 rssi_thold; - } __packed cmd = { - .cmd = { - .rssi_hyst = rssi_hyst, - .rssi_thresholds_list_size = 1, - }, - .rssi_thold = rssi_thold, - }; - struct { struct wmi_cmd_hdr hdr; struct wmi_set_link_monitor_event evt; } __packed reply = { .evt = {.status = WMI_FW_STATUS_FAILURE}, }; + DEFINE_FLEX(struct wmi_set_link_monitor_cmd, cmd, + rssi_thresholds_list, rssi_thresholds_list_size, 1); + + cmd->rssi_hyst = rssi_hyst; + cmd->rssi_thresholds_list[0] = rssi_thold; if (rssi_thold > S8_MAX || rssi_thold < S8_MIN || rssi_hyst > U8_MAX) return -EINVAL; - rc = wmi_call(wil, WMI_SET_LINK_MONITOR_CMDID, vif->mid, &cmd, - sizeof(cmd), WMI_SET_LINK_MONITOR_EVENTID, + rc = wmi_call(wil, WMI_SET_LINK_MONITOR_CMDID, vif->mid, cmd, + __struct_size(cmd), WMI_SET_LINK_MONITOR_EVENTID, &reply, sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); if (rc) { wil_err(wil, "WMI_SET_LINK_MONITOR_CMDID failed, rc %d\n", rc); diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 71bf2ae27a..38f6452401 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -474,7 +474,7 @@ struct wmi_start_scan_cmd { struct { u8 channel; u8 reserved; - } channel_list[]; + } channel_list[] __counted_by(num_channels); } __packed; #define WMI_MAX_PNO_SSID_NUM (16) @@ -3320,7 +3320,7 @@ struct wmi_set_link_monitor_cmd { u8 rssi_hyst; u8 reserved[12]; u8 rssi_thresholds_list_size; - s8 rssi_thresholds_list[]; + s8 rssi_thresholds_list[] __counted_by(rssi_thresholds_list_size); } __packed; /* wmi_link_monitor_event_type */ |