diff options
Diffstat (limited to 'drivers/net/wireless/ath')
78 files changed, 1897 insertions, 500 deletions
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index d73ad60b571c..eeb6ff6aa2e1 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -651,6 +651,7 @@ static const char *const ath10k_core_fw_feature_str[] = { [ATH10K_FW_FEATURE_NON_BMI] = "non-bmi", [ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL] = "single-chan-info-per-channel", [ATH10K_FW_FEATURE_PEER_FIXED_RATE] = "peer-fixed-rate", + [ATH10K_FW_FEATURE_IRAM_RECOVERY] = "iram-recovery", }; static unsigned int ath10k_core_get_fw_feature_str(char *buf, @@ -1349,7 +1350,8 @@ out: static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, const char *boardname, - const char *fallback_boardname, + const char *fallback_boardname1, + const char *fallback_boardname2, const char *filename) { size_t len, magic_len; @@ -1398,8 +1400,11 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, ret = ath10k_core_search_bd(ar, boardname, data, len); /* if we didn't find it and have a fallback name, try that */ - if (ret == -ENOENT && fallback_boardname) - ret = ath10k_core_search_bd(ar, fallback_boardname, data, len); + if (ret == -ENOENT && fallback_boardname1) + ret = ath10k_core_search_bd(ar, fallback_boardname1, data, len); + + if (ret == -ENOENT && fallback_boardname2) + ret = ath10k_core_search_bd(ar, fallback_boardname2, data, len); if (ret == -ENOENT) { ath10k_err(ar, @@ -1419,7 +1424,8 @@ err: } static int ath10k_core_create_board_name(struct ath10k *ar, char *name, - size_t name_len, bool with_variant) + size_t name_len, bool with_variant, + bool with_chip_id) { /* strlen(',variant=') + strlen(ar->id.bdf_ext) */ char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 }; @@ -1438,7 +1444,7 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name, } if (ar->id.qmi_ids_valid) { - if (with_variant && ar->id.bdf_ext[0] != '\0') + if (with_chip_id) scnprintf(name, name_len, "bus=%s,qmi-board-id=%x,qmi-chip-id=%x%s", ath10k_bus_str(ar->hif.bus), @@ -1482,21 +1488,36 @@ static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name, int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type) { - char boardname[100], fallback_boardname[100]; + char boardname[100], fallback_boardname1[100], fallback_boardname2[100]; int ret; if (bd_ie_type == ATH10K_BD_IE_BOARD) { + /* With variant and chip id */ ret = ath10k_core_create_board_name(ar, boardname, - sizeof(boardname), true); + sizeof(boardname), true, + true); if (ret) { ath10k_err(ar, "failed to create board name: %d", ret); return ret; } - ret = ath10k_core_create_board_name(ar, fallback_boardname, - sizeof(boardname), false); + /* Without variant and only chip-id */ + ret = ath10k_core_create_board_name(ar, fallback_boardname1, + sizeof(boardname), false, + true); + if (ret) { + ath10k_err(ar, "failed to create 1st fallback board name: %d", + ret); + return ret; + } + + /* Without variant and without chip-id */ + ret = ath10k_core_create_board_name(ar, fallback_boardname2, + sizeof(boardname), false, + false); if (ret) { - ath10k_err(ar, "failed to create fallback board name: %d", ret); + ath10k_err(ar, "failed to create 2nd fallback board name: %d", + ret); return ret; } } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) { @@ -1510,7 +1531,8 @@ int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type) ar->bd_api = 2; ret = ath10k_core_fetch_board_data_api_n(ar, boardname, - fallback_boardname, + fallback_boardname1, + fallback_boardname2, ATH10K_BOARD_API2_FILE); if (!ret) goto success; @@ -2272,6 +2294,17 @@ static int ath10k_init_hw_params(struct ath10k *ar) return 0; } +void ath10k_core_start_recovery(struct ath10k *ar) +{ + if (test_and_set_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags)) { + ath10k_warn(ar, "already restarting\n"); + return; + } + + queue_work(ar->workqueue, &ar->restart_work); +} +EXPORT_SYMBOL(ath10k_core_start_recovery); + static void ath10k_core_restart(struct work_struct *work) { struct ath10k *ar = container_of(work, struct ath10k, restart_work); @@ -2604,6 +2637,78 @@ static int ath10k_core_compat_services(struct ath10k *ar) return 0; } +#define TGT_IRAM_READ_PER_ITR (8 * 1024) + +static int ath10k_core_copy_target_iram(struct ath10k *ar) +{ + const struct ath10k_hw_mem_layout *hw_mem; + const struct ath10k_mem_region *tmp, *mem_region = NULL; + dma_addr_t paddr; + void *vaddr = NULL; + u8 num_read_itr; + int i, ret; + u32 len, remaining_len; + + hw_mem = ath10k_coredump_get_mem_layout(ar); + if (!hw_mem) + return -ENOMEM; + + for (i = 0; i < hw_mem->region_table.size; i++) { + tmp = &hw_mem->region_table.regions[i]; + if (tmp->type == ATH10K_MEM_REGION_TYPE_REG) { + mem_region = tmp; + break; + } + } + + if (!mem_region) + return -ENOMEM; + + for (i = 0; i < ar->wmi.num_mem_chunks; i++) { + if (ar->wmi.mem_chunks[i].req_id == + WMI_IRAM_RECOVERY_HOST_MEM_REQ_ID) { + vaddr = ar->wmi.mem_chunks[i].vaddr; + len = ar->wmi.mem_chunks[i].len; + break; + } + } + + if (!vaddr || !len) { + ath10k_warn(ar, "No allocated memory for IRAM back up"); + return -ENOMEM; + } + + len = (len < mem_region->len) ? len : mem_region->len; + paddr = mem_region->start; + num_read_itr = len / TGT_IRAM_READ_PER_ITR; + remaining_len = len % TGT_IRAM_READ_PER_ITR; + for (i = 0; i < num_read_itr; i++) { + ret = ath10k_hif_diag_read(ar, paddr, vaddr, + TGT_IRAM_READ_PER_ITR); + if (ret) { + ath10k_warn(ar, "failed to copy firmware IRAM contents: %d", + ret); + return ret; + } + + paddr += TGT_IRAM_READ_PER_ITR; + vaddr += TGT_IRAM_READ_PER_ITR; + } + + if (remaining_len) { + ret = ath10k_hif_diag_read(ar, paddr, vaddr, remaining_len); + if (ret) { + ath10k_warn(ar, "failed to copy firmware IRAM contents: %d", + ret); + return ret; + } + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "target IRAM back up completed\n"); + + return 0; +} + int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, const struct ath10k_fw_components *fw) { @@ -2636,7 +2741,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, if (status) goto err; - /* Some of of qca988x solutions are having global reset issue + /* Some of qca988x solutions are having global reset issue * during target initialization. Bypassing PLL setting before * downloading firmware and letting the SoC run on REF_CLK is * fixing the problem. Corresponding firmware change is also @@ -2765,6 +2870,16 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n", ar->hw->wiphy->fw_version); + if (test_bit(ATH10K_FW_FEATURE_IRAM_RECOVERY, + ar->running_fw->fw_file.fw_features)) { + status = ath10k_core_copy_target_iram(ar); + if (status) { + ath10k_warn(ar, "failed to copy target iram contents: %d", + status); + goto err_hif_stop; + } + } + if (test_bit(WMI_SERVICE_EXT_RES_CFG_SUPPORT, ar->wmi.svc_map) && mode == ATH10K_FIRMWARE_MODE_NORMAL) { val = 0; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index b50ab9e229dc..51f7e960e297 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -84,6 +84,11 @@ #define ATH10K_MAX_RETRY_COUNT 30 +#define ATH10K_ITER_NORMAL_FLAGS (IEEE80211_IFACE_ITER_NORMAL | \ + IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) +#define ATH10K_ITER_RESUME_FLAGS (IEEE80211_IFACE_ITER_RESUME_ALL |\ + IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) + struct ath10k; static inline const char *ath10k_bus_str(enum ath10k_bus bus) @@ -829,6 +834,9 @@ enum ath10k_fw_features { /* Firmware allows setting peer fixed rate */ ATH10K_FW_FEATURE_PEER_FIXED_RATE = 21, + /* Firmware support IRAM recovery */ + ATH10K_FW_FEATURE_IRAM_RECOVERY = 22, + /* keep last */ ATH10K_FW_FEATURE_COUNT, }; @@ -857,6 +865,9 @@ enum ath10k_dev_flags { /* Per Station statistics service */ ATH10K_FLAG_PEER_STATS, + + /* Indicates that ath10k device is during recovery process and not complete */ + ATH10K_FLAG_RESTARTING, }; enum ath10k_cal_mode { @@ -1312,6 +1323,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, const struct ath10k_fw_components *fw_components); int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); void ath10k_core_stop(struct ath10k *ar); +void ath10k_core_start_recovery(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar, const struct ath10k_bus_params *bus_params); void ath10k_core_unregister(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index e8250a665433..fd052f6ed019 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -583,7 +583,7 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, ret = ath10k_debug_fw_assert(ar); } else if (!strcmp(buf, "hw-restart")) { ath10k_info(ar, "user requested hw restart\n"); - queue_work(ar->workqueue, &ar->restart_work); + ath10k_core_start_recovery(ar); ret = 0; } else { ret = -EINVAL; @@ -1764,7 +1764,7 @@ static ssize_t ath10k_write_simulate_radar(struct file *file, struct ath10k *ar = file->private_data; struct ath10k_vif *arvif; - /* Just check for for the first vif alone, as all the vifs will be + /* Just check for the first vif alone, as all the vifs will be * sharing the same channel and if the channel is disabled, all the * vifs will share the same 'is_started' state. */ @@ -2005,7 +2005,7 @@ static ssize_t ath10k_write_btcoex(struct file *file, } } else { ath10k_info(ar, "restarting firmware due to btcoex change"); - queue_work(ar->workqueue, &ar->restart_work); + ath10k_core_start_recovery(ar); } if (val) @@ -2136,7 +2136,7 @@ static ssize_t ath10k_write_peer_stats(struct file *file, ath10k_info(ar, "restarting firmware due to Peer stats change"); - queue_work(ar->workqueue, &ar->restart_work); + ath10k_core_start_recovery(ar); ret = count; exit: diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 5c1af2021883..9c4e6cf2137a 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -3878,7 +3878,6 @@ bool ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) return ath10k_htt_rx_proc_rx_frag_ind(htt, &resp->rx_frag_ind, skb); - break; } case HTT_T2H_MSG_TYPE_TEST: break; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 2e3eb5bbe49c..7d98250380ec 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2066,7 +2066,7 @@ static void ath10k_mac_handle_beacon_iter(void *data, u8 *mac, void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb) { ieee80211_iterate_active_interfaces_atomic(ar->hw, - IEEE80211_IFACE_ITER_NORMAL, + ATH10K_ITER_NORMAL_FLAGS, ath10k_mac_handle_beacon_iter, skb); } @@ -2099,7 +2099,7 @@ static void ath10k_mac_handle_beacon_miss_iter(void *data, u8 *mac, void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id) { ieee80211_iterate_active_interfaces_atomic(ar->hw, - IEEE80211_IFACE_ITER_NORMAL, + ATH10K_ITER_NORMAL_FLAGS, ath10k_mac_handle_beacon_miss_iter, &vdev_id); } @@ -3433,7 +3433,7 @@ void ath10k_mac_tx_unlock(struct ath10k *ar, int reason) return; ieee80211_iterate_active_interfaces_atomic(ar->hw, - IEEE80211_IFACE_ITER_RESUME_ALL, + ATH10K_ITER_RESUME_FLAGS, ath10k_mac_tx_unlock_iter, ar); @@ -3522,7 +3522,7 @@ void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, spin_lock_bh(&ar->htt.tx_lock); ieee80211_iterate_active_interfaces_atomic(ar->hw, - IEEE80211_IFACE_ITER_RESUME_ALL, + ATH10K_ITER_RESUME_FLAGS, ath10k_mac_handle_tx_pause_iter, &arg); spin_unlock_bh(&ar->htt.tx_lock); @@ -5457,7 +5457,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, /* Some firmware revisions don't wait for beacon tx completion before * sending another SWBA event. This could lead to hardware using old * (freed) beacon data in some cases, e.g. tx credit starvation - * combined with missed TBTT. This is very very rare. + * combined with missed TBTT. This is very rare. * * On non-IOMMU-enabled hosts this could be a possible security issue * because hw could beacon some random data on the air. On @@ -7932,6 +7932,7 @@ static void ath10k_reconfig_complete(struct ieee80211_hw *hw, ath10k_info(ar, "device successfully recovered\n"); ar->state = ATH10K_STATE_ON; ieee80211_wake_queues(ar->hw); + clear_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags); } mutex_unlock(&ar->conf_mutex); @@ -8696,7 +8697,7 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw, if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) { ieee80211_iterate_active_interfaces_atomic( hw, - IEEE80211_IFACE_ITER_NORMAL, + ATH10K_ITER_NORMAL_FLAGS, ath10k_mac_change_chanctx_cnt_iter, &arg); if (arg.n_vifs == 0) @@ -8709,7 +8710,7 @@ ath10k_mac_op_change_chanctx(struct ieee80211_hw *hw, ieee80211_iterate_active_interfaces_atomic( hw, - IEEE80211_IFACE_ITER_NORMAL, + ATH10K_ITER_NORMAL_FLAGS, ath10k_mac_change_chanctx_fill_iter, &arg); ath10k_mac_update_vif_chan(ar, arg.vifs, arg.n_vifs); @@ -9169,10 +9170,11 @@ static int ath10k_mac_op_set_tid_config(struct ieee80211_hw *hw, goto exit; } + ret = 0; + if (sta) goto exit; - ret = 0; arvif->tids_rst = 0; data.curr_vif = vif; data.ar = ar; @@ -9593,14 +9595,12 @@ static void ath10k_get_arvif_iter(void *data, u8 *mac, struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id) { struct ath10k_vif_iter arvif_iter; - u32 flags; memset(&arvif_iter, 0, sizeof(struct ath10k_vif_iter)); arvif_iter.vdev_id = vdev_id; - flags = IEEE80211_IFACE_ITER_RESUME_ALL; ieee80211_iterate_active_interfaces_atomic(ar->hw, - flags, + ATH10K_ITER_RESUME_FLAGS, ath10k_get_arvif_iter, &arvif_iter); if (!arvif_iter.arvif) { diff --git a/drivers/net/wireless/ath/ath10k/p2p.c b/drivers/net/wireless/ath/ath10k/p2p.c index 29c737b2f432..517b30f56b72 100644 --- a/drivers/net/wireless/ath/ath10k/p2p.c +++ b/drivers/net/wireless/ath/ath10k/p2p.c @@ -139,7 +139,7 @@ void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id, }; ieee80211_iterate_active_interfaces_atomic(ar->hw, - IEEE80211_IFACE_ITER_NORMAL, + ATH10K_ITER_NORMAL_FLAGS, ath10k_p2p_noa_update_vdev_iter, &arg); } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 36426efdb2ea..2328df09875c 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1774,7 +1774,7 @@ static void ath10k_pci_fw_dump_work(struct work_struct *work) mutex_unlock(&ar->dump_mutex); - queue_work(ar->workqueue, &ar->restart_work); + ath10k_core_start_recovery(ar); } static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) @@ -3236,7 +3236,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar) if (ret == 0) return 0; - /* fall-through */ + /* MHI failed, try legacy irq next */ } /* Try legacy irq diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index ae6b1f402adf..07e478f9a808 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -917,7 +917,7 @@ static void ath10k_qmi_msa_ready_ind(struct qmi_handle *qmi_hdl, ath10k_qmi_driver_event_post(qmi, ATH10K_QMI_EVENT_MSA_READY_IND, NULL); } -static struct qmi_msg_handler qmi_msg_handler[] = { +static const struct qmi_msg_handler qmi_msg_handler[] = { { .type = QMI_INDICATION, .msg_id = QMI_WLFW_FW_READY_IND_V01, @@ -981,7 +981,7 @@ static void ath10k_qmi_del_server(struct qmi_handle *qmi_hdl, NULL); } -static struct qmi_ops ath10k_qmi_ops = { +static const struct qmi_ops ath10k_qmi_ops = { .new_server = ath10k_qmi_new_server, .del_server = ath10k_qmi_del_server, }; diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index dec1582005b9..f2b6bf8f0d60 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -68,7 +68,7 @@ struct rx_attention { * first_msdu is set. * * peer_idx_invalid - * Indicates no matching entries within the the max search + * Indicates no matching entries within the max search * count. Only set when first_msdu is set. * * peer_idx_timeout diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index 81ddaafb6721..c415090d1f37 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -561,7 +561,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar, ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH); ret = -ENOMEM; - queue_work(ar->workqueue, &ar->restart_work); + ath10k_core_start_recovery(ar); ath10k_warn(ar, "exceeds length, start recovery\n"); goto err; @@ -960,7 +960,7 @@ static int ath10k_sdio_mbox_read_int_status(struct ath10k *ar, ret = ath10k_sdio_read(ar, MBOX_HOST_INT_STATUS_ADDRESS, irq_proc_reg, sizeof(*irq_proc_reg)); if (ret) { - queue_work(ar->workqueue, &ar->restart_work); + ath10k_core_start_recovery(ar); ath10k_warn(ar, "read int status fail, start recovery\n"); goto out; } @@ -1248,7 +1248,7 @@ static int ath10k_sdio_bmi_exchange_msg(struct ath10k *ar, * Wait for first 4 bytes to be in FIFO * If CONSERVATIVE_BMI_READ is enabled, also wait for * a BMI command credit, which indicates that the ENTIRE - * response is available in the the FIFO + * response is available in the FIFO * * CASE 3: length > 128 * Wait for the first 4 bytes to be in FIFO @@ -1962,9 +1962,15 @@ static void ath10k_sdio_hif_stop(struct ath10k *ar) { struct ath10k_sdio_bus_request *req, *tmp_req; struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar); + struct sk_buff *skb; ath10k_sdio_irq_disable(ar); + cancel_work_sync(&ar_sdio->async_work_rx); + + while ((skb = skb_dequeue(&ar_sdio->rx_head))) + dev_kfree_skb_any(skb); + cancel_work_sync(&ar_sdio->wr_async_work); spin_lock_bh(&ar_sdio->wr_async_lock); @@ -2231,7 +2237,7 @@ static bool ath10k_sdio_is_fast_dump_supported(struct ath10k *ar) ath10k_dbg(ar, ATH10K_DBG_SDIO, "sdio hi_option_flag2 %x\n", param); - return param & HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_FW; + return !!(param & HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_FW); } static void ath10k_sdio_dump_registers(struct ath10k *ar, @@ -2307,8 +2313,8 @@ static int ath10k_sdio_dump_memory_section(struct ath10k *ar, } count = 0; - - for (i = 0; cur_section; i++) { + i = 0; + for (; cur_section; cur_section = next_section) { section_size = cur_section->end - cur_section->start; if (section_size <= 0) { @@ -2318,7 +2324,7 @@ static int ath10k_sdio_dump_memory_section(struct ath10k *ar, break; } - if ((i + 1) == mem_region->section_table.size) { + if (++i == mem_region->section_table.size) { /* last section */ next_section = NULL; skip_size = 0; @@ -2361,12 +2367,6 @@ static int ath10k_sdio_dump_memory_section(struct ath10k *ar, } count += skip_size; - - if (!next_section) - /* this was the last section */ - break; - - cur_section = next_section; } return count; @@ -2501,7 +2501,7 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar) ath10k_sdio_enable_intrs(ar); - queue_work(ar->workqueue, &ar->restart_work); + ath10k_core_start_recovery(ar); } static int ath10k_sdio_probe(struct sdio_func *func, diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index fd41f25456dc..bf9a8cb713dc 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -1305,7 +1305,7 @@ int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type) switch (type) { case ATH10K_QMI_EVENT_FW_READY_IND: if (test_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags)) { - queue_work(ar->workqueue, &ar->restart_work); + ath10k_core_start_recovery(ar); break; } diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c index 05a620ff6fe2..19b9c27e30e2 100644 --- a/drivers/net/wireless/ath/ath10k/usb.c +++ b/drivers/net/wireless/ath/ath10k/usb.c @@ -997,6 +997,8 @@ static int ath10k_usb_probe(struct usb_interface *interface, ar_usb = ath10k_usb_priv(ar); ret = ath10k_usb_create(ar, interface); + if (ret) + goto err; ar_usb->ar = ar; ar->dev_id = product_id; @@ -1009,7 +1011,7 @@ static int ath10k_usb_probe(struct usb_interface *interface, ret = ath10k_core_register(ar, &bus_params); if (ret) { ath10k_warn(ar, "failed to register driver core: %d\n", ret); - goto err; + goto err_usb_destroy; } /* TODO: remove this once USB support is fully implemented */ @@ -1017,6 +1019,9 @@ static int ath10k_usb_probe(struct usb_interface *interface, return 0; +err_usb_destroy: + ath10k_usb_destroy(ar); + err: ath10k_core_destroy(ar); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 932266d1111b..7b5834157fe5 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1401,13 +1401,15 @@ static int ath10k_wmi_tlv_svc_avail_parse(struct ath10k *ar, u16 tag, u16 len, switch (tag) { case WMI_TLV_TAG_STRUCT_SERVICE_AVAILABLE_EVENT: + arg->service_map_ext_valid = true; arg->service_map_ext_len = *(__le32 *)ptr; arg->service_map_ext = ptr + sizeof(__le32); return 0; default: break; } - return -EPROTO; + + return 0; } static int ath10k_wmi_tlv_op_pull_svc_avail(struct ath10k *ar, diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 1fa7107a5051..1f33947e2088 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1894,7 +1894,7 @@ static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac, static void ath10k_wmi_tx_beacons_nowait(struct ath10k *ar) { ieee80211_iterate_active_interfaces_atomic(ar->hw, - IEEE80211_IFACE_ITER_NORMAL, + ATH10K_ITER_NORMAL_FLAGS, ath10k_wmi_tx_beacons_iter, NULL); } @@ -1937,7 +1937,7 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) if (ret == -EAGAIN) { ath10k_warn(ar, "wmi command %d timeout, restarting hardware\n", cmd_id); - queue_work(ar->workqueue, &ar->restart_work); + ath10k_core_start_recovery(ar); } return ret; @@ -5751,8 +5751,13 @@ void ath10k_wmi_event_service_available(struct ath10k *ar, struct sk_buff *skb) ret); } - ath10k_wmi_map_svc_ext(ar, arg.service_map_ext, ar->wmi.svc_map, - __le32_to_cpu(arg.service_map_ext_len)); + /* + * Initialization of "arg.service_map_ext_valid" to ZERO is necessary + * for the below logic to work. + */ + if (arg.service_map_ext_valid) + ath10k_wmi_map_svc_ext(ar, arg.service_map_ext, ar->wmi.svc_map, + __le32_to_cpu(arg.service_map_ext_len)); } static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 4898e19b0af6..d870f7067cb7 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3060,6 +3060,8 @@ struct host_memory_chunk { __le32 size; } __packed; +#define WMI_IRAM_RECOVERY_HOST_MEM_REQ_ID 8 + struct wmi_host_mem_chunks { __le32 count; /* some fw revisions require at least 1 chunk regardless of count */ @@ -3832,7 +3834,7 @@ enum wmi_pdev_param { WMI_PDEV_PARAM_BEACON_TX_MODE, /* * Resource manager off chan mode . - * 0: turn off off chan mode. 1: turn on offchan mode + * 0: turn off offchan mode. 1: turn on offchan mode */ WMI_PDEV_PARAM_RESMGR_OFFCHAN_MODE, /* @@ -3936,7 +3938,7 @@ enum wmi_10x_pdev_param { WMI_10X_PDEV_PARAM_BEACON_TX_MODE, /* * Resource manager off chan mode . - * 0: turn off off chan mode. 1: turn on offchan mode + * 0: turn off offchan mode. 1: turn on offchan mode */ WMI_10X_PDEV_PARAM_RESMGR_OFFCHAN_MODE, /* @@ -6917,6 +6919,7 @@ struct wmi_svc_rdy_ev_arg { }; struct wmi_svc_avail_ev_arg { + bool service_map_ext_valid; __le32 service_map_ext_len; const __le32 *service_map_ext; }; diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile index c41d87bd025a..c1fce4159f1f 100644 --- a/drivers/net/wireless/ath/ath11k/Makefile +++ b/drivers/net/wireless/ath/ath11k/Makefile @@ -16,7 +16,8 @@ ath11k-y += core.o \ ce.o \ peer.o \ dbring.o \ - hw.o + hw.o \ + wow.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 430723c64adc..d4ef45cd0685 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -340,6 +340,31 @@ static void ath11k_ahb_power_down(struct ath11k_base *ab) rproc_shutdown(ab_ahb->tgt_rproc); } +static int ath11k_ahb_fwreset_from_cold_boot(struct ath11k_base *ab) +{ + int timeout; + + if (ath11k_cold_boot_cal == 0 || ab->qmi.cal_done || + ab->hw_params.cold_boot_calib == 0) + return 0; + + ath11k_dbg(ab, ATH11K_DBG_AHB, "wait for cold boot done\n"); + timeout = wait_event_timeout(ab->qmi.cold_boot_waitq, + (ab->qmi.cal_done == 1), + ATH11K_COLD_BOOT_FW_RESET_DELAY); + if (timeout <= 0) { + ath11k_cold_boot_cal = 0; + ath11k_warn(ab, "Coldboot Calibration failed timed out\n"); + } + + /* reset the firmware */ + ath11k_ahb_power_down(ab); + ath11k_ahb_power_up(ab); + + ath11k_dbg(ab, ATH11K_DBG_AHB, "exited from cold boot mode\n"); + return 0; +} + static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab) { struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; @@ -700,6 +725,8 @@ static int ath11k_ahb_probe(struct platform_device *pdev) goto err_ce_free; } + ath11k_ahb_fwreset_from_cold_boot(ab); + return 0; err_ce_free: @@ -720,6 +747,13 @@ static int ath11k_ahb_remove(struct platform_device *pdev) struct ath11k_base *ab = platform_get_drvdata(pdev); unsigned long left; + if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { + ath11k_ahb_power_down(ab); + ath11k_debugfs_soc_destroy(ab); + ath11k_qmi_deinit_service(ab); + goto qmi_fail; + } + reinit_completion(&ab->driver_recovery); if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) { @@ -733,8 +767,8 @@ static int ath11k_ahb_remove(struct platform_device *pdev) cancel_work_sync(&ab->restart_work); ath11k_core_deinit(ab); +qmi_fail: ath11k_ahb_free_irq(ab); - ath11k_hal_srng_deinit(ab); ath11k_ce_free_pipes(ab); ath11k_core_free(ab); diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index 9d730f8ac816..987c65010272 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -195,7 +195,7 @@ static bool ath11k_ce_need_shadow_fix(int ce_id) return false; } -static void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab) +void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab) { int i; diff --git a/drivers/net/wireless/ath/ath11k/ce.h b/drivers/net/wireless/ath/ath11k/ce.h index 269b599ac0b0..d6eeef919349 100644 --- a/drivers/net/wireless/ath/ath11k/ce.h +++ b/drivers/net/wireless/ath/ath11k/ce.h @@ -190,4 +190,6 @@ int ath11k_ce_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, int ath11k_ce_attr_attach(struct ath11k_base *ab); void ath11k_ce_get_shadow_config(struct ath11k_base *ab, u32 **shadow_cfg, u32 *shadow_cfg_len); +void ath11k_ce_stop_shadow_timers(struct ath11k_base *ab); + #endif diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index ebd6886a8c18..b97c38b9a270 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -7,11 +7,13 @@ #include <linux/slab.h> #include <linux/remoteproc.h> #include <linux/firmware.h> +#include <linux/of.h> #include "core.h" #include "dp_tx.h" #include "dp_rx.h" #include "debug.h" #include "hif.h" +#include "wow.h" unsigned int ath11k_debug_mask; EXPORT_SYMBOL(ath11k_debug_mask); @@ -50,7 +52,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq8074, .svc_to_ce_map_len = 21, .single_pdev_only = false, - .needs_band_to_mac = true, .rxdma1_enable = true, .num_rxmda_per_pdev = 1, .rx_mac_buf_ring = false, @@ -65,6 +66,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_monitor = true, .supports_shadow_regs = false, .idle_ps = false, + .cold_boot_calib = true, + .supports_suspend = false, }, { .hw_rev = ATH11K_HW_IPQ6018_HW10, @@ -87,7 +90,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq6018, .svc_to_ce_map_len = 19, .single_pdev_only = false, - .needs_band_to_mac = true, .rxdma1_enable = true, .num_rxmda_per_pdev = 1, .rx_mac_buf_ring = false, @@ -102,6 +104,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_monitor = true, .supports_shadow_regs = false, .idle_ps = false, + .cold_boot_calib = true, + .supports_suspend = false, }, { .name = "qca6390 hw2.0", @@ -124,7 +128,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390, .svc_to_ce_map_len = 14, .single_pdev_only = true, - .needs_band_to_mac = false, .rxdma1_enable = false, .num_rxmda_per_pdev = 2, .rx_mac_buf_ring = true, @@ -138,17 +141,130 @@ static const struct ath11k_hw_params ath11k_hw_params[] = { .supports_monitor = false, .supports_shadow_regs = true, .idle_ps = true, + .cold_boot_calib = false, + .supports_suspend = true, }, }; +int ath11k_core_suspend(struct ath11k_base *ab) +{ + int ret; + + 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. + */ + msleep(500); + + ret = ath11k_dp_rx_pktlog_stop(ab, true); + if (ret) { + ath11k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n", + ret); + 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", + ret); + return ret; + } + + ath11k_ce_stop_shadow_timers(ab); + ath11k_dp_stop_shadow_timers(ab); + + 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; + } + + return 0; +} +EXPORT_SYMBOL(ath11k_core_suspend); + +int ath11k_core_resume(struct ath11k_base *ab) +{ + int ret; + + if (!ab->hw_params.supports_suspend) + return -EOPNOTSUPP; + + ret = ath11k_hif_resume(ab); + if (ret) { + ath11k_warn(ab, "failed to resume hif during resume: %d\n", ret); + return ret; + } + + ath11k_hif_ce_irq_enable(ab); + ath11k_hif_irq_enable(ab); + + ret = ath11k_dp_rx_pktlog_start(ab); + 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; +} +EXPORT_SYMBOL(ath11k_core_resume); + +int ath11k_core_check_dt(struct ath11k_base *ab) +{ + size_t max_len = sizeof(ab->qmi.target.bdf_ext); + const char *variant = NULL; + struct device_node *node; + + node = ab->dev->of_node; + if (!node) + return -ENOENT; + + of_property_read_string(node, "qcom,ath11k-calibration-variant", + &variant); + if (!variant) + return -ENODATA; + + if (strscpy(ab->qmi.target.bdf_ext, variant, max_len) < 0) + ath11k_dbg(ab, ATH11K_DBG_BOOT, + "bdf variant string is longer than the buffer can accommodate (variant: %s)\n", + variant); + + return 0; +} + static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name, size_t name_len) { + /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ + char variant[9 + ATH11K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; + + if (ab->qmi.target.bdf_ext[0] != '\0') + scnprintf(variant, sizeof(variant), ",variant=%s", + ab->qmi.target.bdf_ext); + scnprintf(name, name_len, - "bus=%s,qmi-chip-id=%d,qmi-board-id=%d", + "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s", ath11k_bus_str(ab->hif.bus), ab->qmi.target.chip_id, - ab->qmi.target.board_id); + ab->qmi.target.board_id, variant); ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot using board name '%s'\n", name); @@ -612,6 +728,15 @@ static int ath11k_core_start(struct ath11k_base *ab, goto err_reo_cleanup; } + /* put hardware to DBS mode */ + if (ab->hw_params.single_pdev_only) { + ret = ath11k_wmi_set_hw_mode(ab, WMI_HOST_HW_MODE_DBS); + if (ret) { + ath11k_err(ab, "failed to send dbs mode: %d\n", ret); + goto err_hif_stop; + } + } + ret = ath11k_dp_tx_htt_h2t_ver_req_msg(ab); if (ret) { ath11k_err(ab, "failed to send htt version request message: %d\n", @@ -774,8 +899,10 @@ static void ath11k_core_restart(struct work_struct *work) complete(&ar->scan.started); complete(&ar->scan.completed); complete(&ar->peer_assoc_done); + complete(&ar->peer_delete_done); complete(&ar->install_key_done); complete(&ar->vdev_setup_done); + complete(&ar->vdev_delete_done); complete(&ar->bss_survey_done); complete(&ar->thermal.wmi_sync); @@ -923,8 +1050,12 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size, INIT_LIST_HEAD(&ab->peers); init_waitqueue_head(&ab->peer_mapping_wq); init_waitqueue_head(&ab->wmi_ab.tx_credits_wq); + init_waitqueue_head(&ab->qmi.cold_boot_waitq); INIT_WORK(&ab->restart_work, ath11k_core_restart); timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); + init_completion(&ab->htc_suspend); + init_completion(&ab->wow.wakeup_completed); + ab->dev = dev; ab->bus_params = *bus_params; ab->hif.bus = bus; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 18b97420f0d8..799bf3de1117 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -75,12 +75,14 @@ static inline enum wme_ac ath11k_tid_to_ac(u32 tid) enum ath11k_skb_flags { ATH11K_SKB_HW_80211_ENCAP = BIT(0), + ATH11K_SKB_CIPHER_SET = BIT(1), }; struct ath11k_skb_cb { dma_addr_t paddr; u8 eid; u8 flags; + u32 cipher; struct ath11k *ar; struct ieee80211_vif *vif; } __packed; @@ -111,8 +113,13 @@ enum ath11k_firmware_mode { /* factory tests etc */ ATH11K_FIRMWARE_MODE_FTM, + + /* Cold boot calibration */ + ATH11K_FIRMWARE_MODE_COLD_BOOT = 7, }; +extern bool ath11k_cold_boot_cal; + #define ATH11K_IRQ_NUM_MAX 52 #define ATH11K_EXT_IRQ_NUM_MAX 16 @@ -178,6 +185,8 @@ enum ath11k_dev_flags { ATH11K_FLAG_RECOVERY, ATH11K_FLAG_UNREGISTERING, ATH11K_FLAG_REGISTERED, + ATH11K_FLAG_QMI_FAIL, + ATH11K_FLAG_HTC_SUSPEND_COMPLETE, }; enum ath11k_monitor_flags { @@ -425,11 +434,7 @@ struct ath11k_per_peer_tx_stats { }; #define ATH11K_FLUSH_TIMEOUT (5 * HZ) - -struct ath11k_vdev_stop_status { - bool stop_in_progress; - u32 vdev_id; -}; +#define ATH11K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ) struct ath11k { struct ath11k_base *ab; @@ -461,6 +466,7 @@ struct ath11k { struct ieee80211_sband_iftype_data iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES]; } mac; + unsigned long dev_flags; unsigned int filter_flags; unsigned long monitor_flags; @@ -500,13 +506,14 @@ struct ath11k { u8 lmac_id; struct completion peer_assoc_done; + struct completion peer_delete_done; int install_key_status; struct completion install_key_done; int last_wmi_vdev_start_status; - struct ath11k_vdev_stop_status vdev_stop_status; struct completion vdev_setup_done; + struct completion vdev_delete_done; int num_peers; int max_num_peers; @@ -666,6 +673,10 @@ struct ath11k_base { const struct ath11k_hif_ops *ops; } hif; + struct { + struct completion wakeup_completed; + } wow; + struct ath11k_ce ce; struct timer_list rx_replenish_retry; struct ath11k_hal hal; @@ -723,13 +734,13 @@ struct ath11k_base { } stats; u32 pktlog_defs_checksum; - /* Round robbin based TCL ring selector */ - atomic_t tcl_ring_selector; - struct ath11k_dbring_cap *db_caps; u32 num_db_cap; struct timer_list mon_reap_timer; + + struct completion htc_suspend; + /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; @@ -883,8 +894,11 @@ void ath11k_core_free(struct ath11k_base *ath11k); int ath11k_core_fetch_bdf(struct ath11k_base *ath11k, struct ath11k_board_data *bd); void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd); +int ath11k_core_check_dt(struct ath11k_base *ath11k); void ath11k_core_halt(struct ath11k *ar); +int ath11k_core_resume(struct ath11k_base *ab); +int ath11k_core_suspend(struct ath11k_base *ab); const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab, const char *filename); @@ -907,6 +921,8 @@ static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state) static inline struct ath11k_skb_cb *ATH11K_SKB_CB(struct sk_buff *skb) { + BUILD_BUG_ON(sizeof(struct ath11k_skb_cb) > + IEEE80211_TX_INFO_DRIVER_DATA_SIZE); return (struct ath11k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data; } diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index 1b914e67d314..554feaf1ed5c 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -867,6 +867,7 @@ void ath11k_debugfs_soc_destroy(struct ath11k_base *ab) debugfs_remove_recursive(ab->debugfs_ath11k); ab->debugfs_ath11k = NULL; } +EXPORT_SYMBOL(ath11k_debugfs_soc_destroy); void ath11k_debugfs_fw_stats_init(struct ath11k *ar) { diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 59dd185a0cfc..04f6c4e0658b 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -304,7 +304,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, return 0; } -static void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab) +void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab) { int i; @@ -381,7 +381,7 @@ static int ath11k_dp_srng_common_setup(struct ath11k_base *ab) HAL_WBM2SW_RELEASE, i, 0, DP_TX_COMP_RING_SIZE); if (ret) { - ath11k_warn(ab, "failed to set up tcl_comp ring ring (%d) :%d\n", + ath11k_warn(ab, "failed to set up tcl_comp ring (%d) :%d\n", i, ret); goto err; } diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index ee8db812589b..ee768ccce46e 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h @@ -40,6 +40,7 @@ struct dp_rx_tid { #define DP_REO_DESC_FREE_THRESHOLD 64 #define DP_REO_DESC_FREE_TIMEOUT_MS 1000 +#define DP_MON_PURGE_TIMEOUT_MS 100 #define DP_MON_SERVICE_BUDGET 128 struct dp_reo_cache_flush_elem { @@ -423,7 +424,7 @@ enum htt_srng_ring_id { * Used only by Consumer ring to generate ring_sw_int_p. * Ring entries low threshold water mark, that is used * in combination with the interrupt timer as well as - * the the clearing of the level interrupt. + * the clearing of the level interrupt. * b'16:18 - prefetch_timer_cfg: * Used only by Consumer ring to set timer mode to * support Application prefetch handling. @@ -1640,5 +1641,6 @@ void ath11k_dp_shadow_stop_timer(struct ath11k_base *ab, void ath11k_dp_shadow_init_timer(struct ath11k_base *ab, struct ath11k_hp_update_timer *update_timer, u32 interval, u32 ring_id); +void ath11k_dp_stop_shadow_timers(struct ath11k_base *ab); #endif diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 01625327eef7..205c0f1a40e9 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -274,6 +274,28 @@ static void ath11k_dp_service_mon_ring(struct timer_list *t) msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL)); } +static int ath11k_dp_purge_mon_ring(struct ath11k_base *ab) +{ + int i, reaped = 0; + unsigned long timeout = jiffies + msecs_to_jiffies(DP_MON_PURGE_TIMEOUT_MS); + + do { + for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) + reaped += ath11k_dp_rx_process_mon_rings(ab, i, + NULL, + DP_MON_SERVICE_BUDGET); + + /* nothing more to reap */ + if (reaped < DP_MON_SERVICE_BUDGET) + return 0; + + } while (time_before(jiffies, timeout)); + + ath11k_warn(ab, "dp mon ring purge timeout"); + + return -ETIMEDOUT; +} + /* Returns number of Rx buffers replenished */ int ath11k_dp_rxbufs_replenish(struct ath11k_base *ab, int mac_id, struct dp_rxdma_ring *rx_ring, @@ -377,7 +399,7 @@ static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, spin_lock_bh(&rx_ring->idr_lock); idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) { idr_remove(&rx_ring->bufs_idr, buf_id); - /* TODO: Understand where internal driver does this dma_unmap of + /* TODO: Understand where internal driver does this dma_unmap * of rxdma_buffer. */ dma_unmap_single(ar->ab->dev, ATH11K_SKB_RXCB(skb)->paddr, @@ -399,7 +421,7 @@ static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar, spin_lock_bh(&rx_ring->idr_lock); idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) { idr_remove(&rx_ring->bufs_idr, buf_id); - /* XXX: Understand where internal driver does this dma_unmap of + /* XXX: Understand where internal driver does this dma_unmap * of rxdma_buffer. */ dma_unmap_single(ar->ab->dev, ATH11K_SKB_RXCB(skb)->paddr, @@ -960,7 +982,7 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id, rx_tid->ba_win_sz = ba_win_sz; - /* TODO: Optimize the memory allocation for qos tid based on the + /* TODO: Optimize the memory allocation for qos tid based on * the actual BA window size in REO tid update path. */ if (tid == HAL_DESC_REO_NON_QOS_TID) @@ -2715,7 +2737,7 @@ static struct sk_buff *ath11k_dp_rx_alloc_mon_status_buf(struct ath11k_base *ab, paddr = dma_map_single(ab->dev, skb->data, skb->len + skb_tailroom(skb), - DMA_BIDIRECTIONAL); + DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(ab->dev, paddr))) goto fail_free_skb; @@ -2731,7 +2753,7 @@ static struct sk_buff *ath11k_dp_rx_alloc_mon_status_buf(struct ath11k_base *ab, fail_dma_unmap: dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), - DMA_BIDIRECTIONAL); + DMA_FROM_DEVICE); fail_free_skb: dev_kfree_skb_any(skb); fail_alloc_skb: @@ -2795,7 +2817,7 @@ fail_desc_get: idr_remove(&rx_ring->bufs_idr, buf_id); spin_unlock_bh(&rx_ring->idr_lock); dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), - DMA_BIDIRECTIONAL); + DMA_FROM_DEVICE); dev_kfree_skb_any(skb); ath11k_hal_srng_access_end(ab, srng); spin_unlock_bh(&srng->lock); @@ -2856,13 +2878,9 @@ static int ath11k_dp_rx_reap_mon_status_ring(struct ath11k_base *ab, int mac_id, rxcb = ATH11K_SKB_RXCB(skb); - dma_sync_single_for_cpu(ab->dev, rxcb->paddr, - skb->len + skb_tailroom(skb), - DMA_FROM_DEVICE); - dma_unmap_single(ab->dev, rxcb->paddr, skb->len + skb_tailroom(skb), - DMA_BIDIRECTIONAL); + DMA_FROM_DEVICE); tlv = (struct hal_tlv_hdr *)skb->data; if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) != @@ -5030,3 +5048,29 @@ int ath11k_dp_rx_pdev_mon_detach(struct ath11k *ar) ath11k_dp_mon_link_free(ar); return 0; } + +int ath11k_dp_rx_pktlog_start(struct ath11k_base *ab) +{ + /* start reap timer */ + mod_timer(&ab->mon_reap_timer, + jiffies + msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL)); + + return 0; +} + +int ath11k_dp_rx_pktlog_stop(struct ath11k_base *ab, bool stop_timer) +{ + int ret; + + if (stop_timer) + del_timer_sync(&ab->mon_reap_timer); + + /* reap all the monitor related rings */ + ret = ath11k_dp_purge_mon_ring(ab); + if (ret) { + ath11k_warn(ab, "failed to purge dp mon ring: %d\n", ret); + return ret; + } + + return 0; +} diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.h b/drivers/net/wireless/ath/ath11k/dp_rx.h index fbea45f79c9b..bf399312b5ff 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.h +++ b/drivers/net/wireless/ath/ath11k/dp_rx.h @@ -91,4 +91,7 @@ int ath11k_dp_rx_pdev_mon_detach(struct ath11k *ar); int ath11k_dp_rx_pdev_mon_attach(struct ath11k *ar); 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); + #endif /* ATH11K_DP_RX_H */ diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 3d962eee4d61..6a3fcea6c233 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -84,7 +84,6 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, struct ath11k_dp *dp = &ab->dp; struct hal_tx_info ti = {0}; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_key_conf *key = info->control.hw_key; struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb); struct hal_srng *tcl_ring; struct ieee80211_hdr *hdr = (void *)skb->data; @@ -105,14 +104,14 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1); - /* Let the default ring selection be based on a round robin - * fashion where one of the 3 tcl rings are selected based on - * the tcl_ring_selector counter. In case that ring + /* Let the default ring selection be based on current processor + * number, where one of the 3 tcl rings are selected based on + * the smp_processor_id(). In case that ring * is full/busy, we resort to other available rings. * If all rings are full, we drop the packet. * //TODO Add throttling logic when all rings are full */ - ring_selector = atomic_inc_return(&ab->tcl_ring_selector); + ring_selector = smp_processor_id(); tcl_ring_sel: tcl_ring_retry = false; @@ -149,9 +148,9 @@ tcl_ring_sel: ti.meta_data_flags = arvif->tcl_metadata; if (ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW) { - if (key) { + if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) { ti.encrypt_type = - ath11k_dp_tx_get_encrypt_type(key->cipher); + ath11k_dp_tx_get_encrypt_type(skb_cb->cipher); if (ieee80211_has_protected(hdr->frame_control)) skb_put(skb, IEEE80211_CCMP_MIC_LEN); diff --git a/drivers/net/wireless/ath/ath11k/hal_desc.h b/drivers/net/wireless/ath/ath11k/hal_desc.h index 8a592814efa0..1b713cb13b90 100644 --- a/drivers/net/wireless/ath/ath11k/hal_desc.h +++ b/drivers/net/wireless/ath/ath11k/hal_desc.h @@ -716,7 +716,7 @@ struct hal_reo_dest_ring { * * rx_msdu_info * General information related to the MSDU that is passed - * on from RXDMA all the way to to the REO destination ring. + * on from RXDMA all the way to the REO destination ring. * * queue_addr_lo * Address (lower 32 bits) of the REO queue descriptor. @@ -1425,7 +1425,7 @@ struct hal_ce_srng_dest_desc { #define HAL_CE_DST_STATUS_DESC_FLAGS_GATHER BIT(11) #define HAL_CE_DST_STATUS_DESC_FLAGS_LEN GENMASK(31, 16) -#define HAL_CE_DST_STATUS_DESC_META_INFO_DATA GENMASK(7, 0) +#define HAL_CE_DST_STATUS_DESC_META_INFO_DATA GENMASK(15, 0) #define HAL_CE_DST_STATUS_DESC_META_INFO_RING_ID GENMASK(27, 20) #define HAL_CE_DST_STATUS_DESC_META_INFO_LOOP_CNT HAL_SRNG_DESC_LOOP_CNT @@ -1946,7 +1946,7 @@ enum hal_rx_reo_queue_pn_size { #define HAL_RX_REO_QUEUE_INFO3_TIMEOUT_COUNT GENMASK(9, 4) #define HAL_RX_REO_QUEUE_INFO3_FWD_DUE_TO_BAR_CNT GENMASK(15, 10) -#define HAL_RX_REO_QUEUE_INFO3_DUPLICATE_COUNT GENMASK(31, 10) +#define HAL_RX_REO_QUEUE_INFO3_DUPLICATE_COUNT GENMASK(31, 16) #define HAL_RX_REO_QUEUE_INFO4_FRAME_IN_ORD_COUNT GENMASK(23, 0) #define HAL_RX_REO_QUEUE_INFO4_BAR_RECVD_COUNT GENMASK(31, 24) @@ -2432,7 +2432,7 @@ struct hal_reo_flush_timeout_list_status { #define HAL_REO_DESC_THRESH_STATUS_INFO1_LINK_DESC_COUNTER0 GENMASK(23, 0) #define HAL_REO_DESC_THRESH_STATUS_INFO2_LINK_DESC_COUNTER1 GENMASK(23, 0) #define HAL_REO_DESC_THRESH_STATUS_INFO3_LINK_DESC_COUNTER2 GENMASK(23, 0) -#define HAL_REO_DESC_THRESH_STATUS_INFO4_LINK_DESC_COUNTER_SUM GENMASK(23, 0) +#define HAL_REO_DESC_THRESH_STATUS_INFO4_LINK_DESC_COUNTER_SUM GENMASK(25, 0) struct hal_reo_desc_thresh_reached_status { struct hal_reo_status_hdr hdr; diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h index dbe5568916e8..6285c52afc44 100644 --- a/drivers/net/wireless/ath/ath11k/hif.h +++ b/drivers/net/wireless/ath/ath11k/hif.h @@ -17,6 +17,8 @@ struct ath11k_hif_ops { void (*stop)(struct ath11k_base *sc); int (*power_up)(struct ath11k_base *sc); void (*power_down)(struct ath11k_base *sc); + int (*suspend)(struct ath11k_base *ab); + int (*resume)(struct ath11k_base *ab); int (*map_service_to_pipe)(struct ath11k_base *sc, u16 service_id, u8 *ul_pipe, u8 *dl_pipe); int (*get_user_msi_vector)(struct ath11k_base *ab, char *user_name, @@ -24,8 +26,22 @@ struct ath11k_hif_ops { u32 *base_vector); void (*get_msi_address)(struct ath11k_base *ab, u32 *msi_addr_lo, u32 *msi_addr_hi); + void (*ce_irq_enable)(struct ath11k_base *ab); + void (*ce_irq_disable)(struct ath11k_base *ab); }; +static inline void ath11k_hif_ce_irq_enable(struct ath11k_base *ab) +{ + if (ab->hif.ops->ce_irq_enable) + ab->hif.ops->ce_irq_enable(ab); +} + +static inline void ath11k_hif_ce_irq_disable(struct ath11k_base *ab) +{ + if (ab->hif.ops->ce_irq_disable) + ab->hif.ops->ce_irq_disable(ab); +} + static inline int ath11k_hif_start(struct ath11k_base *sc) { return sc->hif.ops->start(sc); @@ -56,6 +72,22 @@ static inline void ath11k_hif_power_down(struct ath11k_base *sc) sc->hif.ops->power_down(sc); } +static inline int ath11k_hif_suspend(struct ath11k_base *ab) +{ + if (ab->hif.ops->suspend) + return ab->hif.ops->suspend(ab); + + return 0; +} + +static inline int ath11k_hif_resume(struct ath11k_base *ab) +{ + if (ab->hif.ops->resume) + return ab->hif.ops->resume(ab); + + return 0; +} + static inline u32 ath11k_hif_read32(struct ath11k_base *sc, u32 address) { return sc->hif.ops->read32(sc, address); diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index 6b57dc273e0b..54b1d34724d7 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -60,9 +60,11 @@ static void ath11k_htc_prepare_tx_skb(struct ath11k_htc_ep *ep, memset(hdr, 0, sizeof(*hdr)); hdr->htc_info = FIELD_PREP(HTC_HDR_ENDPOINTID, ep->eid) | FIELD_PREP(HTC_HDR_PAYLOADLEN, - (skb->len - sizeof(*hdr))) | - FIELD_PREP(HTC_HDR_FLAGS, - ATH11K_HTC_FLAG_NEED_CREDIT_UPDATE); + (skb->len - sizeof(*hdr))); + + if (ep->tx_credit_flow_enabled) + hdr->htc_info |= FIELD_PREP(HTC_HDR_FLAGS, + ATH11K_HTC_FLAG_NEED_CREDIT_UPDATE); spin_lock_bh(&ep->htc->tx_lock); hdr->ctrl_info = FIELD_PREP(HTC_HDR_CONTROLBYTES1, ep->seq_no++); @@ -231,6 +233,18 @@ static int ath11k_htc_process_trailer(struct ath11k_htc *htc, return status; } +static void ath11k_htc_suspend_complete(struct ath11k_base *ab, bool ack) +{ + ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot suspend complete %d\n", ack); + + if (ack) + set_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags); + else + clear_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags); + + complete(&ab->htc_suspend); +} + void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, struct sk_buff *skb) { @@ -328,8 +342,17 @@ void ath11k_htc_rx_completion_handler(struct ath11k_base *ab, complete(&htc->ctl_resp); break; + case ATH11K_HTC_MSG_SEND_SUSPEND_COMPLETE: + ath11k_htc_suspend_complete(ab, true); + break; + case ATH11K_HTC_MSG_NACK_SUSPEND: + ath11k_htc_suspend_complete(ab, false); + break; + case ATH11K_HTC_MSG_WAKEUP_FROM_SUSPEND_ID: + break; default: - ath11k_warn(ab, "ignoring unsolicited htc ep0 event\n"); + ath11k_warn(ab, "ignoring unsolicited htc ep0 event %ld\n", + FIELD_GET(HTC_MSG_MESSAGEID, msg->msg_svc_id)); break; } goto out; diff --git a/drivers/net/wireless/ath/ath11k/htc.h b/drivers/net/wireless/ath/ath11k/htc.h index f0a3387567ca..6c8a469d7f9d 100644 --- a/drivers/net/wireless/ath/ath11k/htc.h +++ b/drivers/net/wireless/ath/ath11k/htc.h @@ -65,7 +65,9 @@ enum ath11k_htc_msg_id { ATH11K_HTC_MSG_CONNECT_SERVICE_RESP_ID = 3, ATH11K_HTC_MSG_SETUP_COMPLETE_ID = 4, ATH11K_HTC_MSG_SETUP_COMPLETE_EX_ID = 5, - ATH11K_HTC_MSG_SEND_SUSPEND_COMPLETE = 6 + ATH11K_HTC_MSG_SEND_SUSPEND_COMPLETE = 6, + ATH11K_HTC_MSG_NACK_SUSPEND = 7, + ATH11K_HTC_MSG_WAKEUP_FROM_SUSPEND_ID = 8, }; enum ath11k_htc_version { @@ -221,10 +223,6 @@ enum ath11k_htc_ep_id { ATH11K_HTC_EP_COUNT, }; -struct ath11k_htc_ops { - void (*target_send_suspend_complete)(struct ath11k_base *ar); -}; - struct ath11k_htc_ep_ops { void (*ep_tx_complete)(struct ath11k_base *, struct sk_buff *); void (*ep_rx_complete)(struct ath11k_base *, struct sk_buff *); @@ -284,8 +282,6 @@ struct ath11k_htc { /* protects endpoints */ spinlock_t tx_lock; - struct ath11k_htc_ops htc_ops; - u8 control_resp_buffer[ATH11K_HTC_MAX_CTRL_MSG_LEN]; int control_resp_len; diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 11a411b76fe4..66331da35012 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -127,7 +127,7 @@ static void ath11k_init_wmi_config_ipq8074(struct ath11k_base *ab, config->beacon_tx_offload_max_vdev = ab->num_radios * TARGET_MAX_BCN_OFFLD; config->rx_batchmode = TARGET_RX_BATCHMODE; config->peer_map_unmap_v2_support = 1; - config->twt_ap_pdev_count = 2; + config->twt_ap_pdev_count = ab->num_radios; config->twt_ap_sta_count = 1000; } @@ -157,7 +157,7 @@ static int ath11k_hw_mac_id_to_srng_id_qca6390(struct ath11k_hw_params *hw, const struct ath11k_hw_ops ipq8074_ops = { .get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id, - .wmi_init_config = ath11k_init_wmi_config_qca6390, + .wmi_init_config = ath11k_init_wmi_config_ipq8074, .mac_id_to_pdev_id = ath11k_hw_mac_id_to_pdev_id_ipq8074, .mac_id_to_srng_id = ath11k_hw_mac_id_to_srng_id_ipq8074, }; diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index 1dda4257e6d7..8af0034fdb05 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -143,12 +143,6 @@ struct ath11k_hw_params { bool single_pdev_only; - /* For example on QCA6390 struct - * wmi_init_cmd_param::band_to_mac_config needs to be false as the - * firmware creates the mapping. - */ - bool needs_band_to_mac; - bool rxdma1_enable; int num_rxmda_per_pdev; bool rx_mac_buf_ring; @@ -161,6 +155,8 @@ struct ath11k_hw_params { bool supports_monitor; bool supports_shadow_regs; bool idle_ps; + bool cold_boot_calib; + bool supports_suspend; }; struct ath11k_hw_ops { diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 7f8dd47d2333..5c175e3e09b2 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -537,31 +537,6 @@ struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id) return NULL; } -struct ath11k *ath11k_mac_get_ar_vdev_stop_status(struct ath11k_base *ab, - u32 vdev_id) -{ - int i; - struct ath11k_pdev *pdev; - struct ath11k *ar; - - for (i = 0; i < ab->num_radios; i++) { - pdev = rcu_dereference(ab->pdevs_active[i]); - if (pdev && pdev->ar) { - ar = pdev->ar; - - spin_lock_bh(&ar->data_lock); - if (ar->vdev_stop_status.stop_in_progress && - ar->vdev_stop_status.vdev_id == vdev_id) { - ar->vdev_stop_status.stop_in_progress = false; - spin_unlock_bh(&ar->data_lock); - return ar; - } - spin_unlock_bh(&ar->data_lock); - } - } - return NULL; -} - static void ath11k_pdev_caps_update(struct ath11k *ar) { struct ath11k_base *ab = ar->ab; @@ -1850,6 +1825,52 @@ static void ath11k_recalculate_mgmt_rate(struct ath11k *ar, ath11k_warn(ar->ab, "failed to set beacon tx rate %d\n", ret); } +static int ath11k_mac_fils_discovery(struct ath11k_vif *arvif, + struct ieee80211_bss_conf *info) +{ + struct ath11k *ar = arvif->ar; + struct sk_buff *tmpl; + int ret; + u32 interval; + bool unsol_bcast_probe_resp_enabled = false; + + if (info->fils_discovery.max_interval) { + interval = info->fils_discovery.max_interval; + + tmpl = ieee80211_get_fils_discovery_tmpl(ar->hw, arvif->vif); + if (tmpl) + ret = ath11k_wmi_fils_discovery_tmpl(ar, arvif->vdev_id, + tmpl); + } else if (info->unsol_bcast_probe_resp_interval) { + unsol_bcast_probe_resp_enabled = 1; + interval = info->unsol_bcast_probe_resp_interval; + + tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(ar->hw, + arvif->vif); + if (tmpl) + ret = ath11k_wmi_probe_resp_tmpl(ar, arvif->vdev_id, + tmpl); + } else { /* Disable */ + return ath11k_wmi_fils_discovery(ar, arvif->vdev_id, 0, false); + } + + if (!tmpl) { + ath11k_warn(ar->ab, + "mac vdev %i failed to retrieve %s template\n", + arvif->vdev_id, (unsol_bcast_probe_resp_enabled ? + "unsolicited broadcast probe response" : + "FILS discovery")); + return -EPERM; + } + kfree_skb(tmpl); + + if (!ret) + ret = ath11k_wmi_fils_discovery(ar, arvif->vdev_id, interval, + unsol_bcast_probe_resp_enabled); + + return ret; +} + static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *info, @@ -1904,20 +1925,6 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (ret) ath11k_warn(ar->ab, "failed to update bcn template: %d\n", ret); - - if (vif->bss_conf.he_support) { - ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - WMI_VDEV_PARAM_BA_MODE, - WMI_BA_MODE_BUFFER_SIZE_256); - if (ret) - ath11k_warn(ar->ab, - "failed to set BA BUFFER SIZE 256 for vdev: %d\n", - arvif->vdev_id); - else - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, - "Set BA BUFFER SIZE 256 for VDEV: %d\n", - arvif->vdev_id); - } } if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) { @@ -1948,9 +1955,33 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) ether_addr_copy(arvif->bssid, info->bssid); - if (changed & BSS_CHANGED_BEACON_ENABLED) + if (changed & BSS_CHANGED_BEACON_ENABLED) { ath11k_control_beaconing(arvif, info); + if (arvif->is_up && vif->bss_conf.he_support && + vif->bss_conf.he_oper.params) { + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + WMI_VDEV_PARAM_BA_MODE, + WMI_BA_MODE_BUFFER_SIZE_256); + if (ret) + ath11k_warn(ar->ab, + "failed to set BA BUFFER SIZE 256 for vdev: %d\n", + arvif->vdev_id); + + param_id = WMI_VDEV_PARAM_HEOPS_0_31; + param_value = vif->bss_conf.he_oper.params; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + param_id, param_value); + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "he oper param: %x set for VDEV: %d\n", + param_value, arvif->vdev_id); + + if (ret) + ath11k_warn(ar->ab, "Failed to set he oper params %x for VDEV %d: %i\n", + param_value, arvif->vdev_id, ret); + } + } + if (changed & BSS_CHANGED_ERP_CTS_PROT) { u32 cts_prot; @@ -2111,6 +2142,10 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, } } + if (changed & BSS_CHANGED_FILS_DISCOVERY || + changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP) + ath11k_mac_fils_discovery(arvif, info); + mutex_unlock(&ar->conf_mutex); } @@ -3729,11 +3764,6 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar, he_cap_elem->mac_cap_info[1] &= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK; - he_cap_elem->phy_cap_info[4] &= - ~IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_MASK; - he_cap_elem->phy_cap_info[4] &= - ~IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_MASK; - he_cap_elem->phy_cap_info[4] |= (ar->num_tx_chains - 1) << 2; he_cap_elem->phy_cap_info[5] &= ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK; @@ -3977,21 +4007,20 @@ static void ath11k_mgmt_over_wmi_tx_purge(struct ath11k *ar) static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) { struct ath11k *ar = container_of(work, struct ath11k, wmi_mgmt_tx_work); - struct ieee80211_tx_info *info; + struct ath11k_skb_cb *skb_cb; struct ath11k_vif *arvif; struct sk_buff *skb; int ret; while ((skb = skb_dequeue(&ar->wmi_mgmt_tx_queue)) != NULL) { - info = IEEE80211_SKB_CB(skb); - if (!info->control.vif) { - ath11k_warn(ar->ab, "no vif found for mgmt frame, flags 0x%x\n", - info->control.flags); + skb_cb = ATH11K_SKB_CB(skb); + if (!skb_cb->vif) { + ath11k_warn(ar->ab, "no vif found for mgmt frame\n"); ieee80211_free_txskb(ar->hw, skb); continue; } - arvif = ath11k_vif_to_arvif(info->control.vif); + arvif = ath11k_vif_to_arvif(skb_cb->vif); if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) && arvif->is_started) { ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb); @@ -4004,8 +4033,8 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) } } else { ath11k_warn(ar->ab, - "dropping mgmt frame for vdev %d, flags 0x%x is_started %d\n", - arvif->vdev_id, info->control.flags, + "dropping mgmt frame for vdev %d, is_started %d\n", + arvif->vdev_id, arvif->is_started); ieee80211_free_txskb(ar->hw, skb); } @@ -4053,10 +4082,20 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif = info->control.vif; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_key_conf *key = info->control.hw_key; + u32 info_flags = info->flags; bool is_prb_rsp; int ret; - if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { + memset(skb_cb, 0, sizeof(*skb_cb)); + skb_cb->vif = vif; + + if (key) { + skb_cb->cipher = key->cipher; + skb_cb->flags |= ATH11K_SKB_CIPHER_SET; + } + + if (info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { skb_cb->flags |= ATH11K_SKB_HW_80211_ENCAP; } else if (ieee80211_is_mgmt(hdr->frame_control)) { is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control); @@ -4094,7 +4133,8 @@ static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable) if (enable) { tlv_filter = ath11k_mac_mon_status_filter_default; - tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar); + if (ath11k_debugfs_rx_filter(ar)) + tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar); } for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) { @@ -4106,6 +4146,10 @@ static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable) &tlv_filter); } + if (enable && !ar->ab->hw_params.rxdma1_enable) + mod_timer(&ar->ab->mon_reap_timer, jiffies + + msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL)); + return ret; } @@ -4578,8 +4622,22 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, err_peer_del: if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { + reinit_completion(&ar->peer_delete_done); + + ret = ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, + arvif->vdev_id); + if (ret) { + ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", + arvif->vdev_id, vif->addr); + goto err; + } + + ret = ath11k_wait_for_peer_delete_done(ar, arvif->vdev_id, + vif->addr); + if (ret) + goto err; + ar->num_peers--; - ath11k_wmi_send_peer_delete_cmd(ar, vif->addr, arvif->vdev_id); } err_vdev_del: @@ -4614,6 +4672,7 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, struct ath11k *ar = hw->priv; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ath11k_base *ab = ar->ab; + unsigned long time_left; int ret; int i; @@ -4622,10 +4681,6 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, ath11k_dbg(ab, ATH11K_DBG_MAC, "mac remove interface (vdev %d)\n", arvif->vdev_id); - spin_lock_bh(&ar->data_lock); - list_del(&arvif->list); - spin_unlock_bh(&ar->data_lock); - if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { ret = ath11k_peer_delete(ar, arvif->vdev_id, vif->addr); if (ret) @@ -4633,16 +4688,33 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw, arvif->vdev_id, ret); } + reinit_completion(&ar->vdev_delete_done); + ret = ath11k_wmi_vdev_delete(ar, arvif->vdev_id); - if (ret) + if (ret) { ath11k_warn(ab, "failed to delete WMI vdev %d: %d\n", arvif->vdev_id, ret); + goto err_vdev_del; + } + time_left = wait_for_completion_timeout(&ar->vdev_delete_done, + ATH11K_VDEV_DELETE_TIMEOUT_HZ); + if (time_left == 0) { + ath11k_warn(ab, "Timeout in receiving vdev delete response\n"); + goto err_vdev_del; + } + + ab->free_vdev_map |= 1LL << (arvif->vdev_id); + ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); ar->num_created_vdevs--; + ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n", vif->addr, arvif->vdev_id); - ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id); - ab->free_vdev_map |= 1LL << (arvif->vdev_id); + +err_vdev_del: + spin_lock_bh(&ar->data_lock); + list_del(&arvif->list); + spin_unlock_bh(&ar->data_lock); ath11k_peer_cleanup(ar, arvif->vdev_id); @@ -4946,13 +5018,6 @@ static int ath11k_mac_vdev_stop(struct ath11k_vif *arvif) reinit_completion(&ar->vdev_setup_done); - spin_lock_bh(&ar->data_lock); - - ar->vdev_stop_status.stop_in_progress = true; - ar->vdev_stop_status.vdev_id = arvif->vdev_id; - - spin_unlock_bh(&ar->data_lock); - ret = ath11k_wmi_vdev_stop(ar, arvif->vdev_id); if (ret) { ath11k_warn(ar->ab, "failed to stop WMI vdev %i: %d\n", @@ -4981,10 +5046,6 @@ static int ath11k_mac_vdev_stop(struct ath11k_vif *arvif) return 0; err: - spin_lock_bh(&ar->data_lock); - ar->vdev_stop_status.stop_in_progress = false; - spin_unlock_bh(&ar->data_lock); - return ret; } @@ -5225,20 +5286,26 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, arvif->vdev_type != WMI_VDEV_TYPE_AP && arvif->vdev_type != WMI_VDEV_TYPE_MONITOR) { memcpy(&arvif->chanctx, ctx, sizeof(*ctx)); - mutex_unlock(&ar->conf_mutex); - return 0; + ret = 0; + goto out; } if (WARN_ON(arvif->is_started)) { - mutex_unlock(&ar->conf_mutex); - return -EBUSY; + ret = -EBUSY; + goto out; } if (ab->hw_params.vdev_start_delay) { param.vdev_id = arvif->vdev_id; param.peer_type = WMI_PEER_TYPE_DEFAULT; param.peer_addr = ar->mac_addr; + ret = ath11k_peer_create(ar, arvif, NULL, ¶m); + if (ret) { + ath11k_warn(ab, "failed to create peer after vdev start delay: %d", + ret); + goto out; + } } ret = ath11k_mac_vdev_start(arvif, &ctx->def); @@ -5246,23 +5313,21 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n", arvif->vdev_id, vif->addr, ctx->def.chan->center_freq, ret); - goto err; + goto out; } if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) { ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id); if (ret) - goto err; + goto out; } arvif->is_started = true; /* TODO: Setup ps and cts/rts protection */ - mutex_unlock(&ar->conf_mutex); - - return 0; + ret = 0; -err: +out: mutex_unlock(&ar->conf_mutex); return ret; @@ -6258,6 +6323,13 @@ static int __ath11k_mac_register(struct ath11k *ar) ar->hw->wiphy->num_iftype_ext_capab = ARRAY_SIZE(ath11k_iftypes_ext_capa); + if (ar->supports_6ghz) { + wiphy_ext_feature_set(ar->hw->wiphy, + NL80211_EXT_FEATURE_FILS_DISCOVERY); + wiphy_ext_feature_set(ar->hw->wiphy, + NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP); + } + ath11k_reg_init(ar); if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) { @@ -6397,7 +6469,9 @@ int ath11k_mac_allocate(struct ath11k_base *ab) INIT_LIST_HEAD(&ar->ppdu_stats_info); mutex_init(&ar->conf_mutex); init_completion(&ar->vdev_setup_done); + init_completion(&ar->vdev_delete_done); init_completion(&ar->peer_assoc_done); + init_completion(&ar->peer_delete_done); init_completion(&ar->install_key_done); init_completion(&ar->bss_survey_done); init_completion(&ar->scan.started); diff --git a/drivers/net/wireless/ath/ath11k/mac.h b/drivers/net/wireless/ath/ath11k/mac.h index 0607479774a9..597104a9078d 100644 --- a/drivers/net/wireless/ath/ath11k/mac.h +++ b/drivers/net/wireless/ath/ath11k/mac.h @@ -137,8 +137,6 @@ struct ath11k_vif *ath11k_mac_get_arvif_by_vdev_id(struct ath11k_base *ab, u32 vdev_id); struct ath11k *ath11k_mac_get_ar_by_vdev_id(struct ath11k_base *ab, u32 vdev_id); struct ath11k *ath11k_mac_get_ar_by_pdev_id(struct ath11k_base *ab, u32 pdev_id); -struct ath11k *ath11k_mac_get_ar_vdev_stop_status(struct ath11k_base *ab, - u32 vdev_id); void ath11k_mac_drain_tx(struct ath11k *ar); void ath11k_mac_peer_cleanup_all(struct ath11k *ar); diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index aded9a719d51..09858e516903 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -24,7 +24,6 @@ static struct mhi_channel_config ath11k_mhi_channels[] = { .offload_channel = false, .doorbell_mode_switch = false, .auto_queue = false, - .auto_start = false, }, { .num = 1, @@ -39,7 +38,6 @@ static struct mhi_channel_config ath11k_mhi_channels[] = { .offload_channel = false, .doorbell_mode_switch = false, .auto_queue = false, - .auto_start = false, }, { .num = 20, @@ -54,7 +52,6 @@ static struct mhi_channel_config ath11k_mhi_channels[] = { .offload_channel = false, .doorbell_mode_switch = false, .auto_queue = false, - .auto_start = true, }, { .num = 21, @@ -69,7 +66,6 @@ static struct mhi_channel_config ath11k_mhi_channels[] = { .offload_channel = false, .doorbell_mode_switch = false, .auto_queue = true, - .auto_start = true, }, }; @@ -194,6 +190,15 @@ static void ath11k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl) 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); + + switch (cb) { + case MHI_CB_SYS_ERROR: + ath11k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n"); + break; + default: + break; + } } static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl, @@ -218,7 +223,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) struct mhi_controller *mhi_ctrl; int ret; - mhi_ctrl = kzalloc(sizeof(*mhi_ctrl), GFP_KERNEL); + mhi_ctrl = mhi_alloc_controller(); if (!mhi_ctrl) return -ENOMEM; @@ -234,7 +239,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) ret = ath11k_mhi_get_msi(ab_pci); if (ret) { ath11k_err(ab, "failed to get msi for mhi\n"); - kfree(mhi_ctrl); + mhi_free_controller(mhi_ctrl); return ret; } @@ -252,7 +257,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) ret = mhi_register_controller(mhi_ctrl, &ath11k_mhi_config); if (ret) { ath11k_err(ab, "failed to register to mhi bus, err = %d\n", ret); - kfree(mhi_ctrl); + mhi_free_controller(mhi_ctrl); return ret; } @@ -265,6 +270,7 @@ void ath11k_mhi_unregister(struct ath11k_pci *ab_pci) mhi_unregister_controller(mhi_ctrl); kfree(mhi_ctrl->irq); + mhi_free_controller(mhi_ctrl); } static char *ath11k_mhi_state_to_str(enum ath11k_mhi_state mhi_state) @@ -413,8 +419,10 @@ static int ath11k_mhi_set_state(struct ath11k_pci *ab_pci, ret = 0; break; case ATH11K_MHI_SUSPEND: + ret = mhi_pm_suspend(ab_pci->mhi_ctrl); break; case ATH11K_MHI_RESUME: + ret = mhi_pm_resume(ab_pci->mhi_ctrl); break; case ATH11K_MHI_TRIGGER_RDDM: ret = mhi_force_rddm_mode(ab_pci->mhi_ctrl); @@ -465,3 +473,12 @@ void ath11k_mhi_stop(struct ath11k_pci *ab_pci) ath11k_mhi_set_state(ab_pci, ATH11K_MHI_DEINIT); } +void ath11k_mhi_suspend(struct ath11k_pci *ab_pci) +{ + ath11k_mhi_set_state(ab_pci, ATH11K_MHI_SUSPEND); +} + +void ath11k_mhi_resume(struct ath11k_pci *ab_pci) +{ + ath11k_mhi_set_state(ab_pci, ATH11K_MHI_RESUME); +} diff --git a/drivers/net/wireless/ath/ath11k/mhi.h b/drivers/net/wireless/ath/ath11k/mhi.h index a7fd5e201d18..488dada5d31c 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.h +++ b/drivers/net/wireless/ath/ath11k/mhi.h @@ -36,4 +36,7 @@ void ath11k_mhi_unregister(struct ath11k_pci *ar_pci); void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab); void ath11k_mhi_clear_vector(struct ath11k_base *ab); +void ath11k_mhi_suspend(struct ath11k_pci *ar_pci); +void ath11k_mhi_resume(struct ath11k_pci *ar_pci); + #endif diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index d7eb6b7160bb..857647aa57c8 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -126,6 +126,7 @@ static inline void ath11k_pci_select_window(struct ath11k_pci *ab_pci, u32 offse if (window != ab_pci->register_window) { iowrite32(WINDOW_ENABLE_BIT | window, ab->mem + WINDOW_REG_ADDRESS); + ioread32(ab->mem + WINDOW_REG_ADDRESS); ab_pci->register_window = window; } } @@ -239,15 +240,137 @@ static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) ath11k_dbg(ab, ATH11K_DBG_PCI, "soc reset cause:%d\n", val); } +static int ath11k_pci_set_link_reg(struct ath11k_base *ab, + u32 offset, u32 value, u32 mask) +{ + u32 v; + int i; + + v = ath11k_pci_read32(ab, offset); + if ((v & mask) == value) + return 0; + + for (i = 0; i < 10; i++) { + ath11k_pci_write32(ab, offset, (v & ~mask) | value); + + v = ath11k_pci_read32(ab, offset); + if ((v & mask) == value) + return 0; + + mdelay(2); + } + + ath11k_warn(ab, "failed to set pcie link register 0x%08x: 0x%08x != 0x%08x\n", + offset, v & mask, value); + + return -ETIMEDOUT; +} + +static int ath11k_pci_fix_l1ss(struct ath11k_base *ab) +{ + int ret; + + ret = ath11k_pci_set_link_reg(ab, + PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG, + PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL, + PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK); + if (!ret) { + ath11k_warn(ab, "failed to set sysclk: %d\n", ret); + return ret; + } + + ret = ath11k_pci_set_link_reg(ab, + PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_REG, + PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_VAL, + PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK); + if (!ret) { + ath11k_warn(ab, "failed to set dtct config1 error: %d\n", ret); + return ret; + } + + ret = ath11k_pci_set_link_reg(ab, + PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_REG, + PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_VAL, + PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK); + if (!ret) { + ath11k_warn(ab, "failed to set dtct config2: %d\n", ret); + return ret; + } + + ret = ath11k_pci_set_link_reg(ab, + PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_REG, + PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_VAL, + PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK); + if (!ret) { + ath11k_warn(ab, "failed to set dtct config4: %d\n", ret); + return ret; + } + + return 0; +} + +static void ath11k_pci_enable_ltssm(struct ath11k_base *ab) +{ + u32 val; + int i; + + val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); + + /* PCIE link seems very unstable after the Hot Reset*/ + for (i = 0; val != PARM_LTSSM_VALUE && i < 5; i++) { + if (val == 0xffffffff) + mdelay(5); + + ath11k_pci_write32(ab, PCIE_PCIE_PARF_LTSSM, PARM_LTSSM_VALUE); + val = ath11k_pci_read32(ab, PCIE_PCIE_PARF_LTSSM); + } + + ath11k_dbg(ab, ATH11K_DBG_PCI, "pci ltssm 0x%x\n", val); + + val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); + val |= GCC_GCC_PCIE_HOT_RST_VAL | 0x10; + ath11k_pci_write32(ab, GCC_GCC_PCIE_HOT_RST, val); + val = ath11k_pci_read32(ab, GCC_GCC_PCIE_HOT_RST); + + ath11k_dbg(ab, ATH11K_DBG_PCI, "pci pcie_hot_rst 0x%x\n", val); + + mdelay(5); +} + +static void ath11k_pci_clear_all_intrs(struct ath11k_base *ab) +{ + /* This is a WAR for PCIE Hotreset. + * When target receive Hotreset, but will set the interrupt. + * So when download SBL again, SBL will open Interrupt and + * receive it, and crash immediately. + */ + ath11k_pci_write32(ab, PCIE_PCIE_INT_ALL_CLEAR, PCIE_INT_CLEAR_ALL); +} + +static void ath11k_pci_set_wlaon_pwr_ctrl(struct ath11k_base *ab) +{ + u32 val; + + val = ath11k_pci_read32(ab, WLAON_QFPROM_PWR_CTRL_REG); + val &= ~QFPROM_PWR_CTRL_VDD4BLOW_MASK; + ath11k_pci_write32(ab, WLAON_QFPROM_PWR_CTRL_REG, val); +} + static void ath11k_pci_force_wake(struct ath11k_base *ab) { ath11k_pci_write32(ab, PCIE_SOC_WAKE_PCIE_LOCAL_REG, 1); mdelay(5); } -static void ath11k_pci_sw_reset(struct ath11k_base *ab) +static void ath11k_pci_sw_reset(struct ath11k_base *ab, bool power_on) { - ath11k_pci_soc_global_reset(ab); + if (power_on) { + ath11k_pci_enable_ltssm(ab); + ath11k_pci_clear_all_intrs(ab); + ath11k_pci_set_wlaon_pwr_ctrl(ab); + ath11k_pci_fix_l1ss(ab); + } + ath11k_mhi_clear_vector(ab); ath11k_pci_soc_global_reset(ab); ath11k_mhi_set_mhictrl_reset(ab); @@ -264,13 +387,18 @@ int ath11k_pci_get_msi_irq(struct device *dev, unsigned int vector) static void ath11k_pci_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, u32 *msi_addr_hi) { + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); struct pci_dev *pci_dev = to_pci_dev(ab->dev); pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_LO, msi_addr_lo); - pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, - msi_addr_hi); + if (test_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags)) { + pci_read_config_dword(pci_dev, pci_dev->msi_cap + PCI_MSI_ADDRESS_HI, + msi_addr_hi); + } else { + *msi_addr_hi = 0; + } } int ath11k_pci_get_user_msi_assignment(struct ath11k_pci *ab_pci, char *user_name, @@ -380,9 +508,9 @@ static void ath11k_pci_sync_ce_irqs(struct ath11k_base *ab) } } -static void ath11k_pci_ce_tasklet(unsigned long data) +static void ath11k_pci_ce_tasklet(struct tasklet_struct *t) { - struct ath11k_ce_pipe *ce_pipe = (struct ath11k_ce_pipe *)data; + struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); @@ -581,8 +709,7 @@ static int ath11k_pci_config_irq(struct ath11k_base *ab) irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; - tasklet_init(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet, - (unsigned long)ce_pipe); + tasklet_setup(&ce_pipe->intr_tq, ath11k_pci_ce_tasklet); ret = request_irq(irq, ath11k_pci_ce_interrupt_handler, IRQF_SHARED, irq_name[irq_idx], @@ -659,6 +786,8 @@ static int ath11k_pci_enable_msi(struct ath11k_pci *ab_pci) } ab_pci->msi_ep_base_data = msi_desc->msg.data; + if (msi_desc->msi_attrib.is_64) + set_bit(ATH11K_PCI_FLAG_IS_MSI_64, &ab_pci->flags); ath11k_dbg(ab, ATH11K_DBG_PCI, "msi base data is %d\n", ab_pci->msi_ep_base_data); @@ -764,7 +893,7 @@ static int ath11k_pci_power_up(struct ath11k_base *ab) ab_pci->register_window = 0; clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); - ath11k_pci_sw_reset(ab_pci->ab); + ath11k_pci_sw_reset(ab_pci->ab, true); ret = ath11k_mhi_start(ab_pci); if (ret) { @@ -779,10 +908,28 @@ static void ath11k_pci_power_down(struct ath11k_base *ab) { struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + ath11k_pci_force_wake(ab_pci->ab); ath11k_mhi_stop(ab_pci); clear_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags); - ath11k_pci_force_wake(ab_pci->ab); - ath11k_pci_sw_reset(ab_pci->ab); + ath11k_pci_sw_reset(ab_pci->ab, false); +} + +static int ath11k_pci_hif_suspend(struct ath11k_base *ab) +{ + struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); + + ath11k_mhi_suspend(ar_pci); + + return 0; +} + +static int ath11k_pci_hif_resume(struct ath11k_base *ab) +{ + struct ath11k_pci *ar_pci = ath11k_pci_priv(ab); + + ath11k_mhi_resume(ar_pci); + + return 0; } static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) @@ -799,11 +946,16 @@ static void ath11k_pci_kill_tasklets(struct ath11k_base *ab) } } -static void ath11k_pci_stop(struct ath11k_base *ab) +static void ath11k_pci_ce_irq_disable_sync(struct ath11k_base *ab) { ath11k_pci_ce_irqs_disable(ab); ath11k_pci_sync_ce_irqs(ab); ath11k_pci_kill_tasklets(ab); +} + +static void ath11k_pci_stop(struct ath11k_base *ab) +{ + ath11k_pci_ce_irq_disable_sync(ab); ath11k_ce_cleanup_pipes(ab); } @@ -819,6 +971,16 @@ static int ath11k_pci_start(struct ath11k_base *ab) return 0; } +static void ath11k_pci_hif_ce_irq_enable(struct ath11k_base *ab) +{ + ath11k_pci_ce_irqs_enable(ab); +} + +static void ath11k_pci_hif_ce_irq_disable(struct ath11k_base *ab) +{ + ath11k_pci_ce_irq_disable_sync(ab); +} + static int ath11k_pci_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, u8 *ul_pipe, u8 *dl_pipe) { @@ -869,11 +1031,15 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = { .write32 = ath11k_pci_write32, .power_down = ath11k_pci_power_down, .power_up = ath11k_pci_power_up, + .suspend = ath11k_pci_hif_suspend, + .resume = ath11k_pci_hif_resume, .irq_enable = ath11k_pci_ext_irq_enable, .irq_disable = ath11k_pci_ext_irq_disable, .get_msi_address = ath11k_pci_get_msi_address, .get_user_msi_vector = ath11k_get_user_msi_assignment, .map_service_to_pipe = ath11k_pci_map_service_to_pipe, + .ce_irq_enable = ath11k_pci_hif_ce_irq_enable, + .ce_irq_disable = ath11k_pci_hif_ce_irq_disable, }; static int ath11k_pci_probe(struct pci_dev *pdev, @@ -1008,10 +1174,18 @@ static void ath11k_pci_remove(struct pci_dev *pdev) struct ath11k_base *ab = pci_get_drvdata(pdev); struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) { + ath11k_pci_power_down(ab); + ath11k_debugfs_soc_destroy(ab); + ath11k_qmi_deinit_service(ab); + goto qmi_fail; + } + set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags); ath11k_core_deinit(ab); +qmi_fail: ath11k_mhi_unregister(ab_pci); ath11k_pci_free_irq(ab); @@ -1030,12 +1204,43 @@ static void ath11k_pci_shutdown(struct pci_dev *pdev) ath11k_pci_power_down(ab); } +static __maybe_unused int ath11k_pci_pm_suspend(struct device *dev) +{ + struct ath11k_base *ab = dev_get_drvdata(dev); + int ret; + + ret = ath11k_core_suspend(ab); + if (ret) + ath11k_warn(ab, "failed to suspend core: %d\n", ret); + + return ret; +} + +static __maybe_unused int ath11k_pci_pm_resume(struct device *dev) +{ + struct ath11k_base *ab = dev_get_drvdata(dev); + int ret; + + ret = ath11k_core_resume(ab); + if (ret) + ath11k_warn(ab, "failed to resume core: %d\n", ret); + + return ret; +} + +static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops, + ath11k_pci_pm_suspend, + ath11k_pci_pm_resume); + static struct pci_driver ath11k_pci_driver = { .name = "ath11k_pci", .id_table = ath11k_pci_id_table, .probe = ath11k_pci_probe, .remove = ath11k_pci_remove, .shutdown = ath11k_pci_shutdown, +#ifdef CONFIG_PM + .driver.pm = &ath11k_pci_pm_ops, +#endif }; static int ath11k_pci_init(void) @@ -1060,3 +1265,8 @@ module_exit(ath11k_pci_exit); MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices"); MODULE_LICENSE("Dual BSD/GPL"); + +/* QCA639x 2.0 firmware files */ +MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_BOARD_API2_FILE); +MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_AMSS_FILE); +MODULE_FIRMWARE(ATH11K_FW_DIR "/QCA6390/hw2.0/" ATH11K_M3_FILE); diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h index 43562f774a37..0432a702416b 100644 --- a/drivers/net/wireless/ath/ath11k/pci.h +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -24,6 +24,30 @@ /* register used for handshake mechanism to validate UMAC is awake */ #define PCIE_SOC_WAKE_PCIE_LOCAL_REG 0x3004 +#define PCIE_PCIE_PARF_LTSSM 0x1e081b0 +#define PARM_LTSSM_VALUE 0x111 + +#define GCC_GCC_PCIE_HOT_RST 0x1e402bc +#define GCC_GCC_PCIE_HOT_RST_VAL 0x10 + +#define PCIE_PCIE_INT_ALL_CLEAR 0x1e08228 +#define PCIE_SMLH_REQ_RST_LINK_DOWN 0x2 +#define PCIE_INT_CLEAR_ALL 0xffffffff + +#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG 0x01e0c0ac +#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL 0x10 +#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK 0xffffffff +#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_REG 0x01e0c628 +#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG1_VAL 0x02 +#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_REG 0x01e0c62c +#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG2_VAL 0x52 +#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_REG 0x01e0c634 +#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG4_VAL 0xff +#define PCIE_USB3_PCS_MISC_OSC_DTCT_CONFIG_MSK 0x000000ff + +#define WLAON_QFPROM_PWR_CTRL_REG 0x01f8031c +#define QFPROM_PWR_CTRL_VDD4BLOW_MASK 0x4 + struct ath11k_msi_user { char *name; int num_vectors; @@ -38,6 +62,7 @@ struct ath11k_msi_config { enum ath11k_pci_flags { ATH11K_PCI_FLAG_INIT_DONE, + ATH11K_PCI_FLAG_IS_MSI_64, }; struct ath11k_pci { diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c index 61ad9300eafb..1866d82678fa 100644 --- a/drivers/net/wireless/ath/ath11k/peer.c +++ b/drivers/net/wireless/ath/ath11k/peer.c @@ -177,12 +177,36 @@ static int ath11k_wait_for_peer_deleted(struct ath11k *ar, int vdev_id, const u8 return ath11k_wait_for_peer_common(ar->ab, vdev_id, addr, false); } +int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id, + const u8 *addr) +{ + int ret; + unsigned long time_left; + + ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr); + if (ret) { + ath11k_warn(ar->ab, "failed wait for peer deleted"); + return ret; + } + + time_left = wait_for_completion_timeout(&ar->peer_delete_done, + 3 * HZ); + if (time_left == 0) { + ath11k_warn(ar->ab, "Timeout in receiving peer delete response\n"); + return -ETIMEDOUT; + } + + return 0; +} + int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr) { int ret; lockdep_assert_held(&ar->conf_mutex); + reinit_completion(&ar->peer_delete_done); + ret = ath11k_wmi_send_peer_delete_cmd(ar, addr, vdev_id); if (ret) { ath11k_warn(ar->ab, @@ -191,7 +215,7 @@ int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr) return ret; } - ret = ath11k_wait_for_peer_deleted(ar, vdev_id, addr); + ret = ath11k_wait_for_peer_delete_done(ar, vdev_id, addr); if (ret) return ret; @@ -247,8 +271,22 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif, spin_unlock_bh(&ar->ab->base_lock); ath11k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n", param->peer_addr, param->vdev_id); - ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr, - param->vdev_id); + + reinit_completion(&ar->peer_delete_done); + + ret = ath11k_wmi_send_peer_delete_cmd(ar, param->peer_addr, + param->vdev_id); + if (ret) { + ath11k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n", + param->vdev_id, param->peer_addr); + return ret; + } + + ret = ath11k_wait_for_peer_delete_done(ar, param->vdev_id, + param->peer_addr); + if (ret) + return ret; + return -ENOENT; } diff --git a/drivers/net/wireless/ath/ath11k/peer.h b/drivers/net/wireless/ath/ath11k/peer.h index 5d125ce8984e..bba2e00b6944 100644 --- a/drivers/net/wireless/ath/ath11k/peer.h +++ b/drivers/net/wireless/ath/ath11k/peer.h @@ -41,5 +41,7 @@ void ath11k_peer_cleanup(struct ath11k *ar, u32 vdev_id); int ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, u8 *addr); int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif, struct ieee80211_sta *sta, struct peer_create_params *param); +int ath11k_wait_for_peer_delete_done(struct ath11k *ar, u32 vdev_id, + const u8 *addr); #endif /* _PEER_H_ */ diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index c2b165158225..f0b5c50974f3 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -14,6 +14,12 @@ #define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02 #define HOST_CSTATE_BIT 0x04 +bool ath11k_cold_boot_cal = 1; +EXPORT_SYMBOL(ath11k_cold_boot_cal); +module_param_named(cold_boot_cal, ath11k_cold_boot_cal, bool, 0644); +MODULE_PARM_DESC(cold_boot_cal, + "Decrease the channel switch time but increase the driver load time (Default: true)"); + static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, @@ -1585,15 +1591,17 @@ static int ath11k_qmi_fw_ind_register_send(struct ath11k_base *ab) struct qmi_wlanfw_ind_register_resp_msg_v01 *resp; struct qmi_handle *handle = &ab->qmi.handle; struct qmi_txn txn; - int ret = 0; + int ret; req = kzalloc(sizeof(*req), GFP_KERNEL); if (!req) return -ENOMEM; resp = kzalloc(sizeof(*resp), GFP_KERNEL); - if (!resp) + if (!resp) { + ret = -ENOMEM; goto resp_out; + } req->client_id_valid = 1; req->client_id = QMI_WLANFW_CLIENT_ID; @@ -1769,9 +1777,16 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) ath11k_warn(ab, "qmi mem size is low to load caldata\n"); return -EINVAL; } - /* TODO ath11k does not support cold boot calibration */ - ab->qmi.target_mem[idx].paddr = 0; - ab->qmi.target_mem[idx].vaddr = NULL; + + if (ath11k_cold_boot_cal && ab->hw_params.cold_boot_calib) { + ab->qmi.target_mem[idx].paddr = + ATH11K_QMI_CALDB_ADDRESS; + ab->qmi.target_mem[idx].vaddr = + (void *)ATH11K_QMI_CALDB_ADDRESS; + } else { + ab->qmi.target_mem[idx].paddr = 0; + ab->qmi.target_mem[idx].vaddr = NULL; + } ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; idx++; @@ -1793,6 +1808,7 @@ static int ath11k_qmi_request_target_cap(struct ath11k_base *ab) struct qmi_wlanfw_cap_resp_msg_v01 resp; struct qmi_txn txn = {}; int ret = 0; + int r; memset(&req, 0, sizeof(req)); memset(&resp, 0, sizeof(resp)); @@ -1858,6 +1874,10 @@ static int ath11k_qmi_request_target_cap(struct ath11k_base *ab) ab->qmi.target.fw_build_timestamp, ab->qmi.target.fw_build_id); + r = ath11k_core_check_dt(ab); + if (r) + ath11k_dbg(ab, ATH11K_DBG_QMI, "DT bdf variant name not set.\n"); + out: return ret; } @@ -2352,6 +2372,32 @@ int ath11k_qmi_firmware_start(struct ath11k_base *ab, return 0; } +static int ath11k_qmi_process_coldboot_calibration(struct ath11k_base *ab) +{ + int timeout; + int ret; + + ret = ath11k_qmi_wlanfw_mode_send(ab, ATH11K_FIRMWARE_MODE_COLD_BOOT); + if (ret < 0) { + ath11k_warn(ab, "qmi failed to send wlan fw mode:%d\n", ret); + return ret; + } + + ath11k_dbg(ab, ATH11K_DBG_QMI, "Coldboot calibration wait started\n"); + + timeout = wait_event_timeout(ab->qmi.cold_boot_waitq, + (ab->qmi.cal_done == 1), + ATH11K_COLD_BOOT_FW_RESET_DELAY); + if (timeout <= 0) { + ath11k_warn(ab, "Coldboot Calibration failed - wait ended\n"); + return 0; + } + + ath11k_dbg(ab, ATH11K_DBG_QMI, "Coldboot calibration done\n"); + + return 0; +} + static int ath11k_qmi_driver_event_post(struct ath11k_qmi *qmi, enum ath11k_qmi_event_type type, @@ -2375,7 +2421,7 @@ ath11k_qmi_driver_event_post(struct ath11k_qmi *qmi, return 0; } -static void ath11k_qmi_event_server_arrive(struct ath11k_qmi *qmi) +static int ath11k_qmi_event_server_arrive(struct ath11k_qmi *qmi) { struct ath11k_base *ab = qmi->ab; int ret; @@ -2383,17 +2429,19 @@ static void ath11k_qmi_event_server_arrive(struct ath11k_qmi *qmi) ret = ath11k_qmi_fw_ind_register_send(ab); if (ret < 0) { ath11k_warn(ab, "qmi failed to send FW indication QMI:%d\n", ret); - return; + return ret; } ret = ath11k_qmi_host_cap_send(ab); if (ret < 0) { ath11k_warn(ab, "qmi failed to send host cap QMI:%d\n", ret); - return; + return ret; } + + return ret; } -static void ath11k_qmi_event_mem_request(struct ath11k_qmi *qmi) +static int ath11k_qmi_event_mem_request(struct ath11k_qmi *qmi) { struct ath11k_base *ab = qmi->ab; int ret; @@ -2401,11 +2449,13 @@ static void ath11k_qmi_event_mem_request(struct ath11k_qmi *qmi) ret = ath11k_qmi_respond_fw_mem_request(ab); if (ret < 0) { ath11k_warn(ab, "qmi failed to respond fw mem req:%d\n", ret); - return; + return ret; } + + return ret; } -static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi) +static int ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi) { struct ath11k_base *ab = qmi->ab; int ret; @@ -2413,7 +2463,7 @@ static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi) ret = ath11k_qmi_request_target_cap(ab); if (ret < 0) { ath11k_warn(ab, "qmi failed to req target capabilities:%d\n", ret); - return; + return ret; } if (ab->bus_params.fixed_bdf_addr) @@ -2422,14 +2472,16 @@ static void ath11k_qmi_event_load_bdf(struct ath11k_qmi *qmi) ret = ath11k_qmi_load_bdf_qmi(ab); if (ret < 0) { ath11k_warn(ab, "qmi failed to load board data file:%d\n", ret); - return; + return ret; } ret = ath11k_qmi_wlanfw_m3_info_send(ab); if (ret < 0) { ath11k_warn(ab, "qmi failed to send m3 info req:%d\n", ret); - return; + return ret; } + + return ret; } static void ath11k_qmi_msg_mem_request_cb(struct qmi_handle *qmi_hdl, @@ -2501,11 +2553,18 @@ static void ath11k_qmi_msg_fw_ready_cb(struct qmi_handle *qmi_hdl, ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_FW_READY, NULL); } -static void ath11k_qmi_msg_cold_boot_cal_done_cb(struct qmi_handle *qmi, +static void ath11k_qmi_msg_cold_boot_cal_done_cb(struct qmi_handle *qmi_hdl, struct sockaddr_qrtr *sq, struct qmi_txn *txn, const void *decoded) { + struct ath11k_qmi *qmi = container_of(qmi_hdl, + struct ath11k_qmi, handle); + struct ath11k_base *ab = qmi->ab; + + ab->qmi.cal_done = 1; + wake_up(&ab->qmi.cold_boot_waitq); + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi cold boot calibration done\n"); } static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = { @@ -2562,7 +2621,7 @@ static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl, ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi wifi fw qmi service connected\n"); ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_SERVER_ARRIVE, NULL); - return 0; + return ret; } static void ath11k_qmi_ops_del_server(struct qmi_handle *qmi_hdl, @@ -2586,6 +2645,7 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work) event_work); struct ath11k_qmi_driver_event *event; struct ath11k_base *ab = qmi->ab; + int ret; spin_lock(&qmi->event_lock); while (!list_empty(&qmi->event_list)) { @@ -2599,28 +2659,42 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work) switch (event->type) { case ATH11K_QMI_EVENT_SERVER_ARRIVE: - ath11k_qmi_event_server_arrive(qmi); + ret = ath11k_qmi_event_server_arrive(qmi); + if (ret < 0) + set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags); break; case ATH11K_QMI_EVENT_SERVER_EXIT: set_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags); set_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags); break; case ATH11K_QMI_EVENT_REQUEST_MEM: - ath11k_qmi_event_mem_request(qmi); + ret = ath11k_qmi_event_mem_request(qmi); + if (ret < 0) + set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags); break; case ATH11K_QMI_EVENT_FW_MEM_READY: - ath11k_qmi_event_load_bdf(qmi); + ret = ath11k_qmi_event_load_bdf(qmi); + if (ret < 0) + set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags); break; case ATH11K_QMI_EVENT_FW_READY: + clear_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags); if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) { ath11k_hal_dump_srng_stats(ab); queue_work(ab->workqueue, &ab->restart_work); break; } - ath11k_core_qmi_firmware_ready(ab); - ab->qmi.cal_done = 1; - set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags); + if (ath11k_cold_boot_cal && ab->qmi.cal_done == 0 && + ab->hw_params.cold_boot_calib) { + ath11k_qmi_process_coldboot_calibration(ab); + } else { + clear_bit(ATH11K_FLAG_CRASH_FLUSH, + &ab->dev_flags); + clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags); + ath11k_core_qmi_firmware_ready(ab); + set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags); + } break; case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE: @@ -2682,4 +2756,5 @@ void ath11k_qmi_deinit_service(struct ath11k_base *ab) ath11k_qmi_m3_free(ab); ath11k_qmi_free_target_mem_chunk(ab); } +EXPORT_SYMBOL(ath11k_qmi_deinit_service); diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index b0a818f0401b..92925c9eac67 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -12,6 +12,7 @@ #define ATH11K_HOST_VERSION_STRING "WIN" #define ATH11K_QMI_WLANFW_TIMEOUT_MS 5000 #define ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE 64 +#define ATH11K_QMI_CALDB_ADDRESS 0x4BA00000 #define ATH11K_QMI_BDF_MAX_SIZE (256 * 1024) #define ATH11K_QMI_CALDATA_OFFSET (128 * 1024) #define ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128 @@ -24,6 +25,7 @@ #define ATH11K_QMI_RESP_LEN_MAX 8192 #define ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01 32 #define ATH11K_QMI_CALDB_SIZE 0x480000 +#define ATH11K_QMI_BDF_EXT_STR_LENGTH 0x20 #define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035 #define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037 @@ -33,6 +35,7 @@ #define QMI_WLANFW_MAX_DATA_SIZE_V01 6144 #define ATH11K_FIRMWARE_MODE_OFF 4 #define ATH11K_QMI_TARGET_MEM_MODE_DEFAULT 0 +#define ATH11K_COLD_BOOT_FW_RESET_DELAY (40 * HZ) struct ath11k_base; @@ -101,6 +104,7 @@ struct target_info { u32 fw_version; char fw_build_timestamp[ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01 + 1]; char fw_build_id[ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 + 1]; + char bdf_ext[ATH11K_QMI_BDF_EXT_STR_LENGTH]; }; struct m3_mem_region { @@ -125,6 +129,7 @@ struct ath11k_qmi { struct target_info target; struct m3_mem_region m3_mem; unsigned int service_ins_id; + wait_queue_head_t cold_boot_waitq; }; #define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 189 diff --git a/drivers/net/wireless/ath/ath11k/reg.c b/drivers/net/wireless/ath/ath11k/reg.c index f6a1f0352989..b876fec7fa1b 100644 --- a/drivers/net/wireless/ath/ath11k/reg.c +++ b/drivers/net/wireless/ath/ath11k/reg.c @@ -80,6 +80,7 @@ ath11k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) */ init_country_param.flags = ALPHA_IS_SET; memcpy(&init_country_param.cc_info.alpha2, request->alpha2, 2); + init_country_param.cc_info.alpha2[2] = 0; ret = ath11k_wmi_send_init_country_cmd(ar, init_country_param); if (ret) @@ -277,6 +278,7 @@ ath11k_map_fw_dfs_region(enum ath11k_dfs_region dfs_region) case ATH11K_DFS_REG_KR: return NL80211_DFS_ETSI; case ATH11K_DFS_REG_MKK: + case ATH11K_DFS_REG_MKK_N: return NL80211_DFS_JP; default: return NL80211_DFS_UNSET; @@ -584,7 +586,6 @@ ath11k_reg_build_regd(struct ath11k_base *ab, if (!tmp_regd) goto ret; - tmp_regd->n_reg_rules = num_rules; memcpy(tmp_regd->alpha2, reg_info->alpha2, REG_ALPHA2_LEN + 1); memcpy(alpha2, reg_info->alpha2, REG_ALPHA2_LEN + 1); alpha2[2] = '\0'; @@ -597,7 +598,7 @@ ath11k_reg_build_regd(struct ath11k_base *ab, /* Update reg_rules[] below. Firmware is expected to * send these rules in order(2G rules first and then 5G) */ - for (; i < tmp_regd->n_reg_rules; i++) { + for (; i < num_rules; i++) { if (reg_info->num_2g_reg_rules && (i < reg_info->num_2g_reg_rules)) { reg_rule = reg_info->reg_rules_2g_ptr + i; @@ -652,6 +653,8 @@ ath11k_reg_build_regd(struct ath11k_base *ab, flags); } + tmp_regd->n_reg_rules = i; + if (intersect) { default_regd = ab->default_regd[reg_info->phy_id]; diff --git a/drivers/net/wireless/ath/ath11k/reg.h b/drivers/net/wireless/ath/ath11k/reg.h index 39b7fc943541..65d56d44796f 100644 --- a/drivers/net/wireless/ath/ath11k/reg.h +++ b/drivers/net/wireless/ath/ath11k/reg.h @@ -20,6 +20,7 @@ enum ath11k_dfs_region { ATH11K_DFS_REG_MKK, ATH11K_DFS_REG_CN, ATH11K_DFS_REG_KR, + ATH11K_DFS_REG_MKK_N, ATH11K_DFS_REG_UNDEF, }; diff --git a/drivers/net/wireless/ath/ath11k/rx_desc.h b/drivers/net/wireless/ath/ath11k/rx_desc.h index 1c4264637a41..86494da1069a 100644 --- a/drivers/net/wireless/ath/ath11k/rx_desc.h +++ b/drivers/net/wireless/ath/ath11k/rx_desc.h @@ -170,7 +170,7 @@ struct rx_attention { * * ast_index_not_found * Only valid when first_msdu is set. Indicates no AST matching - * entries within the the max search count. + * entries within the max search count. * * ast_index_timeout * Only valid when first_msdu is set. Indicates an unsuccessful diff --git a/drivers/net/wireless/ath/ath11k/testmode.c b/drivers/net/wireless/ath/ath11k/testmode.c index d2dc9db01491..4bf1931adbaa 100644 --- a/drivers/net/wireless/ath/ath11k/testmode.c +++ b/drivers/net/wireless/ath/ath11k/testmode.c @@ -51,7 +51,7 @@ bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, struct sk_buff *skb) ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI); if (ret) { ath11k_warn(ar->ab, - "failed to to put testmode wmi event cmd attribute: %d\n", + "failed to put testmode wmi event cmd attribute: %d\n", ret); kfree_skb(nl_skb); goto out; @@ -60,7 +60,7 @@ bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, struct sk_buff *skb) ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id); if (ret) { ath11k_warn(ar->ab, - "failed to to put testmode wmi even cmd_id: %d\n", + "failed to put testmode wmi even cmd_id: %d\n", ret); kfree_skb(nl_skb); goto out; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 8eca92520837..da4b546b62cb 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -122,6 +122,12 @@ static const struct wmi_tlv_policy wmi_tlv_policies[] = { = { .min_len = sizeof(struct wmi_stats_event) }, [WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT] = { .min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) }, + [WMI_TAG_HOST_SWFDA_EVENT] = { + .min_len = sizeof(struct wmi_fils_discovery_event) }, + [WMI_TAG_OFFLOAD_PRB_RSP_TX_STATUS_EVENT] = { + .min_len = sizeof(struct wmi_probe_resp_tx_status_event) }, + [WMI_TAG_VDEV_DELETE_RESP_EVENT] = { + .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, }; #define PRIMAP(_hw_mode_) \ @@ -362,7 +368,7 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle, * For example, for 4x4 capable macphys, first 4 chains can be used for first * mac and the remaing 4 chains can be used for the second mac or vice-versa. * In this case, tx/rx chainmask 0xf will be advertised for first mac and 0xf0 - * will be advertised for second mac or vice-versa. Compute the shift value for + * will be advertised for second mac or vice-versa. Compute the shift value * for tx/rx chainmask which will be used to advertise supported ht/vht rates to * mac80211. */ @@ -1682,7 +1688,8 @@ int ath11k_wmi_vdev_install_key(struct ath11k *ar, static inline void ath11k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, - struct peer_assoc_params *param) + struct peer_assoc_params *param, + bool hw_crypto_disabled) { cmd->peer_flags = 0; @@ -1736,7 +1743,8 @@ ath11k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, cmd->peer_flags |= WMI_PEER_AUTH; if (param->need_ptk_4_way) { cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; - cmd->peer_flags &= ~WMI_PEER_AUTH; + if (!hw_crypto_disabled) + cmd->peer_flags &= ~WMI_PEER_AUTH; } if (param->need_gtk_2_way) cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY; @@ -1803,7 +1811,9 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, cmd->peer_new_assoc = param->peer_new_assoc; cmd->peer_associd = param->peer_associd; - ath11k_wmi_copy_peer_flags(cmd, param); + ath11k_wmi_copy_peer_flags(cmd, param, + test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, + &ar->ab->dev_flags)); ether_addr_copy(cmd->peer_macaddr.addr, param->peer_mac); @@ -1946,6 +1956,11 @@ void ath11k_wmi_start_scan_init(struct ath11k *ar, WMI_SCAN_EVENT_DEQUEUED; arg->scan_flags |= WMI_SCAN_CHAN_STAT_EVENT; arg->num_bssid = 1; + + /* fill bssid_list[0] with 0xff, otherwise bssid and RA will be + * ZEROs in probe request + */ + eth_broadcast_addr(arg->bssid_list[0].addr); } static inline void @@ -2198,37 +2213,6 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, } } - len = params->num_hint_s_ssid * sizeof(struct hint_short_ssid); - tlv = ptr; - tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) | - FIELD_PREP(WMI_TLV_LEN, len); - ptr += TLV_HDR_SIZE; - if (params->num_hint_s_ssid) { - s_ssid = ptr; - for (i = 0; i < params->num_hint_s_ssid; ++i) { - s_ssid->freq_flags = params->hint_s_ssid[i].freq_flags; - s_ssid->short_ssid = params->hint_s_ssid[i].short_ssid; - s_ssid++; - } - } - ptr += len; - - len = params->num_hint_bssid * sizeof(struct hint_bssid); - tlv = ptr; - tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) | - FIELD_PREP(WMI_TLV_LEN, len); - ptr += TLV_HDR_SIZE; - if (params->num_hint_bssid) { - hint_bssid = ptr; - for (i = 0; i < params->num_hint_bssid; ++i) { - hint_bssid->freq_flags = - params->hint_bssid[i].freq_flags; - ether_addr_copy(¶ms->hint_bssid[i].bssid.addr[0], - &hint_bssid->bssid.addr[0]); - hint_bssid++; - } - } - ret = ath11k_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID); if (ret) { @@ -3064,6 +3048,137 @@ int ath11k_wmi_send_bss_color_change_enable_cmd(struct ath11k *ar, u32 vdev_id, return ret; } +int ath11k_wmi_fils_discovery_tmpl(struct ath11k *ar, u32 vdev_id, + struct sk_buff *tmpl) +{ + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + int ret, len; + size_t aligned_len; + struct wmi_fils_discovery_tmpl_cmd *cmd; + + aligned_len = roundup(tmpl->len, 4); + len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI vdev %i set FILS discovery template\n", vdev_id); + + skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_fils_discovery_tmpl_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_FILS_DISCOVERY_TMPL_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; + cmd->buf_len = tmpl->len; + ptr = skb->data + sizeof(*cmd); + + tlv = ptr; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | + FIELD_PREP(WMI_TLV_LEN, aligned_len); + memcpy(tlv->value, tmpl->data, tmpl->len); + + ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_FILS_DISCOVERY_TMPL_CMDID); + if (ret) { + ath11k_warn(ar->ab, + "WMI vdev %i failed to send FILS discovery template command\n", + vdev_id); + dev_kfree_skb(skb); + } + return ret; +} + +int ath11k_wmi_probe_resp_tmpl(struct ath11k *ar, u32 vdev_id, + struct sk_buff *tmpl) +{ + struct wmi_probe_tmpl_cmd *cmd; + struct wmi_bcn_prb_info *probe_info; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + int ret, len; + size_t aligned_len = roundup(tmpl->len, 4); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI vdev %i set probe response template\n", vdev_id); + + len = sizeof(*cmd) + sizeof(*probe_info) + TLV_HDR_SIZE + aligned_len; + + skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_probe_tmpl_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PRB_TMPL_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; + cmd->buf_len = tmpl->len; + + ptr = skb->data + sizeof(*cmd); + + probe_info = ptr; + len = sizeof(*probe_info); + probe_info->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_BCN_PRB_INFO) | + FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); + probe_info->caps = 0; + probe_info->erp = 0; + + ptr += sizeof(*probe_info); + + tlv = ptr; + tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) | + FIELD_PREP(WMI_TLV_LEN, aligned_len); + memcpy(tlv->value, tmpl->data, tmpl->len); + + ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_PRB_TMPL_CMDID); + if (ret) { + ath11k_warn(ar->ab, + "WMI vdev %i failed to send probe response template command\n", + vdev_id); + dev_kfree_skb(skb); + } + return ret; +} + +int ath11k_wmi_fils_discovery(struct ath11k *ar, u32 vdev_id, u32 interval, + bool unsol_bcast_probe_resp_enabled) +{ + struct sk_buff *skb; + int ret, len; + struct wmi_fils_discovery_cmd *cmd; + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI vdev %i set %s interval to %u TU\n", + vdev_id, unsol_bcast_probe_resp_enabled ? + "unsolicited broadcast probe response" : "FILS discovery", + interval); + + len = sizeof(*cmd); + skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_fils_discovery_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ENABLE_FILS_CMD) | + FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; + cmd->interval = interval; + cmd->config = unsol_bcast_probe_resp_enabled; + + ret = ath11k_wmi_cmd_send(ar->wmi, skb, WMI_ENABLE_FILS_CMDID); + if (ret) { + ath11k_warn(ar->ab, + "WMI vdev %i failed to send FILS discovery enable/disable command\n", + vdev_id); + dev_kfree_skb(skb); + } + return ret; +} + static void ath11k_fill_band_to_mac_param(struct ath11k_base *soc, struct wmi_host_pdev_band_to_mac *band_to_mac) @@ -3333,6 +3448,35 @@ int ath11k_wmi_wait_for_unified_ready(struct ath11k_base *ab) return 0; } +int ath11k_wmi_set_hw_mode(struct ath11k_base *ab, + enum wmi_host_hw_mode_config_type mode) +{ + struct wmi_pdev_set_hw_mode_cmd_param *cmd; + struct sk_buff *skb; + struct ath11k_wmi_base *wmi_ab = &ab->wmi_ab; + int len; + int ret; + + len = sizeof(*cmd); + + skb = ath11k_wmi_alloc_skb(wmi_ab, len); + cmd = (struct wmi_pdev_set_hw_mode_cmd_param *)skb->data; + + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_PDEV_SET_HW_MODE_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->pdev_id = WMI_PDEV_ID_SOC; + cmd->hw_mode_index = mode; + + ret = ath11k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_HW_MODE_CMDID); + if (ret) { + ath11k_warn(ab, "failed to send WMI_PDEV_SET_HW_MODE_CMDID\n"); + dev_kfree_skb(skb); + } + + return ret; +} + int ath11k_wmi_cmd_init(struct ath11k_base *ab) { struct ath11k_wmi_base *wmi_sc = &ab->wmi_ab; @@ -3351,13 +3495,11 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab) init_param.hw_mode_id = wmi_sc->preferred_hw_mode; init_param.mem_chunks = wmi_sc->mem_chunks; - if (wmi_sc->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE) + if (ab->hw_params.single_pdev_only) init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX; - if (ab->hw_params.needs_band_to_mac) { - init_param.num_band_to_mac = ab->num_radios; - ath11k_fill_band_to_mac_param(ab, init_param.band_to_mac); - } + init_param.num_band_to_mac = ab->num_radios; + ath11k_fill_band_to_mac_param(ab, init_param.band_to_mac); return ath11k_init_cmd_send(&wmi_sc->wmi[0], &init_param); } @@ -4242,6 +4384,34 @@ static int ath11k_pull_peer_del_resp_ev(struct ath11k_base *ab, struct sk_buff * return 0; } +static int ath11k_pull_vdev_del_resp_ev(struct ath11k_base *ab, + struct sk_buff *skb, + u32 *vdev_id) +{ + const void **tb; + const struct wmi_vdev_delete_resp_event *ev; + int ret; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, "failed to parse tlv: %d\n", ret); + return ret; + } + + ev = tb[WMI_TAG_VDEV_DELETE_RESP_EVENT]; + if (!ev) { + ath11k_warn(ab, "failed to fetch vdev delete resp ev"); + kfree(tb); + return -EPROTO; + } + + *vdev_id = ev->vdev_id; + + kfree(tb); + return 0; +} + static int ath11k_pull_bcn_tx_status_ev(struct ath11k_base *ab, void *evt_buf, u32 len, u32 *vdev_id, u32 *tx_status) @@ -5563,15 +5733,54 @@ static int ath11k_ready_event(struct ath11k_base *ab, struct sk_buff *skb) static void ath11k_peer_delete_resp_event(struct ath11k_base *ab, struct sk_buff *skb) { struct wmi_peer_delete_resp_event peer_del_resp; + struct ath11k *ar; if (ath11k_pull_peer_del_resp_ev(ab, skb, &peer_del_resp) != 0) { ath11k_warn(ab, "failed to extract peer delete resp"); return; } - /* TODO: Do we need to validate whether ath11k_peer_find() return NULL - * Why this is needed when there is HTT event for peer delete - */ + rcu_read_lock(); + ar = ath11k_mac_get_ar_by_vdev_id(ab, peer_del_resp.vdev_id); + if (!ar) { + ath11k_warn(ab, "invalid vdev id in peer delete resp ev %d", + peer_del_resp.vdev_id); + rcu_read_unlock(); + return; + } + + complete(&ar->peer_delete_done); + rcu_read_unlock(); + ath11k_dbg(ab, ATH11K_DBG_WMI, "peer delete resp for vdev id %d addr %pM\n", + peer_del_resp.vdev_id, peer_del_resp.peer_macaddr.addr); +} + +static void ath11k_vdev_delete_resp_event(struct ath11k_base *ab, + struct sk_buff *skb) +{ + struct ath11k *ar; + u32 vdev_id = 0; + + if (ath11k_pull_vdev_del_resp_ev(ab, skb, &vdev_id) != 0) { + ath11k_warn(ab, "failed to extract vdev delete resp"); + return; + } + + rcu_read_lock(); + ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id); + if (!ar) { + ath11k_warn(ab, "invalid vdev id in vdev delete resp ev %d", + vdev_id); + rcu_read_unlock(); + return; + } + + complete(&ar->vdev_delete_done); + + rcu_read_unlock(); + + ath11k_dbg(ab, ATH11K_DBG_WMI, "vdev delete resp for vdev id %d\n", + vdev_id); } static inline const char *ath11k_wmi_vdev_resp_print(u32 vdev_resp_status) @@ -5650,7 +5859,7 @@ static void ath11k_vdev_stopped_event(struct ath11k_base *ab, struct sk_buff *sk } rcu_read_lock(); - ar = ath11k_mac_get_ar_vdev_stop_status(ab, vdev_id); + ar = ath11k_mac_get_ar_by_vdev_id(ab, vdev_id); if (!ar) { ath11k_warn(ab, "invalid vdev id in vdev stopped ev %d", vdev_id); @@ -6429,6 +6638,121 @@ ath11k_wmi_pdev_temperature_event(struct ath11k_base *ab, ath11k_thermal_event_temperature(ar, ev.temp); } +static void ath11k_fils_discovery_event(struct ath11k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_fils_discovery_event *ev; + int ret; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, + "failed to parse FILS discovery event tlv %d\n", + ret); + return; + } + + ev = tb[WMI_TAG_HOST_SWFDA_EVENT]; + if (!ev) { + ath11k_warn(ab, "failed to fetch FILS discovery event\n"); + kfree(tb); + return; + } + + ath11k_warn(ab, + "FILS discovery frame expected from host for vdev_id: %u, transmission scheduled at %u, next TBTT: %u\n", + ev->vdev_id, ev->fils_tt, ev->tbtt); + + kfree(tb); +} + +static void ath11k_probe_resp_tx_status_event(struct ath11k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_probe_resp_tx_status_event *ev; + int ret; + + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath11k_warn(ab, + "failed to parse probe response transmission status event tlv: %d\n", + ret); + return; + } + + ev = tb[WMI_TAG_OFFLOAD_PRB_RSP_TX_STATUS_EVENT]; + if (!ev) { + ath11k_warn(ab, + "failed to fetch probe response transmission status event"); + kfree(tb); + return; + } + + if (ev->tx_status) + ath11k_warn(ab, + "Probe response transmission failed for vdev_id %u, status %u\n", + ev->vdev_id, ev->tx_status); + + kfree(tb); +} + +static int ath11k_wmi_tlv_wow_wakeup_host_parse(struct ath11k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + struct wmi_wow_ev_arg *ev = data; + const char *wow_pg_fault; + int wow_pg_len; + + switch (tag) { + case WMI_TAG_WOW_EVENT_INFO: + memcpy(ev, ptr, sizeof(*ev)); + ath11k_dbg(ab, ATH11K_DBG_WMI, "wow wakeup host reason %d %s\n", + ev->wake_reason, wow_reason(ev->wake_reason)); + break; + + case WMI_TAG_ARRAY_BYTE: + if (ev && ev->wake_reason == WOW_REASON_PAGE_FAULT) { + wow_pg_fault = ptr; + /* the first 4 bytes are length */ + wow_pg_len = *(int *)wow_pg_fault; + wow_pg_fault += sizeof(int); + ath11k_dbg(ab, ATH11K_DBG_WMI, "wow data_len = %d\n", + wow_pg_len); + ath11k_dbg_dump(ab, ATH11K_DBG_WMI, + "wow_event_info_type packet present", + "wow_pg_fault ", + wow_pg_fault, + wow_pg_len); + } + break; + default: + break; + } + + return 0; +} + +static void ath11k_wmi_event_wow_wakeup_host(struct ath11k_base *ab, struct sk_buff *skb) +{ + struct wmi_wow_ev_arg ev = { }; + int ret; + + ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len, + ath11k_wmi_tlv_wow_wakeup_host_parse, + &ev); + if (ret) { + ath11k_warn(ab, "failed to parse wmi wow tlv: %d\n", ret); + return; + } + + complete(&ab->wow.wakeup_completed); +} + static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -6515,9 +6839,14 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_PDEV_DMA_RING_BUF_RELEASE_EVENTID: ath11k_wmi_pdev_dma_ring_buf_release_event(ab, skb); break; + case WMI_HOST_FILS_DISCOVERY_EVENTID: + ath11k_fils_discovery_event(ab, skb); + break; + case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID: + ath11k_probe_resp_tx_status_event(ab, skb); + break; /* add Unsupported events here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: - case WMI_VDEV_DELETE_RESP_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID: case WMI_TWT_ENABLE_EVENTID: case WMI_TWT_DISABLE_EVENTID: @@ -6528,6 +6857,12 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) case WMI_PDEV_DFS_RADAR_DETECTION_EVENTID: ath11k_wmi_pdev_dfs_radar_detected_event(ab, skb); break; + case WMI_VDEV_DELETE_RESP_EVENTID: + ath11k_vdev_delete_resp_event(ab, skb); + break; + case WMI_WOW_WAKEUP_HOST_EVENTID: + ath11k_wmi_event_wow_wakeup_host(ab, skb); + break; /* TODO: Add remaining events */ default: ath11k_dbg(ab, ATH11K_DBG_WMI, "Unknown eventid: 0x%x\n", id); @@ -6742,3 +7077,46 @@ void ath11k_wmi_detach(struct ath11k_base *ab) ath11k_wmi_free_dbring_caps(ab); } + +int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar) +{ + struct wmi_wow_host_wakeup_ind *cmd; + struct sk_buff *skb; + size_t len; + + len = sizeof(*cmd); + skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_wow_host_wakeup_ind *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, + WMI_TAG_WOW_HOSTWAKEUP_FROM_SLEEP_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow host wakeup ind\n"); + + return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID); +} + +int ath11k_wmi_wow_enable(struct ath11k *ar) +{ + struct wmi_wow_enable_cmd *cmd; + struct sk_buff *skb; + int len; + + len = sizeof(*cmd); + skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_wow_enable_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_WOW_ENABLE_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + + cmd->enable = 1; + cmd->pause_iface_config = WOW_IFACE_PAUSE_ENABLED; + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "wmi tlv wow enable\n"); + + return ath11k_wmi_cmd_send(ar->wmi, skb, WMI_WOW_ENABLE_CMDID); +} diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 5a32ba0eb4f5..993674228c9e 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -319,6 +319,7 @@ enum wmi_tlv_cmd_id { WMI_BCN_OFFLOAD_CTRL_CMDID, WMI_BSS_COLOR_CHANGE_ENABLE_CMDID, WMI_VDEV_BCN_OFFLOAD_QUIET_CONFIG_CMDID, + WMI_FILS_DISCOVERY_TMPL_CMDID, WMI_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_GRP_BA_NEG), WMI_ADDBA_SEND_CMDID, WMI_ADDBA_STATUS_CMDID, @@ -351,6 +352,8 @@ enum wmi_tlv_cmd_id { WMI_ROAM_CONFIGURE_MAWC_CMDID, WMI_ROAM_SET_MBO_PARAM_CMDID, WMI_ROAM_PER_CONFIG_CMDID, + WMI_ROAM_BTM_CONFIG_CMDID, + WMI_ENABLE_FILS_CMDID, WMI_OFL_SCAN_ADD_AP_PROFILE = WMI_TLV_CMD(WMI_GRP_OFL_SCAN), WMI_OFL_SCAN_REMOVE_AP_PROFILE, WMI_OFL_SCAN_PERIOD, @@ -642,6 +645,8 @@ enum wmi_tlv_event_id { WMI_MGMT_TX_COMPLETION_EVENTID, WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID, WMI_TBTTOFFSET_EXT_UPDATE_EVENTID, + WMI_OFFCHAN_DATA_TX_COMPLETION_EVENTID, + WMI_HOST_FILS_DISCOVERY_EVENTID, WMI_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_CMD(WMI_GRP_BA_NEG), WMI_TX_ADDBA_COMPLETE_EVENTID, WMI_BA_RSP_SSN_EVENTID, @@ -1032,7 +1037,7 @@ enum wmi_tlv_vdev_param { WMI_VDEV_PARAM_PROTOTYPE = 0x8000, WMI_VDEV_PARAM_BSS_COLOR, WMI_VDEV_PARAM_SET_HEMU_MODE, - WMI_VDEV_PARAM_TX_OFDMA_CPLEN, + WMI_VDEV_PARAM_HEOPS_0_31 = 0x8003, }; enum wmi_tlv_peer_flags { @@ -1810,6 +1815,7 @@ enum wmi_tlv_tag { /* TODO add all the missing cmds */ WMI_TAG_PDEV_PEER_PKTLOG_FILTER_CMD = 0x301, WMI_TAG_PDEV_PEER_PKTLOG_FILTER_INFO, + WMI_TAG_FILS_DISCOVERY_TMPL_CMD = 0x344, WMI_TAG_MAX }; @@ -3348,7 +3354,6 @@ struct wmi_mgmt_params { void *pdata; u16 desc_id; u8 *macaddr; - void *qdf_ctx; }; enum wmi_sta_ps_mode { @@ -4013,6 +4018,10 @@ struct wmi_regulatory_rule_struct { u32 flag_info; }; +struct wmi_vdev_delete_resp_event { + u32 vdev_id; +} __packed; + struct wmi_peer_delete_resp_event { u32 vdev_id; struct wmi_mac_addr peer_macaddr; @@ -4076,6 +4085,17 @@ struct wmi_peer_assoc_conf_arg { const u8 *macaddr; }; +struct wmi_fils_discovery_event { + u32 vdev_id; + u32 fils_tt; + u32 tbtt; +} __packed; + +struct wmi_probe_resp_tx_status_event { + u32 vdev_id; + u32 tx_status; +} __packed; + /* * PDEV statistics */ @@ -4908,6 +4928,30 @@ struct wmi_dma_buf_release_meta_data { u32 ch_width; } __packed; +enum wmi_fils_discovery_cmd_type { + WMI_FILS_DISCOVERY_CMD, + WMI_UNSOL_BCAST_PROBE_RESP, +}; + +struct wmi_fils_discovery_cmd { + u32 tlv_header; + u32 vdev_id; + u32 interval; + u32 config; /* enum wmi_fils_discovery_cmd_type */ +} __packed; + +struct wmi_fils_discovery_tmpl_cmd { + u32 tlv_header; + u32 vdev_id; + u32 buf_len; +} __packed; + +struct wmi_probe_tmpl_cmd { + u32 tlv_header; + u32 vdev_id; + u32 buf_len; +} __packed; + struct target_resource_config { u32 num_vdevs; u32 num_peers; @@ -5000,6 +5044,169 @@ struct ath11k_wmi_base { struct ath11k_targ_cap *targ_cap; }; +/* WOW structures */ +enum wmi_wow_wakeup_event { + WOW_BMISS_EVENT = 0, + WOW_BETTER_AP_EVENT, + WOW_DEAUTH_RECVD_EVENT, + WOW_MAGIC_PKT_RECVD_EVENT, + WOW_GTK_ERR_EVENT, + WOW_FOURWAY_HSHAKE_EVENT, + WOW_EAPOL_RECVD_EVENT, + WOW_NLO_DETECTED_EVENT, + WOW_DISASSOC_RECVD_EVENT, + WOW_PATTERN_MATCH_EVENT, + WOW_CSA_IE_EVENT, + WOW_PROBE_REQ_WPS_IE_EVENT, + WOW_AUTH_REQ_EVENT, + WOW_ASSOC_REQ_EVENT, + WOW_HTT_EVENT, + WOW_RA_MATCH_EVENT, + WOW_HOST_AUTO_SHUTDOWN_EVENT, + WOW_IOAC_MAGIC_EVENT, + WOW_IOAC_SHORT_EVENT, + WOW_IOAC_EXTEND_EVENT, + WOW_IOAC_TIMER_EVENT, + WOW_DFS_PHYERR_RADAR_EVENT, + WOW_BEACON_EVENT, + WOW_CLIENT_KICKOUT_EVENT, + WOW_EVENT_MAX, +}; + +enum wmi_wow_interface_cfg { + WOW_IFACE_PAUSE_ENABLED, + WOW_IFACE_PAUSE_DISABLED +}; + +#define C2S(x) case x: return #x + +static inline const char *wow_wakeup_event(enum wmi_wow_wakeup_event ev) +{ + switch (ev) { + C2S(WOW_BMISS_EVENT); + C2S(WOW_BETTER_AP_EVENT); + C2S(WOW_DEAUTH_RECVD_EVENT); + C2S(WOW_MAGIC_PKT_RECVD_EVENT); + C2S(WOW_GTK_ERR_EVENT); + C2S(WOW_FOURWAY_HSHAKE_EVENT); + C2S(WOW_EAPOL_RECVD_EVENT); + C2S(WOW_NLO_DETECTED_EVENT); + C2S(WOW_DISASSOC_RECVD_EVENT); + C2S(WOW_PATTERN_MATCH_EVENT); + C2S(WOW_CSA_IE_EVENT); + C2S(WOW_PROBE_REQ_WPS_IE_EVENT); + C2S(WOW_AUTH_REQ_EVENT); + C2S(WOW_ASSOC_REQ_EVENT); + C2S(WOW_HTT_EVENT); + C2S(WOW_RA_MATCH_EVENT); + C2S(WOW_HOST_AUTO_SHUTDOWN_EVENT); + C2S(WOW_IOAC_MAGIC_EVENT); + C2S(WOW_IOAC_SHORT_EVENT); + C2S(WOW_IOAC_EXTEND_EVENT); + C2S(WOW_IOAC_TIMER_EVENT); + C2S(WOW_DFS_PHYERR_RADAR_EVENT); + C2S(WOW_BEACON_EVENT); + C2S(WOW_CLIENT_KICKOUT_EVENT); + C2S(WOW_EVENT_MAX); + default: + return NULL; + } +} + +enum wmi_wow_wake_reason { + WOW_REASON_UNSPECIFIED = -1, + WOW_REASON_NLOD = 0, + WOW_REASON_AP_ASSOC_LOST, + WOW_REASON_LOW_RSSI, + WOW_REASON_DEAUTH_RECVD, + WOW_REASON_DISASSOC_RECVD, + WOW_REASON_GTK_HS_ERR, + WOW_REASON_EAP_REQ, + WOW_REASON_FOURWAY_HS_RECV, + WOW_REASON_TIMER_INTR_RECV, + WOW_REASON_PATTERN_MATCH_FOUND, + WOW_REASON_RECV_MAGIC_PATTERN, + WOW_REASON_P2P_DISC, + WOW_REASON_WLAN_HB, + WOW_REASON_CSA_EVENT, + WOW_REASON_PROBE_REQ_WPS_IE_RECV, + WOW_REASON_AUTH_REQ_RECV, + WOW_REASON_ASSOC_REQ_RECV, + WOW_REASON_HTT_EVENT, + WOW_REASON_RA_MATCH, + WOW_REASON_HOST_AUTO_SHUTDOWN, + WOW_REASON_IOAC_MAGIC_EVENT, + WOW_REASON_IOAC_SHORT_EVENT, + WOW_REASON_IOAC_EXTEND_EVENT, + WOW_REASON_IOAC_TIMER_EVENT, + WOW_REASON_ROAM_HO, + WOW_REASON_DFS_PHYERR_RADADR_EVENT, + WOW_REASON_BEACON_RECV, + WOW_REASON_CLIENT_KICKOUT_EVENT, + WOW_REASON_PAGE_FAULT = 0x3a, + WOW_REASON_DEBUG_TEST = 0xFF, +}; + +static inline const char *wow_reason(enum wmi_wow_wake_reason reason) +{ + switch (reason) { + C2S(WOW_REASON_UNSPECIFIED); + C2S(WOW_REASON_NLOD); + C2S(WOW_REASON_AP_ASSOC_LOST); + C2S(WOW_REASON_LOW_RSSI); + C2S(WOW_REASON_DEAUTH_RECVD); + C2S(WOW_REASON_DISASSOC_RECVD); + C2S(WOW_REASON_GTK_HS_ERR); + C2S(WOW_REASON_EAP_REQ); + C2S(WOW_REASON_FOURWAY_HS_RECV); + C2S(WOW_REASON_TIMER_INTR_RECV); + C2S(WOW_REASON_PATTERN_MATCH_FOUND); + C2S(WOW_REASON_RECV_MAGIC_PATTERN); + C2S(WOW_REASON_P2P_DISC); + C2S(WOW_REASON_WLAN_HB); + C2S(WOW_REASON_CSA_EVENT); + C2S(WOW_REASON_PROBE_REQ_WPS_IE_RECV); + C2S(WOW_REASON_AUTH_REQ_RECV); + C2S(WOW_REASON_ASSOC_REQ_RECV); + C2S(WOW_REASON_HTT_EVENT); + C2S(WOW_REASON_RA_MATCH); + C2S(WOW_REASON_HOST_AUTO_SHUTDOWN); + C2S(WOW_REASON_IOAC_MAGIC_EVENT); + C2S(WOW_REASON_IOAC_SHORT_EVENT); + C2S(WOW_REASON_IOAC_EXTEND_EVENT); + C2S(WOW_REASON_IOAC_TIMER_EVENT); + C2S(WOW_REASON_ROAM_HO); + C2S(WOW_REASON_DFS_PHYERR_RADADR_EVENT); + C2S(WOW_REASON_BEACON_RECV); + C2S(WOW_REASON_CLIENT_KICKOUT_EVENT); + C2S(WOW_REASON_PAGE_FAULT); + C2S(WOW_REASON_DEBUG_TEST); + default: + return NULL; + } +} + +#undef C2S + +struct wmi_wow_enable_cmd { + u32 tlv_header; + u32 enable; + u32 pause_iface_config; + u32 flags; +} __packed; + +struct wmi_wow_host_wakeup_ind { + u32 tlv_header; + u32 reserved; +} __packed; + +struct wmi_wow_ev_arg { + u32 vdev_id; + u32 flag; + enum wmi_wow_wake_reason wake_reason; + u32 data_len; +}; + int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, u32 cmd_id); struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len); @@ -5121,4 +5328,15 @@ int ath11k_wmi_vdev_spectral_enable(struct ath11k *ar, u32 vdev_id, u32 trigger, u32 enable); int ath11k_wmi_vdev_spectral_conf(struct ath11k *ar, struct ath11k_wmi_vdev_spectral_conf_param *param); +int ath11k_wmi_fils_discovery_tmpl(struct ath11k *ar, u32 vdev_id, + struct sk_buff *tmpl); +int ath11k_wmi_fils_discovery(struct ath11k *ar, u32 vdev_id, u32 interval, + bool unsol_bcast_probe_resp_enabled); +int ath11k_wmi_probe_resp_tmpl(struct ath11k *ar, u32 vdev_id, + struct sk_buff *tmpl); +int ath11k_wmi_set_hw_mode(struct ath11k_base *ab, + enum wmi_host_hw_mode_config_type mode); +int ath11k_wmi_wow_host_wakeup_ind(struct ath11k *ar); +int ath11k_wmi_wow_enable(struct ath11k *ar); + #endif diff --git a/drivers/net/wireless/ath/ath11k/wow.c b/drivers/net/wireless/ath/ath11k/wow.c new file mode 100644 index 000000000000..43c62e99dd0e --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/wow.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + */ + +#include <linux/delay.h> + +#include "mac.h" +#include "core.h" +#include "hif.h" +#include "debug.h" +#include "wmi.h" +#include "wow.h" + +int ath11k_wow_enable(struct ath11k_base *ab) +{ + struct ath11k *ar = ath11k_ab_to_ar(ab, 0); + int i, ret; + + clear_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags); + + for (i = 0; i < ATH11K_WOW_RETRY_NUM; i++) { + reinit_completion(&ab->htc_suspend); + + ret = ath11k_wmi_wow_enable(ar); + if (ret) { + ath11k_warn(ab, "failed to issue wow enable: %d\n", ret); + return ret; + } + + ret = wait_for_completion_timeout(&ab->htc_suspend, 3 * HZ); + if (ret == 0) { + ath11k_warn(ab, + "timed out while waiting for htc suspend completion\n"); + return -ETIMEDOUT; + } + + if (test_bit(ATH11K_FLAG_HTC_SUSPEND_COMPLETE, &ab->dev_flags)) + /* success, suspend complete received */ + return 0; + + ath11k_warn(ab, "htc suspend not complete, retrying (try %d)\n", + i); + msleep(ATH11K_WOW_RETRY_WAIT_MS); + } + + ath11k_warn(ab, "htc suspend not complete, failing after %d tries\n", i); + + return -ETIMEDOUT; +} + +int ath11k_wow_wakeup(struct ath11k_base *ab) +{ + struct ath11k *ar = ath11k_ab_to_ar(ab, 0); + int ret; + + reinit_completion(&ab->wow.wakeup_completed); + + ret = ath11k_wmi_wow_host_wakeup_ind(ar); + if (ret) { + ath11k_warn(ab, "failed to send wow wakeup indication: %d\n", + ret); + return ret; + } + + ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ); + if (ret == 0) { + ath11k_warn(ab, "timed out while waiting for wow wakeup completion\n"); + return -ETIMEDOUT; + } + + return 0; +} diff --git a/drivers/net/wireless/ath/ath11k/wow.h b/drivers/net/wireless/ath/ath11k/wow.h new file mode 100644 index 000000000000..dabc4ee63cf6 --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/wow.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + */ + +#define ATH11K_WOW_RETRY_NUM 3 +#define ATH11K_WOW_RETRY_WAIT_MS 200 + +int ath11k_wow_enable(struct ath11k_base *ab); +int ath11k_wow_wakeup(struct ath11k_base *ab); diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 5e866a193ed0..8f2719ff463c 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -433,6 +433,7 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, case NL80211_IFTYPE_STATION: if (ah->assoc) rfilt |= AR5K_RX_FILTER_BEACON; + break; default: break; } diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c index f3906dbe5495..89c7c4e25169 100644 --- a/drivers/net/wireless/ath/ath6kl/testmode.c +++ b/drivers/net/wireless/ath/ath6kl/testmode.c @@ -94,7 +94,6 @@ int ath6kl_tm_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, return 0; - break; case ATH6KL_TM_CMD_RX_REPORT: default: return -EOPNOTSUPP; diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index dbc47702a268..b137e7f34397 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -1821,8 +1821,8 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb, /* Only for OPT_TX_CMD, use BE endpoint. */ if (cmd_id == WMI_OPT_TX_FRAME_CMDID) { - ret = ath6kl_wmi_data_hdr_add(wmi, skb, OPT_MSGTYPE, - false, false, 0, NULL, if_idx); + ret = ath6kl_wmi_data_hdr_add(wmi, skb, OPT_MSGTYPE, false, + WMI_DATA_HDR_DATA_TYPE_802_3, 0, NULL, if_idx); if (ret) { dev_kfree_skb(skb); return ret; diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 2fa30834a88d..6610d76131fa 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -102,13 +102,8 @@ static void ar5008_write_bank6(struct ath_hw *ah, unsigned int *writecnt) REGWRITE_BUFFER_FLUSH(ah); } -/** +/* * ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters - * @rfbuf: - * @reg32: - * @numBits: - * @firstBit: - * @column: * * Performs analog "swizzling" of parameters into their location. * Used on external AR2133/AR5133 radios. @@ -198,10 +193,8 @@ static void ar5008_hw_force_bias(struct ath_hw *ah, u16 synth_freq) ar5008_write_bank6(ah, ®_writes); } -/** +/* * ar5008_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios - * @ah: atheros hardware structure - * @chan: * * For the external AR2133/AR5133 radios, takes the MHz channel value and set * the channel value. Assumes writes enabled to analog bus and bank6 register @@ -430,10 +423,8 @@ void ar5008_hw_cmn_spur_mitigate(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } -/** +/* * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios - * @ah: atheros hardware structure - * @chan: * * For non single-chip solutions. Converts to baseband spur frequency given the * input channel frequency and compute register settings below. diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index c07866a2fdf9..16d5c0c5e2a8 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -1724,20 +1724,6 @@ static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = { {0x00004044, 0x00000000}, }; -static const u32 ar9300PciePhy_clkreq_enable_L1_2p2[][2] = { - /* Addr allmodes */ - {0x00004040, 0x0825365e}, - {0x00004040, 0x0008003b}, - {0x00004044, 0x00000000}, -}; - -static const u32 ar9300PciePhy_clkreq_disable_L1_2p2[][2] = { - /* Addr allmodes */ - {0x00004040, 0x0821365e}, - {0x00004040, 0x0008003b}, - {0x00004044, 0x00000000}, -}; - static const u32 ar9300_2p2_baseband_core_txfir_coeff_japan_2484[][2] = { /* Addr allmodes */ {0x0000a398, 0x00000000}, diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h index 29479afbc4f1..3e783fc13553 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h @@ -1010,11 +1010,4 @@ static const u32 ar9331_common_rx_gain_1p1[][2] = { {0x0000a1fc, 0x00000296}, }; -static const u32 ar9331_common_tx_gain_offset1_1[][1] = { - {0x00000000}, - {0x00000003}, - {0x00000000}, - {0x00000000}, -}; - #endif /* INITVALS_9330_1P1_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index 2eb163fc1c18..3da4ea564148 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -621,107 +621,6 @@ static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = { {0x00016448, 0x8e481666, 0x8e481666, 0x8e481266, 0x8e481266}, }; -static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, - {0x00009820, 0x206a022e, 0x206a022e, 0x206a00ae, 0x206a00ae}, - {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, - {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec82d2e, 0x7ec82d2e}, - {0x0000a2dc, 0xfef5d402, 0xfef5d402, 0xfdab5b52, 0xfdab5b52}, - {0x0000a2e0, 0xfe896600, 0xfe896600, 0xfd339c84, 0xfd339c84}, - {0x0000a2e4, 0xff01f800, 0xff01f800, 0xfec3e000, 0xfec3e000}, - {0x0000a2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000}, - {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, - {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, - {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, - {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, - {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, - {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, - {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, - {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, - {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, - {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, - {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, - {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, - {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, - {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, - {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, - {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, - {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, - {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, - {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, - {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, - {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, - {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, - {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, - {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, - {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, - {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, - {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, - {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, - {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, - {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, - {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, - {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, - {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, - {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, - {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, - {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, - {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, - {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, - {0x00016048, 0x8e480086, 0x8e480086, 0x8e480086, 0x8e480086}, - {0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, - {0x00016448, 0x8e480086, 0x8e480086, 0x8e480086, 0x8e480086}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, - {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, - {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, - {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, - {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0xfef5d402, 0xfef5d402, 0xfdab5b52, 0xfdab5b52}, - {0x0000b2e0, 0xfe896600, 0xfe896600, 0xfd339c84, 0xfd339c84}, - {0x0000b2e4, 0xff01f800, 0xff01f800, 0xfec3e000, 0xfec3e000}, - {0x0000b2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000}, -}; - static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index bdf6f107f6f1..4afe52c0456e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -1006,13 +1006,6 @@ static const u32 ar9485_1_1_soc_preamble[][2] = { {0x00007048, 0x00000002}, }; -static const u32 ar9485_fast_clock_1_1_baseband_postamble[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00009e00, 0x03721821, 0x03721821}, - {0x0000a230, 0x0000400b, 0x00004016}, - {0x0000a254, 0x00000898, 0x00001130}, -}; - static const u32 ar9485_1_1_baseband_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e06b74a54a69..13b4f5f50f8a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -661,7 +661,6 @@ struct ath9k_vif_iter_data { int naps; /* number of AP vifs */ int nmeshes; /* number of mesh vifs */ int nstations; /* number of station vifs */ - int nwds; /* number of WDS vifs */ int nadhocs; /* number of adhoc vifs */ int nocbs; /* number of OCB vifs */ int nbcnvifs; /* number of beaconing vifs */ diff --git a/drivers/net/wireless/ath/ath9k/common-debug.c b/drivers/net/wireless/ath/ath9k/common-debug.c index 53ca4b063eb9..7aefb79f6bed 100644 --- a/drivers/net/wireless/ath/ath9k/common-debug.c +++ b/drivers/net/wireless/ath/ath9k/common-debug.c @@ -189,7 +189,7 @@ static ssize_t read_file_phy_err(struct file *file, char __user *user_buf, { #define PHY_ERR(s, p) \ len += scnprintf(buf + len, size - len, "%22s : %10u\n", s, \ - rxstats->phy_err_stats[p]); + rxstats->phy_err_stats[p]) struct ath_rx_stats *rxstats = file->private_data; char *buf; diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 26ea51a72156..017a43bc400c 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -735,10 +735,10 @@ static int read_file_misc(struct seq_file *file, void *data) ath9k_calculate_iter_data(sc, ctx, &iter_data); seq_printf(file, - "VIFS: CTX %i(%i) AP: %i STA: %i MESH: %i WDS: %i", + "VIFS: CTX %i(%i) AP: %i STA: %i MESH: %i", i++, (int)(ctx->assigned), iter_data.naps, iter_data.nstations, - iter_data.nmeshes, iter_data.nwds); + iter_data.nmeshes); seq_printf(file, " ADHOC: %i OCB: %i TOTAL: %hi BEACON-VIF: %hi\n", iter_data.nadhocs, iter_data.nocbs, sc->cur_chan->nvifs, sc->nbcnvifs); diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c index 3251c9abe270..2a79c2fa8415 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_debug.c +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c @@ -26,7 +26,7 @@ static struct ath_dfs_pool_stats dfs_pool_stats = { 0 }; #define ATH9K_DFS_STAT(s, p) \ len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \ - sc->debug.stats.dfs_stats.p); + sc->debug.stats.dfs_stats.p) #define ATH9K_DFS_POOL_STAT(s, p) \ len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \ dfs_pool_stats.p); diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c index fbeb4a739d32..321ff54fdb42 100644 --- a/drivers/net/wireless/ath/ath9k/dynack.c +++ b/drivers/net/wireless/ath/ath9k/dynack.c @@ -44,9 +44,8 @@ static u32 ath_dynack_get_max_to(struct ath_hw *ah) return 600; } -/** +/* * ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation - * */ static inline int ath_dynack_ewma(int old, int new) { @@ -247,8 +246,12 @@ void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, ridx = ts->ts_rateindex; da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp; - ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1); - ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2); + + /* ether_addr_copy() gives a false warning on gcc-10 so use memcpy() + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97490 + */ + memcpy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1, ETH_ALEN); + memcpy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2, ETH_ALEN); if (!(info->status.rates[ridx].flags & IEEE80211_TX_RC_MCS)) { const struct ieee80211_rate *rate; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 0bdc4dcb7b8f..8e69e8989f6d 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -297,7 +297,12 @@ static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv, tx_hdr.data_type = ATH9K_HTC_NORMAL; } - if (ieee80211_is_data_qos(hdr->frame_control)) { + /* Transmit all frames that should not be reordered relative + * to each other using the same priority. For other QoS data + * frames extract the priority from the header. + */ + if (!(tx_info->control.flags & IEEE80211_TX_CTRL_DONT_REORDER) && + ieee80211_is_data_qos(hdr->frame_control)) { qc = ieee80211_get_qos_ctl(hdr); tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 6609ce122e6e..b66eeb577272 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2308,7 +2308,6 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period) ath_dbg(ath9k_hw_common(ah), BEACON, "%s: unsupported opmode: %d\n", __func__, ah->opmode); return; - break; } REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 690fe3a1b516..42a208787f5a 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -832,12 +832,6 @@ static const struct ieee80211_iface_limit if_limits[] = { BIT(NL80211_IFTYPE_P2P_GO) }, }; -#ifdef CONFIG_WIRELESS_WDS -static const struct ieee80211_iface_limit wds_limits[] = { - { .max = 2048, .types = BIT(NL80211_IFTYPE_WDS) }, -}; -#endif - #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT static const struct ieee80211_iface_limit if_limits_multi[] = { @@ -874,15 +868,6 @@ static const struct ieee80211_iface_combination if_comb[] = { BIT(NL80211_CHAN_WIDTH_40), #endif }, -#ifdef CONFIG_WIRELESS_WDS - { - .limits = wds_limits, - .n_limits = ARRAY_SIZE(wds_limits), - .max_interfaces = 2048, - .num_different_channels = 1, - .beacon_int_infra_match = true, - }, -#endif }; #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT @@ -897,7 +882,6 @@ static void ath9k_set_mcc_capab(struct ath_softc *sc, struct ieee80211_hw *hw) ieee80211_hw_set(hw, QUEUE_CONTROL); hw->queues = ATH9K_NUM_TX_QUEUES; hw->offchannel_tx_hw_queue = hw->queues - 1; - hw->wiphy->interface_modes &= ~ BIT(NL80211_IFTYPE_WDS); hw->wiphy->iface_combinations = if_comb_multi; hw->wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_multi); hw->wiphy->max_scan_ssids = 255; @@ -953,9 +937,6 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MESH_POINT) | -#ifdef CONFIG_WIRELESS_WDS - BIT(NL80211_IFTYPE_WDS) | -#endif BIT(NL80211_IFTYPE_OCB); if (ath9k_is_chanctx_enabled()) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 8dbf68b94228..caebe3fd6869 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -973,9 +973,6 @@ static void ath9k_vif_iter(struct ath9k_vif_iter_data *iter_data, if (vif->bss_conf.enable_beacon) ath9k_vif_iter_set_beacon(iter_data, vif); break; - case NL80211_IFTYPE_WDS: - iter_data->nwds++; - break; default: break; } @@ -1136,8 +1133,6 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, ah->opmode = NL80211_IFTYPE_MESH_POINT; else if (iter_data.nocbs) ah->opmode = NL80211_IFTYPE_OCB; - else if (iter_data.nwds) - ah->opmode = NL80211_IFTYPE_AP; else if (iter_data.nadhocs) ah->opmode = NL80211_IFTYPE_ADHOC; else diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c index 19009aafc4e1..bb40889d7c72 100644 --- a/drivers/net/wireless/ath/carl9170/debug.c +++ b/drivers/net/wireless/ath/carl9170/debug.c @@ -45,7 +45,7 @@ #include "cmd.h" #define ADD(buf, off, max, fmt, args...) \ - off += scnprintf(&buf[off], max - off, fmt, ##args); + off += scnprintf(&buf[off], max - off, fmt, ##args) struct carl9170_debugfs_fops { @@ -818,7 +818,7 @@ void carl9170_debugfs_register(struct ar9170 *ar) #define DEBUGFS_ADD(name) \ debugfs_create_file(#name, carl_debugfs_##name ##_ops.attr, \ ar->debug_dir, ar, \ - &carl_debugfs_##name ## _ops.fops); + &carl_debugfs_##name ## _ops.fops) DEBUGFS_ADD(usb_tx_anch_urbs); DEBUGFS_ADD(usb_rx_pool_urbs); diff --git a/drivers/net/wireless/ath/carl9170/mac.c b/drivers/net/wireless/ath/carl9170/mac.c index b2eeb9fd68d2..6cdbee5beb07 100644 --- a/drivers/net/wireless/ath/carl9170/mac.c +++ b/drivers/net/wireless/ath/carl9170/mac.c @@ -329,10 +329,6 @@ int carl9170_set_operating_mode(struct ar9170 *ar) /* iwlagn 802.11n STA Workaround */ rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST; break; - case NL80211_IFTYPE_WDS: - cam_mode |= AR9170_MAC_CAM_AP_WDS; - rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST; - break; case NL80211_IFTYPE_STATION: cam_mode |= AR9170_MAC_CAM_STA; rx_ctrl |= AR9170_MAC_RX_CTRL_PASS_TO_HOST; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index dbef9d8fc893..cca3b086aa70 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -646,7 +646,6 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw, case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: if ((vif->type == NL80211_IFTYPE_STATION) || - (vif->type == NL80211_IFTYPE_WDS) || (vif->type == NL80211_IFTYPE_AP) || (vif->type == NL80211_IFTYPE_MESH_POINT)) break; diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 235cf77cd60c..6b8446ff48c8 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -840,6 +840,7 @@ static bool carl9170_tx_rts_check(struct ar9170 *ar, case CARL9170_ERP_RTS: if (likely(!multi)) return true; + break; default: break; diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c index 0813473793df..80390495ea25 100644 --- a/drivers/net/wireless/ath/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/dfs_pattern_detector.c @@ -23,7 +23,7 @@ /** * struct radar_types - contains array of patterns defined for one DFS domain - * @domain: DFS regulatory domain + * @region: regulatory DFS region * @num_radar_types: number of radar types to follow * @radar_types: radar types array */ @@ -133,8 +133,9 @@ static const struct radar_types *dfs_domains[] = { /** * get_dfs_domain_radar_types() - get radar types for a given DFS domain - * @param domain DFS domain - * @return radar_types ptr on success, NULL if DFS domain is not supported + * @region: regulatory DFS region + * + * Return value: radar_types ptr on success, NULL if DFS domain is not supported */ static const struct radar_types * get_dfs_domain_radar_types(enum nl80211_dfs_regions region) @@ -227,9 +228,10 @@ fail: /** * channel_detector_get() - get channel detector for given frequency - * @param dpd instance pointer - * @param freq frequency in MHz - * @return pointer to channel detector on success, NULL otherwise + * @dpd: DPD instance pointer + * @freq: freq frequency in MHz + * + * Return value: pointer to channel detector on success, NULL otherwise * * Return existing channel detector for the given frequency or return a * newly create one. diff --git a/drivers/net/wireless/ath/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c index 05b0464c6b92..d07c454c9c00 100644 --- a/drivers/net/wireless/ath/dfs_pri_detector.c +++ b/drivers/net/wireless/ath/dfs_pri_detector.c @@ -29,18 +29,17 @@ struct ath_dfs_pool_stats global_dfs_pool_stats = {}; (MIN + PRI_TOLERANCE == MAX - PRI_TOLERANCE ? \ MIN + PRI_TOLERANCE : RUNTIME) -/** +/* * struct pulse_elem - elements in pulse queue - * @ts: time stamp in usecs */ struct pulse_elem { struct list_head head; u64 ts; }; -/** +/* * pde_get_multiple() - get number of multiples considering a given tolerance - * @return factor if abs(val - factor*fraction) <= tolerance, 0 otherwise + * Return value: factor if abs(val - factor*fraction) <= tolerance, 0 otherwise */ static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance) { @@ -70,7 +69,7 @@ static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance) return factor; } -/** +/* * DOC: Singleton Pulse and Sequence Pools * * Instances of pri_sequence and pulse_elem are kept in singleton pools to diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index bee9110b91f3..b2400e2417a5 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -360,6 +360,7 @@ ath_reg_apply_beaconing_flags(struct wiphy *wiphy, /** * ath_reg_apply_ir_flags() * @wiphy: the wiphy to use + * @reg: regulatory structure - used for country selection * @initiator: the regulatory hint initiator * * If no country IE has been received always enable passive scan diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 706728fba72d..5867bd9c2f64 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -910,6 +910,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, * place where AID is available. */ wcn36xx_smd_config_sta(wcn, vif, sta); + wcn36xx_enable_keep_alive_null_packet(wcn, vif); } else { wcn36xx_dbg(WCN36XX_DBG_MAC, "disassociated bss %pM vif %pM AID=%d\n", @@ -1246,6 +1247,7 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL); ieee80211_hw_set(wcn->hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(wcn->hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(wcn->hw, CONNECTION_MONITOR); wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 766400f7b61c..5445277dd8de 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -78,6 +78,7 @@ static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = { WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10), WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0), WCN36XX_CFG_VAL(ENABLE_DYNAMIC_RA_START_RATE, 133), /* MCS 5 */ + WCN36XX_CFG_VAL(LINK_FAIL_TX_CNT, 1000), }; static struct wcn36xx_cfg_val wcn3680_cfg_vals[] = { @@ -162,7 +163,7 @@ static struct wcn36xx_cfg_val wcn3680_cfg_vals[] = { WCN36XX_CFG_VAL(ENABLE_RTSCTS_HTVHT, 0), WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_IDLE_WLAN_LEN, 30000), WCN36XX_CFG_VAL(BTC_STATIC_OPP_WLAN_IDLE_BT_LEN, 120000), - WCN36XX_CFG_VAL(LINK_FAIL_TX_CNT, 200), + WCN36XX_CFG_VAL(LINK_FAIL_TX_CNT, 1000), WCN36XX_CFG_VAL(TOGGLE_ARP_BDRATES, 0), WCN36XX_CFG_VAL(OPTIMIZE_CA_EVENT, 0), WCN36XX_CFG_VAL(EXT_SCAN_CONC_MODE, 0), @@ -2175,6 +2176,7 @@ int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif) INIT_HAL_MSG(msg_body, WCN36XX_HAL_EXIT_BMPS_REQ); msg_body.bss_index = vif_priv->bss_index; + msg_body.send_data_null = 1; PREPARE_HAL_BUF(wcn->hal_buf, msg_body); @@ -2568,7 +2570,7 @@ static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len) case WCN36XX_HAL_SCAN_IND_FAILED: case WCN36XX_HAL_SCAN_IND_DEQUEUED: scan_info.aborted = true; - /* fall through */ + fallthrough; case WCN36XX_HAL_SCAN_IND_COMPLETED: mutex_lock(&wcn->scan_lock); wcn->scan_req = NULL; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 421aebbb49e5..8699f8279a8b 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -262,7 +262,7 @@ struct fw_map *wil_find_fw_mapping(const char *section) /** * Check address validity for WMI buffer; remap if needed * @wil: driver data - * @ptr: internal (linker) fw/ucode address + * @ptr_: internal (linker) fw/ucode address * @size: if non zero, validate the block does not * exceed the device memory (bar) * |