diff options
Diffstat (limited to 'drivers/net/wireless/ath')
76 files changed, 4403 insertions, 2159 deletions
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 86907e5..ccba4fe 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -135,6 +135,11 @@ struct ath_ops { struct ath_common; struct ath_bus_ops; +struct ath_ps_ops { + void (*wakeup)(struct ath_common *common); + void (*restore)(struct ath_common *common); +}; + struct ath_common { void *ah; void *priv; @@ -148,7 +153,7 @@ struct ath_common { u16 cachelsz; u16 curaid; u8 macaddr[ETH_ALEN]; - u8 curbssid[ETH_ALEN]; + u8 curbssid[ETH_ALEN] __aligned(2); u8 bssidmask[ETH_ALEN]; u32 rx_bufsize; @@ -169,6 +174,7 @@ struct ath_common { struct ath_regulatory reg_world_copy; const struct ath_ops *ops; const struct ath_bus_ops *bus_ops; + const struct ath_ps_ops *ps_ops; bool btcoex_enabled; bool disable_ani; @@ -178,6 +184,11 @@ struct ath_common { struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; }; +static inline const struct ath_ps_ops *ath_ps_ops(struct ath_common *common) +{ + return common->ps_ops; +} + struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, u32 len, gfp_t gfp_mask); diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 101cadb..a156e6e 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -443,12 +443,12 @@ int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx, u32 paddr) * Guts of ath10k_ce_completed_recv_next. * The caller takes responsibility for any necessary locking. */ -static int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, - void **per_transfer_contextp, - u32 *bufferp, - unsigned int *nbytesp, - unsigned int *transfer_idp, - unsigned int *flagsp) +int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, + void **per_transfer_contextp, + u32 *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *flagsp) { struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; @@ -558,6 +558,7 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, /* sanity */ dest_ring->per_transfer_context[sw_index] = NULL; + desc->nbytes = 0; /* Update sw_index */ sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); @@ -576,11 +577,11 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, * Guts of ath10k_ce_completed_send_next. * The caller takes responsibility for any necessary locking. */ -static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, - void **per_transfer_contextp, - u32 *bufferp, - unsigned int *nbytesp, - unsigned int *transfer_idp) +int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, + void **per_transfer_contextp, + u32 *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp) { struct ath10k_ce_ring *src_ring = ce_state->src_ring; u32 ctrl_addr = ce_state->ctrl_addr; @@ -817,7 +818,10 @@ void ath10k_ce_enable_interrupts(struct ath10k *ar) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ce_id; - for (ce_id = 0; ce_id < CE_COUNT; ce_id++) + /* Skip the last copy engine, CE7 the diagnostic window, as that + * uses polling and isn't initialized for interrupts. + */ + for (ce_id = 0; ce_id < CE_COUNT - 1; ce_id++) ath10k_ce_per_engine_handler_adjust(&ar_pci->ce_states[ce_id]); } @@ -832,8 +836,8 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar, nentries = roundup_pow_of_two(attr->src_nentries); - memset(src_ring->per_transfer_context, 0, - nentries * sizeof(*src_ring->per_transfer_context)); + memset(src_ring->base_addr_owner_space, 0, + nentries * sizeof(struct ce_desc)); src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr); src_ring->sw_index &= src_ring->nentries_mask; @@ -869,8 +873,8 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar, nentries = roundup_pow_of_two(attr->dest_nentries); - memset(dest_ring->per_transfer_context, 0, - nentries * sizeof(*dest_ring->per_transfer_context)); + memset(dest_ring->base_addr_owner_space, 0, + nentries * sizeof(struct ce_desc)); dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr); dest_ring->sw_index &= dest_ring->nentries_mask; @@ -1020,37 +1024,10 @@ ath10k_ce_alloc_dest_ring(struct ath10k *ar, unsigned int ce_id, * initialized by software/firmware. */ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, - const struct ce_attr *attr, - void (*send_cb)(struct ath10k_ce_pipe *), - void (*recv_cb)(struct ath10k_ce_pipe *)) + const struct ce_attr *attr) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; int ret; - /* - * Make sure there's enough CE ringbuffer entries for HTT TX to avoid - * additional TX locking checks. - * - * For the lack of a better place do the check here. - */ - BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC > - (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); - BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC > - (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); - - spin_lock_bh(&ar_pci->ce_lock); - ce_state->ar = ar; - ce_state->id = ce_id; - ce_state->ctrl_addr = ath10k_ce_base_address(ce_id); - ce_state->attr_flags = attr->flags; - ce_state->src_sz_max = attr->src_sz_max; - if (attr->src_nentries) - ce_state->send_cb = send_cb; - if (attr->dest_nentries) - ce_state->recv_cb = recv_cb; - spin_unlock_bh(&ar_pci->ce_lock); - if (attr->src_nentries) { ret = ath10k_ce_init_src_ring(ar, ce_id, attr); if (ret) { @@ -1098,12 +1075,37 @@ void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id) } int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, - const struct ce_attr *attr) + const struct ce_attr *attr, + void (*send_cb)(struct ath10k_ce_pipe *), + void (*recv_cb)(struct ath10k_ce_pipe *)) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id]; int ret; + /* + * Make sure there's enough CE ringbuffer entries for HTT TX to avoid + * additional TX locking checks. + * + * For the lack of a better place do the check here. + */ + BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC > + (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); + BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC > + (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); + + ce_state->ar = ar; + ce_state->id = ce_id; + ce_state->ctrl_addr = ath10k_ce_base_address(ce_id); + ce_state->attr_flags = attr->flags; + ce_state->src_sz_max = attr->src_sz_max; + + if (attr->src_nentries) + ce_state->send_cb = send_cb; + + if (attr->dest_nentries) + ce_state->recv_cb = recv_cb; + if (attr->src_nentries) { ce_state->src_ring = ath10k_ce_alloc_src_ring(ar, ce_id, attr); if (IS_ERR(ce_state->src_ring)) { diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 329b734..617a151 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -192,15 +192,21 @@ int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state, unsigned int *nbytesp, unsigned int *transfer_idp); +int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state, + void **per_transfer_contextp, + u32 *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp); + /*==================CE Engine Initialization=======================*/ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id, - const struct ce_attr *attr, - void (*send_cb)(struct ath10k_ce_pipe *), - void (*recv_cb)(struct ath10k_ce_pipe *)); + const struct ce_attr *attr); void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id); int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, - const struct ce_attr *attr); + const struct ce_attr *attr, + void (*send_cb)(struct ath10k_ce_pipe *), + void (*recv_cb)(struct ath10k_ce_pipe *)); void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id); /*==================CE Engine Shutdown=======================*/ @@ -213,6 +219,13 @@ int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state, void **per_transfer_contextp, u32 *bufferp); +int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, + void **per_transfer_contextp, + u32 *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *flagsp); + /* * Support clean shutdown by allowing the caller to cancel * pending sends. Target DMA must be stopped before using diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index cee18c8..f660553 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -31,12 +31,17 @@ unsigned int ath10k_debug_mask; static bool uart_print; static unsigned int ath10k_p2p; +static bool skip_otp; + module_param_named(debug_mask, ath10k_debug_mask, uint, 0644); module_param(uart_print, bool, 0644); module_param_named(p2p, ath10k_p2p, uint, 0644); +module_param(skip_otp, bool, 0644); + MODULE_PARM_DESC(debug_mask, "Debugging mask"); MODULE_PARM_DESC(uart_print, "Uart target debugging"); MODULE_PARM_DESC(p2p, "Enable ath10k P2P support"); +MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode"); static const struct ath10k_hw_params ath10k_hw_params_list[] = { { @@ -138,7 +143,8 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, return fw; } -static int ath10k_push_board_ext_data(struct ath10k *ar) +static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data, + size_t data_len) { u32 board_data_size = QCA988X_BOARD_DATA_SZ; u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ; @@ -159,14 +165,14 @@ static int ath10k_push_board_ext_data(struct ath10k *ar) if (board_ext_data_addr == 0) return 0; - if (ar->board_len != (board_data_size + board_ext_data_size)) { + if (data_len != (board_data_size + board_ext_data_size)) { ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n", - ar->board_len, board_data_size, board_ext_data_size); + data_len, board_data_size, board_ext_data_size); return -EINVAL; } ret = ath10k_bmi_write_memory(ar, board_ext_data_addr, - ar->board_data + board_data_size, + data + board_data_size, board_ext_data_size); if (ret) { ath10k_err(ar, "could not write board ext data (%d)\n", ret); @@ -184,13 +190,14 @@ static int ath10k_push_board_ext_data(struct ath10k *ar) return 0; } -static int ath10k_download_board_data(struct ath10k *ar) +static int ath10k_download_board_data(struct ath10k *ar, const void *data, + size_t data_len) { u32 board_data_size = QCA988X_BOARD_DATA_SZ; u32 address; int ret; - ret = ath10k_push_board_ext_data(ar); + ret = ath10k_push_board_ext_data(ar, data, data_len); if (ret) { ath10k_err(ar, "could not push board ext data (%d)\n", ret); goto exit; @@ -202,9 +209,9 @@ static int ath10k_download_board_data(struct ath10k *ar) goto exit; } - ret = ath10k_bmi_write_memory(ar, address, ar->board_data, + ret = ath10k_bmi_write_memory(ar, address, data, min_t(u32, board_data_size, - ar->board_len)); + data_len)); if (ret) { ath10k_err(ar, "could not write board data (%d)\n", ret); goto exit; @@ -220,11 +227,39 @@ exit: return ret; } +static int ath10k_download_cal_file(struct ath10k *ar) +{ + int ret; + + if (!ar->cal_file) + return -ENOENT; + + if (IS_ERR(ar->cal_file)) + return PTR_ERR(ar->cal_file); + + ret = ath10k_download_board_data(ar, ar->cal_file->data, + ar->cal_file->size); + if (ret) { + ath10k_err(ar, "failed to download cal_file data: %d\n", ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n"); + + return 0; +} + static int ath10k_download_and_run_otp(struct ath10k *ar) { u32 result, address = ar->hw_params.patch_load_addr; int ret; + ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len); + if (ret) { + ath10k_err(ar, "failed to download board data: %d\n", ret); + return ret; + } + /* OTP is optional */ if (!ar->otp_data || !ar->otp_len) { @@ -250,7 +285,7 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); - if (result != 0) { + if (!skip_otp && result != 0) { ath10k_err(ar, "otp calibration failed: %d", result); return -EINVAL; } @@ -308,6 +343,9 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) if (ar->firmware && !IS_ERR(ar->firmware)) release_firmware(ar->firmware); + if (ar->cal_file && !IS_ERR(ar->cal_file)) + release_firmware(ar->cal_file); + ar->board = NULL; ar->board_data = NULL; ar->board_len = 0; @@ -319,6 +357,27 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) ar->firmware = NULL; ar->firmware_data = NULL; ar->firmware_len = 0; + + ar->cal_file = NULL; +} + +static int ath10k_fetch_cal_file(struct ath10k *ar) +{ + char filename[100]; + + /* cal-<bus>-<id>.bin */ + scnprintf(filename, sizeof(filename), "cal-%s-%s.bin", + ath10k_bus_str(ar->hif.bus), dev_name(ar->dev)); + + ar->cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename); + if (IS_ERR(ar->cal_file)) + /* calibration file is optional, don't print any warnings */ + return PTR_ERR(ar->cal_file); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n", + ATH10K_FW_DIR, filename); + + return 0; } static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar) @@ -562,6 +621,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) { int ret; + /* calibration file is optional, don't check for any errors */ + ath10k_fetch_cal_file(ar); + ar->fw_api = 3; ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); @@ -589,30 +651,32 @@ success: return 0; } -static int ath10k_init_download_firmware(struct ath10k *ar, - enum ath10k_firmware_mode mode) +static int ath10k_download_cal_data(struct ath10k *ar) { int ret; - ret = ath10k_download_board_data(ar); - if (ret) { - ath10k_err(ar, "failed to download board data: %d\n", ret); - return ret; + ret = ath10k_download_cal_file(ar); + if (ret == 0) { + ar->cal_mode = ATH10K_CAL_MODE_FILE; + goto done; } + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot did not find a calibration file, try OTP next: %d\n", + ret); + ret = ath10k_download_and_run_otp(ar); if (ret) { ath10k_err(ar, "failed to run otp: %d\n", ret); return ret; } - ret = ath10k_download_fw(ar, mode); - if (ret) { - ath10k_err(ar, "failed to download firmware: %d\n", ret); - return ret; - } + ar->cal_mode = ATH10K_CAL_MODE_OTP; - return ret; +done: + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n", + ath10k_cal_mode_str(ar->cal_mode)); + return 0; } static int ath10k_init_uart(struct ath10k *ar) @@ -685,6 +749,25 @@ static void ath10k_core_restart(struct work_struct *work) { struct ath10k *ar = container_of(work, struct ath10k, restart_work); + set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); + + /* Place a barrier to make sure the compiler doesn't reorder + * CRASH_FLUSH and calling other functions. + */ + barrier(); + + ieee80211_stop_queues(ar->hw); + ath10k_drain_tx(ar); + complete_all(&ar->scan.started); + complete_all(&ar->scan.completed); + complete_all(&ar->scan.on_channel); + complete_all(&ar->offchan_tx_completed); + complete_all(&ar->install_key_done); + complete_all(&ar->vdev_setup_done); + wake_up(&ar->htt.empty_tx_wq); + wake_up(&ar->wmi.tx_credits_wq); + wake_up(&ar->peer_mapping_wq); + mutex_lock(&ar->conf_mutex); switch (ar->state) { @@ -722,6 +805,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) lockdep_assert_held(&ar->conf_mutex); + clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); + ath10k_bmi_start(ar); if (ath10k_init_configure_target(ar)) { @@ -729,7 +814,11 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) goto err; } - status = ath10k_init_download_firmware(ar, mode); + status = ath10k_download_cal_data(ar); + if (status) + goto err; + + status = ath10k_download_fw(ar, mode); if (status) goto err; @@ -846,9 +935,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode) goto err_hif_stop; if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - ar->free_vdev_map = (1 << TARGET_10X_NUM_VDEVS) - 1; + ar->free_vdev_map = (1LL << TARGET_10X_NUM_VDEVS) - 1; else - ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; + ar->free_vdev_map = (1LL << TARGET_NUM_VDEVS) - 1; INIT_LIST_HEAD(&ar->arvifs); @@ -1084,6 +1173,7 @@ void ath10k_core_unregister(struct ath10k *ar) EXPORT_SYMBOL(ath10k_core_unregister); struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, + enum ath10k_bus bus, const struct ath10k_hif_ops *hif_ops) { struct ath10k *ar; @@ -1100,6 +1190,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ar->dev = dev; ar->hif.ops = hif_ops; + ar->hif.bus = bus; init_completion(&ar->scan.started); init_completion(&ar->scan.completed); @@ -1120,6 +1211,8 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, INIT_LIST_HEAD(&ar->peers); init_waitqueue_head(&ar->peer_mapping_wq); + init_waitqueue_head(&ar->htt.empty_tx_wq); + init_waitqueue_head(&ar->wmi.tx_credits_wq); init_completion(&ar->offchan_tx_completed); INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index fe531ea..8f86bd3 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -63,6 +63,20 @@ struct ath10k; +enum ath10k_bus { + ATH10K_BUS_PCI, +}; + +static inline const char *ath10k_bus_str(enum ath10k_bus bus) +{ + switch (bus) { + case ATH10K_BUS_PCI: + return "pci"; + } + + return "unknown"; +} + struct ath10k_skb_cb { dma_addr_t paddr; u8 vdev_id; @@ -96,8 +110,6 @@ struct ath10k_bmi { bool done_sent; }; -#define ATH10K_MAX_MEM_REQS 16 - struct ath10k_mem_chunk { void *vaddr; dma_addr_t paddr; @@ -115,17 +127,21 @@ struct ath10k_wmi { struct wmi_pdev_param_map *pdev_param; u32 num_mem_chunks; - struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS]; + struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS]; }; -struct ath10k_peer_stat { +struct ath10k_fw_stats_peer { + struct list_head list; + u8 peer_macaddr[ETH_ALEN]; u32 peer_rssi; u32 peer_tx_rate; u32 peer_rx_rate; /* 10x only */ }; -struct ath10k_target_stats { +struct ath10k_fw_stats_pdev { + struct list_head list; + /* PDEV stats */ s32 ch_noise_floor; u32 tx_frame_count; @@ -180,15 +196,11 @@ struct ath10k_target_stats { s32 phy_errs; s32 phy_err_drop; s32 mpdu_errs; +}; - /* VDEV STATS */ - - /* PEER STATS */ - u8 peers; - struct ath10k_peer_stat peer_stat[TARGET_NUM_PEERS]; - - /* TODO: Beacon filter stats */ - +struct ath10k_fw_stats { + struct list_head pdevs; + struct list_head peers; }; struct ath10k_dfs_stats { @@ -234,6 +246,8 @@ struct ath10k_vif { struct sk_buff *beacon; /* protected by data_lock */ bool beacon_sent; + void *beacon_buf; + dma_addr_t beacon_paddr; struct ath10k *ar; struct ieee80211_vif *vif; @@ -273,6 +287,7 @@ struct ath10k_vif { u8 force_sgi; bool use_cts_prot; int num_legacy_stations; + int txpower; }; struct ath10k_vif_iter { @@ -292,17 +307,19 @@ struct ath10k_fw_crash_data { struct ath10k_debug { struct dentry *debugfs_phy; - struct ath10k_target_stats target_stats; + struct ath10k_fw_stats fw_stats; + struct completion fw_stats_complete; + bool fw_stats_done; DECLARE_BITMAP(wmi_service_bitmap, WMI_SERVICE_MAX); - struct completion event_stats_compl; - unsigned long htt_stats_mask; struct delayed_work htt_stats_dwork; struct ath10k_dfs_stats dfs_stats; struct ath_dfs_pool_stats dfs_pool_stats; + /* protected by conf_mutex */ u32 fw_dbglog_mask; + u32 pktlog_filter; u8 htt_max_amsdu; u8 htt_max_ampdu; @@ -321,7 +338,7 @@ enum ath10k_state { * stopped in ath10k_core_restart() work holding conf_mutex. The state * RESTARTED means that the device is up and mac80211 has started hw * reconfiguration. Once mac80211 is done with the reconfiguration we - * set the state to STATE_ON in restart_complete(). */ + * set the state to STATE_ON in reconfig_complete(). */ ATH10K_STATE_RESTARTING, ATH10K_STATE_RESTARTED, @@ -369,8 +386,30 @@ enum ath10k_dev_flags { /* Indicates that ath10k device is during CAC phase of DFS */ ATH10K_CAC_RUNNING, ATH10K_FLAG_CORE_REGISTERED, + + /* Device has crashed and needs to restart. This indicates any pending + * waiters should immediately cancel instead of waiting for a time out. + */ + ATH10K_FLAG_CRASH_FLUSH, }; +enum ath10k_cal_mode { + ATH10K_CAL_MODE_FILE, + ATH10K_CAL_MODE_OTP, +}; + +static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode) +{ + switch (mode) { + case ATH10K_CAL_MODE_FILE: + return "file"; + case ATH10K_CAL_MODE_OTP: + return "otp"; + } + + return "unknown"; +} + enum ath10k_scan_state { ATH10K_SCAN_IDLE, ATH10K_SCAN_STARTING, @@ -421,6 +460,7 @@ struct ath10k { bool p2p; struct { + enum ath10k_bus bus; const struct ath10k_hif_ops *ops; } hif; @@ -456,7 +496,10 @@ struct ath10k { const void *firmware_data; size_t firmware_len; + const struct firmware *cal_file; + int fw_api; + enum ath10k_cal_mode cal_mode; struct { struct completion started; @@ -482,7 +525,7 @@ struct ath10k { /* current operating channel definition */ struct cfg80211_chan_def chandef; - int free_vdev_map; + unsigned long long free_vdev_map; bool monitor; int monitor_vdev_id; bool monitor_started; @@ -563,11 +606,19 @@ struct ath10k { bool utf_monitor; } testmode; + struct { + /* protected by data_lock */ + u32 fw_crash_counter; + u32 fw_warm_reset_counter; + u32 fw_cold_reset_counter; + } stats; + /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, + enum ath10k_bus bus, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 3756feb..a8f5a72 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -23,6 +23,7 @@ #include "core.h" #include "debug.h" +#include "hif.h" /* ms */ #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000 @@ -106,34 +107,36 @@ struct ath10k_dump_file_data { u8 data[0]; } __packed; -int ath10k_info(struct ath10k *ar, const char *fmt, ...) +void ath10k_info(struct ath10k *ar, const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, }; va_list args; - int ret; va_start(args, fmt); vaf.va = &args; - ret = dev_info(ar->dev, "%pV", &vaf); + dev_info(ar->dev, "%pV", &vaf); trace_ath10k_log_info(ar, &vaf); va_end(args); - - return ret; } EXPORT_SYMBOL(ath10k_info); void ath10k_print_driver_info(struct ath10k *ar) { - ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d\n", + ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s\n", ar->hw_params.name, ar->target_version, ar->chip_id, ar->hw->wiphy->fw_version, ar->fw_api, ar->htt.target_version_major, - ar->htt.target_version_minor); + ar->htt.target_version_minor, + ar->fw_version_major, + ar->fw_version_minor, + ar->fw_version_release, + ar->fw_version_build, + ath10k_cal_mode_str(ar->cal_mode)); ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", config_enabled(CONFIG_ATH10K_DEBUG), config_enabled(CONFIG_ATH10K_DEBUGFS), @@ -143,25 +146,22 @@ void ath10k_print_driver_info(struct ath10k *ar) } EXPORT_SYMBOL(ath10k_print_driver_info); -int ath10k_err(struct ath10k *ar, const char *fmt, ...) +void ath10k_err(struct ath10k *ar, const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, }; va_list args; - int ret; va_start(args, fmt); vaf.va = &args; - ret = dev_err(ar->dev, "%pV", &vaf); + dev_err(ar->dev, "%pV", &vaf); trace_ath10k_log_err(ar, &vaf); va_end(args); - - return ret; } EXPORT_SYMBOL(ath10k_err); -int ath10k_warn(struct ath10k *ar, const char *fmt, ...) +void ath10k_warn(struct ath10k *ar, const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, @@ -174,15 +174,13 @@ int ath10k_warn(struct ath10k *ar, const char *fmt, ...) trace_ath10k_log_warn(ar, &vaf); va_end(args); - - return 0; } EXPORT_SYMBOL(ath10k_warn); #ifdef CONFIG_ATH10K_DEBUGFS void ath10k_debug_read_service_map(struct ath10k *ar, - void *service_map, + const void *service_map, size_t map_size) { memcpy(ar->debug.wmi_service_bitmap, service_map, map_size); @@ -242,169 +240,182 @@ static const struct file_operations fops_wmi_services = { .llseek = default_llseek, }; -void ath10k_debug_read_target_stats(struct ath10k *ar, - struct wmi_stats_event *ev) +static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head) { - u8 *tmp = ev->data; - struct ath10k_target_stats *stats; - int num_pdev_stats, num_vdev_stats, num_peer_stats; - struct wmi_pdev_stats_10x *ps; - int i; + struct ath10k_fw_stats_pdev *i, *tmp; + + list_for_each_entry_safe(i, tmp, head, list) { + list_del(&i->list); + kfree(i); + } +} + +static void ath10k_debug_fw_stats_peers_free(struct list_head *head) +{ + struct ath10k_fw_stats_peer *i, *tmp; + + list_for_each_entry_safe(i, tmp, head, list) { + list_del(&i->list); + kfree(i); + } +} +static void ath10k_debug_fw_stats_reset(struct ath10k *ar) +{ spin_lock_bh(&ar->data_lock); + ar->debug.fw_stats_done = false; + ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs); + ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers); + spin_unlock_bh(&ar->data_lock); +} - stats = &ar->debug.target_stats; - - num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); /* 0 or 1 */ - num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); /* 0 or max vdevs */ - num_peer_stats = __le32_to_cpu(ev->num_peer_stats); /* 0 or max peers */ - - if (num_pdev_stats) { - ps = (struct wmi_pdev_stats_10x *)tmp; - - stats->ch_noise_floor = __le32_to_cpu(ps->chan_nf); - stats->tx_frame_count = __le32_to_cpu(ps->tx_frame_count); - stats->rx_frame_count = __le32_to_cpu(ps->rx_frame_count); - stats->rx_clear_count = __le32_to_cpu(ps->rx_clear_count); - stats->cycle_count = __le32_to_cpu(ps->cycle_count); - stats->phy_err_count = __le32_to_cpu(ps->phy_err_count); - stats->chan_tx_power = __le32_to_cpu(ps->chan_tx_pwr); - - stats->comp_queued = __le32_to_cpu(ps->wal.tx.comp_queued); - stats->comp_delivered = - __le32_to_cpu(ps->wal.tx.comp_delivered); - stats->msdu_enqued = __le32_to_cpu(ps->wal.tx.msdu_enqued); - stats->mpdu_enqued = __le32_to_cpu(ps->wal.tx.mpdu_enqued); - stats->wmm_drop = __le32_to_cpu(ps->wal.tx.wmm_drop); - stats->local_enqued = __le32_to_cpu(ps->wal.tx.local_enqued); - stats->local_freed = __le32_to_cpu(ps->wal.tx.local_freed); - stats->hw_queued = __le32_to_cpu(ps->wal.tx.hw_queued); - stats->hw_reaped = __le32_to_cpu(ps->wal.tx.hw_reaped); - stats->underrun = __le32_to_cpu(ps->wal.tx.underrun); - stats->tx_abort = __le32_to_cpu(ps->wal.tx.tx_abort); - stats->mpdus_requed = __le32_to_cpu(ps->wal.tx.mpdus_requed); - stats->tx_ko = __le32_to_cpu(ps->wal.tx.tx_ko); - stats->data_rc = __le32_to_cpu(ps->wal.tx.data_rc); - stats->self_triggers = __le32_to_cpu(ps->wal.tx.self_triggers); - stats->sw_retry_failure = - __le32_to_cpu(ps->wal.tx.sw_retry_failure); - stats->illgl_rate_phy_err = - __le32_to_cpu(ps->wal.tx.illgl_rate_phy_err); - stats->pdev_cont_xretry = - __le32_to_cpu(ps->wal.tx.pdev_cont_xretry); - stats->pdev_tx_timeout = - __le32_to_cpu(ps->wal.tx.pdev_tx_timeout); - stats->pdev_resets = __le32_to_cpu(ps->wal.tx.pdev_resets); - stats->phy_underrun = __le32_to_cpu(ps->wal.tx.phy_underrun); - stats->txop_ovf = __le32_to_cpu(ps->wal.tx.txop_ovf); - - stats->mid_ppdu_route_change = - __le32_to_cpu(ps->wal.rx.mid_ppdu_route_change); - stats->status_rcvd = __le32_to_cpu(ps->wal.rx.status_rcvd); - stats->r0_frags = __le32_to_cpu(ps->wal.rx.r0_frags); - stats->r1_frags = __le32_to_cpu(ps->wal.rx.r1_frags); - stats->r2_frags = __le32_to_cpu(ps->wal.rx.r2_frags); - stats->r3_frags = __le32_to_cpu(ps->wal.rx.r3_frags); - stats->htt_msdus = __le32_to_cpu(ps->wal.rx.htt_msdus); - stats->htt_mpdus = __le32_to_cpu(ps->wal.rx.htt_mpdus); - stats->loc_msdus = __le32_to_cpu(ps->wal.rx.loc_msdus); - stats->loc_mpdus = __le32_to_cpu(ps->wal.rx.loc_mpdus); - stats->oversize_amsdu = - __le32_to_cpu(ps->wal.rx.oversize_amsdu); - stats->phy_errs = __le32_to_cpu(ps->wal.rx.phy_errs); - stats->phy_err_drop = __le32_to_cpu(ps->wal.rx.phy_err_drop); - stats->mpdu_errs = __le32_to_cpu(ps->wal.rx.mpdu_errs); - - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, - ar->fw_features)) { - stats->ack_rx_bad = __le32_to_cpu(ps->ack_rx_bad); - stats->rts_bad = __le32_to_cpu(ps->rts_bad); - stats->rts_good = __le32_to_cpu(ps->rts_good); - stats->fcs_bad = __le32_to_cpu(ps->fcs_bad); - stats->no_beacons = __le32_to_cpu(ps->no_beacons); - stats->mib_int_count = __le32_to_cpu(ps->mib_int_count); - tmp += sizeof(struct wmi_pdev_stats_10x); - } else { - tmp += sizeof(struct wmi_pdev_stats_old); - } +static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head) +{ + struct ath10k_fw_stats_peer *i; + size_t num = 0; + + list_for_each_entry(i, head, list) + ++num; + + return num; +} + +void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) +{ + struct ath10k_fw_stats stats = {}; + bool is_start, is_started, is_end; + size_t num_peers; + int ret; + + INIT_LIST_HEAD(&stats.pdevs); + INIT_LIST_HEAD(&stats.peers); + + spin_lock_bh(&ar->data_lock); + ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats); + if (ret) { + ath10k_warn(ar, "failed to pull fw stats: %d\n", ret); + goto unlock; } - /* 0 or max vdevs */ - /* Currently firmware does not support VDEV stats */ - if (num_vdev_stats) { - struct wmi_vdev_stats *vdev_stats; + /* Stat data may exceed htc-wmi buffer limit. In such case firmware + * splits the stats data and delivers it in a ping-pong fashion of + * request cmd-update event. + * + * However there is no explicit end-of-data. Instead start-of-data is + * used as an implicit one. This works as follows: + * a) discard stat update events until one with pdev stats is + * delivered - this skips session started at end of (b) + * b) consume stat update events until another one with pdev stats is + * delivered which is treated as end-of-data and is itself discarded + */ - for (i = 0; i < num_vdev_stats; i++) { - vdev_stats = (struct wmi_vdev_stats *)tmp; - tmp += sizeof(struct wmi_vdev_stats); - } + if (ar->debug.fw_stats_done) { + ath10k_warn(ar, "received unsolicited stats update event\n"); + goto free; } - if (num_peer_stats) { - struct wmi_peer_stats_10x *peer_stats; - struct ath10k_peer_stat *s; - - stats->peers = num_peer_stats; - - for (i = 0; i < num_peer_stats; i++) { - peer_stats = (struct wmi_peer_stats_10x *)tmp; - s = &stats->peer_stat[i]; - - memcpy(s->peer_macaddr, &peer_stats->peer_macaddr.addr, - ETH_ALEN); - s->peer_rssi = __le32_to_cpu(peer_stats->peer_rssi); - s->peer_tx_rate = - __le32_to_cpu(peer_stats->peer_tx_rate); - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, - ar->fw_features)) { - s->peer_rx_rate = - __le32_to_cpu(peer_stats->peer_rx_rate); - tmp += sizeof(struct wmi_peer_stats_10x); - - } else { - tmp += sizeof(struct wmi_peer_stats_old); - } + num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers); + is_start = (list_empty(&ar->debug.fw_stats.pdevs) && + !list_empty(&stats.pdevs)); + is_end = (!list_empty(&ar->debug.fw_stats.pdevs) && + !list_empty(&stats.pdevs)); + + if (is_start) + list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs); + + if (is_end) + ar->debug.fw_stats_done = true; + + is_started = !list_empty(&ar->debug.fw_stats.pdevs); + + if (is_started && !is_end) { + if (num_peers >= ATH10K_MAX_NUM_PEER_IDS) { + /* Although this is unlikely impose a sane limit to + * prevent firmware from DoS-ing the host. + */ + ath10k_warn(ar, "dropping fw peer stats\n"); + goto free; } + + list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers); } + complete(&ar->debug.fw_stats_complete); + +free: + /* In some cases lists have been spliced and cleared. Free up + * resources if that is not the case. + */ + ath10k_debug_fw_stats_pdevs_free(&stats.pdevs); + ath10k_debug_fw_stats_peers_free(&stats.peers); + +unlock: spin_unlock_bh(&ar->data_lock); - complete(&ar->debug.event_stats_compl); } -static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +static int ath10k_debug_fw_stats_request(struct ath10k *ar) { - struct ath10k *ar = file->private_data; - struct ath10k_target_stats *fw_stats; - char *buf = NULL; - unsigned int len = 0, buf_len = 8000; - ssize_t ret_cnt = 0; - long left; - int i; + unsigned long timeout; int ret; - fw_stats = &ar->debug.target_stats; + lockdep_assert_held(&ar->conf_mutex); - mutex_lock(&ar->conf_mutex); + timeout = jiffies + msecs_to_jiffies(1*HZ); - if (ar->state != ATH10K_STATE_ON) - goto exit; + ath10k_debug_fw_stats_reset(ar); - buf = kzalloc(buf_len, GFP_KERNEL); - if (!buf) - goto exit; + for (;;) { + if (time_after(jiffies, timeout)) + return -ETIMEDOUT; - ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT); - if (ret) { - ath10k_warn(ar, "could not request stats (%d)\n", ret); - goto exit; + reinit_completion(&ar->debug.fw_stats_complete); + + ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT); + if (ret) { + ath10k_warn(ar, "could not request stats (%d)\n", ret); + return ret; + } + + ret = wait_for_completion_timeout(&ar->debug.fw_stats_complete, + 1*HZ); + if (ret <= 0) + return -ETIMEDOUT; + + spin_lock_bh(&ar->data_lock); + if (ar->debug.fw_stats_done) { + spin_unlock_bh(&ar->data_lock); + break; + } + spin_unlock_bh(&ar->data_lock); } - left = wait_for_completion_timeout(&ar->debug.event_stats_compl, 1*HZ); - if (left <= 0) - goto exit; + return 0; +} + +/* FIXME: How to calculate the buffer size sanely? */ +#define ATH10K_FW_STATS_BUF_SIZE (1024*1024) + +static void ath10k_fw_stats_fill(struct ath10k *ar, + struct ath10k_fw_stats *fw_stats, + char *buf) +{ + unsigned int len = 0; + unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE; + const struct ath10k_fw_stats_pdev *pdev; + const struct ath10k_fw_stats_peer *peer; + size_t num_peers; spin_lock_bh(&ar->data_lock); + + pdev = list_first_entry_or_null(&fw_stats->pdevs, + struct ath10k_fw_stats_pdev, list); + if (!pdev) { + ath10k_warn(ar, "failed to get pdev stats\n"); + goto unlock; + } + + num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers); + len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "%30s\n", "ath10k PDEV stats"); @@ -412,29 +423,29 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, "================="); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Channel noise floor", fw_stats->ch_noise_floor); + "Channel noise floor", pdev->ch_noise_floor); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", - "Channel TX power", fw_stats->chan_tx_power); + "Channel TX power", pdev->chan_tx_power); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", - "TX frame count", fw_stats->tx_frame_count); + "TX frame count", pdev->tx_frame_count); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", - "RX frame count", fw_stats->rx_frame_count); + "RX frame count", pdev->rx_frame_count); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", - "RX clear count", fw_stats->rx_clear_count); + "RX clear count", pdev->rx_clear_count); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", - "Cycle count", fw_stats->cycle_count); + "Cycle count", pdev->cycle_count); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", - "PHY error count", fw_stats->phy_err_count); + "PHY error count", pdev->phy_err_count); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", - "RTS bad count", fw_stats->rts_bad); + "RTS bad count", pdev->rts_bad); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", - "RTS good count", fw_stats->rts_good); + "RTS good count", pdev->rts_good); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", - "FCS bad count", fw_stats->fcs_bad); + "FCS bad count", pdev->fcs_bad); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", - "No beacon count", fw_stats->no_beacons); + "No beacon count", pdev->no_beacons); len += scnprintf(buf + len, buf_len - len, "%30s %10u\n", - "MIB int count", fw_stats->mib_int_count); + "MIB int count", pdev->mib_int_count); len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "%30s\n", @@ -443,51 +454,51 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, "================="); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "HTT cookies queued", fw_stats->comp_queued); + "HTT cookies queued", pdev->comp_queued); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "HTT cookies disp.", fw_stats->comp_delivered); + "HTT cookies disp.", pdev->comp_delivered); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MSDU queued", fw_stats->msdu_enqued); + "MSDU queued", pdev->msdu_enqued); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MPDU queued", fw_stats->mpdu_enqued); + "MPDU queued", pdev->mpdu_enqued); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MSDUs dropped", fw_stats->wmm_drop); + "MSDUs dropped", pdev->wmm_drop); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Local enqued", fw_stats->local_enqued); + "Local enqued", pdev->local_enqued); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Local freed", fw_stats->local_freed); + "Local freed", pdev->local_freed); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "HW queued", fw_stats->hw_queued); + "HW queued", pdev->hw_queued); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "PPDUs reaped", fw_stats->hw_reaped); + "PPDUs reaped", pdev->hw_reaped); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Num underruns", fw_stats->underrun); + "Num underruns", pdev->underrun); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "PPDUs cleaned", fw_stats->tx_abort); + "PPDUs cleaned", pdev->tx_abort); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MPDUs requed", fw_stats->mpdus_requed); + "MPDUs requed", pdev->mpdus_requed); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Excessive retries", fw_stats->tx_ko); + "Excessive retries", pdev->tx_ko); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "HW rate", fw_stats->data_rc); + "HW rate", pdev->data_rc); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Sched self tiggers", fw_stats->self_triggers); + "Sched self tiggers", pdev->self_triggers); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", "Dropped due to SW retries", - fw_stats->sw_retry_failure); + pdev->sw_retry_failure); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", "Illegal rate phy errors", - fw_stats->illgl_rate_phy_err); + pdev->illgl_rate_phy_err); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Pdev continous xretry", fw_stats->pdev_cont_xretry); + "Pdev continous xretry", pdev->pdev_cont_xretry); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "TX timeout", fw_stats->pdev_tx_timeout); + "TX timeout", pdev->pdev_tx_timeout); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "PDEV resets", fw_stats->pdev_resets); + "PDEV resets", pdev->pdev_resets); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "PHY underrun", fw_stats->phy_underrun); + "PHY underrun", pdev->phy_underrun); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MPDU is more than txop limit", fw_stats->txop_ovf); + "MPDU is more than txop limit", pdev->txop_ovf); len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "%30s\n", @@ -497,70 +508,161 @@ static ssize_t ath10k_read_fw_stats(struct file *file, char __user *user_buf, len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", "Mid PPDU route change", - fw_stats->mid_ppdu_route_change); + pdev->mid_ppdu_route_change); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Tot. number of statuses", fw_stats->status_rcvd); + "Tot. number of statuses", pdev->status_rcvd); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Extra frags on rings 0", fw_stats->r0_frags); + "Extra frags on rings 0", pdev->r0_frags); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Extra frags on rings 1", fw_stats->r1_frags); + "Extra frags on rings 1", pdev->r1_frags); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Extra frags on rings 2", fw_stats->r2_frags); + "Extra frags on rings 2", pdev->r2_frags); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Extra frags on rings 3", fw_stats->r3_frags); + "Extra frags on rings 3", pdev->r3_frags); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MSDUs delivered to HTT", fw_stats->htt_msdus); + "MSDUs delivered to HTT", pdev->htt_msdus); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MPDUs delivered to HTT", fw_stats->htt_mpdus); + "MPDUs delivered to HTT", pdev->htt_mpdus); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MSDUs delivered to stack", fw_stats->loc_msdus); + "MSDUs delivered to stack", pdev->loc_msdus); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MPDUs delivered to stack", fw_stats->loc_mpdus); + "MPDUs delivered to stack", pdev->loc_mpdus); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "Oversized AMSUs", fw_stats->oversize_amsdu); + "Oversized AMSUs", pdev->oversize_amsdu); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "PHY errors", fw_stats->phy_errs); + "PHY errors", pdev->phy_errs); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "PHY errors drops", fw_stats->phy_err_drop); + "PHY errors drops", pdev->phy_err_drop); len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", - "MPDU errors (FCS, MIC, ENC)", fw_stats->mpdu_errs); + "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs); len += scnprintf(buf + len, buf_len - len, "\n"); - len += scnprintf(buf + len, buf_len - len, "%30s (%d)\n", - "ath10k PEER stats", fw_stats->peers); + len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", + "ath10k PEER stats", num_peers); len += scnprintf(buf + len, buf_len - len, "%30s\n\n", "================="); - for (i = 0; i < fw_stats->peers; i++) { + list_for_each_entry(peer, &fw_stats->peers, list) { len += scnprintf(buf + len, buf_len - len, "%30s %pM\n", - "Peer MAC address", - fw_stats->peer_stat[i].peer_macaddr); + "Peer MAC address", peer->peer_macaddr); len += scnprintf(buf + len, buf_len - len, "%30s %u\n", - "Peer RSSI", fw_stats->peer_stat[i].peer_rssi); + "Peer RSSI", peer->peer_rssi); len += scnprintf(buf + len, buf_len - len, "%30s %u\n", - "Peer TX rate", - fw_stats->peer_stat[i].peer_tx_rate); + "Peer TX rate", peer->peer_tx_rate); len += scnprintf(buf + len, buf_len - len, "%30s %u\n", - "Peer RX rate", - fw_stats->peer_stat[i].peer_rx_rate); + "Peer RX rate", peer->peer_rx_rate); len += scnprintf(buf + len, buf_len - len, "\n"); } + +unlock: spin_unlock_bh(&ar->data_lock); - if (len > buf_len) - len = buf_len; + if (len >= buf_len) + buf[len - 1] = 0; + else + buf[len] = 0; +} - ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); +static int ath10k_fw_stats_open(struct inode *inode, struct file *file) +{ + struct ath10k *ar = inode->i_private; + void *buf = NULL; + int ret; + + mutex_lock(&ar->conf_mutex); + + if (ar->state != ATH10K_STATE_ON) { + ret = -ENETDOWN; + goto err_unlock; + } + + buf = vmalloc(ATH10K_FW_STATS_BUF_SIZE); + if (!buf) { + ret = -ENOMEM; + goto err_unlock; + } + + ret = ath10k_debug_fw_stats_request(ar); + if (ret) { + ath10k_warn(ar, "failed to request fw stats: %d\n", ret); + goto err_free; + } + + ath10k_fw_stats_fill(ar, &ar->debug.fw_stats, buf); + file->private_data = buf; -exit: mutex_unlock(&ar->conf_mutex); - kfree(buf); - return ret_cnt; + return 0; + +err_free: + vfree(buf); + +err_unlock: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static int ath10k_fw_stats_release(struct inode *inode, struct file *file) +{ + vfree(file->private_data); + + return 0; +} + +static ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + const char *buf = file->private_data; + unsigned int len = strlen(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); } static const struct file_operations fops_fw_stats = { - .read = ath10k_read_fw_stats, + .open = ath10k_fw_stats_open, + .release = ath10k_fw_stats_release, + .read = ath10k_fw_stats_read, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + int ret, len, buf_len; + char *buf; + + buf_len = 500; + buf = kmalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + spin_lock_bh(&ar->data_lock); + + len = 0; + len += scnprintf(buf + len, buf_len - len, + "fw_crash_counter\t\t%d\n", ar->stats.fw_crash_counter); + len += scnprintf(buf + len, buf_len - len, + "fw_warm_reset_counter\t\t%d\n", + ar->stats.fw_warm_reset_counter); + len += scnprintf(buf + len, buf_len - len, + "fw_cold_reset_counter\t\t%d\n", + ar->stats.fw_cold_reset_counter); + + spin_unlock_bh(&ar->data_lock); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); + + kfree(buf); + + return ret; +} + +static const struct file_operations fops_fw_reset_stats = { .open = simple_open, + .read = ath10k_debug_fw_reset_stats_read, .owner = THIS_MODULE, .llseek = default_llseek, }; @@ -593,7 +695,8 @@ static ssize_t ath10k_read_simulate_fw_crash(struct file *file, "To simulate firmware crash write one of the keywords to this file:\n" "`soft` - this will send WMI_FORCE_FW_HANG_ASSERT to firmware if FW supports that command.\n" "`hard` - this will send to firmware command with illegal parameters causing firmware crash.\n" - "`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n"; + "`assert` - this will send special illegal parameter to firmware to cause assert failure and crash.\n" + "`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n"; return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); } @@ -646,6 +749,10 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, } else if (!strcmp(buf, "assert")) { ath10k_info(ar, "simulating firmware assert crash\n"); 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); + ret = 0; } else { ret = -EINVAL; goto exit; @@ -1029,6 +1136,166 @@ exit: return ret; } +/* TODO: Would be nice to always support ethtool stats, would need to + * move the stats storage out of ath10k_debug, or always have ath10k_debug + * struct available.. + */ + +/* This generally cooresponds to the debugfs fw_stats file */ +static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = { + "tx_pkts_nic", + "tx_bytes_nic", + "rx_pkts_nic", + "rx_bytes_nic", + "d_noise_floor", + "d_cycle_count", + "d_phy_error", + "d_rts_bad", + "d_rts_good", + "d_tx_power", /* in .5 dbM I think */ + "d_rx_crc_err", /* fcs_bad */ + "d_no_beacon", + "d_tx_mpdus_queued", + "d_tx_msdu_queued", + "d_tx_msdu_dropped", + "d_local_enqued", + "d_local_freed", + "d_tx_ppdu_hw_queued", + "d_tx_ppdu_reaped", + "d_tx_fifo_underrun", + "d_tx_ppdu_abort", + "d_tx_mpdu_requed", + "d_tx_excessive_retries", + "d_tx_hw_rate", + "d_tx_dropped_sw_retries", + "d_tx_illegal_rate", + "d_tx_continuous_xretries", + "d_tx_timeout", + "d_tx_mpdu_txop_limit", + "d_pdev_resets", + "d_rx_mid_ppdu_route_change", + "d_rx_status", + "d_rx_extra_frags_ring0", + "d_rx_extra_frags_ring1", + "d_rx_extra_frags_ring2", + "d_rx_extra_frags_ring3", + "d_rx_msdu_htt", + "d_rx_mpdu_htt", + "d_rx_msdu_stack", + "d_rx_mpdu_stack", + "d_rx_phy_err", + "d_rx_phy_err_drops", + "d_rx_mpdu_errors", /* FCS, MIC, ENC */ + "d_fw_crash_count", + "d_fw_warm_reset_count", + "d_fw_cold_reset_count", +}; + +#define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats) + +void ath10k_debug_get_et_strings(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 sset, u8 *data) +{ + if (sset == ETH_SS_STATS) + memcpy(data, *ath10k_gstrings_stats, + sizeof(ath10k_gstrings_stats)); +} + +int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int sset) +{ + if (sset == ETH_SS_STATS) + return ATH10K_SSTATS_LEN; + + return 0; +} + +void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ethtool_stats *stats, u64 *data) +{ + struct ath10k *ar = hw->priv; + static const struct ath10k_fw_stats_pdev zero_stats = {}; + const struct ath10k_fw_stats_pdev *pdev_stats; + int i = 0, ret; + + mutex_lock(&ar->conf_mutex); + + if (ar->state == ATH10K_STATE_ON) { + ret = ath10k_debug_fw_stats_request(ar); + if (ret) { + /* just print a warning and try to use older results */ + ath10k_warn(ar, + "failed to get fw stats for ethtool: %d\n", + ret); + } + } + + pdev_stats = list_first_entry_or_null(&ar->debug.fw_stats.pdevs, + struct ath10k_fw_stats_pdev, + list); + if (!pdev_stats) { + /* no results available so just return zeroes */ + pdev_stats = &zero_stats; + } + + spin_lock_bh(&ar->data_lock); + + data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */ + data[i++] = 0; /* tx bytes */ + data[i++] = pdev_stats->htt_mpdus; + data[i++] = 0; /* rx bytes */ + data[i++] = pdev_stats->ch_noise_floor; + data[i++] = pdev_stats->cycle_count; + data[i++] = pdev_stats->phy_err_count; + data[i++] = pdev_stats->rts_bad; + data[i++] = pdev_stats->rts_good; + data[i++] = pdev_stats->chan_tx_power; + data[i++] = pdev_stats->fcs_bad; + data[i++] = pdev_stats->no_beacons; + data[i++] = pdev_stats->mpdu_enqued; + data[i++] = pdev_stats->msdu_enqued; + data[i++] = pdev_stats->wmm_drop; + data[i++] = pdev_stats->local_enqued; + data[i++] = pdev_stats->local_freed; + data[i++] = pdev_stats->hw_queued; + data[i++] = pdev_stats->hw_reaped; + data[i++] = pdev_stats->underrun; + data[i++] = pdev_stats->tx_abort; + data[i++] = pdev_stats->mpdus_requed; + data[i++] = pdev_stats->tx_ko; + data[i++] = pdev_stats->data_rc; + data[i++] = pdev_stats->sw_retry_failure; + data[i++] = pdev_stats->illgl_rate_phy_err; + data[i++] = pdev_stats->pdev_cont_xretry; + data[i++] = pdev_stats->pdev_tx_timeout; + data[i++] = pdev_stats->txop_ovf; + data[i++] = pdev_stats->pdev_resets; + data[i++] = pdev_stats->mid_ppdu_route_change; + data[i++] = pdev_stats->status_rcvd; + data[i++] = pdev_stats->r0_frags; + data[i++] = pdev_stats->r1_frags; + data[i++] = pdev_stats->r2_frags; + data[i++] = pdev_stats->r3_frags; + data[i++] = pdev_stats->htt_msdus; + data[i++] = pdev_stats->htt_mpdus; + data[i++] = pdev_stats->loc_msdus; + data[i++] = pdev_stats->loc_mpdus; + data[i++] = pdev_stats->phy_errs; + data[i++] = pdev_stats->phy_err_drop; + data[i++] = pdev_stats->mpdu_errs; + data[i++] = ar->stats.fw_crash_counter; + data[i++] = ar->stats.fw_warm_reset_counter; + data[i++] = ar->stats.fw_cold_reset_counter; + + spin_unlock_bh(&ar->data_lock); + + mutex_unlock(&ar->conf_mutex); + + WARN_ON(i != ATH10K_SSTATS_LEN); +} + static const struct file_operations fops_fw_dbglog = { .read = ath10k_read_fw_dbglog, .write = ath10k_write_fw_dbglog, @@ -1037,6 +1304,84 @@ static const struct file_operations fops_fw_dbglog = { .llseek = default_llseek, }; +static int ath10k_debug_cal_data_open(struct inode *inode, struct file *file) +{ + struct ath10k *ar = inode->i_private; + void *buf; + u32 hi_addr; + __le32 addr; + int ret; + + mutex_lock(&ar->conf_mutex); + + if (ar->state != ATH10K_STATE_ON && + ar->state != ATH10K_STATE_UTF) { + ret = -ENETDOWN; + goto err; + } + + buf = vmalloc(QCA988X_CAL_DATA_LEN); + if (!buf) { + ret = -ENOMEM; + goto err; + } + + hi_addr = host_interest_item_address(HI_ITEM(hi_board_data)); + + ret = ath10k_hif_diag_read(ar, hi_addr, &addr, sizeof(addr)); + if (ret) { + ath10k_warn(ar, "failed to read hi_board_data address: %d\n", ret); + goto err_vfree; + } + + ret = ath10k_hif_diag_read(ar, le32_to_cpu(addr), buf, + QCA988X_CAL_DATA_LEN); + if (ret) { + ath10k_warn(ar, "failed to read calibration data: %d\n", ret); + goto err_vfree; + } + + file->private_data = buf; + + mutex_unlock(&ar->conf_mutex); + + return 0; + +err_vfree: + vfree(buf); + +err: + mutex_unlock(&ar->conf_mutex); + + return ret; +} + +static ssize_t ath10k_debug_cal_data_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + void *buf = file->private_data; + + return simple_read_from_buffer(user_buf, count, ppos, + buf, QCA988X_CAL_DATA_LEN); +} + +static int ath10k_debug_cal_data_release(struct inode *inode, + struct file *file) +{ + vfree(file->private_data); + + return 0; +} + +static const struct file_operations fops_cal_data = { + .open = ath10k_debug_cal_data_open, + .read = ath10k_debug_cal_data_read, + .release = ath10k_debug_cal_data_release, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath10k_debug_start(struct ath10k *ar) { int ret; @@ -1057,7 +1402,22 @@ int ath10k_debug_start(struct ath10k *ar) ret); } - return 0; + if (ar->debug.pktlog_filter) { + ret = ath10k_wmi_pdev_pktlog_enable(ar, + ar->debug.pktlog_filter); + if (ret) + /* not serious */ + ath10k_warn(ar, + "failed to enable pktlog filter %x: %d\n", + ar->debug.pktlog_filter, ret); + } else { + ret = ath10k_wmi_pdev_pktlog_disable(ar); + if (ret) + /* not serious */ + ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); + } + + return ret; } void ath10k_debug_stop(struct ath10k *ar) @@ -1072,6 +1432,8 @@ void ath10k_debug_stop(struct ath10k *ar) ar->debug.htt_max_amsdu = 0; ar->debug.htt_max_ampdu = 0; + + ath10k_wmi_pdev_pktlog_disable(ar); } static ssize_t ath10k_write_simulate_radar(struct file *file, @@ -1154,12 +1516,78 @@ static const struct file_operations fops_dfs_stats = { .llseek = default_llseek, }; +static ssize_t ath10k_write_pktlog_filter(struct file *file, + const char __user *ubuf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + u32 filter; + int ret; + + if (kstrtouint_from_user(ubuf, count, 0, &filter)) + return -EINVAL; + + mutex_lock(&ar->conf_mutex); + + if (ar->state != ATH10K_STATE_ON) { + ar->debug.pktlog_filter = filter; + ret = count; + goto out; + } + + if (filter && (filter != ar->debug.pktlog_filter)) { + ret = ath10k_wmi_pdev_pktlog_enable(ar, filter); + if (ret) { + ath10k_warn(ar, "failed to enable pktlog filter %x: %d\n", + ar->debug.pktlog_filter, ret); + goto out; + } + } else { + ret = ath10k_wmi_pdev_pktlog_disable(ar); + if (ret) { + ath10k_warn(ar, "failed to disable pktlog: %d\n", ret); + goto out; + } + } + + ar->debug.pktlog_filter = filter; + ret = count; + +out: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static ssize_t ath10k_read_pktlog_filter(struct file *file, char __user *ubuf, + size_t count, loff_t *ppos) +{ + char buf[32]; + struct ath10k *ar = file->private_data; + int len = 0; + + mutex_lock(&ar->conf_mutex); + len = scnprintf(buf, sizeof(buf) - len, "%08x\n", + ar->debug.pktlog_filter); + mutex_unlock(&ar->conf_mutex); + + return simple_read_from_buffer(ubuf, count, ppos, buf, len); +} + +static const struct file_operations fops_pktlog_filter = { + .read = ath10k_read_pktlog_filter, + .write = ath10k_write_pktlog_filter, + .open = simple_open +}; + int ath10k_debug_create(struct ath10k *ar) { ar->debug.fw_crash_data = vzalloc(sizeof(*ar->debug.fw_crash_data)); if (!ar->debug.fw_crash_data) return -ENOMEM; + INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs); + INIT_LIST_HEAD(&ar->debug.fw_stats.peers); + return 0; } @@ -1167,6 +1595,8 @@ void ath10k_debug_destroy(struct ath10k *ar) { vfree(ar->debug.fw_crash_data); ar->debug.fw_crash_data = NULL; + + ath10k_debug_fw_stats_reset(ar); } int ath10k_debug_register(struct ath10k *ar) @@ -1183,11 +1613,14 @@ int ath10k_debug_register(struct ath10k *ar) INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork, ath10k_debug_htt_stats_dwork); - init_completion(&ar->debug.event_stats_compl); + init_completion(&ar->debug.fw_stats_complete); debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_fw_stats); + debugfs_create_file("fw_reset_stats", S_IRUSR, ar->debug.debugfs_phy, + ar, &fops_fw_reset_stats); + debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_wmi_services); @@ -1210,6 +1643,9 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy, ar, &fops_fw_dbglog); + debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy, + ar, &fops_cal_data); + if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) { debugfs_create_file("dfs_simulate_radar", S_IWUSR, ar->debug.debugfs_phy, ar, @@ -1224,6 +1660,9 @@ int ath10k_debug_register(struct ath10k *ar) &fops_dfs_stats); } + debugfs_create_file("pktlog_filter", S_IRUGO | S_IWUSR, + ar->debug.debugfs_phy, ar, &fops_pktlog_filter); + return 0; } @@ -1260,11 +1699,26 @@ void ath10k_dbg_dump(struct ath10k *ar, const char *msg, const char *prefix, const void *buf, size_t len) { + char linebuf[256]; + unsigned int linebuflen; + const void *ptr; + if (ath10k_debug_mask & mask) { if (msg) ath10k_dbg(ar, mask, "%s\n", msg); - print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); + for (ptr = buf; (ptr - buf) < len; ptr += 16) { + linebuflen = 0; + linebuflen += scnprintf(linebuf + linebuflen, + sizeof(linebuf) - linebuflen, + "%s%08x: ", + (prefix ? prefix : ""), + (unsigned int)(ptr - buf)); + hex_dump_to_buffer(ptr, len - (ptr - buf), 16, 1, + linebuf + linebuflen, + sizeof(linebuf) - linebuflen, true); + dev_printk(KERN_DEBUG, ar->dev, "%s\n", linebuf); + } } /* tracing code doesn't like null strings :/ */ diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index b3774f7..0c934a8 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -38,11 +38,20 @@ enum ath10k_debug_mask { ATH10K_DBG_ANY = 0xffffffff, }; +enum ath10k_pktlog_filter { + ATH10K_PKTLOG_RX = 0x000000001, + ATH10K_PKTLOG_TX = 0x000000002, + ATH10K_PKTLOG_RCFIND = 0x000000004, + ATH10K_PKTLOG_RCUPDATE = 0x000000008, + ATH10K_PKTLOG_DBG_PRINT = 0x000000010, + ATH10K_PKTLOG_ANY = 0x00000001f, +}; + extern unsigned int ath10k_debug_mask; -__printf(2, 3) int ath10k_info(struct ath10k *ar, const char *fmt, ...); -__printf(2, 3) int ath10k_err(struct ath10k *ar, const char *fmt, ...); -__printf(2, 3) int ath10k_warn(struct ath10k *ar, const char *fmt, ...); +__printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...); +__printf(2, 3) void ath10k_err(struct ath10k *ar, const char *fmt, ...); +__printf(2, 3) void ath10k_warn(struct ath10k *ar, const char *fmt, ...); void ath10k_print_driver_info(struct ath10k *ar); #ifdef CONFIG_ATH10K_DEBUGFS @@ -53,17 +62,24 @@ void ath10k_debug_destroy(struct ath10k *ar); int ath10k_debug_register(struct ath10k *ar); void ath10k_debug_unregister(struct ath10k *ar); void ath10k_debug_read_service_map(struct ath10k *ar, - void *service_map, + const void *service_map, size_t map_size); -void ath10k_debug_read_target_stats(struct ath10k *ar, - struct wmi_stats_event *ev); +void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb); struct ath10k_fw_crash_data * ath10k_debug_get_new_fw_crash_data(struct ath10k *ar); void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len); - #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) +void ath10k_debug_get_et_strings(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u32 sset, u8 *data); +int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int sset); +void ath10k_debug_get_et_stats(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ethtool_stats *stats, u64 *data); + #else static inline int ath10k_debug_start(struct ath10k *ar) { @@ -93,13 +109,13 @@ static inline void ath10k_debug_unregister(struct ath10k *ar) } static inline void ath10k_debug_read_service_map(struct ath10k *ar, - void *service_map, + const void *service_map, size_t map_size) { } -static inline void ath10k_debug_read_target_stats(struct ath10k *ar, - struct wmi_stats_event *ev) +static inline void ath10k_debug_fw_stats_process(struct ath10k *ar, + struct sk_buff *skb) { } @@ -116,6 +132,10 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar) #define ATH10K_DFS_STAT_INC(ar, c) do { } while (0) +#define ath10k_debug_get_et_strings NULL +#define ath10k_debug_get_et_sset_count NULL +#define ath10k_debug_get_et_stats NULL + #endif /* CONFIG_ATH10K_DEBUGFS */ #ifdef CONFIG_ATH10K_DEBUG diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 62323fe..30301f5 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -43,6 +43,10 @@ struct ath10k_hif_ops { int (*tx_sg)(struct ath10k *ar, u8 pipe_id, struct ath10k_hif_sg_item *items, int n_items); + /* read firmware memory through the diagnose interface */ + int (*diag_read)(struct ath10k *ar, u32 address, void *buf, + size_t buf_len); + /* * API to handle HIF-specific BMI message exchanges, this API is * synchronous and only allowed to be called from a context that @@ -98,6 +102,12 @@ static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id, return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items); } +static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf, + size_t buf_len) +{ + return ar->hif.ops->diag_read(ar, address, buf, buf_len); +} + static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar, void *request, u32 request_len, void *response, u32 *response_len) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 3b44217..15c58e8 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -725,7 +725,7 @@ static inline u8 *htt_rx_test_get_chars(struct htt_rx_test *rx_test) */ struct htt_pktlog_msg { u8 pad[3]; - __le32 payload[1 /* or more */]; + u8 payload[0]; } __packed; struct htt_dbg_stats_rx_reorder_stats { diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 60d40a0..52c6306 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -291,6 +291,13 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt) htt->rx_ring.sw_rd_idx.msdu_payld = idx; htt->rx_ring.fill_cnt--; + dma_unmap_single(htt->ar->dev, + ATH10K_SKB_CB(msdu)->paddr, + msdu->len + skb_tailroom(msdu), + DMA_FROM_DEVICE); + ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ", + msdu->data, msdu->len + skb_tailroom(msdu)); + return msdu; } @@ -328,14 +335,6 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, while (msdu) { int last_msdu, msdu_len_invalid, msdu_chained; - dma_unmap_single(htt->ar->dev, - ATH10K_SKB_CB(msdu)->paddr, - msdu->len + skb_tailroom(msdu), - DMA_FROM_DEVICE); - - ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx pop: ", - msdu->data, msdu->len + skb_tailroom(msdu)); - rx_desc = (struct htt_rx_desc *)msdu->data; /* FIXME: we must report msdu payload since this is what caller @@ -426,14 +425,14 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, while (msdu_chained--) { struct sk_buff *next = ath10k_htt_rx_netbuf_pop(htt); - dma_unmap_single(htt->ar->dev, - ATH10K_SKB_CB(next)->paddr, - next->len + skb_tailroom(next), - DMA_FROM_DEVICE); - - ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, - "htt rx chained: ", next->data, - next->len + skb_tailroom(next)); + if (!next) { + ath10k_warn(ar, "failed to pop chained msdu\n"); + ath10k_htt_rx_free_msdu_chain(*head_msdu); + *head_msdu = NULL; + msdu = NULL; + htt->rx_confused = true; + break; + } skb_trim(next, 0); skb_put(next, min(msdu_len, HTT_RX_BUF_SIZE)); @@ -447,6 +446,8 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & RX_MSDU_END_INFO0_LAST_MSDU; + trace_ath10k_htt_rx_desc(ar, &rx_desc->attention, + sizeof(*rx_desc) - sizeof(u32)); if (last_msdu) { msdu->next = NULL; break; @@ -492,6 +493,8 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt) size_t size; struct timer_list *timer = &htt->rx_ring.refill_retry_timer; + htt->rx_confused = false; + htt->rx_ring.size = ath10k_htt_rx_ring_size(htt); if (!is_power_of_2(htt->rx_ring.size)) { ath10k_warn(ar, "htt rx ring size is not power of 2\n"); @@ -581,41 +584,47 @@ static int ath10k_htt_rx_crypto_param_len(struct ath10k *ar, enum htt_rx_mpdu_encrypt_type type) { switch (type) { + case HTT_RX_MPDU_ENCRYPT_NONE: + return 0; case HTT_RX_MPDU_ENCRYPT_WEP40: case HTT_RX_MPDU_ENCRYPT_WEP104: - return 4; + return IEEE80211_WEP_IV_LEN; case HTT_RX_MPDU_ENCRYPT_TKIP_WITHOUT_MIC: - case HTT_RX_MPDU_ENCRYPT_WEP128: /* not tested */ case HTT_RX_MPDU_ENCRYPT_TKIP_WPA: - case HTT_RX_MPDU_ENCRYPT_WAPI: /* not tested */ + return IEEE80211_TKIP_IV_LEN; case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2: - return 8; - case HTT_RX_MPDU_ENCRYPT_NONE: - return 0; + return IEEE80211_CCMP_HDR_LEN; + case HTT_RX_MPDU_ENCRYPT_WEP128: + case HTT_RX_MPDU_ENCRYPT_WAPI: + break; } - ath10k_warn(ar, "unknown encryption type %d\n", type); + ath10k_warn(ar, "unsupported encryption type %d\n", type); return 0; } +#define MICHAEL_MIC_LEN 8 + static int ath10k_htt_rx_crypto_tail_len(struct ath10k *ar, enum htt_rx_mpdu_encrypt_type type) { switch (type) { case HTT_RX_MPDU_ENCRYPT_NONE: + return 0; case HTT_RX_MPDU_ENCRYPT_WEP40: case HTT_RX_MPDU_ENCRYPT_WEP104: - case HTT_RX_MPDU_ENCRYPT_WEP128: - case HTT_RX_MPDU_ENCRYPT_WAPI: - return 0; + return IEEE80211_WEP_ICV_LEN; case HTT_RX_MPDU_ENCRYPT_TKIP_WITHOUT_MIC: case HTT_RX_MPDU_ENCRYPT_TKIP_WPA: - return 4; + return IEEE80211_TKIP_ICV_LEN; case HTT_RX_MPDU_ENCRYPT_AES_CCM_WPA2: - return 8; + return IEEE80211_CCMP_MIC_LEN; + case HTT_RX_MPDU_ENCRYPT_WEP128: + case HTT_RX_MPDU_ENCRYPT_WAPI: + break; } - ath10k_warn(ar, "unknown encryption type %d\n", type); + ath10k_warn(ar, "unsupported encryption type %d\n", type); return 0; } @@ -892,6 +901,8 @@ static void ath10k_process_rx(struct ath10k *ar, !!(status->flag & RX_FLAG_AMSDU_MORE)); ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ", skb->data, skb->len); + trace_ath10k_rx_hdr(ar, skb->data, skb->len); + trace_ath10k_rx_payload(ar, skb->data, skb->len); ieee80211_rx(ar->hw, skb); } @@ -1169,7 +1180,6 @@ static int ath10k_unchain_msdu(struct sk_buff *msdu_head) static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt, struct sk_buff *head, - enum htt_rx_mpdu_status status, bool channel_set, u32 attention) { @@ -1193,22 +1203,11 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k_htt *htt, } /* Skip mgmt frames while we handle this in WMI */ - if (status == HTT_RX_IND_MPDU_STATUS_MGMT_CTRL || - attention & RX_ATTENTION_FLAGS_MGMT_TYPE) { + if (attention & RX_ATTENTION_FLAGS_MGMT_TYPE) { ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx mgmt ctrl\n"); return false; } - if (status != HTT_RX_IND_MPDU_STATUS_OK && - status != HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR && - status != HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER && - !htt->ar->monitor_started) { - ath10k_dbg(ar, ATH10K_DBG_HTT, - "htt rx ignoring frame w/ status %d\n", - status); - return false; - } - if (test_bit(ATH10K_CAC_RUNNING, &htt->ar->dev_flags)) { ath10k_dbg(ar, ATH10K_DBG_HTT, "htt rx CAC running\n"); @@ -1224,8 +1223,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, struct ath10k *ar = htt->ar; struct ieee80211_rx_status *rx_status = &htt->rx_status; struct htt_rx_indication_mpdu_range *mpdu_ranges; - struct htt_rx_desc *rxd; - enum htt_rx_mpdu_status status; struct ieee80211_hdr *hdr; int num_mpdu_ranges; u32 attention; @@ -1273,8 +1270,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, num_mpdu_ranges)); for (i = 0; i < num_mpdu_ranges; i++) { - status = mpdu_ranges[i].mpdu_range_status; - for (j = 0; j < mpdu_ranges[i].mpdu_count; j++) { struct sk_buff *msdu_head, *msdu_tail; @@ -1295,12 +1290,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt, continue; } - rxd = container_of((void *)msdu_head->data, - struct htt_rx_desc, - msdu_payload); - if (!ath10k_htt_rx_amsdu_allowed(htt, msdu_head, - status, channel_set, attention)) { ath10k_htt_rx_free_msdu_chain(msdu_head); @@ -1365,6 +1355,8 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, &attention); spin_unlock_bh(&htt->rx_ring.lock); + tasklet_schedule(&htt->rx_replenish_task); + ath10k_dbg(ar, ATH10K_DBG_HTT_DUMP, "htt rx frag ahead\n"); if (ret) { @@ -1426,7 +1418,7 @@ static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, /* last fragment of TKIP frags has MIC */ if (!ieee80211_has_morefrags(hdr->frame_control) && enctype == HTT_RX_MPDU_ENCRYPT_TKIP_WPA) - trim += 8; + trim += MICHAEL_MIC_LEN; if (trim > msdu_head->len) { ath10k_warn(ar, "htt rx fragment: trailer longer than the frame itself? drop\n"); @@ -1674,6 +1666,15 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) case HTT_T2H_MSG_TYPE_RX_DELBA: ath10k_htt_rx_delba(ar, resp); break; + case HTT_T2H_MSG_TYPE_PKTLOG: { + struct ath10k_pktlog_hdr *hdr = + (struct ath10k_pktlog_hdr *)resp->pktlog_msg.payload; + + trace_ath10k_htt_pktlog(ar, resp->pktlog_msg.payload, + sizeof(*hdr) + + __le16_to_cpu(hdr->size)); + break; + } case HTT_T2H_MSG_TYPE_RX_FLUSH: { /* Ignore this event because mac80211 takes care of Rx * aggregation reordering. @@ -1681,8 +1682,8 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; } default: - ath10k_dbg(ar, ATH10K_DBG_HTT, "htt event (%d) not handled\n", - resp->hdr.msg_type); + ath10k_warn(ar, "htt event (%d) not handled\n", + resp->hdr.msg_type); ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ", skb->data, skb->len); break; diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index bd87a35..5b7e42f 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -92,7 +92,6 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) struct ath10k *ar = htt->ar; spin_lock_init(&htt->tx_lock); - init_waitqueue_head(&htt->empty_tx_wq); if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features)) htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; @@ -557,12 +556,15 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->htt.txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le32(HTT_INVALID_PEERID); + trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid); ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu\n", flags0, flags1, msdu->len, msdu_id, frags_paddr, (u32)skb_cb->paddr, vdev_id, tid); ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", msdu->data, msdu->len); + trace_ath10k_tx_hdr(ar, msdu->data, msdu->len); + trace_ath10k_tx_payload(ar, msdu->data, msdu->len); sg_items[0].transfer_id = 0; sg_items[0].transfer_context = NULL; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 3cf5702..392c250 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -20,15 +20,16 @@ #include "targaddrs.h" +#define ATH10K_FW_DIR "ath10k" + /* QCA988X 1.0 definitions (unsupported) */ #define QCA988X_HW_1_0_CHIP_ID_REV 0x0 /* QCA988X 2.0 definitions */ #define QCA988X_HW_2_0_VERSION 0x4100016c #define QCA988X_HW_2_0_CHIP_ID_REV 0x2 -#define QCA988X_HW_2_0_FW_DIR "ath10k/QCA988X/hw2.0" +#define QCA988X_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA988X/hw2.0" #define QCA988X_HW_2_0_FW_FILE "firmware.bin" -#define QCA988X_HW_2_0_FW_3_FILE "firmware-3.bin" #define QCA988X_HW_2_0_OTP_FILE "otp.bin" #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin" #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234 @@ -43,6 +44,8 @@ #define REG_DUMP_COUNT_QCA988X 60 +#define QCA988X_CAL_DATA_LEN 2116 + struct ath10k_fw_ie { __le32 id; __le32 len; @@ -78,6 +81,15 @@ enum ath10k_mcast2ucast_mode { ATH10K_MCAST2UCAST_ENABLED = 1, }; +struct ath10k_pktlog_hdr { + __le16 flags; + __le16 missed_cnt; + __le16 log_type; + __le16 size; + __le32 timestamp; + u8 payload[0]; +} __packed; + /* Target specific defines for MAIN firmware */ #define TARGET_NUM_VDEVS 8 #define TARGET_NUM_PEER_AST 2 @@ -279,6 +291,7 @@ enum ath10k_mcast2ucast_mode { #define SI_RX_DATA1_OFFSET 0x00000014 #define CORE_CTRL_CPU_INTR_MASK 0x00002000 +#define CORE_CTRL_PCIE_REG_31_MASK 0x00000800 #define CORE_CTRL_ADDRESS 0x0000 #define PCIE_INTR_ENABLE_ADDRESS 0x0008 #define PCIE_INTR_CAUSE_ADDRESS 0x000c diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 4670930..1245ac8 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -479,12 +479,49 @@ static void ath10k_peer_cleanup_all(struct ath10k *ar) /* Interface management */ /************************/ +void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + + lockdep_assert_held(&ar->data_lock); + + if (!arvif->beacon) + return; + + if (!arvif->beacon_buf) + dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr, + arvif->beacon->len, DMA_TO_DEVICE); + + dev_kfree_skb_any(arvif->beacon); + + arvif->beacon = NULL; + arvif->beacon_sent = false; +} + +static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif) +{ + struct ath10k *ar = arvif->ar; + + lockdep_assert_held(&ar->data_lock); + + ath10k_mac_vif_beacon_free(arvif); + + if (arvif->beacon_buf) { + dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN, + arvif->beacon_buf, arvif->beacon_paddr); + arvif->beacon_buf = NULL; + } +} + static inline int ath10k_vdev_setup_sync(struct ath10k *ar) { int ret; lockdep_assert_held(&ar->conf_mutex); + if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) + return -ESHUTDOWN; + ret = wait_for_completion_timeout(&ar->vdev_setup_done, ATH10K_VDEV_SETUP_TIMEOUT_HZ); if (ret == 0) @@ -517,6 +554,8 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) arg.channel.max_reg_power = channel->max_reg_power * 2; arg.channel.max_antenna_gain = channel->max_antenna_gain * 2; + reinit_completion(&ar->vdev_setup_done); + ret = ath10k_wmi_vdev_start(ar, &arg); if (ret) { ath10k_warn(ar, "failed to request monitor vdev %i start: %d\n", @@ -564,6 +603,8 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar) ath10k_warn(ar, "failed to put down monitor vdev %i: %d\n", ar->monitor_vdev_id, ret); + reinit_completion(&ar->vdev_setup_done); + ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n", @@ -590,9 +631,9 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar) return -ENOMEM; } - bit = ffs(ar->free_vdev_map); + bit = __ffs64(ar->free_vdev_map); - ar->monitor_vdev_id = bit - 1; + ar->monitor_vdev_id = bit; ret = ath10k_wmi_vdev_create(ar, ar->monitor_vdev_id, WMI_VDEV_TYPE_MONITOR, @@ -603,7 +644,7 @@ static int ath10k_monitor_vdev_create(struct ath10k *ar) return ret; } - ar->free_vdev_map &= ~(1 << ar->monitor_vdev_id); + ar->free_vdev_map &= ~(1LL << ar->monitor_vdev_id); ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d created\n", ar->monitor_vdev_id); @@ -623,7 +664,7 @@ static int ath10k_monitor_vdev_delete(struct ath10k *ar) return ret; } - ar->free_vdev_map |= 1 << ar->monitor_vdev_id; + ar->free_vdev_map |= 1LL << ar->monitor_vdev_id; ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n", ar->monitor_vdev_id); @@ -909,15 +950,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif, arvif->is_up = false; spin_lock_bh(&arvif->ar->data_lock); - if (arvif->beacon) { - dma_unmap_single(arvif->ar->dev, - ATH10K_SKB_CB(arvif->beacon)->paddr, - arvif->beacon->len, DMA_TO_DEVICE); - dev_kfree_skb_any(arvif->beacon); - - arvif->beacon = NULL; - arvif->beacon_sent = false; - } + ath10k_mac_vif_beacon_free(arvif); spin_unlock_bh(&arvif->ar->data_lock); return; @@ -966,14 +999,6 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif, if (is_zero_ether_addr(arvif->bssid)) return; - ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, - arvif->bssid); - if (ret) { - ath10k_warn(ar, "failed to delete IBSS BSSID peer %pM for vdev %d: %d\n", - arvif->bssid, arvif->vdev_id, ret); - return; - } - memset(arvif->bssid, 0, ETH_ALEN); return; @@ -1042,51 +1067,45 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) /* Station management */ /**********************/ +static u32 ath10k_peer_assoc_h_listen_intval(struct ath10k *ar, + struct ieee80211_vif *vif) +{ + /* Some firmware revisions have unstable STA powersave when listen + * interval is set too high (e.g. 5). The symptoms are firmware doesn't + * generate NullFunc frames properly even if buffered frames have been + * indicated in Beacon TIM. Firmware would seldom wake up to pull + * buffered frames. Often pinging the device from AP would simply fail. + * + * As a workaround set it to 1. + */ + if (vif->type == NL80211_IFTYPE_STATION) + return 1; + + return ar->hw->conf.listen_interval; +} + static void ath10k_peer_assoc_h_basic(struct ath10k *ar, - struct ath10k_vif *arvif, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_bss_conf *bss_conf, struct wmi_peer_assoc_complete_arg *arg) { + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + lockdep_assert_held(&ar->conf_mutex); ether_addr_copy(arg->addr, sta->addr); arg->vdev_id = arvif->vdev_id; arg->peer_aid = sta->aid; arg->peer_flags |= WMI_PEER_AUTH; - - if (arvif->vdev_type == WMI_VDEV_TYPE_STA) - /* - * Seems FW have problems with Power Save in STA - * mode when we setup this parameter to high (eg. 5). - * Often we see that FW don't send NULL (with clean P flags) - * frame even there is info about buffered frames in beacons. - * Sometimes we have to wait more than 10 seconds before FW - * will wakeup. Often sending one ping from AP to our device - * just fail (more than 50%). - * - * Seems setting this FW parameter to 1 couse FW - * will check every beacon and will wakup immediately - * after detection buffered data. - */ - arg->peer_listen_intval = 1; - else - arg->peer_listen_intval = ar->hw->conf.listen_interval; - + arg->peer_listen_intval = ath10k_peer_assoc_h_listen_intval(ar, vif); arg->peer_num_spatial_streams = 1; - - /* - * The assoc capabilities are available only in managed mode. - */ - if (arvif->vdev_type == WMI_VDEV_TYPE_STA && bss_conf) - arg->peer_caps = bss_conf->assoc_capability; + arg->peer_caps = vif->bss_conf.assoc_capability; } static void ath10k_peer_assoc_h_crypto(struct ath10k *ar, - struct ath10k_vif *arvif, + struct ieee80211_vif *vif, struct wmi_peer_assoc_complete_arg *arg) { - struct ieee80211_vif *vif = arvif->vif; struct ieee80211_bss_conf *info = &vif->bss_conf; struct cfg80211_bss *bss; const u8 *rsnie = NULL; @@ -1343,11 +1362,12 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, } static void ath10k_peer_assoc_h_qos(struct ath10k *ar, - struct ath10k_vif *arvif, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_bss_conf *bss_conf, struct wmi_peer_assoc_complete_arg *arg) { + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + switch (arvif->vdev_type) { case WMI_VDEV_TYPE_AP: if (sta->wme) @@ -1359,7 +1379,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, } break; case WMI_VDEV_TYPE_STA: - if (bss_conf->qos) + if (vif->bss_conf.qos) arg->peer_flags |= WMI_PEER_QOS; break; default: @@ -1368,7 +1388,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, } static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, - struct ath10k_vif *arvif, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct wmi_peer_assoc_complete_arg *arg) { @@ -1419,22 +1439,21 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar, } static int ath10k_peer_assoc_prepare(struct ath10k *ar, - struct ath10k_vif *arvif, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_bss_conf *bss_conf, struct wmi_peer_assoc_complete_arg *arg) { lockdep_assert_held(&ar->conf_mutex); memset(arg, 0, sizeof(*arg)); - ath10k_peer_assoc_h_basic(ar, arvif, sta, bss_conf, arg); - ath10k_peer_assoc_h_crypto(ar, arvif, arg); + ath10k_peer_assoc_h_basic(ar, vif, sta, arg); + ath10k_peer_assoc_h_crypto(ar, vif, arg); ath10k_peer_assoc_h_rates(ar, sta, arg); ath10k_peer_assoc_h_ht(ar, sta, arg); ath10k_peer_assoc_h_vht(ar, sta, arg); - ath10k_peer_assoc_h_qos(ar, arvif, sta, bss_conf, arg); - ath10k_peer_assoc_h_phymode(ar, arvif, sta, arg); + ath10k_peer_assoc_h_qos(ar, vif, sta, arg); + ath10k_peer_assoc_h_phymode(ar, vif, sta, arg); return 0; } @@ -1480,6 +1499,9 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, lockdep_assert_held(&ar->conf_mutex); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i assoc bssid %pM aid %d\n", + arvif->vdev_id, arvif->bssid, arvif->aid); + rcu_read_lock(); ap_sta = ieee80211_find_sta(vif, bss_conf->bssid); @@ -1494,8 +1516,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, * before calling ath10k_setup_peer_smps() which might sleep. */ ht_cap = ap_sta->ht_cap; - ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta, - bss_conf, &peer_arg); + ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg); if (ret) { ath10k_warn(ar, "failed to prepare peer assoc for %pM vdev %i: %d\n", bss_conf->bssid, arvif->vdev_id, ret); @@ -1523,6 +1544,8 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, "mac vdev %d up (associated) bssid %pM aid %d\n", arvif->vdev_id, bss_conf->bssid, bss_conf->aid); + WARN_ON(arvif->is_up); + arvif->aid = bss_conf->aid; ether_addr_copy(arvif->bssid, bss_conf->bssid); @@ -1536,9 +1559,6 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, arvif->is_up = true; } -/* - * FIXME: flush TIDs - */ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -1548,45 +1568,30 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, lockdep_assert_held(&ar->conf_mutex); - /* - * For some reason, calling VDEV-DOWN before VDEV-STOP - * makes the FW to send frames via HTT after disassociation. - * No idea why this happens, even though VDEV-DOWN is supposed - * to be analogous to link down, so just stop the VDEV. - */ - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n", - arvif->vdev_id); - - /* FIXME: check return value */ - ret = ath10k_vdev_stop(arvif); + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %i disassoc bssid %pM\n", + arvif->vdev_id, arvif->bssid); - /* - * If we don't call VDEV-DOWN after VDEV-STOP FW will remain active and - * report beacons from previously associated network through HTT. - * This in turn would spam mac80211 WARN_ON if we bring down all - * interfaces as it expects there is no rx when no interface is - * running. - */ - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id); - - /* FIXME: why don't we print error if wmi call fails? */ ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id); + if (ret) + ath10k_warn(ar, "faield to down vdev %i: %d\n", + arvif->vdev_id, ret); arvif->def_wep_key_idx = 0; - - arvif->is_started = false; arvif->is_up = false; } -static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, - struct ieee80211_sta *sta, bool reassoc) +static int ath10k_station_assoc(struct ath10k *ar, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + bool reassoc) { + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct wmi_peer_assoc_complete_arg peer_arg; int ret = 0; lockdep_assert_held(&ar->conf_mutex); - ret = ath10k_peer_assoc_prepare(ar, arvif, sta, NULL, &peer_arg); + ret = ath10k_peer_assoc_prepare(ar, vif, sta, &peer_arg); if (ret) { ath10k_warn(ar, "failed to prepare WMI peer assoc for %pM vdev %i: %i\n", sta->addr, arvif->vdev_id, ret); @@ -1601,43 +1606,51 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif, return ret; } - ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap); - if (ret) { - ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n", - arvif->vdev_id, ret); - return ret; - } - - if (!sta->wme && !reassoc) { - arvif->num_legacy_stations++; - ret = ath10k_recalc_rtscts_prot(arvif); + /* Re-assoc is run only to update supported rates for given station. It + * doesn't make much sense to reconfigure the peer completely. + */ + if (!reassoc) { + ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, + &sta->ht_cap); if (ret) { - ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", + ath10k_warn(ar, "failed to setup peer SMPS for vdev %d: %d\n", arvif->vdev_id, ret); return ret; } - } - ret = ath10k_install_peer_wep_keys(arvif, sta->addr); - if (ret) { - ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", - arvif->vdev_id, ret); - return ret; - } + ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta); + if (ret) { + ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n", + sta->addr, arvif->vdev_id, ret); + return ret; + } - ret = ath10k_peer_assoc_qos_ap(ar, arvif, sta); - if (ret) { - ath10k_warn(ar, "failed to set qos params for STA %pM for vdev %i: %d\n", - sta->addr, arvif->vdev_id, ret); - return ret; + if (!sta->wme) { + arvif->num_legacy_stations++; + ret = ath10k_recalc_rtscts_prot(arvif); + if (ret) { + ath10k_warn(ar, "failed to recalculate rts/cts prot for vdev %d: %d\n", + arvif->vdev_id, ret); + return ret; + } + } + + ret = ath10k_install_peer_wep_keys(arvif, sta->addr); + if (ret) { + ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } } return ret; } -static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif, +static int ath10k_station_disassoc(struct ath10k *ar, + struct ieee80211_vif *vif, struct ieee80211_sta *sta) { + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); int ret = 0; lockdep_assert_held(&ar->conf_mutex); @@ -1729,6 +1742,7 @@ static int ath10k_update_channel_list(struct ath10k *ar) ch->passive = passive; ch->freq = channel->center_freq; + ch->band_center_freq1 = channel->center_freq; ch->min_power = 0; ch->max_power = channel->max_power * 2; ch->max_reg_power = channel->max_reg_power * 2; @@ -2343,7 +2357,7 @@ static void ath10k_tx(struct ieee80211_hw *hw, } /* Must not be called with conf_mutex held as workers can use that also. */ -static void ath10k_drain_tx(struct ath10k *ar) +void ath10k_drain_tx(struct ath10k *ar) { /* make sure rcu-protected mac80211 tx path itself is drained */ synchronize_net(); @@ -2376,16 +2390,8 @@ void ath10k_halt(struct ath10k *ar) ath10k_hif_power_down(ar); spin_lock_bh(&ar->data_lock); - list_for_each_entry(arvif, &ar->arvifs, list) { - if (!arvif->beacon) - continue; - - dma_unmap_single(arvif->ar->dev, - ATH10K_SKB_CB(arvif->beacon)->paddr, - arvif->beacon->len, DMA_TO_DEVICE); - dev_kfree_skb_any(arvif->beacon); - arvif->beacon = NULL; - } + list_for_each_entry(arvif, &ar->arvifs, list) + ath10k_mac_vif_beacon_cleanup(arvif); spin_unlock_bh(&ar->data_lock); } @@ -2677,12 +2683,68 @@ static void ath10k_config_chan(struct ath10k *ar) ath10k_monitor_recalc(ar); } +static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower) +{ + int ret; + u32 param; + + lockdep_assert_held(&ar->conf_mutex); + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac txpower %d\n", txpower); + + param = ar->wmi.pdev_param->txpower_limit2g; + ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2); + if (ret) { + ath10k_warn(ar, "failed to set 2g txpower %d: %d\n", + txpower, ret); + return ret; + } + + param = ar->wmi.pdev_param->txpower_limit5g; + ret = ath10k_wmi_pdev_set_param(ar, param, txpower * 2); + if (ret) { + ath10k_warn(ar, "failed to set 5g txpower %d: %d\n", + txpower, ret); + return ret; + } + + return 0; +} + +static int ath10k_mac_txpower_recalc(struct ath10k *ar) +{ + struct ath10k_vif *arvif; + int ret, txpower = -1; + + lockdep_assert_held(&ar->conf_mutex); + + list_for_each_entry(arvif, &ar->arvifs, list) { + WARN_ON(arvif->txpower < 0); + + if (txpower == -1) + txpower = arvif->txpower; + else + txpower = min(txpower, arvif->txpower); + } + + if (WARN_ON(txpower == -1)) + return -EINVAL; + + ret = ath10k_mac_txpower_setup(ar, txpower); + if (ret) { + ath10k_warn(ar, "failed to setup tx power %d: %d\n", + txpower, ret); + return ret; + } + + return 0; +} + static int ath10k_config(struct ieee80211_hw *hw, u32 changed) { struct ath10k *ar = hw->priv; struct ieee80211_conf *conf = &hw->conf; int ret = 0; - u32 param; mutex_lock(&ar->conf_mutex); @@ -2706,25 +2768,6 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed) } } - if (changed & IEEE80211_CONF_CHANGE_POWER) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac config power %d\n", - hw->conf.power_level); - - param = ar->wmi.pdev_param->txpower_limit2g; - ret = ath10k_wmi_pdev_set_param(ar, param, - hw->conf.power_level * 2); - if (ret) - ath10k_warn(ar, "failed to set 2g txpower %d: %d\n", - hw->conf.power_level, ret); - - param = ar->wmi.pdev_param->txpower_limit5g; - ret = ath10k_wmi_pdev_set_param(ar, param, - hw->conf.power_level * 2); - if (ret) - ath10k_warn(ar, "failed to set 5g txpower %d: %d\n", - hw->conf.power_level, ret); - } - if (changed & IEEE80211_CONF_CHANGE_PS) ath10k_config_ps(ar); @@ -2772,9 +2815,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, ret = -EBUSY; goto err; } - bit = ffs(ar->free_vdev_map); + bit = __ffs64(ar->free_vdev_map); + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac create vdev %i map %llx\n", + bit, ar->free_vdev_map); - arvif->vdev_id = bit - 1; + arvif->vdev_id = bit; arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE; if (ar->p2p) @@ -2804,8 +2850,39 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, break; } - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n", - arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype); + /* 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. + * + * On non-IOMMU-enabled hosts this could be a possible security issue + * because hw could beacon some random data on the air. On + * IOMMU-enabled hosts DMAR faults would occur in most cases and target + * device would crash. + * + * Since there are no beacon tx completions (implicit nor explicit) + * propagated to host the only workaround for this is to allocate a + * DMA-coherent buffer for a lifetime of a vif and use it for all + * beacon tx commands. Worst case for this approach is some beacons may + * become corrupted, e.g. have garbled IEs or out-of-date TIM bitmap. + */ + if (vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_AP) { + arvif->beacon_buf = dma_zalloc_coherent(ar->dev, + IEEE80211_MAX_FRAME_LEN, + &arvif->beacon_paddr, + GFP_ATOMIC); + if (!arvif->beacon_buf) { + ret = -ENOMEM; + ath10k_warn(ar, "failed to allocate beacon buffer: %d\n", + ret); + goto err; + } + } + + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d bcnmode %s\n", + arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, + arvif->beacon_buf ? "single-buf" : "per-skb"); ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype, vif->addr); @@ -2815,7 +2892,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err; } - ar->free_vdev_map &= ~(1 << arvif->vdev_id); + ar->free_vdev_map &= ~(1LL << arvif->vdev_id); list_add(&arvif->list, &ar->arvifs); vdev_param = ar->wmi.vdev_param->def_keyid; @@ -2899,6 +2976,13 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, goto err_peer_delete; } + arvif->txpower = vif->bss_conf.txpower; + ret = ath10k_mac_txpower_recalc(ar); + if (ret) { + ath10k_warn(ar, "failed to recalc tx power: %d\n", ret); + goto err_peer_delete; + } + mutex_unlock(&ar->conf_mutex); return 0; @@ -2908,10 +2992,16 @@ err_peer_delete: err_vdev_delete: ath10k_wmi_vdev_delete(ar, arvif->vdev_id); - ar->free_vdev_map |= 1 << arvif->vdev_id; + ar->free_vdev_map |= 1LL << arvif->vdev_id; list_del(&arvif->list); err: + if (arvif->beacon_buf) { + dma_free_coherent(ar->dev, IEEE80211_MAX_FRAME_LEN, + arvif->beacon_buf, arvif->beacon_paddr); + arvif->beacon_buf = NULL; + } + mutex_unlock(&ar->conf_mutex); return ret; @@ -2929,14 +3019,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, cancel_work_sync(&arvif->wep_key_work); spin_lock_bh(&ar->data_lock); - if (arvif->beacon) { - dma_unmap_single(arvif->ar->dev, - ATH10K_SKB_CB(arvif->beacon)->paddr, - arvif->beacon->len, DMA_TO_DEVICE); - dev_kfree_skb_any(arvif->beacon); - arvif->beacon = NULL; - } - + ath10k_mac_vif_beacon_cleanup(arvif); spin_unlock_bh(&ar->data_lock); ret = ath10k_spectral_vif_stop(arvif); @@ -2944,7 +3027,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ath10k_warn(ar, "failed to stop spectral for vdev %i: %d\n", arvif->vdev_id, ret); - ar->free_vdev_map |= 1 << arvif->vdev_id; + ar->free_vdev_map |= 1LL << arvif->vdev_id; list_del(&arvif->list); if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { @@ -3068,54 +3151,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, arvif->u.ap.hidden_ssid = info->hidden_ssid; } - /* - * Firmware manages AP self-peer internally so make sure to not create - * it in driver. Otherwise AP self-peer deletion may timeout later. - */ - if (changed & BSS_CHANGED_BSSID && - vif->type != NL80211_IFTYPE_AP) { - if (!is_zero_ether_addr(info->bssid)) { - ath10k_dbg(ar, ATH10K_DBG_MAC, - "mac vdev %d create peer %pM\n", - arvif->vdev_id, info->bssid); - - ret = ath10k_peer_create(ar, arvif->vdev_id, - info->bssid); - if (ret) - ath10k_warn(ar, "failed to add peer %pM for vdev %d when changing bssid: %i\n", - info->bssid, arvif->vdev_id, ret); - - if (vif->type == NL80211_IFTYPE_STATION) { - /* - * this is never erased as we it for crypto key - * clearing; this is FW requirement - */ - ether_addr_copy(arvif->bssid, info->bssid); - - ath10k_dbg(ar, ATH10K_DBG_MAC, - "mac vdev %d start %pM\n", - arvif->vdev_id, info->bssid); - - ret = ath10k_vdev_start(arvif); - if (ret) { - ath10k_warn(ar, "failed to start vdev %i: %d\n", - arvif->vdev_id, ret); - goto exit; - } - - arvif->is_started = true; - } - - /* - * Mac80211 does not keep IBSS bssid when leaving IBSS, - * so driver need to store it. It is needed when leaving - * IBSS in order to remove BSSID peer. - */ - if (vif->type == NL80211_IFTYPE_ADHOC) - memcpy(arvif->bssid, info->bssid, - ETH_ALEN); - } - } + if (changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) + ether_addr_copy(arvif->bssid, info->bssid); if (changed & BSS_CHANGED_BEACON_ENABLED) ath10k_control_beaconing(arvif, info); @@ -3177,10 +3214,21 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ath10k_monitor_stop(ar); ath10k_bss_assoc(hw, vif, info); ath10k_monitor_recalc(ar); + } else { + ath10k_bss_disassoc(hw, vif); } } -exit: + if (changed & BSS_CHANGED_TXPOWER) { + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev_id %i txpower %d\n", + arvif->vdev_id, info->txpower); + + arvif->txpower = info->txpower; + ret = ath10k_mac_txpower_recalc(ar); + if (ret) + ath10k_warn(ar, "failed to recalc tx power: %d\n", ret); + } + mutex_unlock(&ar->conf_mutex); } @@ -3266,9 +3314,10 @@ static void ath10k_cancel_hw_scan(struct ieee80211_hw *hw, struct ath10k *ar = hw->priv; mutex_lock(&ar->conf_mutex); - cancel_delayed_work_sync(&ar->scan.timeout); ath10k_scan_abort(ar); mutex_unlock(&ar->conf_mutex); + + cancel_delayed_work_sync(&ar->scan.timeout); } static void ath10k_set_key_h_def_keyidx(struct ath10k *ar, @@ -3453,7 +3502,7 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", sta->addr); - err = ath10k_station_assoc(ar, arvif, sta, true); + err = ath10k_station_assoc(ar, arvif->vif, sta, true); if (err) ath10k_warn(ar, "failed to reassociate station: %pM\n", sta->addr); @@ -3489,8 +3538,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, mutex_lock(&ar->conf_mutex); if (old_state == IEEE80211_STA_NOTEXIST && - new_state == IEEE80211_STA_NONE && - vif->type != NL80211_IFTYPE_STATION) { + new_state == IEEE80211_STA_NONE) { /* * New station addition. */ @@ -3514,6 +3562,21 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, if (ret) ath10k_warn(ar, "failed to add peer %pM for vdev %d when adding a new sta: %i\n", sta->addr, arvif->vdev_id, ret); + + if (vif->type == NL80211_IFTYPE_STATION) { + WARN_ON(arvif->is_started); + + ret = ath10k_vdev_start(arvif); + if (ret) { + ath10k_warn(ar, "failed to start vdev %i: %d\n", + arvif->vdev_id, ret); + WARN_ON(ath10k_peer_delete(ar, arvif->vdev_id, + sta->addr)); + goto exit; + } + + arvif->is_started = true; + } } else if ((old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST)) { /* @@ -3522,13 +3585,23 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d peer delete %pM (sta gone)\n", arvif->vdev_id, sta->addr); + + if (vif->type == NL80211_IFTYPE_STATION) { + WARN_ON(!arvif->is_started); + + ret = ath10k_vdev_stop(arvif); + if (ret) + ath10k_warn(ar, "failed to stop vdev %i: %d\n", + arvif->vdev_id, ret); + + arvif->is_started = false; + } + ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); if (ret) ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n", sta->addr, arvif->vdev_id, ret); - if (vif->type == NL80211_IFTYPE_STATION) - ath10k_bss_disassoc(hw, vif); } else if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC && (vif->type == NL80211_IFTYPE_AP || @@ -3539,7 +3612,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM associated\n", sta->addr); - ret = ath10k_station_assoc(ar, arvif, sta, false); + ret = ath10k_station_assoc(ar, vif, sta, false); if (ret) ath10k_warn(ar, "failed to associate station %pM for vdev %i: %i\n", sta->addr, arvif->vdev_id, ret); @@ -3553,7 +3626,7 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta %pM disassociated\n", sta->addr); - ret = ath10k_station_disassoc(ar, arvif, sta); + ret = ath10k_station_disassoc(ar, vif, sta); if (ret) ath10k_warn(ar, "failed to disassociate station: %pM vdev %i: %i\n", sta->addr, arvif->vdev_id, ret); @@ -3761,10 +3834,11 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; mutex_lock(&ar->conf_mutex); - cancel_delayed_work_sync(&ar->scan.timeout); ath10k_scan_abort(ar); mutex_unlock(&ar->conf_mutex); + cancel_delayed_work_sync(&ar->scan.timeout); + return 0; } @@ -3807,7 +3881,7 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value) ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n", arvif->vdev_id, value); - ret = ath10k_mac_set_rts(arvif, value); + ret = ath10k_mac_set_frag(arvif, value); if (ret) { ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n", arvif->vdev_id, ret); @@ -3843,7 +3917,9 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, empty = (ar->htt.num_pending_tx == 0); spin_unlock_bh(&ar->htt.tx_lock); - skip = (ar->state == ATH10K_STATE_WEDGED); + skip = (ar->state == ATH10K_STATE_WEDGED) || + test_bit(ATH10K_FLAG_CRASH_FLUSH, + &ar->dev_flags); (empty || skip); }), ATH10K_FLUSH_TIMEOUT_HZ); @@ -3929,10 +4005,14 @@ exit: } #endif -static void ath10k_restart_complete(struct ieee80211_hw *hw) +static void ath10k_reconfig_complete(struct ieee80211_hw *hw, + enum ieee80211_reconfig_type reconfig_type) { struct ath10k *ar = hw->priv; + if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) + return; + mutex_lock(&ar->conf_mutex); /* If device failed to restart it will be in a different state, e.g. @@ -3940,6 +4020,7 @@ static void ath10k_restart_complete(struct ieee80211_hw *hw) if (ar->state == ATH10K_STATE_RESTARTED) { ath10k_info(ar, "device successfully recovered\n"); ar->state = ATH10K_STATE_ON; + ieee80211_wake_queues(ar->hw); } mutex_unlock(&ar->conf_mutex); @@ -3975,6 +4056,9 @@ static int ath10k_get_survey(struct ieee80211_hw *hw, int idx, survey->channel = &sband->channels[idx]; + if (ar->rx_channel == survey->channel) + survey->filled |= SURVEY_INFO_IN_USE; + exit: mutex_unlock(&ar->conf_mutex); return ret; @@ -4450,12 +4534,15 @@ static const struct ieee80211_ops ath10k_ops = { .tx_last_beacon = ath10k_tx_last_beacon, .set_antenna = ath10k_set_antenna, .get_antenna = ath10k_get_antenna, - .restart_complete = ath10k_restart_complete, + .reconfig_complete = ath10k_reconfig_complete, .get_survey = ath10k_get_survey, .set_bitrate_mask = ath10k_set_bitrate_mask, .sta_rc_update = ath10k_sta_rc_update, .get_tsf = ath10k_get_tsf, .ampdu_action = ath10k_ampdu_action, + .get_et_sset_count = ath10k_debug_get_et_sset_count, + .get_et_stats = ath10k_debug_get_et_stats, + .get_et_strings = ath10k_debug_get_et_strings, CFG80211_TESTMODE_CMD(ath10k_tm_cmd) @@ -4800,15 +4887,6 @@ int ath10k_mac_register(struct ath10k *ar) BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - /* TODO: Have to deal with 2x2 chips if/when the come out. */ - ar->supp_tx_chainmask = TARGET_10X_TX_CHAIN_MASK; - ar->supp_rx_chainmask = TARGET_10X_RX_CHAIN_MASK; - } else { - ar->supp_tx_chainmask = TARGET_TX_CHAIN_MASK; - ar->supp_rx_chainmask = TARGET_RX_CHAIN_MASK; - } - ar->hw->wiphy->available_antennas_rx = ar->supp_rx_chainmask; ar->hw->wiphy->available_antennas_tx = ar->supp_tx_chainmask; @@ -4854,6 +4932,8 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->max_remain_on_channel_duration = 5000; ar->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; + /* * on LL hardware queues are managed entirely by the FW * so we only advertise to mac we can do the queues thing diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index 6c80eea..4e3c989 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -39,6 +39,8 @@ void ath10k_offchan_tx_work(struct work_struct *work); void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar); void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work); void ath10k_halt(struct ath10k *ar); +void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif); +void ath10k_drain_tx(struct ath10k *ar); static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif) { diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 59e0ea8..3a6b8a5 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -485,6 +485,8 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, void *data_buf = NULL; int i; + spin_lock_bh(&ar_pci->ce_lock); + ce_diag = ar_pci->ce_diag; /* @@ -511,7 +513,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, nbytes = min_t(unsigned int, remaining_bytes, DIAG_TRANSFER_LIMIT); - ret = ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data); + ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, ce_data); if (ret != 0) goto done; @@ -527,15 +529,15 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address); - ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0, - 0); + ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0, + 0); if (ret) goto done; i = 0; - while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf, - &completed_nbytes, - &id) != 0) { + while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf, + &completed_nbytes, + &id) != 0) { mdelay(1); if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { ret = -EBUSY; @@ -554,9 +556,9 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, } i = 0; - while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf, - &completed_nbytes, - &id, &flags) != 0) { + while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf, + &completed_nbytes, + &id, &flags) != 0) { mdelay(1); if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { @@ -591,6 +593,8 @@ done: dma_free_coherent(ar->dev, orig_nbytes, data_buf, ce_data_base); + spin_unlock_bh(&ar_pci->ce_lock); + return ret; } @@ -648,6 +652,8 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, dma_addr_t ce_data_base = 0; int i; + spin_lock_bh(&ar_pci->ce_lock); + ce_diag = ar_pci->ce_diag; /* @@ -688,7 +694,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT); /* Set up to receive directly into Target(!) address */ - ret = ath10k_ce_rx_post_buf(ce_diag, NULL, address); + ret = __ath10k_ce_rx_post_buf(ce_diag, NULL, address); if (ret != 0) goto done; @@ -696,15 +702,15 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, * Request CE to send caller-supplied data that * was copied to bounce buffer to Target(!) address. */ - ret = ath10k_ce_send(ce_diag, NULL, (u32)ce_data, - nbytes, 0, 0); + ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)ce_data, + nbytes, 0, 0); if (ret != 0) goto done; i = 0; - while (ath10k_ce_completed_send_next(ce_diag, NULL, &buf, - &completed_nbytes, - &id) != 0) { + while (ath10k_ce_completed_send_next_nolock(ce_diag, NULL, &buf, + &completed_nbytes, + &id) != 0) { mdelay(1); if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { @@ -724,9 +730,9 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, } i = 0; - while (ath10k_ce_completed_recv_next(ce_diag, NULL, &buf, - &completed_nbytes, - &id, &flags) != 0) { + while (ath10k_ce_completed_recv_next_nolock(ce_diag, NULL, &buf, + &completed_nbytes, + &id, &flags) != 0) { mdelay(1); if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { @@ -760,6 +766,8 @@ done: ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n", address, ret); + spin_unlock_bh(&ar_pci->ce_lock); + return ret; } @@ -861,6 +869,12 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state) } skb_put(skb, nbytes); + + ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n", + ce_state->id, skb->len); + ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ", + skb->data, skb->len); + cb->rx_completion(ar, skb, pipe_info->pipe_num); } @@ -936,6 +950,12 @@ err: return err; } +static int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf, + size_t buf_len) +{ + return ath10k_pci_diag_read_mem(ar, address, buf, buf_len); +} + static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); @@ -986,6 +1006,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar) spin_lock_bh(&ar->data_lock); + ar->stats.fw_crash_counter++; + crash_data = ath10k_debug_get_new_fw_crash_data(ar); if (crash_data) @@ -1121,14 +1143,37 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, &dl_is_polled); } -static void ath10k_pci_irq_disable(struct ath10k *ar) +static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - int i; + u32 val; + + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); + val &= ~CORE_CTRL_PCIE_REG_31_MASK; + + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); +} + +static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) +{ + u32 val; + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); + val |= CORE_CTRL_PCIE_REG_31_MASK; + + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); +} + +static void ath10k_pci_irq_disable(struct ath10k *ar) +{ ath10k_ce_disable_interrupts(ar); ath10k_pci_disable_and_clear_legacy_irq(ar); - /* FIXME: How to mask all MSI interrupts? */ + ath10k_pci_irq_msi_fw_mask(ar); +} + +static void ath10k_pci_irq_sync(struct ath10k *ar) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + int i; for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++) synchronize_irq(ar_pci->pdev->irq + i); @@ -1138,7 +1183,7 @@ static void ath10k_pci_irq_enable(struct ath10k *ar) { ath10k_ce_enable_interrupts(ar); ath10k_pci_enable_legacy_irq(ar); - /* FIXME: How to unmask all MSI interrupts? */ + ath10k_pci_irq_msi_fw_unmask(ar); } static int ath10k_pci_hif_start(struct ath10k *ar) @@ -1151,64 +1196,74 @@ static int ath10k_pci_hif_start(struct ath10k *ar) return 0; } -static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) +static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) { struct ath10k *ar; - struct ath10k_pci *ar_pci; - struct ath10k_ce_pipe *ce_hdl; - u32 buf_sz; - struct sk_buff *netbuf; - u32 ce_data; + struct ath10k_ce_pipe *ce_pipe; + struct ath10k_ce_ring *ce_ring; + struct sk_buff *skb; + int i; - buf_sz = pipe_info->buf_sz; + ar = pci_pipe->hif_ce_state; + ce_pipe = pci_pipe->ce_hdl; + ce_ring = ce_pipe->dest_ring; - /* Unused Copy Engine */ - if (buf_sz == 0) + if (!ce_ring) return; - ar = pipe_info->hif_ce_state; - ar_pci = ath10k_pci_priv(ar); - ce_hdl = pipe_info->ce_hdl; + if (!pci_pipe->buf_sz) + return; - while (ath10k_ce_revoke_recv_next(ce_hdl, (void **)&netbuf, - &ce_data) == 0) { - dma_unmap_single(ar->dev, ATH10K_SKB_CB(netbuf)->paddr, - netbuf->len + skb_tailroom(netbuf), + for (i = 0; i < ce_ring->nentries; i++) { + skb = ce_ring->per_transfer_context[i]; + if (!skb) + continue; + + ce_ring->per_transfer_context[i] = NULL; + + dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, + skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); - dev_kfree_skb_any(netbuf); + dev_kfree_skb_any(skb); } } -static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info) +static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) { struct ath10k *ar; struct ath10k_pci *ar_pci; - struct ath10k_ce_pipe *ce_hdl; - struct sk_buff *netbuf; - u32 ce_data; - unsigned int nbytes; + struct ath10k_ce_pipe *ce_pipe; + struct ath10k_ce_ring *ce_ring; + struct ce_desc *ce_desc; + struct sk_buff *skb; unsigned int id; - u32 buf_sz; + int i; - buf_sz = pipe_info->buf_sz; + ar = pci_pipe->hif_ce_state; + ar_pci = ath10k_pci_priv(ar); + ce_pipe = pci_pipe->ce_hdl; + ce_ring = ce_pipe->src_ring; - /* Unused Copy Engine */ - if (buf_sz == 0) + if (!ce_ring) return; - ar = pipe_info->hif_ce_state; - ar_pci = ath10k_pci_priv(ar); - ce_hdl = pipe_info->ce_hdl; + if (!pci_pipe->buf_sz) + return; - while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf, - &ce_data, &nbytes, &id) == 0) { - /* no need to call tx completion for NULL pointers */ - if (!netbuf) + ce_desc = ce_ring->shadow_base; + if (WARN_ON(!ce_desc)) + return; + + for (i = 0; i < ce_ring->nentries; i++) { + skb = ce_ring->per_transfer_context[i]; + if (!skb) continue; - ar_pci->msg_callbacks_current.tx_completion(ar, - netbuf, - id); + ce_ring->per_transfer_context[i] = NULL; + id = MS(__le16_to_cpu(ce_desc[i].flags), + CE_DESC_FLAGS_META_DATA); + + ar_pci->msg_callbacks_current.tx_completion(ar, skb, id); } } @@ -1266,6 +1321,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) ath10k_pci_warm_reset(ar); ath10k_pci_irq_disable(ar); + ath10k_pci_irq_sync(ar); ath10k_pci_flush(ar); } @@ -1386,6 +1442,9 @@ static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) &nbytes, &transfer_id, &flags)) return; + if (WARN_ON_ONCE(!xfer)) + return; + if (!xfer->wait_for_resp) { ath10k_warn(ar, "unexpected: BMI data received; ignoring\n"); return; @@ -1569,23 +1628,40 @@ static int ath10k_pci_init_config(struct ath10k *ar) return 0; } -static int ath10k_pci_alloc_ce(struct ath10k *ar) +static int ath10k_pci_alloc_pipes(struct ath10k *ar) { + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + struct ath10k_pci_pipe *pipe; int i, ret; for (i = 0; i < CE_COUNT; i++) { - ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]); + pipe = &ar_pci->pipe_info[i]; + pipe->ce_hdl = &ar_pci->ce_states[i]; + pipe->pipe_num = i; + pipe->hif_ce_state = ar; + + ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i], + ath10k_pci_ce_send_done, + ath10k_pci_ce_recv_data); if (ret) { ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n", i, ret); return ret; } + + /* Last CE is Diagnostic Window */ + if (i == CE_COUNT - 1) { + ar_pci->ce_diag = pipe->ce_hdl; + continue; + } + + pipe->buf_sz = (size_t)(host_ce_config_wlan[i].src_sz_max); } return 0; } -static void ath10k_pci_free_ce(struct ath10k *ar) +static void ath10k_pci_free_pipes(struct ath10k *ar) { int i; @@ -1593,39 +1669,17 @@ static void ath10k_pci_free_ce(struct ath10k *ar) ath10k_ce_free_pipe(ar, i); } -static int ath10k_pci_ce_init(struct ath10k *ar) +static int ath10k_pci_init_pipes(struct ath10k *ar) { - struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); - struct ath10k_pci_pipe *pipe_info; - const struct ce_attr *attr; - int pipe_num, ret; + int i, ret; - for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { - pipe_info = &ar_pci->pipe_info[pipe_num]; - pipe_info->ce_hdl = &ar_pci->ce_states[pipe_num]; - pipe_info->pipe_num = pipe_num; - pipe_info->hif_ce_state = ar; - attr = &host_ce_config_wlan[pipe_num]; - - ret = ath10k_ce_init_pipe(ar, pipe_num, attr, - ath10k_pci_ce_send_done, - ath10k_pci_ce_recv_data); + for (i = 0; i < CE_COUNT; i++) { + ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]); if (ret) { ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n", - pipe_num, ret); + i, ret); return ret; } - - if (pipe_num == CE_COUNT - 1) { - /* - * Reserve the ultimate CE for - * diagnostic Window support - */ - ar_pci->ce_diag = pipe_info->ce_hdl; - continue; - } - - pipe_info->buf_sz = (size_t)(attr->src_sz_max); } return 0; @@ -1666,93 +1720,167 @@ static void ath10k_pci_warm_reset_si0(struct ath10k *ar) msleep(10); } -static int ath10k_pci_warm_reset(struct ath10k *ar) +static void ath10k_pci_warm_reset_cpu(struct ath10k *ar) { u32 val; - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n"); - - /* debug */ - val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + - PCIE_INTR_CAUSE_ADDRESS); - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", - val); + ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); - val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + - CPU_INTR_ADDRESS); - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", - val); + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, + val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); +} - /* disable pending irqs */ - ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + - PCIE_INTR_ENABLE_ADDRESS, 0); +static void ath10k_pci_warm_reset_ce(struct ath10k *ar) +{ + u32 val; - ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + - PCIE_INTR_CLR_ADDRESS, ~0); + val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + + SOC_RESET_CONTROL_ADDRESS); - msleep(100); + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, + val | SOC_RESET_CONTROL_CE_RST_MASK); + msleep(10); + ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, + val & ~SOC_RESET_CONTROL_CE_RST_MASK); +} - /* clear fw indicator */ - ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); +static void ath10k_pci_warm_reset_clear_lf(struct ath10k *ar) +{ + u32 val; - /* clear target LF timer interrupts */ val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + SOC_LF_TIMER_CONTROL0_ADDRESS); ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_LF_TIMER_CONTROL0_ADDRESS, val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); +} - /* reset CE */ - val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + - SOC_RESET_CONTROL_ADDRESS); - ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, - val | SOC_RESET_CONTROL_CE_RST_MASK); - val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + - SOC_RESET_CONTROL_ADDRESS); - msleep(10); +static int ath10k_pci_warm_reset(struct ath10k *ar) +{ + int ret; - /* unreset CE */ - ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, - val & ~SOC_RESET_CONTROL_CE_RST_MASK); - val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + - SOC_RESET_CONTROL_ADDRESS); - msleep(10); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n"); + + spin_lock_bh(&ar->data_lock); + ar->stats.fw_warm_reset_counter++; + spin_unlock_bh(&ar->data_lock); + + ath10k_pci_irq_disable(ar); + /* Make sure the target CPU is not doing anything dangerous, e.g. if it + * were to access copy engine while host performs copy engine reset + * then it is possible for the device to confuse pci-e controller to + * the point of bringing host system to a complete stop (i.e. hang). + */ ath10k_pci_warm_reset_si0(ar); + ath10k_pci_warm_reset_cpu(ar); + ath10k_pci_init_pipes(ar); + ath10k_pci_wait_for_target_init(ar); - /* debug */ - val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + - PCIE_INTR_CAUSE_ADDRESS); - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot host cpu intr cause: 0x%08x\n", - val); + ath10k_pci_warm_reset_clear_lf(ar); + ath10k_pci_warm_reset_ce(ar); + ath10k_pci_warm_reset_cpu(ar); + ath10k_pci_init_pipes(ar); - val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + - CPU_INTR_ADDRESS); - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target cpu intr cause: 0x%08x\n", - val); + ret = ath10k_pci_wait_for_target_init(ar); + if (ret) { + ath10k_warn(ar, "failed to wait for target init: %d\n", ret); + return ret; + } - /* CPU warm reset */ - val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + - SOC_RESET_CONTROL_ADDRESS); - ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + SOC_RESET_CONTROL_ADDRESS, - val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n"); - val = ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + - SOC_RESET_CONTROL_ADDRESS); - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target reset state: 0x%08x\n", - val); + return 0; +} + +static int ath10k_pci_chip_reset(struct ath10k *ar) +{ + int i, ret; + u32 val; - msleep(100); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset\n"); - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n"); + /* Some hardware revisions (e.g. CUS223v2) has issues with cold reset. + * It is thus preferred to use warm reset which is safer but may not be + * able to recover the device from all possible fail scenarios. + * + * Warm reset doesn't always work on first try so attempt it a few + * times before giving up. + */ + for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) { + ret = ath10k_pci_warm_reset(ar); + if (ret) { + ath10k_warn(ar, "failed to warm reset attempt %d of %d: %d\n", + i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, + ret); + continue; + } + + /* FIXME: Sometimes copy engine doesn't recover after warm + * reset. In most cases this needs cold reset. In some of these + * cases the device is in such a state that a cold reset may + * lock up the host. + * + * Reading any host interest register via copy engine is + * sufficient to verify if device is capable of booting + * firmware blob. + */ + ret = ath10k_pci_init_pipes(ar); + if (ret) { + ath10k_warn(ar, "failed to init copy engine: %d\n", + ret); + continue; + } + + ret = ath10k_pci_diag_read32(ar, QCA988X_HOST_INTEREST_ADDRESS, + &val); + if (ret) { + ath10k_warn(ar, "failed to poke copy engine: %d\n", + ret); + continue; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (warm)\n"); + return 0; + } + + if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) { + ath10k_warn(ar, "refusing cold reset as requested\n"); + return -EPERM; + } + + ret = ath10k_pci_cold_reset(ar); + if (ret) { + ath10k_warn(ar, "failed to cold reset: %d\n", ret); + return ret; + } + + ret = ath10k_pci_wait_for_target_init(ar); + if (ret) { + ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", + ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (cold)\n"); return 0; } -static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) +static int ath10k_pci_hif_power_up(struct ath10k *ar) { int ret; + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n"); + + ret = ath10k_pci_wake(ar); + if (ret) { + ath10k_err(ar, "failed to wake up target: %d\n", ret); + return ret; + } + /* * Bring the target up cleanly. * @@ -1763,26 +1891,16 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) * is in an unexpected state. We try to catch that here in order to * reset the Target and retry the probe. */ - if (cold_reset) - ret = ath10k_pci_cold_reset(ar); - else - ret = ath10k_pci_warm_reset(ar); - + ret = ath10k_pci_chip_reset(ar); if (ret) { - ath10k_err(ar, "failed to reset target: %d\n", ret); - goto err; + ath10k_err(ar, "failed to reset chip: %d\n", ret); + goto err_sleep; } - ret = ath10k_pci_ce_init(ar); + ret = ath10k_pci_init_pipes(ar); if (ret) { ath10k_err(ar, "failed to initialize CE: %d\n", ret); - goto err; - } - - ret = ath10k_pci_wait_for_target_init(ar); - if (ret) { - ath10k_err(ar, "failed to wait for target to init: %d\n", ret); - goto err_ce; + goto err_sleep; } ret = ath10k_pci_init_config(ar); @@ -1801,73 +1919,21 @@ static int __ath10k_pci_hif_power_up(struct ath10k *ar, bool cold_reset) err_ce: ath10k_pci_ce_deinit(ar); - ath10k_pci_warm_reset(ar); -err: - return ret; -} - -static int ath10k_pci_hif_power_up_warm(struct ath10k *ar) -{ - int i, ret; - - /* - * Sometime warm reset succeeds after retries. - * - * FIXME: It might be possible to tune ath10k_pci_warm_reset() to work - * at first try. - */ - for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) { - ret = __ath10k_pci_hif_power_up(ar, false); - if (ret == 0) - break; - - ath10k_warn(ar, "failed to warm reset (attempt %d out of %d): %d\n", - i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret); - } +err_sleep: + ath10k_pci_sleep(ar); return ret; } -static int ath10k_pci_hif_power_up(struct ath10k *ar) -{ - int ret; - - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n"); - - /* - * Hardware CUS232 version 2 has some issues with cold reset and the - * preferred (and safer) way to perform a device reset is through a - * warm reset. - * - * Warm reset doesn't always work though so fall back to cold reset may - * be necessary. - */ - ret = ath10k_pci_hif_power_up_warm(ar); - if (ret) { - ath10k_warn(ar, "failed to power up target using warm reset: %d\n", - ret); - - if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) - return ret; - - ath10k_warn(ar, "trying cold reset\n"); - - ret = __ath10k_pci_hif_power_up(ar, true); - if (ret) { - ath10k_err(ar, "failed to power up target using cold reset too (%d)\n", - ret); - return ret; - } - } - - return 0; -} - static void ath10k_pci_hif_power_down(struct ath10k *ar) { ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); - ath10k_pci_warm_reset(ar); + /* Currently hif_power_up performs effectively a reset and hif_stop + * resets the chip as well so there's no point in resetting here. + */ + + ath10k_pci_sleep(ar); } #ifdef CONFIG_PM @@ -1921,6 +1987,7 @@ static int ath10k_pci_hif_resume(struct ath10k *ar) static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .tx_sg = ath10k_pci_hif_tx_sg, + .diag_read = ath10k_pci_hif_diag_read, .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, .start = ath10k_pci_hif_start, .stop = ath10k_pci_hif_stop, @@ -2250,14 +2317,14 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) if (ar_pci->num_msi_intrs == 0) /* Fix potential race by repeating CORE_BASE writes */ - ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + - PCIE_INTR_ENABLE_ADDRESS, - PCIE_INTR_FIRMWARE_MASK | - PCIE_INTR_CE_MASK_ALL); + ath10k_pci_enable_legacy_irq(ar); mdelay(10); } while (time_before(jiffies, timeout)); + ath10k_pci_disable_and_clear_legacy_irq(ar); + ath10k_pci_irq_msi_fw_mask(ar); + if (val == 0xffffffff) { ath10k_err(ar, "failed to read device register, device is gone\n"); return -EIO; @@ -2287,6 +2354,12 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n"); + spin_lock_bh(&ar->data_lock); + + ar->stats.fw_cold_reset_counter++; + + spin_unlock_bh(&ar->data_lock); + /* Put Target, including PCIe, into RESET. */ val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS); val |= 1; @@ -2400,6 +2473,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, u32 chip_id; ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, + ATH10K_BUS_PCI, &ath10k_pci_hif_ops); if (!ar) { dev_err(&pdev->dev, "failed to allocate core\n"); @@ -2435,7 +2509,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_sleep; } - ret = ath10k_pci_alloc_ce(ar); + ret = ath10k_pci_alloc_pipes(ar); if (ret) { ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", ret); @@ -2443,25 +2517,12 @@ static int ath10k_pci_probe(struct pci_dev *pdev, } ath10k_pci_ce_deinit(ar); - - ret = ath10k_ce_disable_interrupts(ar); - if (ret) { - ath10k_err(ar, "failed to disable copy engine interrupts: %d\n", - ret); - goto err_free_ce; - } - - /* Workaround: There's no known way to mask all possible interrupts via - * device CSR. The only way to make sure device doesn't assert - * interrupts is to reset it. Interrupts are then disabled on host - * after handlers are registered. - */ - ath10k_pci_warm_reset(ar); + ath10k_pci_irq_disable(ar); ret = ath10k_pci_init_irq(ar); if (ret) { ath10k_err(ar, "failed to init irqs: %d\n", ret); - goto err_free_ce; + goto err_free_pipes; } ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n", @@ -2474,8 +2535,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, goto err_deinit_irq; } - /* This shouldn't race as the device has been reset above. */ - ath10k_pci_irq_disable(ar); + ath10k_pci_sleep(ar); ret = ath10k_core_register(ar, chip_id); if (ret) { @@ -2492,8 +2552,8 @@ err_free_irq: err_deinit_irq: ath10k_pci_deinit_irq(ar); -err_free_ce: - ath10k_pci_free_ce(ar); +err_free_pipes: + ath10k_pci_free_pipes(ar); err_sleep: ath10k_pci_sleep(ar); @@ -2527,8 +2587,7 @@ static void ath10k_pci_remove(struct pci_dev *pdev) ath10k_pci_kill_tasklet(ar); ath10k_pci_deinit_irq(ar); ath10k_pci_ce_deinit(ar); - ath10k_pci_free_ce(ar); - ath10k_pci_sleep(ar); + ath10k_pci_free_pipes(ar); ath10k_pci_release(ar); ath10k_core_destroy(ar); } @@ -2565,5 +2624,7 @@ module_exit(ath10k_pci_exit); MODULE_AUTHOR("Qualcomm Atheros"); MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_3_FILE); +MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE); +MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE); +MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE); MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index 3e1454b..63ce61f 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -56,14 +56,14 @@ static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len, } int ath10k_spectral_process_fft(struct ath10k *ar, - struct wmi_single_phyerr_rx_event *event, - struct phyerr_fft_report *fftr, + const struct wmi_phyerr *phyerr, + const struct phyerr_fft_report *fftr, size_t bin_len, u64 tsf) { struct fft_sample_ath10k *fft_sample; u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS]; u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag; - u32 reg0, reg1, nf_list1, nf_list2; + u32 reg0, reg1; u8 chain_idx, *bins; int dc_pos; @@ -82,7 +82,7 @@ int ath10k_spectral_process_fft(struct ath10k *ar, /* TODO: there might be a reason why the hardware reports 20/40/80 MHz, * but the results/plots suggest that its actually 22/44/88 MHz. */ - switch (event->hdr.chan_width_mhz) { + switch (phyerr->chan_width_mhz) { case 20: fft_sample->chan_width_mhz = 22; break; @@ -101,7 +101,7 @@ int ath10k_spectral_process_fft(struct ath10k *ar, fft_sample->chan_width_mhz = 88; break; default: - fft_sample->chan_width_mhz = event->hdr.chan_width_mhz; + fft_sample->chan_width_mhz = phyerr->chan_width_mhz; } fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB); @@ -110,36 +110,22 @@ int ath10k_spectral_process_fft(struct ath10k *ar, peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG); fft_sample->max_magnitude = __cpu_to_be16(peak_mag); fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX); - fft_sample->rssi = event->hdr.rssi_combined; + fft_sample->rssi = phyerr->rssi_combined; total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB); base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB); fft_sample->total_gain_db = __cpu_to_be16(total_gain_db); fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db); - freq1 = __le16_to_cpu(event->hdr.freq1); - freq2 = __le16_to_cpu(event->hdr.freq2); + freq1 = __le16_to_cpu(phyerr->freq1); + freq2 = __le16_to_cpu(phyerr->freq2); fft_sample->freq1 = __cpu_to_be16(freq1); fft_sample->freq2 = __cpu_to_be16(freq2); - nf_list1 = __le32_to_cpu(event->hdr.nf_list_1); - nf_list2 = __le32_to_cpu(event->hdr.nf_list_2); chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX); - switch (chain_idx) { - case 0: - fft_sample->noise = __cpu_to_be16(nf_list1 & 0xffffu); - break; - case 1: - fft_sample->noise = __cpu_to_be16((nf_list1 >> 16) & 0xffffu); - break; - case 2: - fft_sample->noise = __cpu_to_be16(nf_list2 & 0xffffu); - break; - case 3: - fft_sample->noise = __cpu_to_be16((nf_list2 >> 16) & 0xffffu); - break; - } + fft_sample->noise = __cpu_to_be16( + __le16_to_cpu(phyerr->nf_chains[chain_idx])); bins = (u8 *)fftr; bins += sizeof(*fftr); diff --git a/drivers/net/wireless/ath/ath10k/spectral.h b/drivers/net/wireless/ath/ath10k/spectral.h index ddc57c5..042f5b3 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.h +++ b/drivers/net/wireless/ath/ath10k/spectral.h @@ -47,8 +47,8 @@ enum ath10k_spectral_mode { #ifdef CONFIG_ATH10K_DEBUGFS int ath10k_spectral_process_fft(struct ath10k *ar, - struct wmi_single_phyerr_rx_event *event, - struct phyerr_fft_report *fftr, + const struct wmi_phyerr *phyerr, + const struct phyerr_fft_report *fftr, size_t bin_len, u64 tsf); int ath10k_spectral_start(struct ath10k *ar); int ath10k_spectral_vif_stop(struct ath10k_vif *arvif); @@ -59,8 +59,8 @@ void ath10k_spectral_destroy(struct ath10k *ar); static inline int ath10k_spectral_process_fft(struct ath10k *ar, - struct wmi_single_phyerr_rx_event *event, - struct phyerr_fft_report *fftr, + const struct wmi_phyerr *phyerr, + const struct phyerr_fft_report *fftr, size_t bin_len, u64 tsf) { return 0; diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index 574b75a..ceea566 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h @@ -20,6 +20,13 @@ #include <linux/tracepoint.h> #include "core.h" +#if !defined(_TRACE_H_) +static inline u32 ath10k_frm_hdr_len(void *buf) +{ + return ieee80211_hdrlen(((struct ieee80211_hdr *)buf)->frame_control); +} +#endif + #define _TRACE_H_ /* create empty functions when tracing is disabled */ @@ -254,6 +261,195 @@ TRACE_EVENT(ath10k_wmi_dbglog, ) ); +TRACE_EVENT(ath10k_htt_pktlog, + TP_PROTO(struct ath10k *ar, void *buf, u16 buf_len), + + TP_ARGS(ar, buf, buf_len), + + TP_STRUCT__entry( + __string(device, dev_name(ar->dev)) + __string(driver, dev_driver_string(ar->dev)) + __field(u16, buf_len) + __dynamic_array(u8, pktlog, buf_len) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ar->dev)); + __assign_str(driver, dev_driver_string(ar->dev)); + __entry->buf_len = buf_len; + memcpy(__get_dynamic_array(pktlog), buf, buf_len); + ), + + TP_printk( + "%s %s size %hu", + __get_str(driver), + __get_str(device), + __entry->buf_len + ) +); + +TRACE_EVENT(ath10k_htt_tx, + TP_PROTO(struct ath10k *ar, u16 msdu_id, u16 msdu_len, + u8 vdev_id, u8 tid), + + TP_ARGS(ar, msdu_id, msdu_len, vdev_id, tid), + + TP_STRUCT__entry( + __string(device, dev_name(ar->dev)) + __string(driver, dev_driver_string(ar->dev)) + __field(u16, msdu_id) + __field(u16, msdu_len) + __field(u8, vdev_id) + __field(u8, tid) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ar->dev)); + __assign_str(driver, dev_driver_string(ar->dev)); + __entry->msdu_id = msdu_id; + __entry->msdu_len = msdu_len; + __entry->vdev_id = vdev_id; + __entry->tid = tid; + ), + + TP_printk( + "%s %s msdu_id %d msdu_len %d vdev_id %d tid %d", + __get_str(driver), + __get_str(device), + __entry->msdu_id, + __entry->msdu_len, + __entry->vdev_id, + __entry->tid + ) +); + +TRACE_EVENT(ath10k_txrx_tx_unref, + TP_PROTO(struct ath10k *ar, u16 msdu_id), + + TP_ARGS(ar, msdu_id), + + TP_STRUCT__entry( + __string(device, dev_name(ar->dev)) + __string(driver, dev_driver_string(ar->dev)) + __field(u16, msdu_id) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ar->dev)); + __assign_str(driver, dev_driver_string(ar->dev)); + __entry->msdu_id = msdu_id; + ), + + TP_printk( + "%s %s msdu_id %d", + __get_str(driver), + __get_str(device), + __entry->msdu_id + ) +); + +DECLARE_EVENT_CLASS(ath10k_hdr_event, + TP_PROTO(struct ath10k *ar, void *data, size_t len), + + TP_ARGS(ar, data, len), + + TP_STRUCT__entry( + __string(device, dev_name(ar->dev)) + __string(driver, dev_driver_string(ar->dev)) + __field(size_t, len) + __dynamic_array(u8, data, ath10k_frm_hdr_len(data)) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ar->dev)); + __assign_str(driver, dev_driver_string(ar->dev)); + __entry->len = ath10k_frm_hdr_len(data); + memcpy(__get_dynamic_array(data), data, __entry->len); + ), + + TP_printk( + "%s %s len %zu\n", + __get_str(driver), + __get_str(device), + __entry->len + ) +); + +DECLARE_EVENT_CLASS(ath10k_payload_event, + TP_PROTO(struct ath10k *ar, void *data, size_t len), + + TP_ARGS(ar, data, len), + + TP_STRUCT__entry( + __string(device, dev_name(ar->dev)) + __string(driver, dev_driver_string(ar->dev)) + __field(size_t, len) + __dynamic_array(u8, payload, (len - ath10k_frm_hdr_len(data))) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ar->dev)); + __assign_str(driver, dev_driver_string(ar->dev)); + __entry->len = len - ath10k_frm_hdr_len(data); + memcpy(__get_dynamic_array(payload), + data + ath10k_frm_hdr_len(data), __entry->len); + ), + + TP_printk( + "%s %s len %zu\n", + __get_str(driver), + __get_str(device), + __entry->len + ) +); + +DEFINE_EVENT(ath10k_hdr_event, ath10k_tx_hdr, + TP_PROTO(struct ath10k *ar, void *data, size_t len), + TP_ARGS(ar, data, len) +); + +DEFINE_EVENT(ath10k_payload_event, ath10k_tx_payload, + TP_PROTO(struct ath10k *ar, void *data, size_t len), + TP_ARGS(ar, data, len) +); + +DEFINE_EVENT(ath10k_hdr_event, ath10k_rx_hdr, + TP_PROTO(struct ath10k *ar, void *data, size_t len), + TP_ARGS(ar, data, len) +); + +DEFINE_EVENT(ath10k_payload_event, ath10k_rx_payload, + TP_PROTO(struct ath10k *ar, void *data, size_t len), + TP_ARGS(ar, data, len) +); + +TRACE_EVENT(ath10k_htt_rx_desc, + TP_PROTO(struct ath10k *ar, void *data, size_t len), + + TP_ARGS(ar, data, len), + + TP_STRUCT__entry( + __string(device, dev_name(ar->dev)) + __string(driver, dev_driver_string(ar->dev)) + __field(u16, len) + __dynamic_array(u8, rxdesc, len) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ar->dev)); + __assign_str(driver, dev_driver_string(ar->dev)); + __entry->len = len; + memcpy(__get_dynamic_array(rxdesc), data, len); + ), + + TP_printk( + "%s %s rxdesc len %d", + __get_str(driver), + __get_str(device), + __entry->len + ) +); + #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ /* we don't want to use include/trace/events */ diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index a0cbc21..7579de8 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -78,6 +78,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, info = IEEE80211_SKB_CB(msdu); memset(&info->status, 0, sizeof(info->status)); + trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id); if (tx_done->discard) { ieee80211_free_txskb(htt->ar->hw, msdu); @@ -145,7 +146,8 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, mapped = !!ath10k_peer_find(ar, vdev_id, addr); spin_unlock_bh(&ar->data_lock); - mapped == expect_mapped; + (mapped == expect_mapped || + test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)); }), 3*HZ); if (ret <= 0) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 2c42bd5..c2bc828 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -609,6 +609,40 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, }; +static void +ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, + const struct wmi_channel_arg *arg) +{ + u32 flags = 0; + + memset(ch, 0, sizeof(*ch)); + + if (arg->passive) + flags |= WMI_CHAN_FLAG_PASSIVE; + if (arg->allow_ibss) + flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED; + if (arg->allow_ht) + flags |= WMI_CHAN_FLAG_ALLOW_HT; + if (arg->allow_vht) + flags |= WMI_CHAN_FLAG_ALLOW_VHT; + if (arg->ht40plus) + flags |= WMI_CHAN_FLAG_HT40_PLUS; + if (arg->chan_radar) + flags |= WMI_CHAN_FLAG_DFS; + + ch->mhz = __cpu_to_le32(arg->freq); + ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1); + ch->band_center_freq2 = 0; + ch->min_power = arg->min_power; + ch->max_power = arg->max_power; + ch->reg_power = arg->max_reg_power; + ch->antenna_max = arg->max_antenna_gain; + + /* mode & flags share storage */ + ch->mode = arg->mode; + ch->flags |= __cpu_to_le32(flags); +} + int ath10k_wmi_wait_for_service_ready(struct ath10k *ar) { int ret; @@ -745,6 +779,10 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) ath10k_wmi_tx_beacons_nowait(ar); ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id); + + if (ret && test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) + ret = -ESHUTDOWN; + (ret != -EAGAIN); }), 3*HZ); @@ -800,6 +838,8 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb) ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n", wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE); + trace_ath10k_tx_hdr(ar, skb->data, skb->len); + trace_ath10k_tx_payload(ar, skb->data, skb->len); /* Send the management frame buffer to the target */ ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid); @@ -1079,7 +1119,6 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) struct wmi_mgmt_rx_event_v2 *ev_v2; struct wmi_mgmt_rx_hdr_v1 *ev_hdr; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_channel *ch; struct ieee80211_hdr *hdr; u32 rx_status; u32 channel; @@ -1132,25 +1171,26 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) if (rx_status & WMI_RX_STATUS_ERR_MIC) status->flag |= RX_FLAG_MMIC_ERROR; - /* HW can Rx CCK rates on 5GHz. In that case phy_mode is set to + /* Hardware can Rx CCK rates on 5GHz. In that case phy_mode is set to * MODE_11B. This means phy_mode is not a reliable source for the band - * of mgmt rx. */ - - ch = ar->scan_channel; - if (!ch) - ch = ar->rx_channel; - - if (ch) { - status->band = ch->band; - - if (phy_mode == MODE_11B && - status->band == IEEE80211_BAND_5GHZ) - ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n"); + * of mgmt rx. + */ + if (channel >= 1 && channel <= 14) { + status->band = IEEE80211_BAND_2GHZ; + } else if (channel >= 36 && channel <= 165) { + status->band = IEEE80211_BAND_5GHZ; } else { - ath10k_warn(ar, "using (unreliable) phy_mode to extract band for mgmt rx\n"); - status->band = phy_mode_to_band(phy_mode); + /* Shouldn't happen unless list of advertised channels to + * mac80211 has been changed. + */ + WARN_ON_ONCE(1); + dev_kfree_skb(skb); + return 0; } + if (phy_mode == MODE_11B && status->band == IEEE80211_BAND_5GHZ) + ath10k_dbg(ar, ATH10K_DBG_MGMT, "wmi mgmt rx 11b (CCK) on 5GHz\n"); + status->freq = ieee80211_channel_to_frequency(channel, status->band); status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR; status->rate_idx = get_rate_idx(rate, status->band); @@ -1295,14 +1335,196 @@ static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb) return 0; } +static void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src, + struct ath10k_fw_stats_pdev *dst) +{ + const struct wal_dbg_tx_stats *tx = &src->wal.tx; + const struct wal_dbg_rx_stats *rx = &src->wal.rx; + + dst->ch_noise_floor = __le32_to_cpu(src->chan_nf); + dst->tx_frame_count = __le32_to_cpu(src->tx_frame_count); + dst->rx_frame_count = __le32_to_cpu(src->rx_frame_count); + dst->rx_clear_count = __le32_to_cpu(src->rx_clear_count); + dst->cycle_count = __le32_to_cpu(src->cycle_count); + dst->phy_err_count = __le32_to_cpu(src->phy_err_count); + dst->chan_tx_power = __le32_to_cpu(src->chan_tx_pwr); + + dst->comp_queued = __le32_to_cpu(tx->comp_queued); + dst->comp_delivered = __le32_to_cpu(tx->comp_delivered); + dst->msdu_enqued = __le32_to_cpu(tx->msdu_enqued); + dst->mpdu_enqued = __le32_to_cpu(tx->mpdu_enqued); + dst->wmm_drop = __le32_to_cpu(tx->wmm_drop); + dst->local_enqued = __le32_to_cpu(tx->local_enqued); + dst->local_freed = __le32_to_cpu(tx->local_freed); + dst->hw_queued = __le32_to_cpu(tx->hw_queued); + dst->hw_reaped = __le32_to_cpu(tx->hw_reaped); + dst->underrun = __le32_to_cpu(tx->underrun); + dst->tx_abort = __le32_to_cpu(tx->tx_abort); + dst->mpdus_requed = __le32_to_cpu(tx->mpdus_requed); + dst->tx_ko = __le32_to_cpu(tx->tx_ko); + dst->data_rc = __le32_to_cpu(tx->data_rc); + dst->self_triggers = __le32_to_cpu(tx->self_triggers); + dst->sw_retry_failure = __le32_to_cpu(tx->sw_retry_failure); + dst->illgl_rate_phy_err = __le32_to_cpu(tx->illgl_rate_phy_err); + dst->pdev_cont_xretry = __le32_to_cpu(tx->pdev_cont_xretry); + dst->pdev_tx_timeout = __le32_to_cpu(tx->pdev_tx_timeout); + dst->pdev_resets = __le32_to_cpu(tx->pdev_resets); + dst->phy_underrun = __le32_to_cpu(tx->phy_underrun); + dst->txop_ovf = __le32_to_cpu(tx->txop_ovf); + + dst->mid_ppdu_route_change = __le32_to_cpu(rx->mid_ppdu_route_change); + dst->status_rcvd = __le32_to_cpu(rx->status_rcvd); + dst->r0_frags = __le32_to_cpu(rx->r0_frags); + dst->r1_frags = __le32_to_cpu(rx->r1_frags); + dst->r2_frags = __le32_to_cpu(rx->r2_frags); + dst->r3_frags = __le32_to_cpu(rx->r3_frags); + dst->htt_msdus = __le32_to_cpu(rx->htt_msdus); + dst->htt_mpdus = __le32_to_cpu(rx->htt_mpdus); + dst->loc_msdus = __le32_to_cpu(rx->loc_msdus); + dst->loc_mpdus = __le32_to_cpu(rx->loc_mpdus); + dst->oversize_amsdu = __le32_to_cpu(rx->oversize_amsdu); + dst->phy_errs = __le32_to_cpu(rx->phy_errs); + dst->phy_err_drop = __le32_to_cpu(rx->phy_err_drop); + dst->mpdu_errs = __le32_to_cpu(rx->mpdu_errs); +} + +static void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src, + struct ath10k_fw_stats_peer *dst) +{ + ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr); + dst->peer_rssi = __le32_to_cpu(src->peer_rssi); + dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate); +} + +static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) +{ + const struct wmi_stats_event *ev = (void *)skb->data; + u32 num_pdev_stats, num_vdev_stats, num_peer_stats; + int i; + + if (!skb_pull(skb, sizeof(*ev))) + return -EPROTO; + + num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); + num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); + num_peer_stats = __le32_to_cpu(ev->num_peer_stats); + + for (i = 0; i < num_pdev_stats; i++) { + const struct wmi_pdev_stats *src; + struct ath10k_fw_stats_pdev *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_pdev_stats(src, dst); + list_add_tail(&dst->list, &stats->pdevs); + } + + /* fw doesn't implement vdev stats */ + + for (i = 0; i < num_peer_stats; i++) { + const struct wmi_peer_stats *src; + struct ath10k_fw_stats_peer *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_peer_stats(src, dst); + list_add_tail(&dst->list, &stats->peers); + } + + return 0; +} + +static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar, + struct sk_buff *skb, + struct ath10k_fw_stats *stats) +{ + const struct wmi_stats_event *ev = (void *)skb->data; + u32 num_pdev_stats, num_vdev_stats, num_peer_stats; + int i; + + if (!skb_pull(skb, sizeof(*ev))) + return -EPROTO; + + num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); + num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); + num_peer_stats = __le32_to_cpu(ev->num_peer_stats); + + for (i = 0; i < num_pdev_stats; i++) { + const struct wmi_10x_pdev_stats *src; + struct ath10k_fw_stats_pdev *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_pdev_stats(&src->old, dst); + + dst->ack_rx_bad = __le32_to_cpu(src->ack_rx_bad); + dst->rts_bad = __le32_to_cpu(src->rts_bad); + dst->rts_good = __le32_to_cpu(src->rts_good); + dst->fcs_bad = __le32_to_cpu(src->fcs_bad); + dst->no_beacons = __le32_to_cpu(src->no_beacons); + dst->mib_int_count = __le32_to_cpu(src->mib_int_count); + + list_add_tail(&dst->list, &stats->pdevs); + } + + /* fw doesn't implement vdev stats */ + + for (i = 0; i < num_peer_stats; i++) { + const struct wmi_10x_peer_stats *src; + struct ath10k_fw_stats_peer *dst; + + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + + ath10k_wmi_pull_peer_stats(&src->old, dst); + + dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate); + + list_add_tail(&dst->list, &stats->peers); + } + + return 0; +} + +int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, + struct ath10k_fw_stats *stats) +{ + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) + return ath10k_wmi_10x_pull_fw_stats(ar, skb, stats); + else + return ath10k_wmi_main_pull_fw_stats(ar, skb, stats); +} + static void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb) { - struct wmi_stats_event *ev = (struct wmi_stats_event *)skb->data; - ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n"); - - ath10k_debug_read_target_stats(ar, ev); + ath10k_debug_fw_stats_process(ar, skb); } static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, @@ -1579,6 +1801,7 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) struct wmi_bcn_info *bcn_info; struct ath10k_vif *arvif; struct sk_buff *bcn; + dma_addr_t paddr; int ret, vdev_id = 0; ev = (struct wmi_host_swba_event *)skb->data; @@ -1647,27 +1870,37 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ath10k_warn(ar, "SWBA overrun on vdev %d\n", arvif->vdev_id); - dma_unmap_single(arvif->ar->dev, - ATH10K_SKB_CB(arvif->beacon)->paddr, - arvif->beacon->len, DMA_TO_DEVICE); - dev_kfree_skb_any(arvif->beacon); - arvif->beacon = NULL; + ath10k_mac_vif_beacon_free(arvif); } - ATH10K_SKB_CB(bcn)->paddr = dma_map_single(arvif->ar->dev, - bcn->data, bcn->len, - DMA_TO_DEVICE); - ret = dma_mapping_error(arvif->ar->dev, - ATH10K_SKB_CB(bcn)->paddr); - if (ret) { - ath10k_warn(ar, "failed to map beacon: %d\n", ret); - dev_kfree_skb_any(bcn); - goto skip; + if (!arvif->beacon_buf) { + paddr = dma_map_single(arvif->ar->dev, bcn->data, + bcn->len, DMA_TO_DEVICE); + ret = dma_mapping_error(arvif->ar->dev, paddr); + if (ret) { + ath10k_warn(ar, "failed to map beacon: %d\n", + ret); + dev_kfree_skb_any(bcn); + goto skip; + } + + ATH10K_SKB_CB(bcn)->paddr = paddr; + } else { + if (bcn->len > IEEE80211_MAX_FRAME_LEN) { + ath10k_warn(ar, "trimming beacon %d -> %d bytes!\n", + bcn->len, IEEE80211_MAX_FRAME_LEN); + skb_trim(bcn, IEEE80211_MAX_FRAME_LEN); + } + memcpy(arvif->beacon_buf, bcn->data, bcn->len); + ATH10K_SKB_CB(bcn)->paddr = arvif->beacon_paddr; } arvif->beacon = bcn; arvif->beacon_sent = false; + trace_ath10k_tx_hdr(ar, bcn->data, bcn->len); + trace_ath10k_tx_payload(ar, bcn->data, bcn->len); + ath10k_wmi_tx_beacon_nowait(arvif); skip: spin_unlock_bh(&ar->data_lock); @@ -1681,8 +1914,8 @@ static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, } static void ath10k_dfs_radar_report(struct ath10k *ar, - struct wmi_single_phyerr_rx_event *event, - struct phyerr_radar_report *rr, + const struct wmi_phyerr *phyerr, + const struct phyerr_radar_report *rr, u64 tsf) { u32 reg0, reg1, tsf32l; @@ -1715,12 +1948,12 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, return; /* report event to DFS pattern detector */ - tsf32l = __le32_to_cpu(event->hdr.tsf_timestamp); + tsf32l = __le32_to_cpu(phyerr->tsf_timestamp); tsf64 = tsf & (~0xFFFFFFFFULL); tsf64 |= tsf32l; width = MS(reg1, RADAR_REPORT_REG1_PULSE_DUR); - rssi = event->hdr.rssi_combined; + rssi = phyerr->rssi_combined; /* hardware store this as 8 bit signed value, * set to zero if negative number @@ -1759,8 +1992,8 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, } static int ath10k_dfs_fft_report(struct ath10k *ar, - struct wmi_single_phyerr_rx_event *event, - struct phyerr_fft_report *fftr, + const struct wmi_phyerr *phyerr, + const struct phyerr_fft_report *fftr, u64 tsf) { u32 reg0, reg1; @@ -1768,7 +2001,7 @@ static int ath10k_dfs_fft_report(struct ath10k *ar, reg0 = __le32_to_cpu(fftr->reg0); reg1 = __le32_to_cpu(fftr->reg1); - rssi = event->hdr.rssi_combined; + rssi = phyerr->rssi_combined; ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "wmi phyerr fft report total_gain_db %d base_pwr_db %d fft_chn_idx %d peak_sidx %d\n", @@ -1797,20 +2030,20 @@ static int ath10k_dfs_fft_report(struct ath10k *ar, } static void ath10k_wmi_event_dfs(struct ath10k *ar, - struct wmi_single_phyerr_rx_event *event, + const struct wmi_phyerr *phyerr, u64 tsf) { int buf_len, tlv_len, res, i = 0; - struct phyerr_tlv *tlv; - struct phyerr_radar_report *rr; - struct phyerr_fft_report *fftr; - u8 *tlv_buf; + const struct phyerr_tlv *tlv; + const struct phyerr_radar_report *rr; + const struct phyerr_fft_report *fftr; + const u8 *tlv_buf; - buf_len = __le32_to_cpu(event->hdr.buf_len); + buf_len = __le32_to_cpu(phyerr->buf_len); ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "wmi event dfs err_code %d rssi %d tsfl 0x%X tsf64 0x%llX len %d\n", - event->hdr.phy_err_code, event->hdr.rssi_combined, - __le32_to_cpu(event->hdr.tsf_timestamp), tsf, buf_len); + phyerr->phy_err_code, phyerr->rssi_combined, + __le32_to_cpu(phyerr->tsf_timestamp), tsf, buf_len); /* Skip event if DFS disabled */ if (!config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) @@ -1825,9 +2058,9 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar, return; } - tlv = (struct phyerr_tlv *)&event->bufp[i]; + tlv = (struct phyerr_tlv *)&phyerr->buf[i]; tlv_len = __le16_to_cpu(tlv->len); - tlv_buf = &event->bufp[i + sizeof(*tlv)]; + tlv_buf = &phyerr->buf[i + sizeof(*tlv)]; ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "wmi event dfs tlv_len %d tlv_tag 0x%02X tlv_sig 0x%02X\n", tlv_len, tlv->tag, tlv->sig); @@ -1841,7 +2074,7 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar, } rr = (struct phyerr_radar_report *)tlv_buf; - ath10k_dfs_radar_report(ar, event, rr, tsf); + ath10k_dfs_radar_report(ar, phyerr, rr, tsf); break; case PHYERR_TLV_TAG_SEARCH_FFT_REPORT: if (i + sizeof(*tlv) + sizeof(*fftr) > buf_len) { @@ -1851,7 +2084,7 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar, } fftr = (struct phyerr_fft_report *)tlv_buf; - res = ath10k_dfs_fft_report(ar, event, fftr, tsf); + res = ath10k_dfs_fft_report(ar, phyerr, fftr, tsf); if (res) return; break; @@ -1863,16 +2096,16 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar, static void ath10k_wmi_event_spectral_scan(struct ath10k *ar, - struct wmi_single_phyerr_rx_event *event, + const struct wmi_phyerr *phyerr, u64 tsf) { int buf_len, tlv_len, res, i = 0; struct phyerr_tlv *tlv; - u8 *tlv_buf; - struct phyerr_fft_report *fftr; + const void *tlv_buf; + const struct phyerr_fft_report *fftr; size_t fftr_len; - buf_len = __le32_to_cpu(event->hdr.buf_len); + buf_len = __le32_to_cpu(phyerr->buf_len); while (i < buf_len) { if (i + sizeof(*tlv) > buf_len) { @@ -1881,9 +2114,9 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar, return; } - tlv = (struct phyerr_tlv *)&event->bufp[i]; + tlv = (struct phyerr_tlv *)&phyerr->buf[i]; tlv_len = __le16_to_cpu(tlv->len); - tlv_buf = &event->bufp[i + sizeof(*tlv)]; + tlv_buf = &phyerr->buf[i + sizeof(*tlv)]; if (i + sizeof(*tlv) + tlv_len > buf_len) { ath10k_warn(ar, "failed to parse phyerr tlv payload at byte %d\n", @@ -1900,8 +2133,8 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar, } fftr_len = tlv_len - sizeof(*fftr); - fftr = (struct phyerr_fft_report *)tlv_buf; - res = ath10k_spectral_process_fft(ar, event, + fftr = tlv_buf; + res = ath10k_spectral_process_fft(ar, phyerr, fftr, fftr_len, tsf); if (res < 0) { @@ -1918,8 +2151,8 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar, static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) { - struct wmi_comb_phyerr_rx_event *comb_event; - struct wmi_single_phyerr_rx_event *event; + const struct wmi_phyerr_event *ev; + const struct wmi_phyerr *phyerr; u32 count, i, buf_len, phy_err_code; u64 tsf; int left_len = skb->len; @@ -1927,38 +2160,38 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) ATH10K_DFS_STAT_INC(ar, phy_errors); /* Check if combined event available */ - if (left_len < sizeof(*comb_event)) { + if (left_len < sizeof(*ev)) { ath10k_warn(ar, "wmi phyerr combined event wrong len\n"); return; } - left_len -= sizeof(*comb_event); + left_len -= sizeof(*ev); /* Check number of included events */ - comb_event = (struct wmi_comb_phyerr_rx_event *)skb->data; - count = __le32_to_cpu(comb_event->hdr.num_phyerr_events); + ev = (const struct wmi_phyerr_event *)skb->data; + count = __le32_to_cpu(ev->num_phyerrs); - tsf = __le32_to_cpu(comb_event->hdr.tsf_u32); + tsf = __le32_to_cpu(ev->tsf_u32); tsf <<= 32; - tsf |= __le32_to_cpu(comb_event->hdr.tsf_l32); + tsf |= __le32_to_cpu(ev->tsf_l32); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event phyerr count %d tsf64 0x%llX\n", count, tsf); - event = (struct wmi_single_phyerr_rx_event *)comb_event->bufp; + phyerr = ev->phyerrs; for (i = 0; i < count; i++) { /* Check if we can read event header */ - if (left_len < sizeof(*event)) { + if (left_len < sizeof(*phyerr)) { ath10k_warn(ar, "single event (%d) wrong head len\n", i); return; } - left_len -= sizeof(*event); + left_len -= sizeof(*phyerr); - buf_len = __le32_to_cpu(event->hdr.buf_len); - phy_err_code = event->hdr.phy_err_code; + buf_len = __le32_to_cpu(phyerr->buf_len); + phy_err_code = phyerr->phy_err_code; if (left_len < buf_len) { ath10k_warn(ar, "single event (%d) wrong buf len\n", i); @@ -1969,20 +2202,20 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb) switch (phy_err_code) { case PHY_ERROR_RADAR: - ath10k_wmi_event_dfs(ar, event, tsf); + ath10k_wmi_event_dfs(ar, phyerr, tsf); break; case PHY_ERROR_SPECTRAL_SCAN: - ath10k_wmi_event_spectral_scan(ar, event, tsf); + ath10k_wmi_event_spectral_scan(ar, phyerr, tsf); break; case PHY_ERROR_FALSE_RADAR_EXT: - ath10k_wmi_event_dfs(ar, event, tsf); - ath10k_wmi_event_spectral_scan(ar, event, tsf); + ath10k_wmi_event_dfs(ar, phyerr, tsf); + ath10k_wmi_event_spectral_scan(ar, phyerr, tsf); break; default: break; } - event += sizeof(*event) + buf_len; + phyerr = (void *)phyerr + sizeof(*phyerr) + buf_len; } } @@ -2163,30 +2396,113 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, return 0; } -static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, - struct sk_buff *skb) +static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg) { - struct wmi_service_ready_event *ev = (void *)skb->data; + struct wmi_service_ready_event *ev; + size_t i, n; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + ev = (void *)skb->data; + skb_pull(skb, sizeof(*ev)); + arg->min_tx_power = ev->hw_min_tx_power; + arg->max_tx_power = ev->hw_max_tx_power; + arg->ht_cap = ev->ht_cap_info; + arg->vht_cap = ev->vht_cap_info; + arg->sw_ver0 = ev->sw_version; + arg->sw_ver1 = ev->sw_version_1; + arg->phy_capab = ev->phy_capability; + arg->num_rf_chains = ev->num_rf_chains; + arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; + arg->num_mem_reqs = ev->num_mem_reqs; + arg->service_map = ev->wmi_service_bitmap; + + n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), + ARRAY_SIZE(arg->mem_reqs)); + for (i = 0; i < n; i++) + arg->mem_reqs[i] = &ev->mem_reqs[i]; + + if (skb->len < + __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0])) + return -EPROTO; + + return 0; +} + +static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb, + struct wmi_svc_rdy_ev_arg *arg) +{ + struct wmi_10x_service_ready_event *ev; + int i, n; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + ev = (void *)skb->data; + skb_pull(skb, sizeof(*ev)); + arg->min_tx_power = ev->hw_min_tx_power; + arg->max_tx_power = ev->hw_max_tx_power; + arg->ht_cap = ev->ht_cap_info; + arg->vht_cap = ev->vht_cap_info; + arg->sw_ver0 = ev->sw_version; + arg->phy_capab = ev->phy_capability; + arg->num_rf_chains = ev->num_rf_chains; + arg->eeprom_rd = ev->hal_reg_capabilities.eeprom_rd; + arg->num_mem_reqs = ev->num_mem_reqs; + arg->service_map = ev->wmi_service_bitmap; + + n = min_t(size_t, __le32_to_cpu(arg->num_mem_reqs), + ARRAY_SIZE(arg->mem_reqs)); + for (i = 0; i < n; i++) + arg->mem_reqs[i] = &ev->mem_reqs[i]; + + if (skb->len < + __le32_to_cpu(arg->num_mem_reqs) * sizeof(arg->mem_reqs[0])) + return -EPROTO; + + return 0; +} + +static void ath10k_wmi_event_service_ready(struct ath10k *ar, + struct sk_buff *skb) +{ + struct wmi_svc_rdy_ev_arg arg = {}; + u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {}; + int ret; + + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg); + wmi_10x_svc_map(arg.service_map, svc_bmap); + } else { + ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg); + wmi_main_svc_map(arg.service_map, svc_bmap); + } - if (skb->len < sizeof(*ev)) { - ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n", - skb->len, sizeof(*ev)); + if (ret) { + ath10k_warn(ar, "failed to parse service ready: %d\n", ret); return; } - ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power); - ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power); - ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info); - ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info); + ar->hw_min_tx_power = __le32_to_cpu(arg.min_tx_power); + ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power); + ar->ht_cap_info = __le32_to_cpu(arg.ht_cap); + ar->vht_cap_info = __le32_to_cpu(arg.vht_cap); ar->fw_version_major = - (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24; - ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff); + (__le32_to_cpu(arg.sw_ver0) & 0xff000000) >> 24; + ar->fw_version_minor = (__le32_to_cpu(arg.sw_ver0) & 0x00ffffff); ar->fw_version_release = - (__le32_to_cpu(ev->sw_version_1) & 0xffff0000) >> 16; - ar->fw_version_build = (__le32_to_cpu(ev->sw_version_1) & 0x0000ffff); - ar->phy_capability = __le32_to_cpu(ev->phy_capability); - ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains); + (__le32_to_cpu(arg.sw_ver1) & 0xffff0000) >> 16; + ar->fw_version_build = (__le32_to_cpu(arg.sw_ver1) & 0x0000ffff); + ar->phy_capability = __le32_to_cpu(arg.phy_capab); + ar->num_rf_chains = __le32_to_cpu(arg.num_rf_chains); + ar->ath_common.regulatory.current_rd = __le32_to_cpu(arg.eeprom_rd); + + ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap)); + ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", + arg.service_map, sizeof(arg.service_map)); /* only manually set fw features when not using FW IE format */ if (ar->fw_api == 1 && ar->fw_version_build > 636) @@ -2198,13 +2514,8 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; } - ar->ath_common.regulatory.current_rd = - __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); - - wmi_main_svc_map(ev->wmi_service_bitmap, svc_bmap); - ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap)); - ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", - ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap)); + ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1; + ar->supp_rx_chainmask = (1 << ar->num_rf_chains) - 1; if (strlen(ar->hw->wiphy->fw_version) == 0) { snprintf(ar->hw->wiphy->fw_version, @@ -2216,93 +2527,18 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar, ar->fw_version_build); } - /* FIXME: it probably should be better to support this */ - if (__le32_to_cpu(ev->num_mem_reqs) > 0) { - ath10k_warn(ar, "target requested %d memory chunks; ignoring\n", - __le32_to_cpu(ev->num_mem_reqs)); - } - - ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi event service ready sw_ver 0x%08x sw_ver1 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n", - __le32_to_cpu(ev->sw_version), - __le32_to_cpu(ev->sw_version_1), - __le32_to_cpu(ev->abi_version), - __le32_to_cpu(ev->phy_capability), - __le32_to_cpu(ev->ht_cap_info), - __le32_to_cpu(ev->vht_cap_info), - __le32_to_cpu(ev->vht_supp_mcs), - __le32_to_cpu(ev->sys_cap_info), - __le32_to_cpu(ev->num_mem_reqs), - __le32_to_cpu(ev->num_rf_chains)); - - complete(&ar->wmi.service_ready); -} - -static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, - struct sk_buff *skb) -{ - u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i; - int ret; - struct wmi_service_ready_event_10x *ev = (void *)skb->data; - DECLARE_BITMAP(svc_bmap, WMI_SERVICE_MAX) = {}; - - if (skb->len < sizeof(*ev)) { - ath10k_warn(ar, "Service ready event was %d B but expected %zu B. Wrong firmware version?\n", - skb->len, sizeof(*ev)); - return; - } - - ar->hw_min_tx_power = __le32_to_cpu(ev->hw_min_tx_power); - ar->hw_max_tx_power = __le32_to_cpu(ev->hw_max_tx_power); - ar->ht_cap_info = __le32_to_cpu(ev->ht_cap_info); - ar->vht_cap_info = __le32_to_cpu(ev->vht_cap_info); - ar->fw_version_major = - (__le32_to_cpu(ev->sw_version) & 0xff000000) >> 24; - ar->fw_version_minor = (__le32_to_cpu(ev->sw_version) & 0x00ffffff); - ar->phy_capability = __le32_to_cpu(ev->phy_capability); - ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains); - - if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { - ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n", - ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); - ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; - } - - ar->ath_common.regulatory.current_rd = - __le32_to_cpu(ev->hal_reg_capabilities.eeprom_rd); - - wmi_10x_svc_map(ev->wmi_service_bitmap, svc_bmap); - ath10k_debug_read_service_map(ar, svc_bmap, sizeof(svc_bmap)); - ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ", - ev->wmi_service_bitmap, sizeof(ev->wmi_service_bitmap)); - - if (strlen(ar->hw->wiphy->fw_version) == 0) { - snprintf(ar->hw->wiphy->fw_version, - sizeof(ar->hw->wiphy->fw_version), - "%u.%u", - ar->fw_version_major, - ar->fw_version_minor); - } - - num_mem_reqs = __le32_to_cpu(ev->num_mem_reqs); - - if (num_mem_reqs > ATH10K_MAX_MEM_REQS) { + num_mem_reqs = __le32_to_cpu(arg.num_mem_reqs); + if (num_mem_reqs > WMI_MAX_MEM_REQS) { ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n", num_mem_reqs); return; } - if (!num_mem_reqs) - goto exit; - - ath10k_dbg(ar, ATH10K_DBG_WMI, "firmware has requested %d memory chunks\n", - num_mem_reqs); - for (i = 0; i < num_mem_reqs; ++i) { - req_id = __le32_to_cpu(ev->mem_reqs[i].req_id); - num_units = __le32_to_cpu(ev->mem_reqs[i].num_units); - unit_size = __le32_to_cpu(ev->mem_reqs[i].unit_size); - num_unit_info = __le32_to_cpu(ev->mem_reqs[i].num_unit_info); + req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id); + num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units); + unit_size = __le32_to_cpu(arg.mem_reqs[i]->unit_size); + num_unit_info = __le32_to_cpu(arg.mem_reqs[i]->num_unit_info); if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) /* number of units to allocate is number of @@ -2316,7 +2552,7 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n", req_id, - __le32_to_cpu(ev->mem_reqs[i].num_units), + __le32_to_cpu(arg.mem_reqs[i]->num_units), num_unit_info, unit_size, num_units); @@ -2327,23 +2563,23 @@ static void ath10k_wmi_10x_service_ready_event_rx(struct ath10k *ar, return; } -exit: ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi event service ready sw_ver 0x%08x abi_ver %u phy_cap 0x%08x ht_cap 0x%08x vht_cap 0x%08x vht_supp_msc 0x%08x sys_cap_info 0x%08x mem_reqs %u num_rf_chains %u\n", - __le32_to_cpu(ev->sw_version), - __le32_to_cpu(ev->abi_version), - __le32_to_cpu(ev->phy_capability), - __le32_to_cpu(ev->ht_cap_info), - __le32_to_cpu(ev->vht_cap_info), - __le32_to_cpu(ev->vht_supp_mcs), - __le32_to_cpu(ev->sys_cap_info), - __le32_to_cpu(ev->num_mem_reqs), - __le32_to_cpu(ev->num_rf_chains)); + "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n", + __le32_to_cpu(arg.min_tx_power), + __le32_to_cpu(arg.max_tx_power), + __le32_to_cpu(arg.ht_cap), + __le32_to_cpu(arg.vht_cap), + __le32_to_cpu(arg.sw_ver0), + __le32_to_cpu(arg.sw_ver1), + __le32_to_cpu(arg.phy_capab), + __le32_to_cpu(arg.num_rf_chains), + __le32_to_cpu(arg.eeprom_rd), + __le32_to_cpu(arg.num_mem_reqs)); complete(&ar->wmi.service_ready); } -static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb) +static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb) { struct wmi_ready_event *ev = (struct wmi_ready_event *)skb->data; @@ -2466,10 +2702,10 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_vdev_install_key_complete(ar, skb); break; case WMI_SERVICE_READY_EVENTID: - ath10k_wmi_service_ready_event_rx(ar, skb); + ath10k_wmi_event_service_ready(ar, skb); break; case WMI_READY_EVENTID: - ath10k_wmi_ready_event_rx(ar, skb); + ath10k_wmi_event_ready(ar, skb); break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); @@ -2586,10 +2822,10 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_vdev_resume_req(ar, skb); break; case WMI_10X_SERVICE_READY_EVENTID: - ath10k_wmi_10x_service_ready_event_rx(ar, skb); + ath10k_wmi_event_service_ready(ar, skb); break; case WMI_10X_READY_EVENTID: - ath10k_wmi_ready_event_rx(ar, skb); + ath10k_wmi_event_ready(ar, skb); break; case WMI_10X_PDEV_UTF_EVENTID: /* ignore utf events */ @@ -2697,10 +2933,10 @@ static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_vdev_resume_req(ar, skb); break; case WMI_10_2_SERVICE_READY_EVENTID: - ath10k_wmi_10x_service_ready_event_rx(ar, skb); + ath10k_wmi_event_service_ready(ar, skb); break; case WMI_10_2_READY_EVENTID: - ath10k_wmi_ready_event_rx(ar, skb); + ath10k_wmi_event_ready(ar, skb); break; case WMI_10_2_RTT_KEEPALIVE_EVENTID: case WMI_10_2_GPIO_INPUT_EVENTID: @@ -2732,45 +2968,6 @@ static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) } } -/* WMI Initialization functions */ -int ath10k_wmi_attach(struct ath10k *ar) -{ - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { - if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - ar->wmi.cmd = &wmi_10_2_cmd_map; - else - ar->wmi.cmd = &wmi_10x_cmd_map; - - ar->wmi.vdev_param = &wmi_10x_vdev_param_map; - ar->wmi.pdev_param = &wmi_10x_pdev_param_map; - } else { - ar->wmi.cmd = &wmi_cmd_map; - ar->wmi.vdev_param = &wmi_vdev_param_map; - ar->wmi.pdev_param = &wmi_pdev_param_map; - } - - init_completion(&ar->wmi.service_ready); - init_completion(&ar->wmi.unified_ready); - init_waitqueue_head(&ar->wmi.tx_credits_wq); - - return 0; -} - -void ath10k_wmi_detach(struct ath10k *ar) -{ - int i; - - /* free the host memory chunks requested by firmware */ - for (i = 0; i < ar->wmi.num_mem_chunks; i++) { - dma_free_coherent(ar->dev, - ar->wmi.mem_chunks[i].len, - ar->wmi.mem_chunks[i].vaddr, - ar->wmi.mem_chunks[i].paddr); - } - - ar->wmi.num_mem_chunks = 0; -} - int ath10k_wmi_connect(struct ath10k *ar) { int status; @@ -2865,42 +3062,6 @@ int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, ctl2g, ctl5g); } -int ath10k_wmi_pdev_set_channel(struct ath10k *ar, - const struct wmi_channel_arg *arg) -{ - struct wmi_set_channel_cmd *cmd; - struct sk_buff *skb; - u32 ch_flags = 0; - - if (arg->passive) - return -EINVAL; - - skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); - if (!skb) - return -ENOMEM; - - if (arg->chan_radar) - ch_flags |= WMI_CHAN_FLAG_DFS; - - cmd = (struct wmi_set_channel_cmd *)skb->data; - cmd->chan.mhz = __cpu_to_le32(arg->freq); - cmd->chan.band_center_freq1 = __cpu_to_le32(arg->freq); - cmd->chan.mode = arg->mode; - cmd->chan.flags |= __cpu_to_le32(ch_flags); - cmd->chan.min_power = arg->min_power; - cmd->chan.max_power = arg->max_power; - cmd->chan.reg_power = arg->max_reg_power; - cmd->chan.reg_classid = arg->reg_class_id; - cmd->chan.antenna_max = arg->max_antenna_gain; - - ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi set channel mode %d freq %d\n", - arg->mode, arg->freq); - - return ath10k_wmi_cmd_send(ar, skb, - ar->wmi.cmd->pdev_set_channel_cmdid); -} - int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt) { struct wmi_pdev_suspend_cmd *cmd; @@ -2951,13 +3112,34 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value) return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid); } +static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar, + struct wmi_host_mem_chunks *chunks) +{ + struct host_memory_chunk *chunk; + int i; + + chunks->count = __cpu_to_le32(ar->wmi.num_mem_chunks); + + for (i = 0; i < ar->wmi.num_mem_chunks; i++) { + chunk = &chunks->items[i]; + chunk->ptr = __cpu_to_le32(ar->wmi.mem_chunks[i].paddr); + chunk->size = __cpu_to_le32(ar->wmi.mem_chunks[i].len); + chunk->req_id = __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi chunk %d len %d requested, addr 0x%llx\n", + i, + ar->wmi.mem_chunks[i].len, + (unsigned long long)ar->wmi.mem_chunks[i].paddr); + } +} + static int ath10k_wmi_main_cmd_init(struct ath10k *ar) { struct wmi_init_cmd *cmd; struct sk_buff *buf; struct wmi_resource_config config = {}; u32 len, val; - int i; config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS); config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS + TARGET_NUM_VDEVS); @@ -3019,32 +3201,8 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar) cmd = (struct wmi_init_cmd *)buf->data; - if (ar->wmi.num_mem_chunks == 0) { - cmd->num_host_mem_chunks = 0; - goto out; - } - - ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", - ar->wmi.num_mem_chunks); - - cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); - - for (i = 0; i < ar->wmi.num_mem_chunks; i++) { - cmd->host_mem_chunks[i].ptr = - __cpu_to_le32(ar->wmi.mem_chunks[i].paddr); - cmd->host_mem_chunks[i].size = - __cpu_to_le32(ar->wmi.mem_chunks[i].len); - cmd->host_mem_chunks[i].req_id = - __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); - - ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi chunk %d len %d requested, addr 0x%llx\n", - i, - ar->wmi.mem_chunks[i].len, - (unsigned long long)ar->wmi.mem_chunks[i].paddr); - } -out: memcpy(&cmd->resource_config, &config, sizeof(config)); + ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n"); return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); @@ -3056,7 +3214,6 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) struct sk_buff *buf; struct wmi_resource_config_10x config = {}; u32 len, val; - int i; config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS); config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); @@ -3110,32 +3267,8 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar) cmd = (struct wmi_init_cmd_10x *)buf->data; - if (ar->wmi.num_mem_chunks == 0) { - cmd->num_host_mem_chunks = 0; - goto out; - } - - ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", - ar->wmi.num_mem_chunks); - - cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); - - for (i = 0; i < ar->wmi.num_mem_chunks; i++) { - cmd->host_mem_chunks[i].ptr = - __cpu_to_le32(ar->wmi.mem_chunks[i].paddr); - cmd->host_mem_chunks[i].size = - __cpu_to_le32(ar->wmi.mem_chunks[i].len); - cmd->host_mem_chunks[i].req_id = - __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); - - ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi chunk %d len %d requested, addr 0x%llx\n", - i, - ar->wmi.mem_chunks[i].len, - (unsigned long long)ar->wmi.mem_chunks[i].paddr); - } -out: memcpy(&cmd->resource_config, &config, sizeof(config)); + ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n"); return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); @@ -3147,7 +3280,6 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) struct sk_buff *buf; struct wmi_resource_config_10x config = {}; u32 len, val; - int i; config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS); config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS); @@ -3201,32 +3333,8 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar) cmd = (struct wmi_init_cmd_10_2 *)buf->data; - if (ar->wmi.num_mem_chunks == 0) { - cmd->num_host_mem_chunks = 0; - goto out; - } - - ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n", - ar->wmi.num_mem_chunks); - - cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks); - - for (i = 0; i < ar->wmi.num_mem_chunks; i++) { - cmd->host_mem_chunks[i].ptr = - __cpu_to_le32(ar->wmi.mem_chunks[i].paddr); - cmd->host_mem_chunks[i].size = - __cpu_to_le32(ar->wmi.mem_chunks[i].len); - cmd->host_mem_chunks[i].req_id = - __cpu_to_le32(ar->wmi.mem_chunks[i].req_id); - - ath10k_dbg(ar, ATH10K_DBG_WMI, - "wmi chunk %d len %d requested, addr 0x%llx\n", - i, - ar->wmi.mem_chunks[i].len, - (unsigned long long)ar->wmi.mem_chunks[i].paddr); - } -out: memcpy(&cmd->resource_config.common, &config, sizeof(config)); + ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n"); return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid); @@ -3248,52 +3356,50 @@ int ath10k_wmi_cmd_init(struct ath10k *ar) return ret; } -static int ath10k_wmi_start_scan_calc_len(struct ath10k *ar, - const struct wmi_start_scan_arg *arg) +static int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) { - int len; + if (arg->ie_len && !arg->ie) + return -EINVAL; + if (arg->n_channels && !arg->channels) + return -EINVAL; + if (arg->n_ssids && !arg->ssids) + return -EINVAL; + if (arg->n_bssids && !arg->bssids) + return -EINVAL; - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - len = sizeof(struct wmi_start_scan_cmd_10x); - else - len = sizeof(struct wmi_start_scan_cmd); + if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN) + return -EINVAL; + if (arg->n_channels > ARRAY_SIZE(arg->channels)) + return -EINVAL; + if (arg->n_ssids > WLAN_SCAN_PARAMS_MAX_SSID) + return -EINVAL; + if (arg->n_bssids > WLAN_SCAN_PARAMS_MAX_BSSID) + return -EINVAL; - if (arg->ie_len) { - if (!arg->ie) - return -EINVAL; - if (arg->ie_len > WLAN_SCAN_PARAMS_MAX_IE_LEN) - return -EINVAL; + return 0; +} + +static size_t +ath10k_wmi_start_scan_tlvs_len(const struct wmi_start_scan_arg *arg) +{ + int len = 0; + if (arg->ie_len) { len += sizeof(struct wmi_ie_data); len += roundup(arg->ie_len, 4); } if (arg->n_channels) { - if (!arg->channels) - return -EINVAL; - if (arg->n_channels > ARRAY_SIZE(arg->channels)) - return -EINVAL; - len += sizeof(struct wmi_chan_list); len += sizeof(__le32) * arg->n_channels; } if (arg->n_ssids) { - if (!arg->ssids) - return -EINVAL; - if (arg->n_ssids > WLAN_SCAN_PARAMS_MAX_SSID) - return -EINVAL; - len += sizeof(struct wmi_ssid_list); len += sizeof(struct wmi_ssid) * arg->n_ssids; } if (arg->n_bssids) { - if (!arg->bssids) - return -EINVAL; - if (arg->n_bssids > WLAN_SCAN_PARAMS_MAX_BSSID) - return -EINVAL; - len += sizeof(struct wmi_bssid_list); len += sizeof(struct wmi_mac_addr) * arg->n_bssids; } @@ -3301,28 +3407,12 @@ static int ath10k_wmi_start_scan_calc_len(struct ath10k *ar, return len; } -int ath10k_wmi_start_scan(struct ath10k *ar, - const struct wmi_start_scan_arg *arg) +static void +ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn, + const struct wmi_start_scan_arg *arg) { - struct wmi_start_scan_cmd *cmd; - struct sk_buff *skb; - struct wmi_ie_data *ie; - struct wmi_chan_list *channels; - struct wmi_ssid_list *ssids; - struct wmi_bssid_list *bssids; u32 scan_id; u32 scan_req_id; - int off; - int len = 0; - int i; - - len = ath10k_wmi_start_scan_calc_len(ar, arg); - if (len < 0) - return len; /* len contains error code here */ - - skb = ath10k_wmi_alloc_skb(ar, len); - if (!skb) - return -ENOMEM; scan_id = WMI_HOST_SCAN_REQ_ID_PREFIX; scan_id |= arg->scan_id; @@ -3330,35 +3420,36 @@ int ath10k_wmi_start_scan(struct ath10k *ar, scan_req_id = WMI_HOST_SCAN_REQUESTOR_ID_PREFIX; scan_req_id |= arg->scan_req_id; - cmd = (struct wmi_start_scan_cmd *)skb->data; - cmd->scan_id = __cpu_to_le32(scan_id); - cmd->scan_req_id = __cpu_to_le32(scan_req_id); - cmd->vdev_id = __cpu_to_le32(arg->vdev_id); - cmd->scan_priority = __cpu_to_le32(arg->scan_priority); - cmd->notify_scan_events = __cpu_to_le32(arg->notify_scan_events); - cmd->dwell_time_active = __cpu_to_le32(arg->dwell_time_active); - cmd->dwell_time_passive = __cpu_to_le32(arg->dwell_time_passive); - cmd->min_rest_time = __cpu_to_le32(arg->min_rest_time); - cmd->max_rest_time = __cpu_to_le32(arg->max_rest_time); - cmd->repeat_probe_time = __cpu_to_le32(arg->repeat_probe_time); - cmd->probe_spacing_time = __cpu_to_le32(arg->probe_spacing_time); - cmd->idle_time = __cpu_to_le32(arg->idle_time); - cmd->max_scan_time = __cpu_to_le32(arg->max_scan_time); - cmd->probe_delay = __cpu_to_le32(arg->probe_delay); - cmd->scan_ctrl_flags = __cpu_to_le32(arg->scan_ctrl_flags); - - /* TLV list starts after fields included in the struct */ - /* There's just one filed that differes the two start_scan - * structures - burst_duration, which we are not using btw, - no point to make the split here, just shift the buffer to fit with - given FW */ - if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) - off = sizeof(struct wmi_start_scan_cmd_10x); - else - off = sizeof(struct wmi_start_scan_cmd); + cmn->scan_id = __cpu_to_le32(scan_id); + cmn->scan_req_id = __cpu_to_le32(scan_req_id); + cmn->vdev_id = __cpu_to_le32(arg->vdev_id); + cmn->scan_priority = __cpu_to_le32(arg->scan_priority); + cmn->notify_scan_events = __cpu_to_le32(arg->notify_scan_events); + cmn->dwell_time_active = __cpu_to_le32(arg->dwell_time_active); + cmn->dwell_time_passive = __cpu_to_le32(arg->dwell_time_passive); + cmn->min_rest_time = __cpu_to_le32(arg->min_rest_time); + cmn->max_rest_time = __cpu_to_le32(arg->max_rest_time); + cmn->repeat_probe_time = __cpu_to_le32(arg->repeat_probe_time); + cmn->probe_spacing_time = __cpu_to_le32(arg->probe_spacing_time); + cmn->idle_time = __cpu_to_le32(arg->idle_time); + cmn->max_scan_time = __cpu_to_le32(arg->max_scan_time); + cmn->probe_delay = __cpu_to_le32(arg->probe_delay); + cmn->scan_ctrl_flags = __cpu_to_le32(arg->scan_ctrl_flags); +} + +static void +ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs, + const struct wmi_start_scan_arg *arg) +{ + struct wmi_ie_data *ie; + struct wmi_chan_list *channels; + struct wmi_ssid_list *ssids; + struct wmi_bssid_list *bssids; + void *ptr = tlvs->tlvs; + int i; if (arg->n_channels) { - channels = (void *)skb->data + off; + channels = ptr; channels->tag = __cpu_to_le32(WMI_CHAN_LIST_TAG); channels->num_chan = __cpu_to_le32(arg->n_channels); @@ -3366,12 +3457,12 @@ int ath10k_wmi_start_scan(struct ath10k *ar, channels->channel_list[i].freq = __cpu_to_le16(arg->channels[i]); - off += sizeof(*channels); - off += sizeof(__le32) * arg->n_channels; + ptr += sizeof(*channels); + ptr += sizeof(__le32) * arg->n_channels; } if (arg->n_ssids) { - ssids = (void *)skb->data + off; + ssids = ptr; ssids->tag = __cpu_to_le32(WMI_SSID_LIST_TAG); ssids->num_ssids = __cpu_to_le32(arg->n_ssids); @@ -3383,12 +3474,12 @@ int ath10k_wmi_start_scan(struct ath10k *ar, arg->ssids[i].len); } - off += sizeof(*ssids); - off += sizeof(struct wmi_ssid) * arg->n_ssids; + ptr += sizeof(*ssids); + ptr += sizeof(struct wmi_ssid) * arg->n_ssids; } if (arg->n_bssids) { - bssids = (void *)skb->data + off; + bssids = ptr; bssids->tag = __cpu_to_le32(WMI_BSSID_LIST_TAG); bssids->num_bssid = __cpu_to_le32(arg->n_bssids); @@ -3397,23 +3488,57 @@ int ath10k_wmi_start_scan(struct ath10k *ar, arg->bssids[i].bssid, ETH_ALEN); - off += sizeof(*bssids); - off += sizeof(struct wmi_mac_addr) * arg->n_bssids; + ptr += sizeof(*bssids); + ptr += sizeof(struct wmi_mac_addr) * arg->n_bssids; } if (arg->ie_len) { - ie = (void *)skb->data + off; + ie = ptr; ie->tag = __cpu_to_le32(WMI_IE_TAG); ie->ie_len = __cpu_to_le32(arg->ie_len); memcpy(ie->ie_data, arg->ie, arg->ie_len); - off += sizeof(*ie); - off += roundup(arg->ie_len, 4); + ptr += sizeof(*ie); + ptr += roundup(arg->ie_len, 4); } +} - if (off != skb->len) { - dev_kfree_skb(skb); - return -EINVAL; +int ath10k_wmi_start_scan(struct ath10k *ar, + const struct wmi_start_scan_arg *arg) +{ + struct sk_buff *skb; + size_t len; + int ret; + + ret = ath10k_wmi_start_scan_verify(arg); + if (ret) + return ret; + + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) + len = sizeof(struct wmi_10x_start_scan_cmd) + + ath10k_wmi_start_scan_tlvs_len(arg); + else + len = sizeof(struct wmi_start_scan_cmd) + + ath10k_wmi_start_scan_tlvs_len(arg); + + skb = ath10k_wmi_alloc_skb(ar, len); + if (!skb) + return -ENOMEM; + + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + struct wmi_10x_start_scan_cmd *cmd; + + cmd = (struct wmi_10x_start_scan_cmd *)skb->data; + ath10k_wmi_put_start_scan_common(&cmd->common, arg); + ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); + } else { + struct wmi_start_scan_cmd *cmd; + + cmd = (struct wmi_start_scan_cmd *)skb->data; + cmd->burst_duration_ms = __cpu_to_le32(0); + + ath10k_wmi_put_start_scan_common(&cmd->common, arg); + ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg); } ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n"); @@ -3532,7 +3657,6 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar, struct sk_buff *skb; const char *cmdname; u32 flags = 0; - u32 ch_flags = 0; if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid && cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid) @@ -3559,8 +3683,6 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar, flags |= WMI_VDEV_START_HIDDEN_SSID; if (arg->pmf_enabled) flags |= WMI_VDEV_START_PMF_ENABLED; - if (arg->channel.chan_radar) - ch_flags |= WMI_CHAN_FLAG_DFS; cmd = (struct wmi_vdev_start_request_cmd *)skb->data; cmd->vdev_id = __cpu_to_le32(arg->vdev_id); @@ -3576,18 +3698,7 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar, memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len); } - cmd->chan.mhz = __cpu_to_le32(arg->channel.freq); - - cmd->chan.band_center_freq1 = - __cpu_to_le32(arg->channel.band_center_freq1); - - cmd->chan.mode = arg->channel.mode; - cmd->chan.flags |= __cpu_to_le32(ch_flags); - cmd->chan.min_power = arg->channel.min_power; - cmd->chan.max_power = arg->channel.max_power; - cmd->chan.reg_power = arg->channel.max_reg_power; - cmd->chan.reg_classid = arg->channel.reg_class_id; - cmd->chan.antenna_max = arg->channel.max_antenna_gain; + ath10k_wmi_put_wmi_channel(&cmd->chan, &arg->channel); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, ch_flags: 0x%0X, max_power: %d\n", @@ -3968,35 +4079,10 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar, cmd->num_scan_chans = __cpu_to_le32(arg->n_channels); for (i = 0; i < arg->n_channels; i++) { - u32 flags = 0; - ch = &arg->channels[i]; ci = &cmd->chan_info[i]; - if (ch->passive) - flags |= WMI_CHAN_FLAG_PASSIVE; - if (ch->allow_ibss) - flags |= WMI_CHAN_FLAG_ADHOC_ALLOWED; - if (ch->allow_ht) - flags |= WMI_CHAN_FLAG_ALLOW_HT; - if (ch->allow_vht) - flags |= WMI_CHAN_FLAG_ALLOW_VHT; - if (ch->ht40plus) - flags |= WMI_CHAN_FLAG_HT40_PLUS; - if (ch->chan_radar) - flags |= WMI_CHAN_FLAG_DFS; - - ci->mhz = __cpu_to_le32(ch->freq); - ci->band_center_freq1 = __cpu_to_le32(ch->freq); - ci->band_center_freq2 = 0; - ci->min_power = ch->min_power; - ci->max_power = ch->max_power; - ci->reg_power = ch->max_reg_power; - ci->antenna_max = ch->max_antenna_gain; - - /* mode & flags share storage */ - ci->mode = ch->mode; - ci->flags |= __cpu_to_le32(flags); + ath10k_wmi_put_wmi_channel(ci, ch); } return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid); @@ -4108,9 +4194,9 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar, if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) - ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg); - else ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg); + else + ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg); } else { ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg); } @@ -4267,3 +4353,73 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable) return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid); } + +int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_bitmap) +{ + struct wmi_pdev_pktlog_enable_cmd *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + ev_bitmap &= ATH10K_PKTLOG_ANY; + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi enable pktlog filter:%x\n", ev_bitmap); + + cmd = (struct wmi_pdev_pktlog_enable_cmd *)skb->data; + cmd->ev_bitmap = __cpu_to_le32(ev_bitmap); + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_pktlog_enable_cmdid); +} + +int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar) +{ + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, 0); + if (!skb) + return -ENOMEM; + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi disable pktlog\n"); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_pktlog_disable_cmdid); +} + +int ath10k_wmi_attach(struct ath10k *ar) +{ + if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) { + if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features)) + ar->wmi.cmd = &wmi_10_2_cmd_map; + else + ar->wmi.cmd = &wmi_10x_cmd_map; + + ar->wmi.vdev_param = &wmi_10x_vdev_param_map; + ar->wmi.pdev_param = &wmi_10x_pdev_param_map; + } else { + ar->wmi.cmd = &wmi_cmd_map; + ar->wmi.vdev_param = &wmi_vdev_param_map; + ar->wmi.pdev_param = &wmi_pdev_param_map; + } + + init_completion(&ar->wmi.service_ready); + init_completion(&ar->wmi.unified_ready); + + return 0; +} + +void ath10k_wmi_detach(struct ath10k *ar) +{ + int i; + + /* free the host memory chunks requested by firmware */ + for (i = 0; i < ar->wmi.num_mem_chunks; i++) { + dma_free_coherent(ar->dev, + ar->wmi.mem_chunks[i].len, + ar->wmi.mem_chunks[i].vaddr, + ar->wmi.mem_chunks[i].paddr); + } + + ar->wmi.num_mem_chunks = 0; +} diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 86f5ebc..a38d788 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -1428,11 +1428,11 @@ struct wmi_service_ready_event { * where FW can access this memory directly (or) by DMA. */ __le32 num_mem_reqs; - struct wlan_host_mem_req mem_reqs[1]; + struct wlan_host_mem_req mem_reqs[0]; } __packed; /* This is the definition from 10.X firmware branch */ -struct wmi_service_ready_event_10x { +struct wmi_10x_service_ready_event { __le32 sw_version; __le32 abi_version; @@ -1467,7 +1467,7 @@ struct wmi_service_ready_event_10x { */ __le32 num_mem_reqs; - struct wlan_host_mem_req mem_reqs[1]; + struct wlan_host_mem_req mem_reqs[0]; } __packed; #define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ) @@ -1883,38 +1883,26 @@ struct host_memory_chunk { __le32 size; } __packed; +struct wmi_host_mem_chunks { + __le32 count; + /* some fw revisions require at least 1 chunk regardless of count */ + struct host_memory_chunk items[1]; +} __packed; + struct wmi_init_cmd { struct wmi_resource_config resource_config; - __le32 num_host_mem_chunks; - - /* - * variable number of host memory chunks. - * This should be the last element in the structure - */ - struct host_memory_chunk host_mem_chunks[1]; + struct wmi_host_mem_chunks mem_chunks; } __packed; /* _10x stucture is from 10.X FW API */ struct wmi_init_cmd_10x { struct wmi_resource_config_10x resource_config; - __le32 num_host_mem_chunks; - - /* - * variable number of host memory chunks. - * This should be the last element in the structure - */ - struct host_memory_chunk host_mem_chunks[1]; + struct wmi_host_mem_chunks mem_chunks; } __packed; struct wmi_init_cmd_10_2 { struct wmi_resource_config_10_2 resource_config; - __le32 num_host_mem_chunks; - - /* - * variable number of host memory chunks. - * This should be the last element in the structure - */ - struct host_memory_chunk host_mem_chunks[1]; + struct wmi_host_mem_chunks mem_chunks; } __packed; struct wmi_chan_list_entry { @@ -1974,7 +1962,7 @@ enum wmi_scan_priority { WMI_SCAN_PRIORITY_COUNT /* number of priorities supported */ }; -struct wmi_start_scan_cmd { +struct wmi_start_scan_common { /* Scan ID */ __le32 scan_id; /* Scan requestor ID */ @@ -2032,95 +2020,25 @@ struct wmi_start_scan_cmd { __le32 probe_delay; /* Scan control flags */ __le32 scan_ctrl_flags; - - /* Burst duration time in msecs */ - __le32 burst_duration; - /* - * TLV (tag length value ) paramerters follow the scan_cmd structure. - * TLV can contain channel list, bssid list, ssid list and - * ie. the TLV tags are defined above; - */ } __packed; -/* This is the definition from 10.X firmware branch */ -struct wmi_start_scan_cmd_10x { - /* Scan ID */ - __le32 scan_id; - - /* Scan requestor ID */ - __le32 scan_req_id; - - /* VDEV id(interface) that is requesting scan */ - __le32 vdev_id; - - /* Scan Priority, input to scan scheduler */ - __le32 scan_priority; - - /* Scan events subscription */ - __le32 notify_scan_events; - - /* dwell time in msec on active channels */ - __le32 dwell_time_active; - - /* dwell time in msec on passive channels */ - __le32 dwell_time_passive; - - /* - * min time in msec on the BSS channel,only valid if atleast one - * VDEV is active - */ - __le32 min_rest_time; - - /* - * max rest time in msec on the BSS channel,only valid if at least - * one VDEV is active - */ - /* - * the scanner will rest on the bss channel at least min_rest_time - * after min_rest_time the scanner will start checking for tx/rx - * activity on all VDEVs. if there is no activity the scanner will - * switch to off channel. if there is activity the scanner will let - * the radio on the bss channel until max_rest_time expires.at - * max_rest_time scanner will switch to off channel irrespective of - * activity. activity is determined by the idle_time parameter. - */ - __le32 max_rest_time; - - /* - * time before sending next set of probe requests. - * The scanner keeps repeating probe requests transmission with - * period specified by repeat_probe_time. - * The number of probe requests specified depends on the ssid_list - * and bssid_list - */ - __le32 repeat_probe_time; - - /* time in msec between 2 consequetive probe requests with in a set. */ - __le32 probe_spacing_time; - - /* - * data inactivity time in msec on bss channel that will be used by - * scanner for measuring the inactivity. - */ - __le32 idle_time; - - /* maximum time in msec allowed for scan */ - __le32 max_scan_time; - - /* - * delay in msec before sending first probe request after switching - * to a channel +struct wmi_start_scan_tlvs { + /* TLV parameters. These includes channel list, ssid list, bssid list, + * extra ies. */ - __le32 probe_delay; + u8 tlvs[0]; +} __packed; - /* Scan control flags */ - __le32 scan_ctrl_flags; +struct wmi_start_scan_cmd { + struct wmi_start_scan_common common; + __le32 burst_duration_ms; + struct wmi_start_scan_tlvs tlvs; +} __packed; - /* - * TLV (tag length value ) paramerters follow the scan_cmd structure. - * TLV can contain channel list, bssid list, ssid list and - * ie. the TLV tags are defined above; - */ +/* This is the definition from 10.X firmware branch */ +struct wmi_10x_start_scan_cmd { + struct wmi_start_scan_common common; + struct wmi_start_scan_tlvs tlvs; } __packed; struct wmi_ssid_arg { @@ -2306,94 +2224,25 @@ struct wmi_mgmt_rx_event_v2 { #define PHY_ERROR_FALSE_RADAR_EXT 0x24 #define PHY_ERROR_RADAR 0x05 -struct wmi_single_phyerr_rx_hdr { - /* TSF timestamp */ +struct wmi_phyerr { __le32 tsf_timestamp; - - /* - * Current freq1, freq2 - * - * [7:0]: freq1[lo] - * [15:8] : freq1[hi] - * [23:16]: freq2[lo] - * [31:24]: freq2[hi] - */ __le16 freq1; __le16 freq2; - - /* - * Combined RSSI over all chains and channel width for this PHY error - * - * [7:0]: RSSI combined - * [15:8]: Channel width (MHz) - * [23:16]: PHY error code - * [24:16]: reserved (future use) - */ u8 rssi_combined; u8 chan_width_mhz; u8 phy_err_code; u8 rsvd0; - - /* - * RSSI on chain 0 through 3 - * - * This is formatted the same as the PPDU_START RX descriptor - * field: - * - * [7:0]: pri20 - * [15:8]: sec20 - * [23:16]: sec40 - * [31:24]: sec80 - */ - - __le32 rssi_chain0; - __le32 rssi_chain1; - __le32 rssi_chain2; - __le32 rssi_chain3; - - /* - * Last calibrated NF value for chain 0 through 3 - * - * nf_list_1: - * - * + [15:0] - chain 0 - * + [31:16] - chain 1 - * - * nf_list_2: - * - * + [15:0] - chain 2 - * + [31:16] - chain 3 - */ - __le32 nf_list_1; - __le32 nf_list_2; - - /* Length of the frame */ + __le32 rssi_chains[4]; + __le16 nf_chains[4]; __le32 buf_len; + u8 buf[0]; } __packed; -struct wmi_single_phyerr_rx_event { - /* Phy error event header */ - struct wmi_single_phyerr_rx_hdr hdr; - /* frame buffer */ - u8 bufp[0]; -} __packed; - -struct wmi_comb_phyerr_rx_hdr { - /* Phy error phy error count */ - __le32 num_phyerr_events; +struct wmi_phyerr_event { + __le32 num_phyerrs; __le32 tsf_l32; __le32 tsf_u32; -} __packed; - -struct wmi_comb_phyerr_rx_event { - /* Phy error phy error count */ - struct wmi_comb_phyerr_rx_hdr hdr; - /* - * frame buffer - contains multiple payloads in the order: - * header - payload, header - payload... - * (The header is of type: wmi_single_phyerr_rx_hdr) - */ - u8 bufp[0]; + struct wmi_phyerr phyerrs[0]; } __packed; #define PHYERR_TLV_SIG 0xBB @@ -2908,11 +2757,6 @@ enum wmi_tp_scale { WMI_TP_SCALE_SIZE = 5, /* max num of enum */ }; -struct wmi_set_channel_cmd { - /* channel (only frequency and mode info are used) */ - struct wmi_channel chan; -} __packed; - struct wmi_pdev_chanlist_update_event { /* number of channels */ __le32 num_chan; @@ -2943,6 +2787,10 @@ struct wmi_pdev_set_channel_cmd { struct wmi_channel chan; } __packed; +struct wmi_pdev_pktlog_enable_cmd { + __le32 ev_bitmap; +} __packed; + /* Customize the DSCP (bit) to TID (0-7) mapping for QOS */ #define WMI_DSCP_MAP_MAX (64) struct wmi_pdev_set_dscp_tid_map_cmd { @@ -3177,7 +3025,7 @@ struct wmi_stats_event { * PDEV statistics * TODO: add all PDEV stats here */ -struct wmi_pdev_stats_old { +struct wmi_pdev_stats { __le32 chan_nf; /* Channel noise floor */ __le32 tx_frame_count; /* TX frame count */ __le32 rx_frame_count; /* RX frame count */ @@ -3188,15 +3036,8 @@ struct wmi_pdev_stats_old { struct wal_dbg_stats wal; /* WAL dbg stats */ } __packed; -struct wmi_pdev_stats_10x { - __le32 chan_nf; /* Channel noise floor */ - __le32 tx_frame_count; /* TX frame count */ - __le32 rx_frame_count; /* RX frame count */ - __le32 rx_clear_count; /* rx clear count */ - __le32 cycle_count; /* cycle count */ - __le32 phy_err_count; /* Phy error count */ - __le32 chan_tx_pwr; /* channel tx power */ - struct wal_dbg_stats wal; /* WAL dbg stats */ +struct wmi_10x_pdev_stats { + struct wmi_pdev_stats old; __le32 ack_rx_bad; __le32 rts_bad; __le32 rts_good; @@ -3217,16 +3058,14 @@ struct wmi_vdev_stats { * peer statistics. * TODO: add more stats */ -struct wmi_peer_stats_old { +struct wmi_peer_stats { struct wmi_mac_addr peer_macaddr; __le32 peer_rssi; __le32 peer_tx_rate; } __packed; -struct wmi_peer_stats_10x { - struct wmi_mac_addr peer_macaddr; - __le32 peer_rssi; - __le32 peer_tx_rate; +struct wmi_10x_peer_stats { + struct wmi_peer_stats old; __le32 peer_rx_rate; } __packed; @@ -4719,8 +4558,26 @@ struct wmi_dbglog_cfg_cmd { /* By default disable power save for IBSS */ #define ATH10K_DEFAULT_ATIM 0 +#define WMI_MAX_MEM_REQS 16 + +struct wmi_svc_rdy_ev_arg { + __le32 min_tx_power; + __le32 max_tx_power; + __le32 ht_cap; + __le32 vht_cap; + __le32 sw_ver0; + __le32 sw_ver1; + __le32 phy_capab; + __le32 num_rf_chains; + __le32 eeprom_rd; + __le32 num_mem_reqs; + const __le32 *service_map; + const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS]; +}; + struct ath10k; struct ath10k_vif; +struct ath10k_fw_stats; int ath10k_wmi_attach(struct ath10k *ar); void ath10k_wmi_detach(struct ath10k *ar); @@ -4732,8 +4589,6 @@ int ath10k_wmi_connect(struct ath10k *ar); struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len); int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); -int ath10k_wmi_pdev_set_channel(struct ath10k *ar, - const struct wmi_channel_arg *); int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt); int ath10k_wmi_pdev_resume_target(struct ath10k *ar); int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, @@ -4794,5 +4649,9 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar, enum wmi_force_fw_hang_type type, u32 delay_ms); int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb); int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable); +int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, + struct ath10k_fw_stats *stats); +int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_list); +int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar); #endif /* _WMI_H_ */ diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index ab2709a..19eab2a 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -547,7 +547,9 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, static void -ath5k_sw_scan_start(struct ieee80211_hw *hw) +ath5k_sw_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *mac_addr) { struct ath5k_hw *ah = hw->priv; if (!ah->assoc) @@ -556,7 +558,7 @@ ath5k_sw_scan_start(struct ieee80211_hw *hw) static void -ath5k_sw_scan_complete(struct ieee80211_hw *hw) +ath5k_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath5k_hw *ah = hw->priv; ath5k_hw_set_ledstate(ah, ah->assoc ? diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index ba60e37..7a53378 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2976,11 +2976,11 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static int ath6kl_del_station(struct wiphy *wiphy, struct net_device *dev, - const u8 *mac) + struct station_del_parameters *params) { struct ath6kl *ar = ath6kl_priv(dev); struct ath6kl_vif *vif = netdev_priv(dev); - const u8 *addr = mac ? mac : bcast_addr; + const u8 *addr = params->mac ? params->mac : bcast_addr; return ath6kl_wmi_ap_set_mlme(ar->wmi, vif->fw_vif_idx, WMI_AP_DEAUTH, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h index 05debf7..4f82e86 100644 --- a/drivers/net/wireless/ath/ath6kl/common.h +++ b/drivers/net/wireless/ath/ath6kl/common.h @@ -22,7 +22,7 @@ #define ATH6KL_MAX_IE 256 -__printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...); +__printf(2, 3) void ath6kl_printk(const char *level, const char *fmt, ...); /* * Reflects the version of binary interface exposed by ATH6KL target diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index 55c4064d..81ba48d 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -37,76 +37,64 @@ struct ath6kl_fwlog_slot { #define ATH6KL_FWLOG_VALID_MASK 0x1ffff -int ath6kl_printk(const char *level, const char *fmt, ...) +void ath6kl_printk(const char *level, const char *fmt, ...) { struct va_format vaf; va_list args; - int rtn; va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - rtn = printk("%sath6kl: %pV", level, &vaf); + printk("%sath6kl: %pV", level, &vaf); va_end(args); - - return rtn; } EXPORT_SYMBOL(ath6kl_printk); -int ath6kl_info(const char *fmt, ...) +void ath6kl_info(const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, }; va_list args; - int ret; va_start(args, fmt); vaf.va = &args; - ret = ath6kl_printk(KERN_INFO, "%pV", &vaf); + ath6kl_printk(KERN_INFO, "%pV", &vaf); trace_ath6kl_log_info(&vaf); va_end(args); - - return ret; } EXPORT_SYMBOL(ath6kl_info); -int ath6kl_err(const char *fmt, ...) +void ath6kl_err(const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, }; va_list args; - int ret; va_start(args, fmt); vaf.va = &args; - ret = ath6kl_printk(KERN_ERR, "%pV", &vaf); + ath6kl_printk(KERN_ERR, "%pV", &vaf); trace_ath6kl_log_err(&vaf); va_end(args); - - return ret; } EXPORT_SYMBOL(ath6kl_err); -int ath6kl_warn(const char *fmt, ...) +void ath6kl_warn(const char *fmt, ...) { struct va_format vaf = { .fmt = fmt, }; va_list args; - int ret; va_start(args, fmt); vaf.va = &args; - ret = ath6kl_printk(KERN_WARNING, "%pV", &vaf); + ath6kl_printk(KERN_WARNING, "%pV", &vaf); trace_ath6kl_log_warn(&vaf); va_end(args); - - return ret; } EXPORT_SYMBOL(ath6kl_warn); diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h index e194c10d..19106ed 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.h +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -50,10 +50,10 @@ enum ATH6K_DEBUG_MASK { }; extern unsigned int debug_mask; -__printf(2, 3) int ath6kl_printk(const char *level, const char *fmt, ...); -__printf(1, 2) int ath6kl_info(const char *fmt, ...); -__printf(1, 2) int ath6kl_err(const char *fmt, ...); -__printf(1, 2) int ath6kl_warn(const char *fmt, ...); +__printf(2, 3) void ath6kl_printk(const char *level, const char *fmt, ...); +__printf(1, 2) void ath6kl_info(const char *fmt, ...); +__printf(1, 2) void ath6kl_err(const char *fmt, ...); +__printf(1, 2) void ath6kl_warn(const char *fmt, ...); enum ath6kl_war { ATH6KL_WAR_INVALID_RATE, @@ -81,10 +81,9 @@ int ath6kl_debug_init_fs(struct ath6kl *ar); void ath6kl_debug_cleanup(struct ath6kl *ar); #else -static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask, - const char *fmt, ...) +static inline void ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask, + const char *fmt, ...) { - return 0; } static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index a6a5e40..9da3594 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -1193,18 +1193,10 @@ static int ath6kl_usb_pm_resume(struct usb_interface *interface) return 0; } -static int ath6kl_usb_pm_reset_resume(struct usb_interface *intf) -{ - if (usb_get_intfdata(intf)) - ath6kl_usb_remove(intf); - return 0; -} - #else #define ath6kl_usb_pm_suspend NULL #define ath6kl_usb_pm_resume NULL -#define ath6kl_usb_pm_reset_resume NULL #endif @@ -1222,7 +1214,6 @@ static struct usb_driver ath6kl_usb_driver = { .probe = ath6kl_usb_probe, .suspend = ath6kl_usb_pm_suspend, .resume = ath6kl_usb_pm_resume, - .reset_resume = ath6kl_usb_pm_reset_resume, .disconnect = ath6kl_usb_remove, .id_table = ath6kl_usb_ids, .supports_autosuspend = true, diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index 896e632..fee0cad 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -3,6 +3,8 @@ config ATH9K_HW config ATH9K_COMMON tristate select ATH_COMMON + select DEBUG_FS + select RELAY config ATH9K_DFS_DEBUGFS def_bool y depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED @@ -148,6 +150,11 @@ config ATH9K_CHANNEL_CONTEXT for multi-channel concurrency. Enable this if P2P PowerSave support is required. +config ATH9K_PCOEM + bool "Atheros ath9k support for PC OEM cards" if EXPERT + depends on ATH9K + default y + config ATH9K_HTC tristate "Atheros HTC based wireless cards support" depends on USB && MAC80211 diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 73704c1..4739722 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -16,8 +16,7 @@ ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o ath9k-$(CONFIG_ATH9K_TX99) += tx99.o ath9k-$(CONFIG_ATH9K_WOW) += wow.o -ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o \ - spectral.o +ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o ath9k-$(CONFIG_ATH9K_STATION_STATISTICS) += debug_sta.o @@ -32,7 +31,6 @@ ath9k_hw-y:= \ ar5008_phy.o \ ar9002_calib.o \ ar9003_calib.o \ - ar9003_rtt.o \ calib.o \ eeprom.o \ eeprom_def.o \ @@ -50,6 +48,8 @@ ath9k_hw-$(CONFIG_ATH9K_WOW) += ar9003_wow.o ath9k_hw-$(CONFIG_ATH9K_BTCOEX_SUPPORT) += btcoex.o \ ar9003_mci.o +ath9k_hw-$(CONFIG_ATH9K_PCOEM) += ar9003_rtt.o + ath9k_hw-$(CONFIG_ATH9K_DYNACK) += dynack.o obj-$(CONFIG_ATH9K_HW) += ath9k_hw.o @@ -58,7 +58,8 @@ obj-$(CONFIG_ATH9K_COMMON) += ath9k_common.o ath9k_common-y:= common.o \ common-init.o \ common-beacon.o \ - common-debug.o + common-debug.o \ + common-spectral.o ath9k_htc-y += htc_hst.o \ hif_usb.o \ diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index b72d0be..5829074 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -1190,7 +1190,7 @@ static void ar5008_hw_set_nf_limits(struct ath_hw *ah) static void ar5008_hw_set_radar_params(struct ath_hw *ah, struct ath_hw_radar_conf *conf) { - u32 radar_0 = 0, radar_1 = 0; + u32 radar_0 = 0, radar_1; if (!conf) { REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); @@ -1204,6 +1204,9 @@ static void ar5008_hw_set_radar_params(struct ath_hw *ah, radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI); radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND); + radar_1 = REG_READ(ah, AR_PHY_RADAR_1); + radar_1 &= ~(AR_PHY_RADAR_1_MAXLEN | AR_PHY_RADAR_1_RELSTEP_THRESH | + AR_PHY_RADAR_1_RELPWR_THRESH); radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI; radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK; radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN); @@ -1225,7 +1228,7 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah) conf->fir_power = -33; conf->radar_rssi = 20; conf->pulse_height = 10; - conf->pulse_rssi = 24; + conf->pulse_rssi = 15; conf->pulse_inband = 15; conf->pulse_maxlen = 255; conf->pulse_inband_step = 12; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index cdc7400..42190b6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -657,31 +657,29 @@ static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah) ar9280_hw_olc_temp_compensation(ah); } -static bool ar9002_hw_calibrate(struct ath_hw *ah, - struct ath9k_channel *chan, - u8 rxchainmask, - bool longcal) +static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal) { - bool iscaldone = true; struct ath9k_cal_list *currCal = ah->cal_list_curr; - bool nfcal, nfcal_pending = false; + bool nfcal, nfcal_pending = false, percal_pending; + int ret; nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF); if (ah->caldata) nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags); - if (currCal && !nfcal && - (currCal->calState == CAL_RUNNING || - currCal->calState == CAL_WAITING)) { - iscaldone = ar9002_hw_per_calibration(ah, chan, - rxchainmask, currCal); - if (iscaldone) { - ah->cal_list_curr = currCal = currCal->calNext; - - if (currCal->calState == CAL_WAITING) { - iscaldone = false; - ath9k_hw_reset_calibration(ah, currCal); - } + percal_pending = (currCal && + (currCal->calState == CAL_RUNNING || + currCal->calState == CAL_WAITING)); + + if (percal_pending && !nfcal) { + if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal)) + return 0; + + ah->cal_list_curr = currCal = currCal->calNext; + if (currCal->calState == CAL_WAITING) { + ath9k_hw_reset_calibration(ah, currCal); + return 0; } } @@ -698,7 +696,9 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah, * NF is slow time-variant, so it is OK to use a * historical value. */ - ath9k_hw_loadnf(ah, ah->curchan); + ret = ath9k_hw_loadnf(ah, ah->curchan); + if (ret < 0) + return ret; } if (longcal) { @@ -709,7 +709,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah, } } - return iscaldone; + return !percal_pending; } /* Carrier leakage Calibration fix */ @@ -856,6 +856,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) /* Do PA Calibration */ ar9002_hw_pa_cal(ah, true); + ath9k_hw_loadnf(ah, chan); + ath9k_hw_start_nfcal(ah, true); if (ah->caldata) set_bit(NFCAL_PENDING, &ah->caldata->cal_flags); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index 9a2afa2..fc08162 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -643,9 +643,12 @@ static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, * and fix otherwise. */ count = param->count; - if (param->endless) - count = 0x80; - else if (count & 0x80) + if (param->endless) { + if (AR_SREV_9271(ah)) + count = 0; + else + count = 0x80; + } else if (count & 0x80) count = 0x7f; REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index ac8301e..06ab71db 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -121,13 +121,12 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah, return iscaldone; } -static bool ar9003_hw_calibrate(struct ath_hw *ah, - struct ath9k_channel *chan, - u8 rxchainmask, - bool longcal) +static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal) { bool iscaldone = true; struct ath9k_cal_list *currCal = ah->cal_list_curr; + int ret; /* * For given calibration: @@ -163,7 +162,9 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah, * NF is slow time-variant, so it is OK to use a historical * value. */ - ath9k_hw_loadnf(ah, ah->curchan); + ret = ath9k_hw_loadnf(ah, ah->curchan); + if (ret < 0) + return ret; /* start NF calibration, without updating BB NF register */ ath9k_hw_start_nfcal(ah, false); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 80c6eac..e726e40 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -4079,27 +4079,28 @@ static int ar9003_hw_get_thermometer(struct ath_hw *ah) static void ar9003_hw_thermometer_apply(struct ath_hw *ah) { + struct ath9k_hw_capabilities *pCap = &ah->caps; int thermometer = ar9003_hw_get_thermometer(ah); u8 therm_on = (thermometer < 0) ? 0 : 1; REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); - if (ah->caps.tx_chainmask & BIT(1)) + if (pCap->chip_chainmask & BIT(1)) REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); - if (ah->caps.tx_chainmask & BIT(2)) + if (pCap->chip_chainmask & BIT(2)) REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON_OVR, therm_on); therm_on = (thermometer < 0) ? 0 : (thermometer == 0); REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); - if (ah->caps.tx_chainmask & BIT(1)) { + if (pCap->chip_chainmask & BIT(1)) { therm_on = (thermometer < 0) ? 0 : (thermometer == 1); REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); } - if (ah->caps.tx_chainmask & BIT(2)) { + if (pCap->chip_chainmask & BIT(2)) { therm_on = (thermometer < 0) ? 0 : (thermometer == 2); REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_CH0_RXTX4_THERM_ON, therm_on); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index ddef9ee..06ad217 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -333,12 +333,29 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) qca953x_1p0_soc_preamble); INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], qca953x_1p0_soc_postamble); - INIT_INI_ARRAY(&ah->iniModesRxGain, - qca953x_1p0_common_wo_xlna_rx_gain_table); - INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, - qca953x_1p0_common_wo_xlna_rx_gain_bounds); - INIT_INI_ARRAY(&ah->iniModesTxGain, - qca953x_1p0_modes_no_xpa_tx_gain_table); + + if (AR_SREV_9531_20(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca953x_2p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca953x_2p0_common_wo_xlna_rx_gain_bounds); + } else { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca953x_1p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca953x_1p0_common_wo_xlna_rx_gain_bounds); + } + + if (AR_SREV_9531_20(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_2p0_modes_no_xpa_tx_gain_table); + else if (AR_SREV_9531_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p1_modes_no_xpa_tx_gain_table); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p0_modes_no_xpa_tx_gain_table); + INIT_INI_ARRAY(&ah->iniModesFastClock, qca953x_1p0_modes_fast_clock); } else if (AR_SREV_9580(ah)) { @@ -518,9 +535,15 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) else if (AR_SREV_9550(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar955x_1p0_modes_xpa_tx_gain_table); - else if (AR_SREV_9531(ah)) + else if (AR_SREV_9531_10(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p0_modes_xpa_tx_gain_table); + else if (AR_SREV_9531_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p1_modes_xpa_tx_gain_table); + else if (AR_SREV_9531_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - qca953x_1p0_modes_xpa_tx_gain_table); + qca953x_2p0_modes_xpa_tx_gain_table); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_lowest_ob_db_tx_gain_table); @@ -562,7 +585,10 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesTxGain, ar955x_1p0_modes_no_xpa_tx_gain_table); else if (AR_SREV_9531(ah)) { - if (AR_SREV_9531_11(ah)) + if (AR_SREV_9531_20(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_2p0_modes_no_xpa_tx_gain_table); + else if (AR_SREV_9531_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, qca953x_1p1_modes_no_xpa_tx_gain_table); else @@ -670,9 +696,6 @@ static void ar9003_tx_gain_table_mode5(struct ath_hw *ah) if (AR_SREV_9485_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_green_ob_db_tx_gain_1_1); - else if (AR_SREV_9340(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9340Modes_ub124_tx_gain_table_1p0); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_type5_tx_gain_table); @@ -792,11 +815,16 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) ar955x_1p0_common_wo_xlna_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, ar955x_1p0_common_wo_xlna_rx_gain_bounds); - } else if (AR_SREV_9531(ah)) { + } else if (AR_SREV_9531_10(ah) || AR_SREV_9531_11(ah)) { INIT_INI_ARRAY(&ah->iniModesRxGain, qca953x_1p0_common_wo_xlna_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, qca953x_1p0_common_wo_xlna_rx_gain_bounds); + } else if (AR_SREV_9531_20(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca953x_2p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca953x_2p0_common_wo_xlna_rx_gain_bounds); } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_wo_xlna_rx_gain_table); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 1e8ea5e..2df6d2e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -1361,7 +1361,7 @@ static void ar9003_hw_set_radar_params(struct ath_hw *ah, struct ath_hw_radar_conf *conf) { unsigned int regWrites = 0; - u32 radar_0 = 0, radar_1 = 0; + u32 radar_0 = 0, radar_1; if (!conf) { REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA); @@ -1375,6 +1375,9 @@ static void ar9003_hw_set_radar_params(struct ath_hw *ah, radar_0 |= SM(conf->pulse_rssi, AR_PHY_RADAR_0_PRSSI); radar_0 |= SM(conf->pulse_inband, AR_PHY_RADAR_0_INBAND); + radar_1 = REG_READ(ah, AR_PHY_RADAR_1); + radar_1 &= ~(AR_PHY_RADAR_1_MAXLEN | AR_PHY_RADAR_1_RELSTEP_THRESH | + AR_PHY_RADAR_1_RELPWR_THRESH); radar_1 |= AR_PHY_RADAR_1_MAX_RRSSI; radar_1 |= AR_PHY_RADAR_1_BLOCK_CHECK; radar_1 |= SM(conf->pulse_maxlen, AR_PHY_RADAR_1_MAXLEN); @@ -1401,7 +1404,7 @@ static void ar9003_hw_set_radar_conf(struct ath_hw *ah) conf->fir_power = -28; conf->radar_rssi = 0; conf->pulse_height = 10; - conf->pulse_rssi = 24; + conf->pulse_rssi = 15; conf->pulse_inband = 8; conf->pulse_maxlen = 255; conf->pulse_inband_step = 12; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.h b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h index a43b30d..6290467 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_rtt.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h @@ -17,6 +17,7 @@ #ifndef AR9003_RTT_H #define AR9003_RTT_H +#ifdef CONFIG_ATH9K_PCOEM void ar9003_hw_rtt_enable(struct ath_hw *ah); void ar9003_hw_rtt_disable(struct ath_hw *ah); void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask); @@ -25,5 +26,40 @@ void ar9003_hw_rtt_load_hist(struct ath_hw *ah); void ar9003_hw_rtt_fill_hist(struct ath_hw *ah); void ar9003_hw_rtt_clear_hist(struct ath_hw *ah); bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan); +#else +static inline void ar9003_hw_rtt_enable(struct ath_hw *ah) +{ +} + +static inline void ar9003_hw_rtt_disable(struct ath_hw *ah) +{ +} + +static inline void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask) +{ +} + +static inline bool ar9003_hw_rtt_force_restore(struct ath_hw *ah) +{ + return false; +} + +static inline void ar9003_hw_rtt_load_hist(struct ath_hw *ah) +{ +} + +static inline void ar9003_hw_rtt_fill_hist(struct ath_hw *ah) +{ +} + +static inline void ar9003_hw_rtt_clear_hist(struct ath_hw *ah) +{ +} + +static inline bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan) +{ + return false; +} +#endif #endif diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h index 812a9d7..159cc6f 100644 --- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h @@ -20,6 +20,8 @@ #define qca953x_1p0_mac_postamble ar9300_2p2_mac_postamble +#define qca953x_1p0_soc_preamble ar955x_1p0_soc_preamble + #define qca953x_1p0_soc_postamble ar9300_2p2_soc_postamble #define qca953x_1p0_common_rx_gain_table ar9300Common_rx_gain_table_2p2 @@ -28,6 +30,10 @@ #define qca953x_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2 +#define qca953x_1p0_common_wo_xlna_rx_gain_bounds ar955x_1p0_common_wo_xlna_rx_gain_bounds + +#define qca953x_1p0_common_rx_gain_bounds ar955x_1p0_common_rx_gain_bounds + static const u32 qca953x_1p0_mac_core[][2] = { /* Addr allmodes */ {0x00000008, 0x00000000}, @@ -490,35 +496,6 @@ static const u32 qca953x_1p0_radio_postamble[][5] = { {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, }; -static const u32 qca953x_1p0_soc_preamble[][2] = { - /* Addr allmodes */ - {0x00007000, 0x00000000}, - {0x00007004, 0x00000000}, - {0x00007008, 0x00000000}, - {0x0000700c, 0x00000000}, - {0x0000701c, 0x00000000}, - {0x00007020, 0x00000000}, - {0x00007024, 0x00000000}, - {0x00007028, 0x00000000}, - {0x0000702c, 0x00000000}, - {0x00007030, 0x00000000}, - {0x00007034, 0x00000002}, - {0x00007038, 0x000004c2}, - {0x00007048, 0x00000000}, -}; - -static const u32 qca953x_1p0_common_rx_gain_bounds[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, - {0x00009e48, 0x5030201a, 0x5030201a, 0x50302018, 0x50302018}, -}; - -static const u32 qca953x_1p0_common_wo_xlna_rx_gain_bounds[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, - {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, -}; - static const u32 qca953x_1p0_modes_xpa_tx_gain_table[][2] = { /* Addr allmodes */ {0x0000a2dc, 0xfffd5aaa}, @@ -715,8 +692,73 @@ static const u32 qca953x_1p1_modes_no_xpa_tx_gain_table[][2] = { {0x00016448, 0x6c927a70}, }; +static const u32 qca953x_1p1_modes_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xfffb52aa}, + {0x0000a2e0, 0xfffd64cc}, + {0x0000a2e4, 0xfffe80f0}, + {0x0000a2e8, 0xffffff00}, + {0x0000a410, 0x000050d5}, + {0x0000a500, 0x00000000}, + {0x0000a504, 0x04000002}, + {0x0000a508, 0x08000004}, + {0x0000a50c, 0x0c000006}, + {0x0000a510, 0x1000000a}, + {0x0000a514, 0x1400000c}, + {0x0000a518, 0x1800000e}, + {0x0000a51c, 0x1c000048}, + {0x0000a520, 0x2000004a}, + {0x0000a524, 0x2400004c}, + {0x0000a528, 0x2800004e}, + {0x0000a52c, 0x2b00024a}, + {0x0000a530, 0x2f00024c}, + {0x0000a534, 0x3300024e}, + {0x0000a538, 0x36000668}, + {0x0000a53c, 0x38000669}, + {0x0000a540, 0x3a000868}, + {0x0000a544, 0x3d00086a}, + {0x0000a548, 0x4000086c}, + {0x0000a54c, 0x4200086e}, + {0x0000a550, 0x43000a6e}, + {0x0000a554, 0x43000a6e}, + {0x0000a558, 0x43000a6e}, + {0x0000a55c, 0x43000a6e}, + {0x0000a560, 0x43000a6e}, + {0x0000a564, 0x43000a6e}, + {0x0000a568, 0x43000a6e}, + {0x0000a56c, 0x43000a6e}, + {0x0000a570, 0x43000a6e}, + {0x0000a574, 0x43000a6e}, + {0x0000a578, 0x43000a6e}, + {0x0000a57c, 0x43000a6e}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x03804000}, + {0x0000a610, 0x03804e01}, + {0x0000a614, 0x03804e01}, + {0x0000a618, 0x03804e01}, + {0x0000a61c, 0x04009002}, + {0x0000a620, 0x04009002}, + {0x0000a624, 0x04009002}, + {0x0000a628, 0x04009002}, + {0x0000a62c, 0x04009002}, + {0x0000a630, 0x04009002}, + {0x0000a634, 0x04009002}, + {0x0000a638, 0x04009002}, + {0x0000a63c, 0x04009002}, + {0x0000b2dc, 0xfffb52aa}, + {0x0000b2e0, 0xfffd64cc}, + {0x0000b2e4, 0xfffe80f0}, + {0x0000b2e8, 0xffffff00}, + {0x00016044, 0x024922db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x024922db}, + {0x00016448, 0x6c927a70}, +}; + static const u32 qca953x_2p0_baseband_core[][2] = { - /* Addr allmodes */ + /* Addr allmodes */ {0x00009800, 0xafe68e30}, {0x00009804, 0xfd14e000}, {0x00009808, 0x9c0a9f6b}, @@ -914,4 +956,400 @@ static const u32 qca953x_2p0_baseband_postamble[][5] = { {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, }; +static const u32 qca953x_2p0_common_wo_xlna_rx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x03820190}, + {0x0000a030, 0x03840383}, + {0x0000a034, 0x03880385}, + {0x0000a038, 0x038a0389}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x29292929}, + {0x0000a084, 0x29292929}, + {0x0000a088, 0x29292929}, + {0x0000a08c, 0x29292929}, + {0x0000a090, 0x22292929}, + {0x0000a094, 0x1d1d2222}, + {0x0000a098, 0x0c111117}, + {0x0000a09c, 0x00030303}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 qca953x_2p0_common_wo_xlna_rx_gain_bounds[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, +}; + +static const u32 qca953x_2p0_modes_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xfffb52aa}, + {0x0000a2e0, 0xfffd64cc}, + {0x0000a2e4, 0xfffe80f0}, + {0x0000a2e8, 0xffffff00}, + {0x0000a410, 0x000050d5}, + {0x0000a500, 0x00000000}, + {0x0000a504, 0x04000002}, + {0x0000a508, 0x08000004}, + {0x0000a50c, 0x0c000006}, + {0x0000a510, 0x1000000a}, + {0x0000a514, 0x1400000c}, + {0x0000a518, 0x1800000e}, + {0x0000a51c, 0x1c000048}, + {0x0000a520, 0x2000004a}, + {0x0000a524, 0x2400004c}, + {0x0000a528, 0x2800004e}, + {0x0000a52c, 0x2b00024a}, + {0x0000a530, 0x2f00024c}, + {0x0000a534, 0x3300024e}, + {0x0000a538, 0x36000668}, + {0x0000a53c, 0x38000669}, + {0x0000a540, 0x3a000868}, + {0x0000a544, 0x3d00086a}, + {0x0000a548, 0x4000086c}, + {0x0000a54c, 0x4200086e}, + {0x0000a550, 0x43000a6e}, + {0x0000a554, 0x43000a6e}, + {0x0000a558, 0x43000a6e}, + {0x0000a55c, 0x43000a6e}, + {0x0000a560, 0x43000a6e}, + {0x0000a564, 0x43000a6e}, + {0x0000a568, 0x43000a6e}, + {0x0000a56c, 0x43000a6e}, + {0x0000a570, 0x43000a6e}, + {0x0000a574, 0x43000a6e}, + {0x0000a578, 0x43000a6e}, + {0x0000a57c, 0x43000a6e}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x03804000}, + {0x0000a610, 0x03804e01}, + {0x0000a614, 0x03804e01}, + {0x0000a618, 0x03804e01}, + {0x0000a61c, 0x04009002}, + {0x0000a620, 0x04009002}, + {0x0000a624, 0x04009002}, + {0x0000a628, 0x04009002}, + {0x0000a62c, 0x04009002}, + {0x0000a630, 0x04009002}, + {0x0000a634, 0x04009002}, + {0x0000a638, 0x04009002}, + {0x0000a63c, 0x04009002}, + {0x0000b2dc, 0xfffb52aa}, + {0x0000b2e0, 0xfffd64cc}, + {0x0000b2e4, 0xfffe80f0}, + {0x0000b2e8, 0xffffff00}, + {0x00016044, 0x024922db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x024922db}, + {0x00016448, 0x6c927a70}, +}; + +static const u32 qca953x_2p0_modes_no_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xffd5f552}, + {0x0000a2e0, 0xffe60664}, + {0x0000a2e4, 0xfff80780}, + {0x0000a2e8, 0xfffff800}, + {0x0000a410, 0x000050de}, + {0x0000a500, 0x00000061}, + {0x0000a504, 0x04000063}, + {0x0000a508, 0x08000065}, + {0x0000a50c, 0x0c000261}, + {0x0000a510, 0x10000263}, + {0x0000a514, 0x14000265}, + {0x0000a518, 0x18000482}, + {0x0000a51c, 0x1b000484}, + {0x0000a520, 0x1f000486}, + {0x0000a524, 0x240008c2}, + {0x0000a528, 0x28000cc1}, + {0x0000a52c, 0x2d000ce3}, + {0x0000a530, 0x31000ce5}, + {0x0000a534, 0x350010e5}, + {0x0000a538, 0x360012e5}, + {0x0000a53c, 0x380014e5}, + {0x0000a540, 0x3b0018e5}, + {0x0000a544, 0x3d001d04}, + {0x0000a548, 0x3e001d05}, + {0x0000a54c, 0x40001d07}, + {0x0000a550, 0x42001f27}, + {0x0000a554, 0x43001f67}, + {0x0000a558, 0x46001fe7}, + {0x0000a55c, 0x47001f2b}, + {0x0000a560, 0x49001f0d}, + {0x0000a564, 0x4b001ed2}, + {0x0000a568, 0x4c001ed4}, + {0x0000a56c, 0x4e001f15}, + {0x0000a570, 0x4f001ff6}, + {0x0000a574, 0x4f001ff6}, + {0x0000a578, 0x4f001ff6}, + {0x0000a57c, 0x4f001ff6}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00804201}, + {0x0000a610, 0x01008201}, + {0x0000a614, 0x0180c402}, + {0x0000a618, 0x0180c603}, + {0x0000a61c, 0x0180c603}, + {0x0000a620, 0x01c10603}, + {0x0000a624, 0x01c10704}, + {0x0000a628, 0x02c18b05}, + {0x0000a62c, 0x02c14c07}, + {0x0000a630, 0x01008704}, + {0x0000a634, 0x01c10402}, + {0x0000a638, 0x0301cc07}, + {0x0000a63c, 0x0301cc07}, + {0x0000b2dc, 0xffd5f552}, + {0x0000b2e0, 0xffe60664}, + {0x0000b2e4, 0xfff80780}, + {0x0000b2e8, 0xfffff800}, + {0x00016044, 0x049242db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x049242db}, + {0x00016448, 0x6c927a70}, +}; + #endif /* INITVALS_953X_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h index 74d8bc0..fd6a84c 100644 --- a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h @@ -507,7 +507,7 @@ static const u32 ar955x_1p0_baseband_core[][2] = { {0x00009d04, 0x40206c10}, {0x00009d08, 0x009c4060}, {0x00009d0c, 0x9883800a}, - {0x00009d10, 0x01834061}, + {0x00009d10, 0x01884061}, {0x00009d14, 0x00c0040b}, {0x00009d18, 0x00000000}, {0x00009e08, 0x0038230c}, @@ -545,9 +545,9 @@ static const u32 ar955x_1p0_baseband_core[][2] = { {0x0000a370, 0x00000000}, {0x0000a390, 0x00000001}, {0x0000a394, 0x00000444}, - {0x0000a398, 0x1f020503}, - {0x0000a39c, 0x29180c03}, - {0x0000a3a0, 0x9a8b6844}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, {0x0000a3a4, 0x00000000}, {0x0000a3a8, 0xaaaaaaaa}, {0x0000a3ac, 0x3c466478}, diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index a5ca652..5d4629f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -24,7 +24,149 @@ #define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble -#define ar9580_1p0_radio_core ar9300_2p2_radio_core +static const u32 ar9580_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db2db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x7f80fff8}, + {0x0001604c, 0x76d005b5}, + {0x00016050, 0x556cf031}, + {0x00016054, 0x13449440}, + {0x00016058, 0x0c51c92c}, + {0x0001605c, 0x3db7fffc}, + {0x00016060, 0xfffffffc}, + {0x00016064, 0x000f0278}, + {0x0001606c, 0x6db60000}, + {0x00016080, 0x00000000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x54214514}, + {0x0001608c, 0x119f481e}, + {0x00016090, 0x24926490}, + {0x00016098, 0xd2888888}, + {0x000160a0, 0x0a108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160b4, 0x92480080}, + {0x000160c0, 0x00adb6d0}, + {0x000160c4, 0x6db6db60}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x01e6c000}, + {0x00016100, 0x3fffbe01}, + {0x00016104, 0xfff80000}, + {0x00016108, 0x00080010}, + {0x00016144, 0x02084080}, + {0x00016148, 0x00000000}, + {0x00016280, 0x058a0001}, + {0x00016284, 0x3d840208}, + {0x00016288, 0x05a20408}, + {0x0001628c, 0x00038c07}, + {0x00016290, 0x00000004}, + {0x00016294, 0x458a214f}, + {0x00016380, 0x00000000}, + {0x00016384, 0x00000000}, + {0x00016388, 0x00800700}, + {0x0001638c, 0x00800700}, + {0x00016390, 0x00800700}, + {0x00016394, 0x00000000}, + {0x00016398, 0x00000000}, + {0x0001639c, 0x00000000}, + {0x000163a0, 0x00000001}, + {0x000163a4, 0x00000001}, + {0x000163a8, 0x00000000}, + {0x000163ac, 0x00000000}, + {0x000163b0, 0x00000000}, + {0x000163b4, 0x00000000}, + {0x000163b8, 0x00000000}, + {0x000163bc, 0x00000000}, + {0x000163c0, 0x000000a0}, + {0x000163c4, 0x000c0000}, + {0x000163c8, 0x14021402}, + {0x000163cc, 0x00001402}, + {0x000163d0, 0x00000000}, + {0x000163d4, 0x00000000}, + {0x00016400, 0x36db2db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016440, 0x7f80fff8}, + {0x0001644c, 0x76d005b5}, + {0x00016450, 0x556cf031}, + {0x00016454, 0x13449440}, + {0x00016458, 0x0c51c92c}, + {0x0001645c, 0x3db7fffc}, + {0x00016460, 0xfffffffc}, + {0x00016464, 0x000f0278}, + {0x0001646c, 0x6db60000}, + {0x00016500, 0x3fffbe01}, + {0x00016504, 0xfff80000}, + {0x00016508, 0x00080010}, + {0x00016544, 0x02084080}, + {0x00016548, 0x00000000}, + {0x00016780, 0x00000000}, + {0x00016784, 0x00000000}, + {0x00016788, 0x00800700}, + {0x0001678c, 0x00800700}, + {0x00016790, 0x00800700}, + {0x00016794, 0x00000000}, + {0x00016798, 0x00000000}, + {0x0001679c, 0x00000000}, + {0x000167a0, 0x00000001}, + {0x000167a4, 0x00000001}, + {0x000167a8, 0x00000000}, + {0x000167ac, 0x00000000}, + {0x000167b0, 0x00000000}, + {0x000167b4, 0x00000000}, + {0x000167b8, 0x00000000}, + {0x000167bc, 0x00000000}, + {0x000167c0, 0x000000a0}, + {0x000167c4, 0x000c0000}, + {0x000167c8, 0x14021402}, + {0x000167cc, 0x00001402}, + {0x000167d0, 0x00000000}, + {0x000167d4, 0x00000000}, + {0x00016800, 0x36db2db6}, + {0x00016804, 0x6db6db40}, + {0x00016808, 0x73f00000}, + {0x0001680c, 0x00000000}, + {0x00016840, 0x7f80fff8}, + {0x0001684c, 0x76d005b5}, + {0x00016850, 0x556cf031}, + {0x00016854, 0x13449440}, + {0x00016858, 0x0c51c92c}, + {0x0001685c, 0x3db7fffc}, + {0x00016860, 0xfffffffc}, + {0x00016864, 0x000f0278}, + {0x0001686c, 0x6db60000}, + {0x00016900, 0x3fffbe01}, + {0x00016904, 0xfff80000}, + {0x00016908, 0x00080010}, + {0x00016944, 0x02084080}, + {0x00016948, 0x00000000}, + {0x00016b80, 0x00000000}, + {0x00016b84, 0x00000000}, + {0x00016b88, 0x00800700}, + {0x00016b8c, 0x00800700}, + {0x00016b90, 0x00800700}, + {0x00016b94, 0x00000000}, + {0x00016b98, 0x00000000}, + {0x00016b9c, 0x00000000}, + {0x00016ba0, 0x00000001}, + {0x00016ba4, 0x00000001}, + {0x00016ba8, 0x00000000}, + {0x00016bac, 0x00000000}, + {0x00016bb0, 0x00000000}, + {0x00016bb4, 0x00000000}, + {0x00016bb8, 0x00000000}, + {0x00016bbc, 0x00000000}, + {0x00016bc0, 0x000000a0}, + {0x00016bc4, 0x000c0000}, + {0x00016bc8, 0x14021402}, + {0x00016bcc, 0x00001402}, + {0x00016bd0, 0x00000000}, + {0x00016bd4, 0x00000000}, +}; #define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 01a7db0..abe8bd6 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -28,7 +28,6 @@ #include "debug.h" #include "mci.h" #include "dfs.h" -#include "spectral.h" struct ath_node; struct ath_vif; @@ -345,7 +344,9 @@ struct ath_chanctx { u64 tsf_val; u32 last_beacon; + int flush_timeout; u16 txpower; + u16 cur_txpower; bool offchannel; bool stopped; bool active; @@ -362,7 +363,7 @@ enum ath_chanctx_event { ATH_CHANCTX_EVENT_BEACON_SENT, ATH_CHANCTX_EVENT_TSF_TIMER, ATH_CHANCTX_EVENT_BEACON_RECEIVED, - ATH_CHANCTX_EVENT_ASSOC, + ATH_CHANCTX_EVENT_AUTHORIZED, ATH_CHANCTX_EVENT_SWITCH, ATH_CHANCTX_EVENT_ASSIGN, ATH_CHANCTX_EVENT_UNASSIGN, @@ -380,10 +381,12 @@ enum ath_chanctx_state { struct ath_chanctx_sched { bool beacon_pending; + bool beacon_adjust; bool offchannel_pending; bool wait_switch; bool force_noa_update; bool extend_absence; + bool mgd_prepare_tx; enum ath_chanctx_state state; u8 beacon_miss; @@ -468,6 +471,7 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force); void ath_offchannel_next(struct ath_softc *sc); void ath_scan_complete(struct ath_softc *sc, bool abort); void ath_roc_complete(struct ath_softc *sc, bool abort); +struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc); #else @@ -540,7 +544,6 @@ static inline void ath_chanctx_check_active(struct ath_softc *sc, #endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */ -int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan); void ath_startrecv(struct ath_softc *sc); bool ath_stoprecv(struct ath_softc *sc); u32 ath_calcrxfilter(struct ath_softc *sc); @@ -595,7 +598,7 @@ struct ath_vif { u16 seq_no; /* BSS info */ - u8 bssid[ETH_ALEN]; + u8 bssid[ETH_ALEN] __aligned(2); u16 aid; bool assoc; @@ -618,6 +621,7 @@ struct ath_vif { u32 noa_start; u32 noa_duration; bool periodic_noa; + bool oneshot_noa; }; struct ath9k_vif_iter_data { @@ -715,7 +719,8 @@ int ath_update_survey_stats(struct ath_softc *sc); void ath_update_survey_nf(struct ath_softc *sc, int channel); void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); void ath_ps_full_sleep(unsigned long data); -void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop); +void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop, + bool sw_pending, bool timeout_override); /**********/ /* BTCOEX */ @@ -927,6 +932,7 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); #define ATH9K_PCI_AR9565_2ANT 0x0100 #define ATH9K_PCI_NO_PLL_PWRSAVE 0x0200 #define ATH9K_PCI_KILLER 0x0400 +#define ATH9K_PCI_LED_ACT_HI 0x0800 /* * Default cache line size, in bytes. @@ -975,6 +981,7 @@ struct ath_softc { struct ath_chanctx_sched sched; struct ath_offchannel offchannel; struct ath_chanctx *next_chan; + struct completion go_beacon; #endif unsigned long driver_data; @@ -982,7 +989,6 @@ struct ath_softc { u8 gtt_cnt; u32 intrstatus; u16 ps_flags; /* PS_* */ - u16 curtxpow; bool ps_enabled; bool ps_idle; short nbcnvifs; @@ -1023,10 +1029,8 @@ struct ath_softc { struct dfs_pattern_detector *dfs_detector; u64 dfs_prev_pulse_ts; u32 wow_enabled; - /* relay(fs) channel for spectral scan */ - struct rchan *rfs_chan_spec_scan; - enum spectral_mode spectral_mode; - struct ath_spec_scan spec_config; + + struct ath_spec_scan_priv spec_priv; struct ieee80211_vif *tx99_vif; struct sk_buff *tx99_skb; @@ -1069,7 +1073,7 @@ void ath9k_tasklet(unsigned long data); int ath_cabq_update(struct ath_softc *); u8 ath9k_parse_mpdudensity(u8 mpdudensity); irqreturn_t ath_isr(int irq, void *dev); -int ath_reset(struct ath_softc *sc); +int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan); void ath_cancel_work(struct ath_softc *sc); void ath_restart_work(struct ath_softc *sc); int ath9k_init_device(u16 devid, struct ath_softc *sc, diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index 278365b..e200a6e 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -234,7 +234,7 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update) REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); } -void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) +int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath9k_nfcal_hist *h = NULL; unsigned i, j; @@ -301,7 +301,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) ath_dbg(common, ANY, "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n", REG_READ(ah, AR_PHY_AGC_CONTROL)); - return; + return -ETIMEDOUT; } /* @@ -322,6 +322,8 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) } } REGWRITE_BUFFER_FLUSH(ah); + + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index b8ed95e..87badf4 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -109,7 +109,7 @@ struct ath9k_pacal_info{ bool ath9k_hw_reset_calvalid(struct ath_hw *ah); void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update); -void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); +int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan); void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, struct ath9k_channel *chan); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 945c898..2066650 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -66,7 +66,7 @@ static int ath_set_channel(struct ath_softc *sc) } hchan = &sc->sc_ah->channels[pos]; - r = ath_reset_internal(sc, hchan); + r = ath_reset(sc, hchan); if (r) return r; @@ -92,8 +92,8 @@ static int ath_set_channel(struct ath_softc *sc) } else { /* perform spectral scan if requested. */ if (test_bit(ATH_OP_SCANNING, &common->op_flags) && - sc->spectral_mode == SPECTRAL_CHANSCAN) - ath9k_spectral_scan_trigger(hw); + sc->spec_priv.spectral_mode == SPECTRAL_CHANSCAN) + ath9k_cmn_spectral_scan_trigger(common, &sc->spec_priv); } return 0; @@ -117,6 +117,7 @@ void ath_chanctx_init(struct ath_softc *sc) cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20); INIT_LIST_HEAD(&ctx->vifs); ctx->txpower = ATH_TXPOWER_MAX; + ctx->flush_timeout = HZ / 5; /* 200ms */ for (j = 0; j < ARRAY_SIZE(ctx->acq); j++) INIT_LIST_HEAD(&ctx->acq[j]); } @@ -145,6 +146,36 @@ void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx, #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +/*************/ +/* Utilities */ +/*************/ + +struct ath_chanctx* ath_is_go_chanctx_present(struct ath_softc *sc) +{ + struct ath_chanctx *ctx; + struct ath_vif *avp; + struct ieee80211_vif *vif; + + spin_lock_bh(&sc->chan_lock); + + ath_for_each_chanctx(sc, ctx) { + if (!ctx->active) + continue; + + list_for_each_entry(avp, &ctx->vifs, list) { + vif = avp->vif; + + if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_P2P_GO) { + spin_unlock_bh(&sc->chan_lock); + return ctx; + } + } + } + + spin_unlock_bh(&sc->chan_lock); + return NULL; +} + /**********************************************************/ /* Functions to handle the channel context state machine. */ /**********************************************************/ @@ -171,7 +202,7 @@ static const char *chanctx_event_string(enum ath_chanctx_event ev) case_rtn_string(ATH_CHANCTX_EVENT_BEACON_SENT); case_rtn_string(ATH_CHANCTX_EVENT_TSF_TIMER); case_rtn_string(ATH_CHANCTX_EVENT_BEACON_RECEIVED); - case_rtn_string(ATH_CHANCTX_EVENT_ASSOC); + case_rtn_string(ATH_CHANCTX_EVENT_AUTHORIZED); case_rtn_string(ATH_CHANCTX_EVENT_SWITCH); case_rtn_string(ATH_CHANCTX_EVENT_ASSIGN); case_rtn_string(ATH_CHANCTX_EVENT_UNASSIGN); @@ -198,6 +229,7 @@ static const char *chanctx_state_string(enum ath_chanctx_state state) void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_chanctx *ictx; struct ath_vif *avp; bool active = false; u8 n_active = 0; @@ -205,6 +237,28 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) if (!ctx) return; + if (ctx == &sc->offchannel.chan) { + spin_lock_bh(&sc->chan_lock); + + if (likely(sc->sched.channel_switch_time)) + ctx->flush_timeout = + usecs_to_jiffies(sc->sched.channel_switch_time); + else + ctx->flush_timeout = + msecs_to_jiffies(10); + + spin_unlock_bh(&sc->chan_lock); + + /* + * There is no need to iterate over the + * active/assigned channel contexts if + * the current context is offchannel. + */ + return; + } + + ictx = ctx; + list_for_each_entry(avp, &ctx->vifs, list) { struct ieee80211_vif *vif = avp->vif; @@ -227,12 +281,23 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx) n_active++; } + spin_lock_bh(&sc->chan_lock); + if (n_active <= 1) { + ictx->flush_timeout = HZ / 5; clear_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags); + spin_unlock_bh(&sc->chan_lock); return; } - if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + + ictx->flush_timeout = usecs_to_jiffies(sc->sched.channel_switch_time); + + if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) { + spin_unlock_bh(&sc->chan_lock); return; + } + + spin_unlock_bh(&sc->chan_lock); if (ath9k_is_chanctx_enabled()) { ath_chanctx_event(sc, NULL, @@ -301,6 +366,111 @@ static void ath_chanctx_setup_timer(struct ath_softc *sc, u32 tsf_time) "Setup chanctx timer with timeout: %d ms\n", jiffies_to_msecs(tsf_time)); } +static void ath_chanctx_handle_bmiss(struct ath_softc *sc, + struct ath_chanctx *ctx, + struct ath_vif *avp) +{ + /* + * Clear the extend_absence flag if it had been + * set during the previous beacon transmission, + * since we need to revert to the normal NoA + * schedule. + */ + if (ctx->active && sc->sched.extend_absence) { + avp->noa_duration = 0; + sc->sched.extend_absence = false; + } + + /* If at least two consecutive beacons were missed on the STA + * chanctx, stay on the STA channel for one extra beacon period, + * to resync the timer properly. + */ + if (ctx->active && sc->sched.beacon_miss >= 2) { + avp->noa_duration = 0; + sc->sched.extend_absence = true; + } +} + +static void ath_chanctx_offchannel_noa(struct ath_softc *sc, + struct ath_chanctx *ctx, + struct ath_vif *avp, + u32 tsf_time) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + avp->noa_index++; + avp->offchannel_start = tsf_time; + avp->offchannel_duration = sc->sched.offchannel_duration; + + ath_dbg(common, CHAN_CTX, + "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n", + avp->offchannel_duration, + avp->offchannel_start, + avp->noa_index); + + /* + * When multiple contexts are active, the NoA + * has to be recalculated and advertised after + * an offchannel operation. + */ + if (ctx->active && avp->noa_duration) + avp->noa_duration = 0; +} + +static void ath_chanctx_set_periodic_noa(struct ath_softc *sc, + struct ath_vif *avp, + struct ath_beacon_config *cur_conf, + u32 tsf_time, + u32 beacon_int) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + avp->noa_index++; + avp->noa_start = tsf_time; + + if (sc->sched.extend_absence) + avp->noa_duration = (3 * beacon_int / 2) + + sc->sched.channel_switch_time; + else + avp->noa_duration = + TU_TO_USEC(cur_conf->beacon_interval) / 2 + + sc->sched.channel_switch_time; + + if (test_bit(ATH_OP_SCANNING, &common->op_flags) || + sc->sched.extend_absence) + avp->periodic_noa = false; + else + avp->periodic_noa = true; + + ath_dbg(common, CHAN_CTX, + "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n", + avp->noa_duration, + avp->noa_start, + avp->noa_index, + avp->periodic_noa); +} + +static void ath_chanctx_set_oneshot_noa(struct ath_softc *sc, + struct ath_vif *avp, + u32 tsf_time, + u32 duration) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + avp->noa_index++; + avp->noa_start = tsf_time; + avp->periodic_noa = false; + avp->oneshot_noa = true; + avp->noa_duration = duration + sc->sched.channel_switch_time; + + ath_dbg(common, CHAN_CTX, + "oneshot noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n", + avp->noa_duration, + avp->noa_start, + avp->noa_index, + avp->periodic_noa); +} + void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, enum ath_chanctx_event ev) { @@ -327,6 +497,14 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, if (avp->offchannel_duration) avp->offchannel_duration = 0; + if (avp->oneshot_noa) { + avp->noa_duration = 0; + avp->oneshot_noa = false; + + ath_dbg(common, CHAN_CTX, + "Clearing oneshot NoA\n"); + } + if (avp->chanctx != sc->cur_chan) { ath_dbg(common, CHAN_CTX, "Contexts differ, not preparing beacon\n"); @@ -356,6 +534,24 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, "Move chanctx state from WAIT_FOR_TIMER to WAIT_FOR_BEACON\n"); } + if (sc->sched.mgd_prepare_tx) + sc->sched.state = ATH_CHANCTX_STATE_WAIT_FOR_BEACON; + + /* + * When a context becomes inactive, for example, + * disassociation of a station context, the NoA + * attribute needs to be removed from subsequent + * beacons. + */ + if (!ctx->active && avp->noa_duration && + sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) { + avp->noa_duration = 0; + avp->periodic_noa = false; + + ath_dbg(common, CHAN_CTX, + "Clearing NoA schedule\n"); + } + if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) break; @@ -378,45 +574,22 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, * values and increment the index. */ if (sc->next_chan == &sc->offchannel.chan) { - avp->noa_index++; - avp->offchannel_start = tsf_time; - avp->offchannel_duration = sc->sched.offchannel_duration; - - ath_dbg(common, CHAN_CTX, - "offchannel noa_duration: %d, noa_start: %d, noa_index: %d\n", - avp->offchannel_duration, - avp->offchannel_start, - avp->noa_index); - - /* - * When multiple contexts are active, the NoA - * has to be recalculated and advertised after - * an offchannel operation. - */ - if (ctx->active && avp->noa_duration) - avp->noa_duration = 0; - + ath_chanctx_offchannel_noa(sc, ctx, avp, tsf_time); break; } - /* - * Clear the extend_absence flag if it had been - * set during the previous beacon transmission, - * since we need to revert to the normal NoA - * schedule. - */ - if (ctx->active && sc->sched.extend_absence) { - avp->noa_duration = 0; - sc->sched.extend_absence = false; - } + ath_chanctx_handle_bmiss(sc, ctx, avp); - /* If at least two consecutive beacons were missed on the STA - * chanctx, stay on the STA channel for one extra beacon period, - * to resync the timer properly. + /* + * If a mgd_prepare_tx() has been called by mac80211, + * a one-shot NoA needs to be sent. This can happen + * with one or more active channel contexts - in both + * cases, a new NoA schedule has to be advertised. */ - if (ctx->active && sc->sched.beacon_miss >= 2) { - avp->noa_duration = 0; - sc->sched.extend_absence = true; + if (sc->sched.mgd_prepare_tx) { + ath_chanctx_set_oneshot_noa(sc, avp, tsf_time, + jiffies_to_usecs(HZ / 5)); + break; } /* Prevent wrap-around issues */ @@ -429,31 +602,9 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, * announcement. */ if (ctx->active && - (!avp->noa_duration || sc->sched.force_noa_update)) { - avp->noa_index++; - avp->noa_start = tsf_time; - - if (sc->sched.extend_absence) - avp->noa_duration = (3 * beacon_int / 2) + - sc->sched.channel_switch_time; - else - avp->noa_duration = - TU_TO_USEC(cur_conf->beacon_interval) / 2 + - sc->sched.channel_switch_time; - - if (test_bit(ATH_OP_SCANNING, &common->op_flags) || - sc->sched.extend_absence) - avp->periodic_noa = false; - else - avp->periodic_noa = true; - - ath_dbg(common, CHAN_CTX, - "noa_duration: %d, noa_start: %d, noa_index: %d, periodic: %d\n", - avp->noa_duration, - avp->noa_start, - avp->noa_index, - avp->periodic_noa); - } + (!avp->noa_duration || sc->sched.force_noa_update)) + ath_chanctx_set_periodic_noa(sc, avp, cur_conf, + tsf_time, beacon_int); if (ctx->active && sc->sched.force_noa_update) sc->sched.force_noa_update = false; @@ -467,6 +618,15 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, } sc->sched.beacon_pending = false; + + if (sc->sched.mgd_prepare_tx) { + sc->sched.mgd_prepare_tx = false; + complete(&sc->go_beacon); + ath_dbg(common, CHAN_CTX, + "Beacon sent, complete go_beacon\n"); + break; + } + if (sc->sched.state != ATH_CHANCTX_STATE_WAIT_FOR_BEACON) break; @@ -495,10 +655,16 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, sc->cur_chan == &sc->offchannel.chan) break; - ath_chanctx_adjust_tbtt_delta(sc); sc->sched.beacon_pending = false; sc->sched.beacon_miss = 0; + if (sc->sched.state == ATH_CHANCTX_STATE_FORCE_ACTIVE || + !sc->sched.beacon_adjust || + !sc->cur_chan->tsf_val) + break; + + ath_chanctx_adjust_tbtt_delta(sc); + /* TSF time might have been updated by the incoming beacon, * need update the channel switch timer to reflect the change. */ @@ -507,10 +673,10 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ath9k_hw_get_tsf_offset(&sc->cur_chan->tsf_ts, NULL); tsf_time += ath9k_hw_gettsf32(ah); - + sc->sched.beacon_adjust = false; ath_chanctx_setup_timer(sc, tsf_time); break; - case ATH_CHANCTX_EVENT_ASSOC: + case ATH_CHANCTX_EVENT_AUTHORIZED: if (sc->sched.state != ATH_CHANCTX_STATE_FORCE_ACTIVE || avp->chanctx != sc->cur_chan) break; @@ -552,6 +718,7 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ath_chanctx_setup_timer(sc, tsf_time); sc->sched.beacon_pending = true; + sc->sched.beacon_adjust = true; break; case ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL: if (sc->cur_chan == &sc->offchannel.chan || @@ -578,22 +745,6 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif, ieee80211_queue_work(sc->hw, &sc->chanctx_work); break; case ATH_CHANCTX_EVENT_ASSIGN: - /* - * When adding a new channel context, check if a scan - * is in progress and abort it since the addition of - * a new channel context is usually followed by VIF - * assignment, in which case we have to start multi-channel - * operation. - */ - if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { - ath_dbg(common, CHAN_CTX, - "Aborting HW scan to add new context\n"); - - spin_unlock_bh(&sc->chan_lock); - del_timer_sync(&sc->offchannel.timer); - ath_scan_complete(sc, true); - spin_lock_bh(&sc->chan_lock); - } break; case ATH_CHANCTX_EVENT_CHANGE: break; @@ -751,6 +902,11 @@ void ath_offchannel_next(struct ath_softc *sc) sc->offchannel.state = ATH_OFFCHANNEL_ROC_START; ath_chanctx_offchan_switch(sc, sc->offchannel.roc_chan); } else { + spin_lock_bh(&sc->chan_lock); + sc->sched.offchannel_pending = false; + sc->sched.wait_switch = false; + spin_unlock_bh(&sc->chan_lock); + ath_chanctx_switch(sc, ath_chanctx_get_oper_chan(sc, false), NULL); sc->offchannel.state = ATH_OFFCHANNEL_IDLE; @@ -770,8 +926,7 @@ void ath_roc_complete(struct ath_softc *sc, bool abort) sc->offchannel.roc_vif = NULL; sc->offchannel.roc_chan = NULL; - if (!abort) - ieee80211_remain_on_channel_expired(sc->hw); + ieee80211_remain_on_channel_expired(sc->hw); ath_offchannel_next(sc); ath9k_ps_restore(sc); } @@ -808,7 +963,7 @@ static void ath_scan_send_probe(struct ath_softc *sc, struct ieee80211_tx_info *info; int band = sc->offchannel.chan.chandef.chan->band; - skb = ieee80211_probereq_get(sc->hw, vif, + skb = ieee80211_probereq_get(sc->hw, vif->addr, ssid->ssid, ssid->ssid_len, req->ie_len); if (!skb) return; @@ -902,9 +1057,8 @@ static void ath_offchannel_timer(unsigned long data) break; case ATH_OFFCHANNEL_ROC_START: case ATH_OFFCHANNEL_ROC_WAIT: - ctx = ath_chanctx_get_oper_chan(sc, false); sc->offchannel.state = ATH_OFFCHANNEL_ROC_DONE; - ath_chanctx_switch(sc, ctx, NULL); + ath_roc_complete(sc, false); break; default: break; @@ -1034,7 +1188,6 @@ static void ath_offchannel_channel_change(struct ath_softc *sc) ieee80211_ready_on_channel(sc->hw); break; case ATH_OFFCHANNEL_ROC_DONE: - ath_roc_complete(sc, false); break; default: break; @@ -1082,10 +1235,11 @@ void ath_chanctx_set_next(struct ath_softc *sc, bool force) ath9k_chanctx_stop_queues(sc, sc->cur_chan); queues_stopped = true; - __ath9k_flush(sc->hw, ~0, true); + __ath9k_flush(sc->hw, ~0, true, false, false); if (ath_chanctx_send_ps_frame(sc, true)) - __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false); + __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), + false, false, false); send_ps = true; spin_lock_bh(&sc->chan_lock); @@ -1177,6 +1331,8 @@ void ath9k_init_channel_context(struct ath_softc *sc) (unsigned long)sc); setup_timer(&sc->sched.timer, ath_chanctx_timer, (unsigned long)sc); + + init_completion(&sc->go_beacon); } void ath9k_deinit_channel_context(struct ath_softc *sc) diff --git a/drivers/net/wireless/ath/ath9k/spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 8f68426..ec93ddf 100644 --- a/drivers/net/wireless/ath/ath9k/spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -24,23 +24,24 @@ static s8 fix_rssi_inv_only(u8 rssi_val) return (s8) rssi_val; } -static void ath_debug_send_fft_sample(struct ath_softc *sc, +static void ath_debug_send_fft_sample(struct ath_spec_scan_priv *spec_priv, struct fft_sample_tlv *fft_sample_tlv) { int length; - if (!sc->rfs_chan_spec_scan) + if (!spec_priv->rfs_chan_spec_scan) return; length = __be16_to_cpu(fft_sample_tlv->length) + sizeof(*fft_sample_tlv); - relay_write(sc->rfs_chan_spec_scan, fft_sample_tlv, length); + relay_write(spec_priv->rfs_chan_spec_scan, fft_sample_tlv, length); } /* returns 1 if this was a spectral frame, even if not handled. */ -int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, +int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr, struct ath_rx_status *rs, u64 tsf) { - struct ath_hw *ah = sc->sc_ah; + struct ath_hw *ah = spec_priv->ah; + struct ath_common *common = ath9k_hw_common(spec_priv->ah); u8 num_bins, *bins, *vdata = (u8 *)hdr; struct fft_sample_ht20 fft_sample_20; struct fft_sample_ht20_40 fft_sample_40; @@ -67,7 +68,7 @@ int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) return 0; - chan_type = cfg80211_get_chandef_type(&sc->hw->conf.chandef); + chan_type = cfg80211_get_chandef_type(&common->hw->conf.chandef); if ((chan_type == NL80211_CHAN_HT40MINUS) || (chan_type == NL80211_CHAN_HT40PLUS)) { fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN; @@ -199,10 +200,11 @@ int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, tlv = (struct fft_sample_tlv *)&fft_sample_20; } - ath_debug_send_fft_sample(sc, tlv); + ath_debug_send_fft_sample(spec_priv, tlv); return 1; } +EXPORT_SYMBOL(ath_cmn_process_fft); /*********************/ /* spectral_scan_ctl */ @@ -211,11 +213,11 @@ int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct ath_softc *sc = file->private_data; + struct ath_spec_scan_priv *spec_priv = file->private_data; char *mode = ""; unsigned int len; - switch (sc->spectral_mode) { + switch (spec_priv->spectral_mode) { case SPECTRAL_DISABLED: mode = "disable"; break; @@ -233,12 +235,84 @@ static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf, return simple_read_from_buffer(user_buf, count, ppos, mode, len); } +void ath9k_cmn_spectral_scan_trigger(struct ath_common *common, + struct ath_spec_scan_priv *spec_priv) +{ + struct ath_hw *ah = spec_priv->ah; + u32 rxfilter; + + if (config_enabled(CONFIG_ATH9K_TX99)) + return; + + if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { + ath_err(common, "spectrum analyzer not implemented on this hardware\n"); + return; + } + + ath_ps_ops(common)->wakeup(common); + rxfilter = ath9k_hw_getrxfilter(ah); + ath9k_hw_setrxfilter(ah, rxfilter | + ATH9K_RX_FILTER_PHYRADAR | + ATH9K_RX_FILTER_PHYERR); + + /* TODO: usually this should not be neccesary, but for some reason + * (or in some mode?) the trigger must be called after the + * configuration, otherwise the register will have its values reset + * (on my ar9220 to value 0x01002310) + */ + ath9k_cmn_spectral_scan_config(common, spec_priv, spec_priv->spectral_mode); + ath9k_hw_ops(ah)->spectral_scan_trigger(ah); + ath_ps_ops(common)->restore(common); +} +EXPORT_SYMBOL(ath9k_cmn_spectral_scan_trigger); + +int ath9k_cmn_spectral_scan_config(struct ath_common *common, + struct ath_spec_scan_priv *spec_priv, + enum spectral_mode spectral_mode) +{ + struct ath_hw *ah = spec_priv->ah; + + if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { + ath_err(common, "spectrum analyzer not implemented on this hardware\n"); + return -1; + } + + switch (spectral_mode) { + case SPECTRAL_DISABLED: + spec_priv->spec_config.enabled = 0; + break; + case SPECTRAL_BACKGROUND: + /* send endless samples. + * TODO: is this really useful for "background"? + */ + spec_priv->spec_config.endless = 1; + spec_priv->spec_config.enabled = 1; + break; + case SPECTRAL_CHANSCAN: + case SPECTRAL_MANUAL: + spec_priv->spec_config.endless = 0; + spec_priv->spec_config.enabled = 1; + break; + default: + return -1; + } + + ath_ps_ops(common)->wakeup(common); + ath9k_hw_ops(ah)->spectral_scan_config(ah, &spec_priv->spec_config); + ath_ps_ops(common)->restore(common); + + spec_priv->spectral_mode = spectral_mode; + + return 0; +} +EXPORT_SYMBOL(ath9k_cmn_spectral_scan_config); + static ssize_t write_file_spec_scan_ctl(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct ath_softc *sc = file->private_data; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_spec_scan_priv *spec_priv = file->private_data; + struct ath_common *common = ath9k_hw_common(spec_priv->ah); char buf[32]; ssize_t len; @@ -252,18 +326,18 @@ static ssize_t write_file_spec_scan_ctl(struct file *file, buf[len] = '\0'; if (strncmp("trigger", buf, 7) == 0) { - ath9k_spectral_scan_trigger(sc->hw); + ath9k_cmn_spectral_scan_trigger(common, spec_priv); } else if (strncmp("background", buf, 10) == 0) { - ath9k_spectral_scan_config(sc->hw, SPECTRAL_BACKGROUND); + ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_BACKGROUND); ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n"); } else if (strncmp("chanscan", buf, 8) == 0) { - ath9k_spectral_scan_config(sc->hw, SPECTRAL_CHANSCAN); + ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_CHANSCAN); ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n"); } else if (strncmp("manual", buf, 6) == 0) { - ath9k_spectral_scan_config(sc->hw, SPECTRAL_MANUAL); + ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_MANUAL); ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n"); } else if (strncmp("disable", buf, 7) == 0) { - ath9k_spectral_scan_config(sc->hw, SPECTRAL_DISABLED); + ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_DISABLED); ath_dbg(common, CONFIG, "spectral scan: disabled\n"); } else { return -EINVAL; @@ -288,11 +362,11 @@ static ssize_t read_file_spectral_short_repeat(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct ath_softc *sc = file->private_data; + struct ath_spec_scan_priv *spec_priv = file->private_data; char buf[32]; unsigned int len; - len = sprintf(buf, "%d\n", sc->spec_config.short_repeat); + len = sprintf(buf, "%d\n", spec_priv->spec_config.short_repeat); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -300,7 +374,7 @@ static ssize_t write_file_spectral_short_repeat(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct ath_softc *sc = file->private_data; + struct ath_spec_scan_priv *spec_priv = file->private_data; unsigned long val; char buf[32]; ssize_t len; @@ -316,7 +390,7 @@ static ssize_t write_file_spectral_short_repeat(struct file *file, if (val > 1) return -EINVAL; - sc->spec_config.short_repeat = val; + spec_priv->spec_config.short_repeat = val; return count; } @@ -336,11 +410,11 @@ static ssize_t read_file_spectral_count(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct ath_softc *sc = file->private_data; + struct ath_spec_scan_priv *spec_priv = file->private_data; char buf[32]; unsigned int len; - len = sprintf(buf, "%d\n", sc->spec_config.count); + len = sprintf(buf, "%d\n", spec_priv->spec_config.count); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -348,7 +422,7 @@ static ssize_t write_file_spectral_count(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct ath_softc *sc = file->private_data; + struct ath_spec_scan_priv *spec_priv = file->private_data; unsigned long val; char buf[32]; ssize_t len; @@ -364,7 +438,7 @@ static ssize_t write_file_spectral_count(struct file *file, if (val > 255) return -EINVAL; - sc->spec_config.count = val; + spec_priv->spec_config.count = val; return count; } @@ -384,11 +458,11 @@ static ssize_t read_file_spectral_period(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct ath_softc *sc = file->private_data; + struct ath_spec_scan_priv *spec_priv = file->private_data; char buf[32]; unsigned int len; - len = sprintf(buf, "%d\n", sc->spec_config.period); + len = sprintf(buf, "%d\n", spec_priv->spec_config.period); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -396,7 +470,7 @@ static ssize_t write_file_spectral_period(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct ath_softc *sc = file->private_data; + struct ath_spec_scan_priv *spec_priv = file->private_data; unsigned long val; char buf[32]; ssize_t len; @@ -412,7 +486,7 @@ static ssize_t write_file_spectral_period(struct file *file, if (val > 255) return -EINVAL; - sc->spec_config.period = val; + spec_priv->spec_config.period = val; return count; } @@ -432,11 +506,11 @@ static ssize_t read_file_spectral_fft_period(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct ath_softc *sc = file->private_data; + struct ath_spec_scan_priv *spec_priv = file->private_data; char buf[32]; unsigned int len; - len = sprintf(buf, "%d\n", sc->spec_config.fft_period); + len = sprintf(buf, "%d\n", spec_priv->spec_config.fft_period); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -444,7 +518,7 @@ static ssize_t write_file_spectral_fft_period(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct ath_softc *sc = file->private_data; + struct ath_spec_scan_priv *spec_priv = file->private_data; unsigned long val; char buf[32]; ssize_t len; @@ -460,7 +534,7 @@ static ssize_t write_file_spectral_fft_period(struct file *file, if (val > 15) return -EINVAL; - sc->spec_config.fft_period = val; + spec_priv->spec_config.fft_period = val; return count; } @@ -506,38 +580,41 @@ static struct rchan_callbacks rfs_spec_scan_cb = { /* Debug Init/Deinit */ /*********************/ -void ath9k_spectral_deinit_debug(struct ath_softc *sc) +void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv) { - if (config_enabled(CONFIG_ATH9K_DEBUGFS) && sc->rfs_chan_spec_scan) { - relay_close(sc->rfs_chan_spec_scan); - sc->rfs_chan_spec_scan = NULL; + if (config_enabled(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) { + relay_close(spec_priv->rfs_chan_spec_scan); + spec_priv->rfs_chan_spec_scan = NULL; } } +EXPORT_SYMBOL(ath9k_cmn_spectral_deinit_debug); -void ath9k_spectral_init_debug(struct ath_softc *sc) +void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, + struct dentry *debugfs_phy) { - sc->rfs_chan_spec_scan = relay_open("spectral_scan", - sc->debug.debugfs_phy, + spec_priv->rfs_chan_spec_scan = relay_open("spectral_scan", + debugfs_phy, 1024, 256, &rfs_spec_scan_cb, NULL); debugfs_create_file("spectral_scan_ctl", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, + debugfs_phy, spec_priv, &fops_spec_scan_ctl); debugfs_create_file("spectral_short_repeat", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, + debugfs_phy, spec_priv, &fops_spectral_short_repeat); debugfs_create_file("spectral_count", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, + debugfs_phy, spec_priv, &fops_spectral_count); debugfs_create_file("spectral_period", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, + debugfs_phy, spec_priv, &fops_spectral_period); debugfs_create_file("spectral_fft_period", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, + debugfs_phy, spec_priv, &fops_spectral_fft_period); } +EXPORT_SYMBOL(ath9k_cmn_spectral_init_debug); diff --git a/drivers/net/wireless/ath/ath9k/spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h index 7b410c6..82d9dd2 100644 --- a/drivers/net/wireless/ath/ath9k/spectral.h +++ b/drivers/net/wireless/ath/ath9k/common-spectral.h @@ -92,6 +92,13 @@ struct ath_ht20_40_fft_packet { struct ath_radar_info radar_info; } __packed; +struct ath_spec_scan_priv { + struct ath_hw *ah; + /* relay(fs) channel for spectral scan */ + struct rchan *rfs_chan_spec_scan; + enum spectral_mode spectral_mode; + struct ath_spec_scan spec_config; +}; #define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet)) @@ -123,23 +130,15 @@ static inline u8 spectral_bitmap_weight(u8 *bins) return bins[0] & 0x3f; } -void ath9k_spectral_init_debug(struct ath_softc *sc); -void ath9k_spectral_deinit_debug(struct ath_softc *sc); +void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, struct dentry *debugfs_phy); +void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv); -void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw); -int ath9k_spectral_scan_config(struct ieee80211_hw *hw, +void ath9k_cmn_spectral_scan_trigger(struct ath_common *common, + struct ath_spec_scan_priv *spec_priv); +int ath9k_cmn_spectral_scan_config(struct ath_common *common, + struct ath_spec_scan_priv *spec_priv, enum spectral_mode spectral_mode); - -#ifdef CONFIG_ATH9K_DEBUGFS -int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, +int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr, struct ath_rx_status *rs, u64 tsf); -#else -static inline int ath_process_fft(struct ath_softc *sc, - struct ieee80211_hdr *hdr, - struct ath_rx_status *rs, u64 tsf) -{ - return 0; -} -#endif /* CONFIG_ATH9K_DEBUGFS */ #endif /* SPECTRAL_H */ diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 33b0c7a..e8c6994 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -159,7 +159,7 @@ void ath9k_cmn_rx_skb_postprocess(struct ath_common *common, if (test_bit(keyix, common->keymap)) rxs->flag |= RX_FLAG_DECRYPTED; } - if (ah->sw_mgmt_crypto && + if (ah->sw_mgmt_crypto_rx && (rxs->flag & RX_FLAG_DECRYPTED) && ieee80211_is_mgmt(fc)) /* Use software decrypt for management frames. */ diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index ffc454b..2b79a56 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -24,6 +24,7 @@ #include "common-init.h" #include "common-beacon.h" #include "common-debug.h" +#include "common-spectral.h" /* Common header for Atheros 802.11n base driver cores */ diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 5c45e78..696e3d5 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -828,13 +828,14 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, i = 0; ath_for_each_chanctx(sc, ctx) { - if (!ctx->assigned || list_empty(&ctx->vifs)) + if (list_empty(&ctx->vifs)) continue; ath9k_calculate_iter_data(sc, ctx, &iter_data); len += scnprintf(buf + len, sizeof(buf) - len, - "VIF-COUNTS: CTX %i AP: %i STA: %i MESH: %i WDS: %i", - i++, iter_data.naps, iter_data.nstations, + "VIFS: CTX %i(%i) AP: %i STA: %i MESH: %i WDS: %i", + i++, (int)(ctx->assigned), iter_data.naps, + iter_data.nstations, iter_data.nmeshes, iter_data.nwds); len += scnprintf(buf + len, sizeof(buf) - len, " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n", @@ -852,36 +853,31 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; + static const char * const reset_cause[__RESET_TYPE_MAX] = { + [RESET_TYPE_BB_HANG] = "Baseband Hang", + [RESET_TYPE_BB_WATCHDOG] = "Baseband Watchdog", + [RESET_TYPE_FATAL_INT] = "Fatal HW Error", + [RESET_TYPE_TX_ERROR] = "TX HW error", + [RESET_TYPE_TX_GTT] = "Transmit timeout", + [RESET_TYPE_TX_HANG] = "TX Path Hang", + [RESET_TYPE_PLL_HANG] = "PLL RX Hang", + [RESET_TYPE_MAC_HANG] = "MAC Hang", + [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon", + [RESET_TYPE_MCI] = "MCI Reset", + [RESET_TYPE_CALIBRATION] = "Calibration error", + }; char buf[512]; unsigned int len = 0; + int i; - len += scnprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "Baseband Hang", - sc->debug.stats.reset[RESET_TYPE_BB_HANG]); - len += scnprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "Baseband Watchdog", - sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]); - len += scnprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "Fatal HW Error", - sc->debug.stats.reset[RESET_TYPE_FATAL_INT]); - len += scnprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "TX HW error", - sc->debug.stats.reset[RESET_TYPE_TX_ERROR]); - len += scnprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "TX Path Hang", - sc->debug.stats.reset[RESET_TYPE_TX_HANG]); - len += scnprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "PLL RX Hang", - sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); - len += scnprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "MAC Hang", - sc->debug.stats.reset[RESET_TYPE_MAC_HANG]); - len += scnprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "Stuck Beacon", - sc->debug.stats.reset[RESET_TYPE_BEACON_STUCK]); - len += scnprintf(buf + len, sizeof(buf) - len, - "%17s: %2d\n", "MCI Reset", - sc->debug.stats.reset[RESET_TYPE_MCI]); + for (i = 0; i < ARRAY_SIZE(reset_cause); i++) { + if (!reset_cause[i]) + continue; + + len += scnprintf(buf + len, sizeof(buf) - len, + "%17s: %2d\n", reset_cause[i], + sc->debug.stats.reset[i]); + } if (len > sizeof(buf)) len = sizeof(buf); @@ -1315,7 +1311,7 @@ void ath9k_get_et_stats(struct ieee80211_hw *hw, void ath9k_deinit_debug(struct ath_softc *sc) { - ath9k_spectral_deinit_debug(sc); + ath9k_cmn_spectral_deinit_debug(&sc->spec_priv); } int ath9k_init_debug(struct ath_hw *ah) @@ -1335,7 +1331,7 @@ int ath9k_init_debug(struct ath_hw *ah) ath9k_dfs_init_debug(sc); ath9k_tx99_init_debug(sc); - ath9k_spectral_init_debug(sc); + ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy); debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_dma); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 53ae15b..bd75b1f 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -49,6 +49,7 @@ enum ath_reset_type { RESET_TYPE_MAC_HANG, RESET_TYPE_BEACON_STUCK, RESET_TYPE_MCI, + RESET_TYPE_CALIBRATION, __RESET_TYPE_MAX }; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 3218ca9..122b846 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -262,7 +262,7 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) { struct ar5416_eeprom_def *eep = &ah->eeprom.def; struct ath_common *common = ath9k_hw_common(ah); - u16 *eepdata, temp, magic, magic2; + u16 *eepdata, temp, magic; u32 sum = 0, el; bool need_swap = false; int i, addr, size; @@ -272,27 +272,16 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) return false; } - if (!ath9k_hw_use_flash(ah)) { - ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - size = sizeof(struct ar5416_eeprom_def); - need_swap = true; - eepdata = (u16 *) (&ah->eeprom); + if (swab16(magic) == AR5416_EEPROM_MAGIC && + !(ah->ah_flags & AH_NO_EEP_SWAP)) { + size = sizeof(struct ar5416_eeprom_def); + need_swap = true; + eepdata = (u16 *) (&ah->eeprom); - for (addr = 0; addr < size / sizeof(u16); addr++) { - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - } - } else { - ath_err(common, - "Invalid EEPROM Magic. Endianness mismatch.\n"); - return -EINVAL; - } + for (addr = 0; addr < size / sizeof(u16); addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; } } diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index b1956bf..2fef7a4 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -25,7 +25,12 @@ static void ath_led_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev); - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, (brightness == LED_OFF)); + u32 val = (brightness == LED_OFF); + + if (sc->sc_ah->config.led_active_high) + val = !val; + + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val); } void ath_deinit_leds(struct ath_softc *sc) @@ -82,7 +87,7 @@ void ath_fill_led_pin(struct ath_softc *sc) ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); /* LED off, active low */ - ath9k_hw_set_gpio(ah, ah->led_pin, 1); + ath9k_hw_set_gpio(ah, ah->led_pin, (ah->config.led_active_high) ? 0 : 1); } #endif diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 09a5d72..9dde265 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -481,6 +481,7 @@ struct ath9k_htc_priv { unsigned long op_flags; struct ath9k_hw_cal_data caldata; + struct ath_spec_scan_priv spec_priv; spinlock_t beacon_lock; struct ath_beacon_config cur_beacon_conf; @@ -625,8 +626,12 @@ int ath9k_htc_resume(struct htc_target *htc_handle); #endif #ifdef CONFIG_ATH9K_HTC_DEBUGFS int ath9k_htc_init_debug(struct ath_hw *ah); +void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv); #else static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; }; +static inline void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv) +{ +} #endif /* CONFIG_ATH9K_HTC_DEBUGFS */ #endif /* HTC_H */ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 8b529e4..8cef1ed 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -490,6 +490,10 @@ void ath9k_htc_get_et_stats(struct ieee80211_hw *hw, WARN_ON(i != ATH9K_HTC_SSTATS_LEN); } +void ath9k_htc_deinit_debug(struct ath9k_htc_priv *priv) +{ + ath9k_cmn_spectral_deinit_debug(&priv->spec_priv); +} int ath9k_htc_init_debug(struct ath_hw *ah) { @@ -501,6 +505,8 @@ int ath9k_htc_init_debug(struct ath_hw *ah) if (!priv->debug.debugfs_phy) return -ENOMEM; + ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy); + debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, priv, &fops_tgt_int_stats); debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 4014c4b..e8fa944 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -53,6 +53,21 @@ static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { }; #endif +static void ath9k_htc_op_ps_wakeup(struct ath_common *common) +{ + ath9k_htc_ps_wakeup((struct ath9k_htc_priv *) common->priv); +} + +static void ath9k_htc_op_ps_restore(struct ath_common *common) +{ + ath9k_htc_ps_restore((struct ath9k_htc_priv *) common->priv); +} + +static struct ath_ps_ops ath9k_htc_ps_ops = { + .wakeup = ath9k_htc_op_ps_wakeup, + .restore = ath9k_htc_op_ps_restore, +}; + static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) { int time_left; @@ -87,6 +102,7 @@ static void ath9k_deinit_device(struct ath9k_htc_priv *priv) wiphy_rfkill_stop_polling(hw->wiphy); ath9k_deinit_leds(priv); + ath9k_htc_deinit_debug(priv); ieee80211_unregister_hw(hw); ath9k_rx_cleanup(priv); ath9k_tx_cleanup(priv); @@ -449,6 +465,14 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv) common->last_rssi = ATH_RSSI_DUMMY_MARKER; priv->ah->opmode = NL80211_IFTYPE_STATION; + + priv->spec_priv.ah = priv->ah; + priv->spec_priv.spec_config.enabled = 0; + priv->spec_priv.spec_config.short_repeat = false; + priv->spec_priv.spec_config.count = 8; + priv->spec_priv.spec_config.endless = false; + priv->spec_priv.spec_config.period = 0x12; + priv->spec_priv.spec_config.fft_period = 0x02; } static int ath9k_init_priv(struct ath9k_htc_priv *priv, @@ -478,6 +502,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, common = ath9k_hw_common(ah); common->ops = &ah->reg_ops; + common->ps_ops = &ath9k_htc_ps_ops; common->bus_ops = &ath9k_usb_bus_ops; common->ah = ah; common->hw = priv->hw; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 994fff1..92d5a6c 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -314,6 +314,10 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, mod_timer(&priv->tx.cleanup_timer, jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); + /* perform spectral scan if requested. */ + if (test_bit(ATH_OP_SCANNING, &common->op_flags) && + priv->spec_priv.spectral_mode == SPECTRAL_CHANSCAN) + ath9k_cmn_spectral_scan_trigger(common, &priv->spec_priv); err: ath9k_htc_ps_restore(priv); return ret; @@ -1443,7 +1447,7 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw, key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; if (key->cipher == WLAN_CIPHER_SUITE_TKIP) key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - if (priv->ah->sw_mgmt_crypto && + if (priv->ah->sw_mgmt_crypto_tx && key->cipher == WLAN_CIPHER_SUITE_CCMP) key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; ret = 0; @@ -1687,7 +1691,9 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, return ret; } -static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) +static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *mac_addr) { struct ath9k_htc_priv *priv = hw->priv; struct ath_common *common = ath9k_hw_common(priv->ah); @@ -1701,7 +1707,8 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); } -static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) +static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath9k_htc_priv *priv = hw->priv; struct ath_common *common = ath9k_hw_common(priv->ah); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index f0484b1..a0f58e2 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -946,7 +946,7 @@ static inline void convert_htc_flag(struct ath_rx_status *rx_stats, static void rx_status_htc_to_ath(struct ath_rx_status *rx_stats, struct ath_htc_rx_status *rxstatus) { - rx_stats->rs_datalen = rxstatus->rs_datalen; + rx_stats->rs_datalen = be16_to_cpu(rxstatus->rs_datalen); rx_stats->rs_status = rxstatus->rs_status; rx_stats->rs_phyerr = rxstatus->rs_phyerr; rx_stats->rs_rssi = rxstatus->rs_rssi; @@ -1012,6 +1012,20 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, * separately to avoid doing two lookups for a rate for each frame. */ hdr = (struct ieee80211_hdr *)skb->data; + + /* + * Process PHY errors and return so that the packet + * can be dropped. + */ + if (rx_stats.rs_status & ATH9K_RXERR_PHY) { + /* TODO: Not using DFS processing now. */ + if (ath_cmn_process_fft(&priv->spec_priv, hdr, + &rx_stats, rx_status->mactime)) { + /* TODO: Code to collect spectral scan statistics */ + } + goto rx_next; + } + if (!ath9k_cmn_rx_accept(common, hdr, rx_status, &rx_stats, &decrypt_error, priv->rxfilter)) goto rx_next; diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index 8e85efe..88769b6 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -41,10 +41,9 @@ static inline void ath9k_hw_set_desc_link(struct ath_hw *ah, void *ds, ath9k_hw_ops(ah)->set_desc_link(ds, link); } -static inline bool ath9k_hw_calibrate(struct ath_hw *ah, - struct ath9k_channel *chan, - u8 rxchainmask, - bool longcal) +static inline int ath9k_hw_calibrate(struct ath_hw *ah, + struct ath9k_channel *chan, + u8 rxchainmask, bool longcal) { return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal); } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 2ad6057..6d4b273 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/time.h> #include <linux/bitops.h> +#include <linux/etherdevice.h> #include <asm/unaligned.h> #include "hw.h" @@ -446,8 +447,16 @@ static int ath9k_hw_init_macaddr(struct ath_hw *ah) common->macaddr[2 * i] = eeval >> 8; common->macaddr[2 * i + 1] = eeval & 0xff; } - if (sum == 0 || sum == 0xffff * 3) - return -EADDRNOTAVAIL; + if (!is_valid_ether_addr(common->macaddr)) { + ath_err(common, + "eeprom contains invalid mac address: %pM\n", + common->macaddr); + + random_ether_addr(common->macaddr); + ath_err(common, + "random mac address will be used: %pM\n", + common->macaddr); + } return 0; } @@ -1576,16 +1585,22 @@ static void ath9k_hw_init_mfp(struct ath_hw *ah) * frames when constructing CCMP AAD. */ REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, 0xc7ff); - ah->sw_mgmt_crypto = false; + if (AR_SREV_9271(ah) || AR_DEVID_7010(ah)) + ah->sw_mgmt_crypto_tx = true; + else + ah->sw_mgmt_crypto_tx = false; + ah->sw_mgmt_crypto_rx = false; } else if (AR_SREV_9160_10_OR_LATER(ah)) { /* Disable hardware crypto for management frames */ REG_CLR_BIT(ah, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE); REG_SET_BIT(ah, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT); - ah->sw_mgmt_crypto = true; + ah->sw_mgmt_crypto_tx = true; + ah->sw_mgmt_crypto_rx = true; } else { - ah->sw_mgmt_crypto = true; + ah->sw_mgmt_crypto_tx = true; + ah->sw_mgmt_crypto_rx = true; } } @@ -1932,6 +1947,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REGWRITE_BUFFER_FLUSH(ah); + ath9k_hw_gen_timer_start_tsf2(ah); + ath9k_hw_init_desc(ah); if (ath9k_hw_btcoex_is_enabled(ah)) @@ -1940,8 +1957,10 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (ath9k_hw_mci_is_enabled(ah)) ar9003_mci_check_bt(ah); - ath9k_hw_loadnf(ah, chan); - ath9k_hw_start_nfcal(ah, true); + if (AR_SREV_9300_20_OR_LATER(ah)) { + ath9k_hw_loadnf(ah, chan); + ath9k_hw_start_nfcal(ah, true); + } if (AR_SREV_9300_20_OR_LATER(ah)) ar9003_hw_bb_watchdog_config(ah); @@ -2309,7 +2328,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); - unsigned int chip_chainmask; u16 eeval; u8 ant_div_ctl1, tx_chainmask, rx_chainmask; @@ -2329,31 +2347,40 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) } eeval = ah->eep_ops->get_eeprom(ah, EEP_OP_MODE); - if ((eeval & (AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A)) == 0) { - ath_err(common, - "no band has been marked as supported in EEPROM\n"); - return -EINVAL; + + if (eeval & AR5416_OPFLAGS_11A) { + if (ah->disable_5ghz) + ath_warn(common, "disabling 5GHz band\n"); + else + pCap->hw_caps |= ATH9K_HW_CAP_5GHZ; } - if (eeval & AR5416_OPFLAGS_11A) - pCap->hw_caps |= ATH9K_HW_CAP_5GHZ; + if (eeval & AR5416_OPFLAGS_11G) { + if (ah->disable_2ghz) + ath_warn(common, "disabling 2GHz band\n"); + else + pCap->hw_caps |= ATH9K_HW_CAP_2GHZ; + } - if (eeval & AR5416_OPFLAGS_11G) - pCap->hw_caps |= ATH9K_HW_CAP_2GHZ; + if ((pCap->hw_caps & (ATH9K_HW_CAP_2GHZ | ATH9K_HW_CAP_5GHZ)) == 0) { + ath_err(common, "both bands are disabled\n"); + return -EINVAL; + } if (AR_SREV_9485(ah) || AR_SREV_9285(ah) || AR_SREV_9330(ah) || AR_SREV_9565(ah)) - chip_chainmask = 1; - else if (AR_SREV_9462(ah)) - chip_chainmask = 3; + pCap->chip_chainmask = 1; else if (!AR_SREV_9280_20_OR_LATER(ah)) - chip_chainmask = 7; - else if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9340(ah)) - chip_chainmask = 3; + pCap->chip_chainmask = 7; + else if (!AR_SREV_9300_20_OR_LATER(ah) || + AR_SREV_9340(ah) || + AR_SREV_9462(ah) || + AR_SREV_9531(ah)) + pCap->chip_chainmask = 3; else - chip_chainmask = 7; + pCap->chip_chainmask = 7; pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); /* @@ -2371,8 +2398,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) /* Use rx_chainmask from EEPROM. */ pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); - pCap->tx_chainmask = fixup_chainmask(chip_chainmask, pCap->tx_chainmask); - pCap->rx_chainmask = fixup_chainmask(chip_chainmask, pCap->rx_chainmask); + pCap->tx_chainmask = fixup_chainmask(pCap->chip_chainmask, pCap->tx_chainmask); + pCap->rx_chainmask = fixup_chainmask(pCap->chip_chainmask, pCap->rx_chainmask); ah->txchainmask = pCap->tx_chainmask; ah->rxchainmask = pCap->rx_chainmask; @@ -2886,6 +2913,16 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_gettsf32); +void ath9k_hw_gen_timer_start_tsf2(struct ath_hw *ah) +{ + struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; + + if (timer_table->tsf2_enabled) { + REG_SET_BIT(ah, AR_DIRECT_CONNECT, AR_DC_AP_STA_EN); + REG_SET_BIT(ah, AR_RESET_TSF, AR_RESET_TSF2_ONCE); + } +} + struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, void (*trigger)(void *), void (*overflow)(void *), @@ -2896,7 +2933,11 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, struct ath_gen_timer *timer; if ((timer_index < AR_FIRST_NDP_TIMER) || - (timer_index >= ATH_MAX_GEN_TIMER)) + (timer_index >= ATH_MAX_GEN_TIMER)) + return NULL; + + if ((timer_index > AR_FIRST_NDP_TIMER) && + !AR_SREV_9300_20_OR_LATER(ah)) return NULL; timer = kzalloc(sizeof(struct ath_gen_timer), GFP_KERNEL); @@ -2910,6 +2951,11 @@ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, timer->overflow = overflow; timer->arg = arg; + if ((timer_index > AR_FIRST_NDP_TIMER) && !timer_table->tsf2_enabled) { + timer_table->tsf2_enabled = true; + ath9k_hw_gen_timer_start_tsf2(ah); + } + return timer; } EXPORT_SYMBOL(ath_gen_timer_alloc); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 975074f..4cf9e0a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -244,13 +244,20 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_2GHZ = BIT(11), ATH9K_HW_CAP_5GHZ = BIT(12), ATH9K_HW_CAP_APM = BIT(13), +#ifdef CONFIG_ATH9K_PCOEM ATH9K_HW_CAP_RTT = BIT(14), ATH9K_HW_CAP_MCI = BIT(15), - ATH9K_HW_CAP_DFS = BIT(16), - ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17), - ATH9K_HW_CAP_PAPRD = BIT(18), - ATH9K_HW_CAP_FCC_BAND_SWITCH = BIT(19), - ATH9K_HW_CAP_BT_ANT_DIV = BIT(20), + ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(16), + ATH9K_HW_CAP_BT_ANT_DIV = BIT(17), +#else + ATH9K_HW_CAP_RTT = 0, + ATH9K_HW_CAP_MCI = 0, + ATH9K_HW_WOW_DEVICE_CAPABLE = 0, + ATH9K_HW_CAP_BT_ANT_DIV = 0, +#endif + ATH9K_HW_CAP_DFS = BIT(18), + ATH9K_HW_CAP_PAPRD = BIT(19), + ATH9K_HW_CAP_FCC_BAND_SWITCH = BIT(20), }; /* @@ -269,6 +276,7 @@ struct ath9k_hw_capabilities { u16 rts_aggr_limit; u8 tx_chainmask; u8 rx_chainmask; + u8 chip_chainmask; u8 max_txchains; u8 max_rxchains; u8 num_gpio_pins; @@ -322,6 +330,7 @@ struct ath9k_ops_config { bool alt_mingainidx; bool no_pll_pwrsave; bool tx_gain_buffalo; + bool led_active_high; }; enum ath9k_int { @@ -517,6 +526,7 @@ struct ath_gen_timer { struct ath_gen_timer_table { struct ath_gen_timer *timers[ATH_MAX_GEN_TIMER]; u16 timer_mask; + bool tsf2_enabled; }; struct ath_hw_antcomb_conf { @@ -681,10 +691,8 @@ struct ath_hw_ops { bool power_off); void (*rx_enable)(struct ath_hw *ah); void (*set_desc_link)(void *ds, u32 link); - bool (*calibrate)(struct ath_hw *ah, - struct ath9k_channel *chan, - u8 rxchainmask, - bool longcal); + int (*calibrate)(struct ath_hw *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal); bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked, u32 *sync_cause_p); void (*set_txdesc)(struct ath_hw *ah, void *ds, @@ -726,6 +734,7 @@ enum ath_cal_list { #define AH_USE_EEPROM 0x1 #define AH_UNPLUGGED 0x2 /* The card has been physically removed. */ #define AH_FASTCC 0x4 +#define AH_NO_EEP_SWAP 0x8 /* Do not swap EEPROM data */ struct ath_hw { struct ath_ops reg_ops; @@ -747,7 +756,8 @@ struct ath_hw { } eeprom; const struct eeprom_ops *eep_ops; - bool sw_mgmt_crypto; + bool sw_mgmt_crypto_tx; + bool sw_mgmt_crypto_rx; bool is_pciexpress; bool aspm_enabled; bool is_monitoring; @@ -924,6 +934,8 @@ struct ath_hw { bool is_clk_25mhz; int (*get_mac_revision)(void); int (*external_reset)(void); + bool disable_2ghz; + bool disable_5ghz; const struct firmware *eeprom_blob; @@ -1027,6 +1039,7 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, u32 timer_next, u32 timer_period); +void ath9k_hw_gen_timer_start_tsf2(struct ath_hw *ah); void ath9k_hw_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer); void ath_gen_timer_free(struct ath_hw *ah, struct ath_gen_timer *timer); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 3bd0304..59d679c 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -88,6 +88,21 @@ static const struct ieee80211_tpt_blink ath9k_tpt_blink[] = { static void ath9k_deinit_softc(struct ath_softc *sc); +static void ath9k_op_ps_wakeup(struct ath_common *common) +{ + ath9k_ps_wakeup((struct ath_softc *) common->priv); +} + +static void ath9k_op_ps_restore(struct ath_common *common) +{ + ath9k_ps_restore((struct ath_softc *) common->priv); +} + +static struct ath_ps_ops ath9k_ps_ops = { + .wakeup = ath9k_op_ps_wakeup, + .restore = ath9k_op_ps_restore, +}; + /* * Read and write, they both share the same lock. We do this to serialize * reads and writes on Atheros 802.11n PCI devices only. This is required @@ -172,17 +187,20 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, ath_reg_notifier_apply(wiphy, request, reg); /* Set tx power */ - if (ah->curchan) { - sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power; - ath9k_ps_wakeup(sc); - ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); - sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; - /* synchronize DFS detector if regulatory domain changed */ - if (sc->dfs_detector != NULL) - sc->dfs_detector->set_dfs_domain(sc->dfs_detector, - request->dfs_region); - ath9k_ps_restore(sc); - } + if (!ah->curchan) + return; + + sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power; + ath9k_ps_wakeup(sc); + ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); + ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, + sc->cur_chan->txpower, + &sc->cur_chan->cur_txpower); + /* synchronize DFS detector if regulatory domain changed */ + if (sc->dfs_detector != NULL) + sc->dfs_detector->set_dfs_domain(sc->dfs_detector, + request->dfs_region); + ath9k_ps_restore(sc); } /* @@ -348,12 +366,13 @@ static void ath9k_init_misc(struct ath_softc *sc) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; - sc->spec_config.enabled = 0; - sc->spec_config.short_repeat = true; - sc->spec_config.count = 8; - sc->spec_config.endless = false; - sc->spec_config.period = 0xFF; - sc->spec_config.fft_period = 0xF; + sc->spec_priv.ah = sc->sc_ah; + sc->spec_priv.spec_config.enabled = 0; + sc->spec_priv.spec_config.short_repeat = true; + sc->spec_priv.spec_config.count = 8; + sc->spec_priv.spec_config.endless = false; + sc->spec_priv.spec_config.period = 0xFF; + sc->spec_priv.spec_config.fft_period = 0xF; } static void ath9k_init_pcoem_platform(struct ath_softc *sc) @@ -362,6 +381,9 @@ static void ath9k_init_pcoem_platform(struct ath_softc *sc) struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); + if (!IS_ENABLED(CONFIG_ATH9K_PCOEM)) + return; + if (common->bus_ops->ath_bus_type != ATH_PCI) return; @@ -419,6 +441,9 @@ static void ath9k_init_pcoem_platform(struct ath_softc *sc) ah->config.no_pll_pwrsave = true; ath_info(common, "Disable PLL PowerSave\n"); } + + if (sc->driver_data & ATH9K_PCI_LED_ACT_HI) + ah->config.led_active_high = true; } static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob, @@ -528,10 +553,15 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ah->is_clk_25mhz = pdata->is_clk_25mhz; ah->get_mac_revision = pdata->get_mac_revision; ah->external_reset = pdata->external_reset; + ah->disable_2ghz = pdata->disable_2ghz; + ah->disable_5ghz = pdata->disable_5ghz; + if (!pdata->endian_check) + ah->ah_flags |= AH_NO_EEP_SWAP; } common->ops = &ah->reg_ops; common->bus_ops = bus_ops; + common->ps_ops = &ath9k_ps_ops; common->ah = ah; common->hw = sc->hw; common->priv = sc; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 2343f56..b829263 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -371,9 +371,15 @@ void ath_ani_calibrate(unsigned long data) /* Perform calibration if necessary */ if (longcal || shortcal) { - common->ani.caldone = - ath9k_hw_calibrate(ah, ah->curchan, - ah->rxchainmask, longcal); + int ret = ath9k_hw_calibrate(ah, ah->curchan, ah->rxchainmask, + longcal); + if (ret < 0) { + common->ani.caldone = 0; + ath9k_queue_reset(sc, RESET_TYPE_CALIBRATION); + return; + } + + common->ani.caldone = ret; } ath_dbg(common, ANI, diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 4f18a6b..ebbbfc7 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -54,7 +54,8 @@ u8 ath9k_parse_mpdudensity(u8 mpdudensity) } } -static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq) +static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq, + bool sw_pending) { bool pending = false; @@ -65,6 +66,9 @@ static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq) goto out; } + if (!sw_pending) + goto out; + if (txq->mac80211_qnum >= 0) { struct list_head *list; @@ -229,8 +233,9 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath9k_calculate_summary_state(sc, sc->cur_chan); ath_startrecv(sc); - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->cur_chan->txpower, &sc->curtxpow); + ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, + sc->cur_chan->txpower, + &sc->cur_chan->cur_txpower); clear_bit(ATH_OP_HW_RESET, &common->op_flags); if (!sc->cur_chan->offchannel && start) { @@ -270,7 +275,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) return true; } -int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) +static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -281,6 +286,7 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) __ath_cancel_work(sc); tasklet_disable(&sc->intr_tq); + tasklet_disable(&sc->bcon_tasklet); spin_lock_bh(&sc->sc_pcu_lock); if (!sc->cur_chan->offchannel) { @@ -326,6 +332,7 @@ int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan) out: spin_unlock_bh(&sc->sc_pcu_lock); + tasklet_enable(&sc->bcon_tasklet); tasklet_enable(&sc->intr_tq); return r; @@ -539,11 +546,10 @@ irqreturn_t ath_isr(int irq, void *dev) sched = true; /* - * If a FATAL or RXORN interrupt is received, we have to reset the - * chip immediately. + * If a FATAL interrupt is received, we have to reset the chip + * immediately. */ - if ((status & ATH9K_INT_FATAL) || ((status & ATH9K_INT_RXORN) && - !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))) + if (status & ATH9K_INT_FATAL) goto chip_reset; if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) && @@ -598,17 +604,29 @@ chip_reset: #undef SCHED_INTR } -int ath_reset(struct ath_softc *sc) +/* + * This function is called when a HW reset cannot be deferred + * and has to be immediate. + */ +int ath_reset(struct ath_softc *sc, struct ath9k_channel *hchan) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); int r; + set_bit(ATH_OP_HW_RESET, &common->op_flags); + ath9k_ps_wakeup(sc); - r = ath_reset_internal(sc, NULL); + r = ath_reset_internal(sc, hchan); ath9k_ps_restore(sc); return r; } +/* + * When a HW reset can be deferred, it is added to the + * hw_reset_work workqueue, but we set ATH_OP_HW_RESET before + * queueing. + */ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -623,7 +641,9 @@ void ath_reset_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); - ath_reset(sc); + ath9k_ps_wakeup(sc); + ath_reset_internal(sc, NULL); + ath9k_ps_restore(sc); } /**********************/ @@ -707,7 +727,8 @@ static int ath9k_start(struct ieee80211_hw *hw) if (ah->led_pin >= 0) { ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(ah, ah->led_pin, 0); + ath9k_hw_set_gpio(ah, ah->led_pin, + (ah->config.led_active_high) ? 1 : 0); } /* @@ -849,7 +870,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) spin_lock_bh(&sc->sc_pcu_lock); if (ah->led_pin >= 0) { - ath9k_hw_set_gpio(ah, ah->led_pin, 1); + ath9k_hw_set_gpio(ah, ah->led_pin, + (ah->config.led_active_high) ? 0 : 1); ath9k_hw_cfg_gpio_input(ah, ah->led_pin); } @@ -1036,7 +1058,7 @@ static void ath9k_set_offchannel_state(struct ath_softc *sc) eth_zero_addr(common->curbssid); eth_broadcast_addr(common->bssidmask); - ether_addr_copy(common->macaddr, vif->addr); + memcpy(common->macaddr, vif->addr, ETH_ALEN); common->curaid = 0; ah->opmode = vif->type; ah->imask &= ~ATH9K_INT_SWBA; @@ -1077,7 +1099,7 @@ void ath9k_calculate_summary_state(struct ath_softc *sc, ath9k_calculate_iter_data(sc, ctx, &iter_data); if (iter_data.has_hw_macaddr) - ether_addr_copy(common->macaddr, iter_data.hw_macaddr); + memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN); memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); ath_hw_setbssidmask(common); @@ -1167,7 +1189,8 @@ static void ath9k_assign_hw_queues(struct ieee80211_hw *hw, for (i = 0; i < IEEE80211_NUM_ACS; i++) vif->hw_queue[i] = i; - if (vif->type == NL80211_IFTYPE_AP) + if (vif->type == NL80211_IFTYPE_AP || + vif->type == NL80211_IFTYPE_MESH_POINT) vif->cab_queue = hw->queues - 2; else vif->cab_queue = IEEE80211_INVAL_HW_QUEUE; @@ -1323,78 +1346,6 @@ static void ath9k_disable_ps(struct ath_softc *sc) ath_dbg(common, PS, "PowerSave disabled\n"); } -void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw) -{ - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - u32 rxfilter; - - if (config_enabled(CONFIG_ATH9K_TX99)) - return; - - if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { - ath_err(common, "spectrum analyzer not implemented on this hardware\n"); - return; - } - - ath9k_ps_wakeup(sc); - rxfilter = ath9k_hw_getrxfilter(ah); - ath9k_hw_setrxfilter(ah, rxfilter | - ATH9K_RX_FILTER_PHYRADAR | - ATH9K_RX_FILTER_PHYERR); - - /* TODO: usually this should not be neccesary, but for some reason - * (or in some mode?) the trigger must be called after the - * configuration, otherwise the register will have its values reset - * (on my ar9220 to value 0x01002310) - */ - ath9k_spectral_scan_config(hw, sc->spectral_mode); - ath9k_hw_ops(ah)->spectral_scan_trigger(ah); - ath9k_ps_restore(sc); -} - -int ath9k_spectral_scan_config(struct ieee80211_hw *hw, - enum spectral_mode spectral_mode) -{ - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - - if (!ath9k_hw_ops(ah)->spectral_scan_trigger) { - ath_err(common, "spectrum analyzer not implemented on this hardware\n"); - return -1; - } - - switch (spectral_mode) { - case SPECTRAL_DISABLED: - sc->spec_config.enabled = 0; - break; - case SPECTRAL_BACKGROUND: - /* send endless samples. - * TODO: is this really useful for "background"? - */ - sc->spec_config.endless = 1; - sc->spec_config.enabled = 1; - break; - case SPECTRAL_CHANSCAN: - case SPECTRAL_MANUAL: - sc->spec_config.endless = 0; - sc->spec_config.enabled = 1; - break; - default: - return -1; - } - - ath9k_ps_wakeup(sc); - ath9k_hw_ops(ah)->spectral_scan_config(ah, &sc->spec_config); - ath9k_ps_restore(sc); - - sc->spectral_mode = spectral_mode; - - return 0; -} - static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; @@ -1455,8 +1406,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_POWER) { ath_dbg(common, CONFIG, "Set power: %d\n", conf->power_level); sc->cur_chan->txpower = 2 * conf->power_level; - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->cur_chan->txpower, &sc->curtxpow); + ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, + sc->cur_chan->txpower, + &sc->cur_chan->cur_txpower); } mutex_unlock(&sc->mutex); @@ -1553,6 +1505,40 @@ static int ath9k_sta_remove(struct ieee80211_hw *hw, return 0; } +static int ath9k_sta_state(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + int ret = 0; + + if (old_state == IEEE80211_STA_AUTH && + new_state == IEEE80211_STA_ASSOC) { + ret = ath9k_sta_add(hw, vif, sta); + ath_dbg(common, CONFIG, + "Add station: %pM\n", sta->addr); + } else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTH) { + ret = ath9k_sta_remove(hw, vif, sta); + ath_dbg(common, CONFIG, + "Remove station: %pM\n", sta->addr); + } + + if (ath9k_is_chanctx_enabled()) { + if (vif->type == NL80211_IFTYPE_STATION) { + if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTHORIZED) + ath_chanctx_event(sc, vif, + ATH_CHANCTX_EVENT_AUTHORIZED); + } + } + + return ret; +} + static void ath9k_sta_set_tx_filter(struct ath_hw *ah, struct ath_node *an, bool set) @@ -1677,7 +1663,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw, key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; if (key->cipher == WLAN_CIPHER_SUITE_TKIP) key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - if (sc->sc_ah->sw_mgmt_crypto && + if (sc->sc_ah->sw_mgmt_crypto_tx && key->cipher == WLAN_CIPHER_SUITE_CCMP) key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; ret = 0; @@ -1737,17 +1723,11 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n", bss_conf->bssid, bss_conf->assoc); - ether_addr_copy(avp->bssid, bss_conf->bssid); + memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN); avp->aid = bss_conf->aid; avp->assoc = bss_conf->assoc; ath9k_calculate_summary_state(sc, avp->chanctx); - - if (ath9k_is_chanctx_enabled()) { - if (bss_conf->assoc) - ath_chanctx_event(sc, vif, - ATH_CHANCTX_EVENT_ASSOC); - } } if (changed & BSS_CHANGED_IBSS) { @@ -1843,6 +1823,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, u16 tid, u16 *ssn, u8 buf_size) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); bool flush = false; int ret = 0; @@ -1854,6 +1835,12 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_RX_STOP: break; case IEEE80211_AMPDU_TX_START: + if (ath9k_is_chanctx_enabled()) { + if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { + ret = -EBUSY; + break; + } + } ath9k_ps_wakeup(sc); ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (!ret) @@ -1967,7 +1954,8 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, mutex_unlock(&sc->mutex); } -static bool ath9k_has_tx_pending(struct ath_softc *sc) +static bool ath9k_has_tx_pending(struct ath_softc *sc, + bool sw_pending) { int i, npend = 0; @@ -1975,7 +1963,8 @@ static bool ath9k_has_tx_pending(struct ath_softc *sc) if (!ATH_TXQ_SETUP(sc, i)) continue; - npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]); + npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i], + sw_pending); if (npend) break; } @@ -1987,18 +1976,38 @@ static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop) { struct ath_softc *sc = hw->priv; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + if (ath9k_is_chanctx_enabled()) { + if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) + goto flush; + /* + * If MCC is active, extend the flush timeout + * and wait for the HW/SW queues to become + * empty. This needs to be done outside the + * sc->mutex lock to allow the channel scheduler + * to switch channel contexts. + * + * The vif queues have been stopped in mac80211, + * so there won't be any incoming frames. + */ + __ath9k_flush(hw, queues, drop, true, true); + return; + } +flush: mutex_lock(&sc->mutex); - __ath9k_flush(hw, queues, drop); + __ath9k_flush(hw, queues, drop, true, false); mutex_unlock(&sc->mutex); } -void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) +void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop, + bool sw_pending, bool timeout_override) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - int timeout = HZ / 5; /* 200 ms */ + int timeout; bool drain_txq; cancel_delayed_work_sync(&sc->tx_complete_work); @@ -2013,7 +2022,17 @@ void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) return; } - if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc), + spin_lock_bh(&sc->chan_lock); + if (timeout_override) + timeout = HZ / 5; + else + timeout = sc->cur_chan->flush_timeout; + spin_unlock_bh(&sc->chan_lock); + + ath_dbg(common, CHAN_CTX, + "Flush timeout: %d\n", jiffies_to_msecs(timeout)); + + if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc, sw_pending), timeout) > 0) drop = false; @@ -2024,7 +2043,7 @@ void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop) spin_unlock_bh(&sc->sc_pcu_lock); if (!drain_txq) - ath_reset(sc); + ath_reset(sc, NULL); ath9k_ps_restore(sc); } @@ -2036,7 +2055,7 @@ static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - return ath9k_has_tx_pending(sc); + return ath9k_has_tx_pending(sc, true); } static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) @@ -2167,14 +2186,17 @@ static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) return 0; } -static void ath9k_sw_scan_start(struct ieee80211_hw *hw) +static void ath9k_sw_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *mac_addr) { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); set_bit(ATH_OP_SCANNING, &common->op_flags); } -static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) +static void ath9k_sw_scan_complete(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -2183,6 +2205,28 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw) #ifdef CONFIG_ATH9K_CHANNEL_CONTEXT +static void ath9k_cancel_pending_offchannel(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + if (sc->offchannel.roc_vif) { + ath_dbg(common, CHAN_CTX, + "%s: Aborting RoC\n", __func__); + + del_timer_sync(&sc->offchannel.timer); + if (sc->offchannel.state >= ATH_OFFCHANNEL_ROC_START) + ath_roc_complete(sc, true); + } + + if (test_bit(ATH_OP_SCANNING, &common->op_flags)) { + ath_dbg(common, CHAN_CTX, + "%s: Aborting HW scan\n", __func__); + + del_timer_sync(&sc->offchannel.timer); + ath_scan_complete(sc, true); + } +} + static int ath9k_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *hw_req) { @@ -2313,7 +2357,6 @@ static int ath9k_add_chanctx(struct ieee80211_hw *hw, conf->def.chan->center_freq); ath_chanctx_set_channel(sc, ctx, &conf->def); - ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ASSIGN); mutex_unlock(&sc->mutex); return 0; @@ -2370,6 +2413,8 @@ static int ath9k_assign_vif_chanctx(struct ieee80211_hw *hw, struct ath_chanctx *ctx = ath_chanctx_get(conf); int i; + ath9k_cancel_pending_offchannel(sc); + mutex_lock(&sc->mutex); ath_dbg(common, CHAN_CTX, @@ -2399,6 +2444,8 @@ static void ath9k_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ath_chanctx *ctx = ath_chanctx_get(conf); int ac; + ath9k_cancel_pending_offchannel(sc); + mutex_lock(&sc->mutex); ath_dbg(common, CHAN_CTX, @@ -2422,7 +2469,11 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_vif *avp = (struct ath_vif *) vif->drv_priv; + struct ath_beacon_config *cur_conf; + struct ath_chanctx *go_ctx; + unsigned long timeout; bool changed = false; + u32 beacon_int; if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) return; @@ -2433,19 +2484,57 @@ static void ath9k_mgd_prepare_tx(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); spin_lock_bh(&sc->chan_lock); - if (sc->next_chan || (sc->cur_chan != avp->chanctx)) { - sc->next_chan = avp->chanctx; + if (sc->next_chan || (sc->cur_chan != avp->chanctx)) changed = true; + spin_unlock_bh(&sc->chan_lock); + + if (!changed) + goto out; + + ath9k_cancel_pending_offchannel(sc); + + go_ctx = ath_is_go_chanctx_present(sc); + + if (go_ctx) { + /* + * Wait till the GO interface gets a chance + * to send out an NoA. + */ + spin_lock_bh(&sc->chan_lock); + sc->sched.mgd_prepare_tx = true; + cur_conf = &go_ctx->beacon; + beacon_int = TU_TO_USEC(cur_conf->beacon_interval); + spin_unlock_bh(&sc->chan_lock); + + timeout = usecs_to_jiffies(beacon_int * 2); + init_completion(&sc->go_beacon); + + mutex_unlock(&sc->mutex); + + if (wait_for_completion_timeout(&sc->go_beacon, + timeout) == 0) { + ath_dbg(common, CHAN_CTX, + "Failed to send new NoA\n"); + + spin_lock_bh(&sc->chan_lock); + sc->sched.mgd_prepare_tx = false; + spin_unlock_bh(&sc->chan_lock); + } + + mutex_lock(&sc->mutex); } + ath_dbg(common, CHAN_CTX, - "%s: Set chanctx state to FORCE_ACTIVE, changed: %d\n", - __func__, changed); + "%s: Set chanctx state to FORCE_ACTIVE for vif: %pM\n", + __func__, vif->addr); + + spin_lock_bh(&sc->chan_lock); + sc->next_chan = avp->chanctx; sc->sched.state = ATH_CHANCTX_STATE_FORCE_ACTIVE; spin_unlock_bh(&sc->chan_lock); - if (changed) - ath_chanctx_set_next(sc, true); - + ath_chanctx_set_next(sc, true); +out: mutex_unlock(&sc->mutex); } @@ -2468,6 +2557,24 @@ void ath9k_fill_chanctx_ops(void) #endif +static int ath9k_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + int *dbm) +{ + struct ath_softc *sc = hw->priv; + struct ath_vif *avp = (void *)vif->drv_priv; + + mutex_lock(&sc->mutex); + if (avp->chanctx) + *dbm = avp->chanctx->cur_txpower; + else + *dbm = sc->cur_chan->cur_txpower; + mutex_unlock(&sc->mutex); + + *dbm /= 2; + + return 0; +} + struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -2477,8 +2584,7 @@ struct ieee80211_ops ath9k_ops = { .remove_interface = ath9k_remove_interface, .config = ath9k_config, .configure_filter = ath9k_configure_filter, - .sta_add = ath9k_sta_add, - .sta_remove = ath9k_sta_remove, + .sta_state = ath9k_sta_state, .sta_notify = ath9k_sta_notify, .conf_tx = ath9k_conf_tx, .bss_info_changed = ath9k_bss_info_changed, @@ -2515,4 +2621,5 @@ struct ieee80211_ops ath9k_ops = { #endif .sw_scan_start = ath9k_sw_scan_start, .sw_scan_complete = ath9k_sw_scan_complete, + .get_txpower = ath9k_get_txpower, }; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index c018dea..f009b5b 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -30,6 +30,7 @@ static const struct pci_device_id ath_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ +#ifdef CONFIG_ATH9K_PCOEM { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x002A, PCI_VENDOR_ID_AZWAVE, @@ -82,6 +83,7 @@ static const struct pci_device_id ath_pci_id_table[] = { PCI_VENDOR_ID_AZWAVE, 0x2C37), .driver_data = ATH9K_PCI_BT_ANT_DIV }, +#endif { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x002C) }, /* PCI-E 802.11n bonded out */ @@ -102,6 +104,7 @@ static const struct pci_device_id ath_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */ +#ifdef CONFIG_ATH9K_PCOEM /* PCI-E CUS198 */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0032, @@ -294,10 +297,12 @@ static const struct pci_device_id ath_pci_id_table[] = { PCI_VENDOR_ID_ASUSTEK, 0x850D), .driver_data = ATH9K_PCI_NO_PLL_PWRSAVE }, +#endif { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */ { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E AR9580 */ +#ifdef CONFIG_ATH9K_PCOEM /* PCI-E CUS217 */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0034, @@ -652,11 +657,14 @@ static const struct pci_device_id ath_pci_id_table[] = { 0x0036, PCI_VENDOR_ID_DELL, 0x020E), - .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + .driver_data = ATH9K_PCI_AR9565_2ANT | + ATH9K_PCI_BT_ANT_DIV | + ATH9K_PCI_LED_ACT_HI}, /* PCI-E AR9565 (WB335) */ { PCI_VDEVICE(ATHEROS, 0x0036), .driver_data = ATH9K_PCI_BT_ANT_DIV }, +#endif { 0 } }; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6914e21..7395afb 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -870,7 +870,7 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, */ if (rx_stats->rs_status & ATH9K_RXERR_PHY) { ath9k_dfs_process_phyerr(sc, hdr, rx_stats, rx_status->mactime); - if (ath_process_fft(sc, hdr, rx_stats, rx_status->mactime)) + if (ath_cmn_process_fft(&sc->spec_priv, hdr, rx_stats, rx_status->mactime)) RX_STAT_INC(rx_spectral); return -EINVAL; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 2a938f4..ced36b4 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -892,10 +892,21 @@ (AR_SREV_9330((_ah)) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9330_12)) +#ifdef CONFIG_ATH9K_PCOEM +#define AR_SREV_9462(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462)) #define AR_SREV_9485(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485)) +#define AR_SREV_9565(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565)) +#else +#define AR_SREV_9462(_ah) 0 +#define AR_SREV_9485(_ah) 0 +#define AR_SREV_9565(_ah) 0 +#endif + #define AR_SREV_9485_11_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485) && \ + (AR_SREV_9485(_ah) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9485_11)) #define AR_SREV_9485_OR_LATER(_ah) \ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485)) @@ -915,34 +926,30 @@ (AR_SREV_9285_12_OR_LATER(_ah) && \ ((REG_READ(_ah, AR_AN_SYNTH9) & 0x7) == 0x1)) -#define AR_SREV_9462(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462)) #define AR_SREV_9462_20(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + (AR_SREV_9462(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20)) #define AR_SREV_9462_21(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + (AR_SREV_9462(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_21)) #define AR_SREV_9462_20_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + (AR_SREV_9462(_ah) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20)) #define AR_SREV_9462_21_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + (AR_SREV_9462(_ah) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_21)) -#define AR_SREV_9565(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565)) #define AR_SREV_9565_10(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ + (AR_SREV_9565(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_10)) #define AR_SREV_9565_101(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ + (AR_SREV_9565(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_101)) #define AR_SREV_9565_11(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ + (AR_SREV_9565(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9565_11)) #define AR_SREV_9565_11_OR_LATER(_ah) \ - (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565) && \ + (AR_SREV_9565(_ah) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9565_11)) #define AR_SREV_9550(_ah) \ @@ -1598,6 +1605,7 @@ enum { #define AR_RESET_TSF 0x8020 #define AR_RESET_TSF_ONCE 0x01000000 +#define AR_RESET_TSF2_ONCE 0x02000000 #define AR_MAX_CFP_DUR 0x8038 #define AR_CFP_VAL 0x0000FFFF @@ -1959,6 +1967,8 @@ enum { #define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000 #define AR_MAC_PCU_GEN_TIMER_TSF_SEL 0x83d8 +#define AR_DIRECT_CONNECT 0x83a0 +#define AR_DC_AP_STA_EN 0x00000001 #define AR_AES_MUTE_MASK0 0x805c #define AR_AES_MUTE_MASK0_FC 0x0000FFFF diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index 40ab65e..ac4781f 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -99,7 +99,7 @@ static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc) static void ath9k_tx99_deinit(struct ath_softc *sc) { - ath_reset(sc); + ath_reset(sc, NULL); ath9k_ps_wakeup(sc); ath9k_tx99_stop(sc); @@ -127,7 +127,7 @@ static int ath9k_tx99_init(struct ath_softc *sc) memset(&txctl, 0, sizeof(txctl)); txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; - ath_reset(sc); + ath_reset(sc, NULL); ath9k_ps_wakeup(sc); diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c index b80b213..dca6df1 100644 --- a/drivers/net/wireless/ath/carl9170/phy.c +++ b/drivers/net/wireless/ath/carl9170/phy.c @@ -994,7 +994,7 @@ static int carl9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz, refsel0 = 0; refsel1 = 1; } - chansel = byte_rev_table[chansel]; + chansel = bitrev8(chansel); } else { if (freq == 2484) { chansel = 10 + (freq - 2274) / 5; @@ -1002,7 +1002,7 @@ static int carl9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz, } else chansel = 16 + (freq - 2272) / 5; chansel *= 4; - chansel = byte_rev_table[chansel]; + chansel = bitrev8(chansel); } d1 = chansel; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index b71d2b3..267c35d 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -494,7 +494,9 @@ out: return ret; } -static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw) +static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *mac_addr) { struct wcn36xx *wcn = hw->priv; @@ -502,7 +504,8 @@ static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw) wcn36xx_smd_start_scan(wcn); } -static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw) +static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct wcn36xx *wcn = hw->priv; diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index d9f4b30..0fc0b9f 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -792,12 +792,13 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, } static int wil_cfg80211_del_station(struct wiphy *wiphy, - struct net_device *dev, const u8 *mac) + struct net_device *dev, + struct station_del_parameters *params) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); mutex_lock(&wil->mutex); - wil6210_disconnect(wil, mac); + wil6210_disconnect(wil, params->mac, false); mutex_unlock(&wil->mutex); return 0; diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 6500caf..6212983 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -38,6 +38,35 @@ static unsigned int itr_trsh = WIL6210_ITR_TRSH_DEFAULT; module_param(itr_trsh, uint, S_IRUGO); MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs."); +/* We allow allocation of more than 1 page buffers to support large packets. + * It is suboptimal behavior performance wise in case MTU above page size. + */ +unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - ETH_HLEN; +static int mtu_max_set(const char *val, const struct kernel_param *kp) +{ + int ret; + + /* sets mtu_max directly. no need to restore it in case of + * illegal value since we assume this will fail insmod + */ + ret = param_set_uint(val, kp); + if (ret) + return ret; + + if (mtu_max < 68 || mtu_max > IEEE80211_MAX_DATA_LEN_DMG) + ret = -EINVAL; + + return ret; +} + +static struct kernel_param_ops mtu_max_ops = { + .set = mtu_max_set, + .get = param_get_uint, +}; + +module_param_cb(mtu_max, &mtu_max_ops, &mtu_max, S_IRUGO); +MODULE_PARM_DESC(mtu_max, " Max MTU value."); + #define RST_DELAY (20) /* msec, for loop in @wil_target_reset */ #define RST_COUNT (1 + 1000/RST_DELAY) /* round up to be above 1 sec total */ @@ -74,7 +103,8 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, __raw_writel(*s++, d++); } -static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) +static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, + bool from_event) { uint i; struct net_device *ndev = wil_to_ndev(wil); @@ -86,7 +116,10 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) sta->data_port_open = false; if (sta->status != wil_sta_unused) { - wmi_disconnect_sta(wil, sta->addr, WLAN_REASON_DEAUTH_LEAVING); + if (!from_event) + wmi_disconnect_sta(wil, sta->addr, + WLAN_REASON_DEAUTH_LEAVING); + switch (wdev->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: @@ -118,7 +151,8 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid) memset(&sta->stats, 0, sizeof(sta->stats)); } -static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) +static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, + bool from_event) { int cid = -ENOENT; struct net_device *ndev = wil_to_ndev(wil); @@ -133,10 +167,10 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) } if (cid >= 0) /* disconnect 1 peer */ - wil_disconnect_cid(wil, cid); + wil_disconnect_cid(wil, cid, from_event); else /* disconnect all */ for (cid = 0; cid < WIL6210_MAX_CID; cid++) - wil_disconnect_cid(wil, cid); + wil_disconnect_cid(wil, cid, from_event); /* link state */ switch (wdev->iftype) { @@ -166,7 +200,7 @@ static void wil_disconnect_worker(struct work_struct *work) struct wil6210_priv, disconnect_worker); mutex_lock(&wil->mutex); - _wil6210_disconnect(wil, NULL); + _wil6210_disconnect(wil, NULL, false); mutex_unlock(&wil->mutex); } @@ -223,6 +257,11 @@ static void wil_fw_error_worker(struct work_struct *work) wil_dbg_misc(wil, "fw error worker\n"); + if (!netif_running(wil_to_ndev(wil))) { + wil_info(wil, "No recovery - interface is down\n"); + return; + } + /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO * passed since last recovery attempt */ @@ -257,9 +296,12 @@ static void wil_fw_error_worker(struct work_struct *work) break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: + wil_info(wil, "No recovery for AP-like interface\n"); /* recovery in these modes is done by upper layers */ break; default: + wil_err(wil, "No recovery - unknown interface type %d\n", + wdev->iftype); break; } mutex_unlock(&wil->mutex); @@ -346,12 +388,22 @@ int wil_priv_init(struct wil6210_priv *wil) return 0; } -void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid) +/** + * wil6210_disconnect - disconnect one connection + * @wil: driver context + * @bssid: peer to disconnect, NULL to disconnect all + * @from_event: whether is invoked from FW event handler + * + * Disconnect and release associated resources. If invoked not from the + * FW event handler, issue WMI command(s) to trigger MAC disconnect. + */ +void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, + bool from_event) { wil_dbg_misc(wil, "%s()\n", __func__); del_timer_sync(&wil->connect_timer); - _wil6210_disconnect(wil, bssid); + _wil6210_disconnect(wil, bssid, from_event); } void wil_priv_deinit(struct wil6210_priv *wil) @@ -363,7 +415,7 @@ void wil_priv_deinit(struct wil6210_priv *wil) cancel_work_sync(&wil->disconnect_worker); cancel_work_sync(&wil->fw_error_worker); mutex_lock(&wil->mutex); - wil6210_disconnect(wil, NULL); + wil6210_disconnect(wil, NULL, false); mutex_unlock(&wil->mutex); wmi_event_flush(wil); destroy_workqueue(wil->wmi_wq_conn); @@ -395,7 +447,7 @@ static inline void wil_release_cpu(struct wil6210_priv *wil) static int wil_target_reset(struct wil6210_priv *wil) { int delay = 0; - u32 hw_state; + u32 x; u32 rev_id; bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW); @@ -410,9 +462,22 @@ static int wil_target_reset(struct wil6210_priv *wil) S(RGF_USER_CLKS_CTL_SW_RST_MASK_0, BIT_CAR_PERST_RST); wil_halt_cpu(wil); - C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); /* 40 MHz */ if (is_sparrow) { + S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN); + /* XTAL stabilization should take about 3ms */ + usleep_range(5000, 7000); + x = R(RGF_CAF_PLL_LOCK_STATUS); + if (!(x & BIT_CAF_OSC_DIG_XTAL_STABLE)) { + wil_err(wil, "Xtal stabilization timeout\n" + "RGF_CAF_PLL_LOCK_STATUS = 0x%08x\n", x); + return -ETIME; + } + /* switch 10k to XTAL*/ + C(RGF_USER_SPARROW_M_4, BIT_SPARROW_M_4_SEL_SLEEP_OR_REF); + /* 40 MHz */ + C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_CAR_AHB_SW_SEL); + W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x3ff81f); W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0xf); } @@ -453,13 +518,13 @@ static int wil_target_reset(struct wil6210_priv *wil) /* wait until device ready. typical time is 200..250 msec */ do { msleep(RST_DELAY); - hw_state = R(RGF_USER_HW_MACHINE_STATE); + x = R(RGF_USER_HW_MACHINE_STATE); if (delay++ > RST_COUNT) { wil_err(wil, "Reset not completed, hw_state 0x%08x\n", - hw_state); + x); return -ETIME; } - } while (hw_state != HW_MACHINE_BOOT_DONE); + } while (x != HW_MACHINE_BOOT_DONE); /* TODO: Erez check rev_id != 1 */ if (!is_sparrow && (rev_id != 1)) @@ -535,7 +600,7 @@ int wil_reset(struct wil6210_priv *wil) WARN_ON(test_bit(wil_status_napi_en, &wil->status)); cancel_work_sync(&wil->disconnect_worker); - wil6210_disconnect(wil, NULL); + wil6210_disconnect(wil, NULL, false); wil->status = 0; /* prevent NAPI from being scheduled */ diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 2399651..e81703c 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -41,7 +41,7 @@ static int wil_change_mtu(struct net_device *ndev, int new_mtu) { struct wil6210_priv *wil = ndev_to_wil(ndev); - if (new_mtu < 68 || new_mtu > (TX_BUF_LEN - ETH_HLEN)) { + if (new_mtu < 68 || new_mtu > mtu_max) { wil_err(wil, "invalid MTU %d\n", new_mtu); return -EINVAL; } diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 2936ef0..c680906 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -206,7 +206,7 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, u32 i, int headroom) { struct device *dev = wil_to_dev(wil); - unsigned int sz = RX_BUF_LEN; + unsigned int sz = mtu_max + ETH_HLEN; struct vring_rx_desc dd, *d = ⅆ volatile struct vring_rx_desc *_d = &vring->va[i].rx; dma_addr_t pa; @@ -385,7 +385,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, struct vring_rx_desc *d; struct sk_buff *skb; dma_addr_t pa; - unsigned int sz = RX_BUF_LEN; + unsigned int sz = mtu_max + ETH_HLEN; u16 dmalen; u8 ftype; u8 ds_bits; @@ -646,7 +646,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, .action = cpu_to_le32(WMI_VRING_CMD_ADD), .vring_cfg = { .tx_sw_ring = { - .max_mpdu_size = cpu_to_le16(TX_BUF_LEN), + .max_mpdu_size = + cpu_to_le16(mtu_max + ETH_HLEN), .ring_size = cpu_to_le16(size), }, .ringid = id, diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index de04671..630aeb5 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -21,8 +21,8 @@ #define BUF_HW_OWNED (0) /* size of max. Tx/Rx buffers, as supported by FW */ -#define RX_BUF_LEN (2242) -#define TX_BUF_LEN (2242) +#define TXRX_BUF_LEN_DEFAULT (2242) + /* how many bytes to reserve for rtap header? */ #define WIL6210_RTAP_SIZE (128) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index ce6488e..95d3a06 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -24,6 +24,7 @@ #include "wil_platform.h" extern bool no_fw_recovery; +extern unsigned int mtu_max; #define WIL_NAME "wil6210" #define WIL_FW_NAME "wil6210.fw" @@ -117,6 +118,8 @@ struct RGF_ICR { #define BIT_USER_USER_ICR_SW_INT_2 BIT(18) #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0 (0x880c18) #define RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1 (0x880c2c) +#define RGF_USER_SPARROW_M_4 (0x880c50) /* Sparrow */ + #define BIT_SPARROW_M_4_SEL_SLEEP_OR_REF BIT(2) #define RGF_DMA_EP_TX_ICR (0x881bb4) /* struct RGF_ICR */ #define BIT_DMA_EP_TX_ICR_TX_DONE BIT(0) @@ -152,6 +155,10 @@ struct RGF_ICR { #define RGF_MAC_MTRL_COUNTER_0 (0x886aa8) #define RGF_CAF_ICR (0x88946c) /* struct RGF_ICR */ +#define RGF_CAF_OSC_CONTROL (0x88afa4) + #define BIT_CAF_OSC_XTAL_EN BIT(0) +#define RGF_CAF_PLL_LOCK_STATUS (0x88afec) + #define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0) /* popular locations */ #define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD) @@ -463,8 +470,11 @@ struct wil6210_priv { #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr)) #define wil_to_pcie_dev(i) (&i->pdev->dev) +__printf(2, 3) void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...); +__printf(2, 3) void wil_err(struct wil6210_priv *wil, const char *fmt, ...); +__printf(2, 3) void wil_info(struct wil6210_priv *wil, const char *fmt, ...); #define wil_dbg(wil, fmt, arg...) do { \ netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \ @@ -575,7 +585,8 @@ void wil_wdev_free(struct wil6210_priv *wil); int wmi_set_mac_address(struct wil6210_priv *wil, void *addr); int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan); int wmi_pcp_stop(struct wil6210_priv *wil); -void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid); +void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, + bool from_event); int wil_rx_init(struct wil6210_priv *wil); void wil_rx_fini(struct wil6210_priv *wil); diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 4311df9..bb1e066 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -486,7 +486,7 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, wil->sinfo_gen++; mutex_lock(&wil->mutex); - wil6210_disconnect(wil, evt->bssid); + wil6210_disconnect(wil, evt->bssid, true); mutex_unlock(&wil->mutex); } @@ -1025,7 +1025,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) struct wmi_cfg_rx_chain_cmd cmd = { .action = WMI_RX_CHAIN_ADD, .rx_sw_ring = { - .max_mpdu_size = cpu_to_le16(RX_BUF_LEN), + .max_mpdu_size = cpu_to_le16(mtu_max + ETH_HLEN), .ring_mem_base = cpu_to_le64(vring->pa), .ring_size = cpu_to_le16(vring->size), }, |