Loading drivers/net/wireless/ath/ath10k/ce.c +8 −27 Original line number Diff line number Diff line Loading @@ -283,7 +283,7 @@ static int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, if (unlikely(CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) <= 0)) { ret = -EIO; ret = -ENOSR; goto exit; } Loading Loading @@ -338,38 +338,19 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, return ret; } int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, unsigned int transfer_id, u32 paddr, unsigned int nbytes, u32 flags) int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) { struct ath10k_ce_ring *src_ring = ce_state->src_ring; struct ath10k *ar = ce_state->ar; struct ath10k *ar = pipe->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); unsigned int nentries_mask = src_ring->nentries_mask; unsigned int sw_index; unsigned int write_index; int delta, ret = -ENOMEM; int delta; spin_lock_bh(&ar_pci->ce_lock); sw_index = src_ring->sw_index; write_index = src_ring->write_index; delta = CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); if (delta >= 1) { ret = ath10k_ce_send_nolock(ce_state, per_transfer_context, paddr, nbytes, transfer_id, flags); if (ret) ath10k_warn("CE send failed: %d\n", ret); } delta = CE_RING_DELTA(pipe->src_ring->nentries_mask, pipe->src_ring->write_index, pipe->src_ring->sw_index - 1); spin_unlock_bh(&ar_pci->ce_lock); return ret; return delta; } int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state, Loading drivers/net/wireless/ath/ath10k/ce.h +1 −15 Original line number Diff line number Diff line Loading @@ -156,21 +156,7 @@ void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, void (*send_cb)(struct ath10k_ce_pipe *), int disable_interrupts); /* * Queue a "sendlist" of buffers to be sent using gather to a single * anonymous destination buffer * ce - which copy engine to use * sendlist - list of simple buffers to send using gather * transfer_id - arbitrary ID; reflected to destination * Returns 0 on success; otherwise an error status. * * Implemenation note: Pushes multiple buffers with Gather to Source ring. */ int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, unsigned int transfer_id, u32 paddr, unsigned int nbytes, u32 flags); int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe); /*==================Recv=======================*/ Loading drivers/net/wireless/ath/ath10k/core.c +238 −47 Original line number Diff line number Diff line Loading @@ -59,27 +59,6 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) wake_up(&ar->event_queue); } static int ath10k_check_fw_version(struct ath10k *ar) { char version[32]; if (ar->fw_version_major >= SUPPORTED_FW_MAJOR && ar->fw_version_minor >= SUPPORTED_FW_MINOR && ar->fw_version_release >= SUPPORTED_FW_RELEASE && ar->fw_version_build >= SUPPORTED_FW_BUILD) return 0; snprintf(version, sizeof(version), "%u.%u.%u.%u", SUPPORTED_FW_MAJOR, SUPPORTED_FW_MINOR, SUPPORTED_FW_RELEASE, SUPPORTED_FW_BUILD); ath10k_warn("WARNING: Firmware version %s is not officially supported.\n", ar->hw->wiphy->fw_version); ath10k_warn("Please upgrade to version %s (or newer)\n", version); return 0; } static int ath10k_init_connect_htc(struct ath10k *ar) { int status; Loading Loading @@ -189,8 +168,7 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, return fw; } static int ath10k_push_board_ext_data(struct ath10k *ar, const struct firmware *fw) static int ath10k_push_board_ext_data(struct ath10k *ar) { u32 board_data_size = QCA988X_BOARD_DATA_SZ; u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ; Loading @@ -210,14 +188,14 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, if (board_ext_data_addr == 0) return 0; if (fw->size != (board_data_size + board_ext_data_size)) { if (ar->board_len != (board_data_size + board_ext_data_size)) { ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n", fw->size, board_data_size, board_ext_data_size); ar->board_len, board_data_size, board_ext_data_size); return -EINVAL; } ret = ath10k_bmi_write_memory(ar, board_ext_data_addr, fw->data + board_data_size, ar->board_data + board_data_size, board_ext_data_size); if (ret) { ath10k_err("could not write board ext data (%d)\n", ret); Loading @@ -236,12 +214,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, static int ath10k_download_board_data(struct ath10k *ar) { const struct firmware *fw = ar->board_data; u32 board_data_size = QCA988X_BOARD_DATA_SZ; u32 address; int ret; ret = ath10k_push_board_ext_data(ar, fw); ret = ath10k_push_board_ext_data(ar); if (ret) { ath10k_err("could not push board ext data (%d)\n", ret); goto exit; Loading @@ -253,8 +230,9 @@ static int ath10k_download_board_data(struct ath10k *ar) goto exit; } ret = ath10k_bmi_write_memory(ar, address, fw->data, min_t(u32, board_data_size, fw->size)); ret = ath10k_bmi_write_memory(ar, address, ar->board_data, min_t(u32, board_data_size, ar->board_len)); if (ret) { ath10k_err("could not write board data (%d)\n", ret); goto exit; Loading @@ -272,17 +250,16 @@ static int ath10k_download_board_data(struct ath10k *ar) static int ath10k_download_and_run_otp(struct ath10k *ar) { const struct firmware *fw = ar->otp; u32 address = ar->hw_params.patch_load_addr; u32 exec_param; int ret; /* OTP is optional */ if (!ar->otp) if (!ar->otp_data || !ar->otp_len) return 0; ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); if (ret) { ath10k_err("could not write otp (%d)\n", ret); goto exit; Loading @@ -301,13 +278,13 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) static int ath10k_download_fw(struct ath10k *ar) { const struct firmware *fw = ar->firmware; u32 address; int ret; address = ar->hw_params.patch_load_addr; ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data, ar->firmware_len); if (ret) { ath10k_err("could not write fw (%d)\n", ret); goto exit; Loading @@ -319,8 +296,8 @@ static int ath10k_download_fw(struct ath10k *ar) static void ath10k_core_free_firmware_files(struct ath10k *ar) { if (ar->board_data && !IS_ERR(ar->board_data)) release_firmware(ar->board_data); if (ar->board && !IS_ERR(ar->board)) release_firmware(ar->board); if (ar->otp && !IS_ERR(ar->otp)) release_firmware(ar->otp); Loading @@ -328,12 +305,20 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) if (ar->firmware && !IS_ERR(ar->firmware)) release_firmware(ar->firmware); ar->board = NULL; ar->board_data = NULL; ar->board_len = 0; ar->otp = NULL; ar->otp_data = NULL; ar->otp_len = 0; ar->firmware = NULL; ar->firmware_data = NULL; ar->firmware_len = 0; } static int ath10k_core_fetch_firmware_files(struct ath10k *ar) static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar) { int ret = 0; Loading @@ -347,15 +332,18 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) return -EINVAL; } ar->board_data = ath10k_fetch_fw_file(ar, ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.board); if (IS_ERR(ar->board_data)) { ret = PTR_ERR(ar->board_data); if (IS_ERR(ar->board)) { ret = PTR_ERR(ar->board); ath10k_err("could not fetch board data (%d)\n", ret); goto err; } ar->board_data = ar->board->data; ar->board_len = ar->board->size; ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.fw); Loading @@ -365,6 +353,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) goto err; } ar->firmware_data = ar->firmware->data; ar->firmware_len = ar->firmware->size; /* OTP may be undefined. If so, don't fetch it at all */ if (ar->hw_params.fw.otp == NULL) return 0; Loading @@ -378,6 +369,172 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) goto err; } ar->otp_data = ar->otp->data; ar->otp_len = ar->otp->size; return 0; err: ath10k_core_free_firmware_files(ar); return ret; } static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) { size_t magic_len, len, ie_len; int ie_id, i, index, bit, ret; struct ath10k_fw_ie *hdr; const u8 *data; __le32 *timestamp; /* first fetch the firmware file (firmware-*.bin) */ ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name); if (IS_ERR(ar->firmware)) { ath10k_err("Could not fetch firmware file '%s': %ld\n", name, PTR_ERR(ar->firmware)); return PTR_ERR(ar->firmware); } data = ar->firmware->data; len = ar->firmware->size; /* magic also includes the null byte, check that as well */ magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1; if (len < magic_len) { ath10k_err("firmware image too small to contain magic: %zu\n", len); ret = -EINVAL; goto err; } if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) { ath10k_err("Invalid firmware magic\n"); ret = -EINVAL; goto err; } /* jump over the padding */ magic_len = ALIGN(magic_len, 4); len -= magic_len; data += magic_len; /* loop elements */ while (len > sizeof(struct ath10k_fw_ie)) { hdr = (struct ath10k_fw_ie *)data; ie_id = le32_to_cpu(hdr->id); ie_len = le32_to_cpu(hdr->len); len -= sizeof(*hdr); data += sizeof(*hdr); if (len < ie_len) { ath10k_err("Invalid length for FW IE %d (%zu < %zu)\n", ie_id, len, ie_len); ret = -EINVAL; goto err; } switch (ie_id) { case ATH10K_FW_IE_FW_VERSION: if (ie_len > sizeof(ar->hw->wiphy->fw_version) - 1) break; memcpy(ar->hw->wiphy->fw_version, data, ie_len); ar->hw->wiphy->fw_version[ie_len] = '\0'; ath10k_dbg(ATH10K_DBG_BOOT, "found fw version %s\n", ar->hw->wiphy->fw_version); break; case ATH10K_FW_IE_TIMESTAMP: if (ie_len != sizeof(u32)) break; timestamp = (__le32 *)data; ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n", le32_to_cpup(timestamp)); break; case ATH10K_FW_IE_FEATURES: ath10k_dbg(ATH10K_DBG_BOOT, "found firmware features ie (%zd B)\n", ie_len); for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) { index = i / 8; bit = i % 8; if (index == ie_len) break; if (data[index] & (1 << bit)) __set_bit(i, ar->fw_features); } ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", ar->fw_features, sizeof(ar->fw_features)); break; case ATH10K_FW_IE_FW_IMAGE: ath10k_dbg(ATH10K_DBG_BOOT, "found fw image ie (%zd B)\n", ie_len); ar->firmware_data = data; ar->firmware_len = ie_len; break; case ATH10K_FW_IE_OTP_IMAGE: ath10k_dbg(ATH10K_DBG_BOOT, "found otp image ie (%zd B)\n", ie_len); ar->otp_data = data; ar->otp_len = ie_len; break; default: ath10k_warn("Unknown FW IE: %u\n", le32_to_cpu(hdr->id)); break; } /* jump over the padding */ ie_len = ALIGN(ie_len, 4); len -= ie_len; data += ie_len; } if (!ar->firmware_data || !ar->firmware_len) { ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from %s, skipping\n", name); ret = -ENOMEDIUM; goto err; } /* now fetch the board file */ if (ar->hw_params.fw.board == NULL) { ath10k_err("board data file not defined"); ret = -EINVAL; goto err; } ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.board); if (IS_ERR(ar->board)) { ret = PTR_ERR(ar->board); ath10k_err("could not fetch board data (%d)\n", ret); goto err; } ar->board_data = ar->board->data; ar->board_len = ar->board->size; return 0; err: Loading @@ -385,6 +542,28 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) return ret; } static int ath10k_core_fetch_firmware_files(struct ath10k *ar) { int ret; ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE); if (ret == 0) { ar->fw_api = 2; goto out; } ret = ath10k_core_fetch_firmware_api_1(ar); if (ret) return ret; ar->fw_api = 1; out: ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); return 0; } static int ath10k_init_download_firmware(struct ath10k *ar) { int ret; Loading Loading @@ -541,6 +720,9 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); skb_queue_head_init(&ar->offchan_tx_queue); INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work); skb_queue_head_init(&ar->wmi_mgmt_tx_queue); init_waitqueue_head(&ar->event_queue); INIT_WORK(&ar->restart_work, ath10k_core_restart); Loading @@ -555,6 +737,8 @@ EXPORT_SYMBOL(ath10k_core_create); void ath10k_core_destroy(struct ath10k *ar) { ath10k_debug_destroy(ar); flush_workqueue(ar->workqueue); destroy_workqueue(ar->workqueue); Loading @@ -566,6 +750,8 @@ int ath10k_core_start(struct ath10k *ar) { int status; lockdep_assert_held(&ar->conf_mutex); ath10k_bmi_start(ar); if (ath10k_init_configure_target(ar)) { Loading Loading @@ -616,10 +802,6 @@ int ath10k_core_start(struct ath10k *ar) ath10k_info("firmware %s booted\n", ar->hw->wiphy->fw_version); status = ath10k_check_fw_version(ar); if (status) goto err_disconnect_htc; status = ath10k_wmi_cmd_init(ar); if (status) { ath10k_err("could not send WMI init command (%d)\n", status); Loading @@ -642,6 +824,7 @@ int ath10k_core_start(struct ath10k *ar) goto err_disconnect_htc; ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; INIT_LIST_HEAD(&ar->arvifs); return 0; Loading @@ -658,6 +841,8 @@ EXPORT_SYMBOL(ath10k_core_start); void ath10k_core_stop(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); ath10k_debug_stop(ar); ath10k_htc_stop(&ar->htc); ath10k_htt_detach(&ar->htt); Loading Loading @@ -705,15 +890,21 @@ static int ath10k_core_probe_fw(struct ath10k *ar) return ret; } mutex_lock(&ar->conf_mutex); ret = ath10k_core_start(ar); if (ret) { ath10k_err("could not init core (%d)\n", ret); ath10k_core_free_firmware_files(ar); ath10k_hif_power_down(ar); mutex_unlock(&ar->conf_mutex); return ret; } ath10k_core_stop(ar); mutex_unlock(&ar->conf_mutex); ath10k_hif_power_down(ar); return 0; } Loading drivers/net/wireless/ath/ath10k/core.h +44 −3 Original line number Diff line number Diff line Loading @@ -43,15 +43,17 @@ /* Antenna noise floor */ #define ATH10K_DEFAULT_NOISE_FLOOR -95 #define ATH10K_MAX_NUM_MGMT_PENDING 16 struct ath10k; struct ath10k_skb_cb { dma_addr_t paddr; bool is_mapped; bool is_aborted; u8 vdev_id; struct { u8 vdev_id; u8 tid; bool is_offchan; Loading Loading @@ -102,11 +104,26 @@ struct ath10k_bmi { bool done_sent; }; #define ATH10K_MAX_MEM_REQS 16 struct ath10k_mem_chunk { void *vaddr; dma_addr_t paddr; u32 len; u32 req_id; }; struct ath10k_wmi { enum ath10k_htc_ep_id eid; struct completion service_ready; struct completion unified_ready; wait_queue_head_t tx_credits_wq; struct wmi_cmd_map *cmd; struct wmi_vdev_param_map *vdev_param; struct wmi_pdev_param_map *pdev_param; u32 num_mem_chunks; struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS]; }; struct ath10k_peer_stat { Loading Loading @@ -188,6 +205,8 @@ struct ath10k_peer { #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) struct ath10k_vif { struct list_head list; u32 vdev_id; enum wmi_vdev_type vdev_type; enum wmi_vdev_subtype vdev_subtype; Loading @@ -198,8 +217,10 @@ struct ath10k_vif { struct ath10k *ar; struct ieee80211_vif *vif; struct work_struct wep_key_work; struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; u8 def_wep_key_index; u8 def_wep_key_idx; u8 def_wep_key_newidx; u16 tx_seq_no; Loading Loading @@ -268,6 +289,12 @@ enum ath10k_fw_features { /* wmi_mgmt_rx_hdr contains extra RSSI information */ ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0, /* firmware from 10X branch */ ATH10K_FW_FEATURE_WMI_10X = 1, /* firmware support tx frame management over WMI, otherwise it's HTT */ ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX = 2, /* keep last */ ATH10K_FW_FEATURE_COUNT, }; Loading Loading @@ -324,9 +351,19 @@ struct ath10k { } fw; } hw_params; const struct firmware *board_data; const struct firmware *board; const void *board_data; size_t board_len; const struct firmware *otp; const void *otp_data; size_t otp_len; const struct firmware *firmware; const void *firmware_data; size_t firmware_len; int fw_api; struct { struct completion started; Loading Loading @@ -369,6 +406,7 @@ struct ath10k { /* protects shared structure data */ spinlock_t data_lock; struct list_head arvifs; struct list_head peers; wait_queue_head_t peer_mapping_wq; Loading @@ -377,6 +415,9 @@ struct ath10k { struct completion offchan_tx_completed; struct sk_buff *offchan_tx_skb; struct work_struct wmi_mgmt_tx_work; struct sk_buff_head wmi_mgmt_tx_queue; enum ath10k_state state; struct work_struct restart_work; Loading drivers/net/wireless/ath/ath10k/debug.c +14 −1 Original line number Diff line number Diff line Loading @@ -618,6 +618,8 @@ int ath10k_debug_start(struct ath10k *ar) { int ret; lockdep_assert_held(&ar->conf_mutex); ret = ath10k_debug_htt_stats_req(ar); if (ret) /* continue normally anyway, this isn't serious */ Loading @@ -628,7 +630,13 @@ int ath10k_debug_start(struct ath10k *ar) void ath10k_debug_stop(struct ath10k *ar) { cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); lockdep_assert_held(&ar->conf_mutex); /* Must not use _sync to avoid deadlock, we do that in * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid * warning from del_timer(). */ if (ar->debug.htt_stats_mask != 0) cancel_delayed_work(&ar->debug.htt_stats_dwork); } int ath10k_debug_create(struct ath10k *ar) Loading Loading @@ -662,6 +670,11 @@ int ath10k_debug_create(struct ath10k *ar) return 0; } void ath10k_debug_destroy(struct ath10k *ar) { cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); } #endif /* CONFIG_ATH10K_DEBUGFS */ #ifdef CONFIG_ATH10K_DEBUG Loading Loading
drivers/net/wireless/ath/ath10k/ce.c +8 −27 Original line number Diff line number Diff line Loading @@ -283,7 +283,7 @@ static int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state, if (unlikely(CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) <= 0)) { ret = -EIO; ret = -ENOSR; goto exit; } Loading Loading @@ -338,38 +338,19 @@ int ath10k_ce_send(struct ath10k_ce_pipe *ce_state, return ret; } int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, unsigned int transfer_id, u32 paddr, unsigned int nbytes, u32 flags) int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe) { struct ath10k_ce_ring *src_ring = ce_state->src_ring; struct ath10k *ar = ce_state->ar; struct ath10k *ar = pipe->ar; struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); unsigned int nentries_mask = src_ring->nentries_mask; unsigned int sw_index; unsigned int write_index; int delta, ret = -ENOMEM; int delta; spin_lock_bh(&ar_pci->ce_lock); sw_index = src_ring->sw_index; write_index = src_ring->write_index; delta = CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); if (delta >= 1) { ret = ath10k_ce_send_nolock(ce_state, per_transfer_context, paddr, nbytes, transfer_id, flags); if (ret) ath10k_warn("CE send failed: %d\n", ret); } delta = CE_RING_DELTA(pipe->src_ring->nentries_mask, pipe->src_ring->write_index, pipe->src_ring->sw_index - 1); spin_unlock_bh(&ar_pci->ce_lock); return ret; return delta; } int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state, Loading
drivers/net/wireless/ath/ath10k/ce.h +1 −15 Original line number Diff line number Diff line Loading @@ -156,21 +156,7 @@ void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state, void (*send_cb)(struct ath10k_ce_pipe *), int disable_interrupts); /* * Queue a "sendlist" of buffers to be sent using gather to a single * anonymous destination buffer * ce - which copy engine to use * sendlist - list of simple buffers to send using gather * transfer_id - arbitrary ID; reflected to destination * Returns 0 on success; otherwise an error status. * * Implemenation note: Pushes multiple buffers with Gather to Source ring. */ int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state, void *per_transfer_context, unsigned int transfer_id, u32 paddr, unsigned int nbytes, u32 flags); int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe); /*==================Recv=======================*/ Loading
drivers/net/wireless/ath/ath10k/core.c +238 −47 Original line number Diff line number Diff line Loading @@ -59,27 +59,6 @@ static void ath10k_send_suspend_complete(struct ath10k *ar) wake_up(&ar->event_queue); } static int ath10k_check_fw_version(struct ath10k *ar) { char version[32]; if (ar->fw_version_major >= SUPPORTED_FW_MAJOR && ar->fw_version_minor >= SUPPORTED_FW_MINOR && ar->fw_version_release >= SUPPORTED_FW_RELEASE && ar->fw_version_build >= SUPPORTED_FW_BUILD) return 0; snprintf(version, sizeof(version), "%u.%u.%u.%u", SUPPORTED_FW_MAJOR, SUPPORTED_FW_MINOR, SUPPORTED_FW_RELEASE, SUPPORTED_FW_BUILD); ath10k_warn("WARNING: Firmware version %s is not officially supported.\n", ar->hw->wiphy->fw_version); ath10k_warn("Please upgrade to version %s (or newer)\n", version); return 0; } static int ath10k_init_connect_htc(struct ath10k *ar) { int status; Loading Loading @@ -189,8 +168,7 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, return fw; } static int ath10k_push_board_ext_data(struct ath10k *ar, const struct firmware *fw) static int ath10k_push_board_ext_data(struct ath10k *ar) { u32 board_data_size = QCA988X_BOARD_DATA_SZ; u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ; Loading @@ -210,14 +188,14 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, if (board_ext_data_addr == 0) return 0; if (fw->size != (board_data_size + board_ext_data_size)) { if (ar->board_len != (board_data_size + board_ext_data_size)) { ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n", fw->size, board_data_size, board_ext_data_size); ar->board_len, board_data_size, board_ext_data_size); return -EINVAL; } ret = ath10k_bmi_write_memory(ar, board_ext_data_addr, fw->data + board_data_size, ar->board_data + board_data_size, board_ext_data_size); if (ret) { ath10k_err("could not write board ext data (%d)\n", ret); Loading @@ -236,12 +214,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, static int ath10k_download_board_data(struct ath10k *ar) { const struct firmware *fw = ar->board_data; u32 board_data_size = QCA988X_BOARD_DATA_SZ; u32 address; int ret; ret = ath10k_push_board_ext_data(ar, fw); ret = ath10k_push_board_ext_data(ar); if (ret) { ath10k_err("could not push board ext data (%d)\n", ret); goto exit; Loading @@ -253,8 +230,9 @@ static int ath10k_download_board_data(struct ath10k *ar) goto exit; } ret = ath10k_bmi_write_memory(ar, address, fw->data, min_t(u32, board_data_size, fw->size)); ret = ath10k_bmi_write_memory(ar, address, ar->board_data, min_t(u32, board_data_size, ar->board_len)); if (ret) { ath10k_err("could not write board data (%d)\n", ret); goto exit; Loading @@ -272,17 +250,16 @@ static int ath10k_download_board_data(struct ath10k *ar) static int ath10k_download_and_run_otp(struct ath10k *ar) { const struct firmware *fw = ar->otp; u32 address = ar->hw_params.patch_load_addr; u32 exec_param; int ret; /* OTP is optional */ if (!ar->otp) if (!ar->otp_data || !ar->otp_len) return 0; ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); if (ret) { ath10k_err("could not write otp (%d)\n", ret); goto exit; Loading @@ -301,13 +278,13 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) static int ath10k_download_fw(struct ath10k *ar) { const struct firmware *fw = ar->firmware; u32 address; int ret; address = ar->hw_params.patch_load_addr; ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data, ar->firmware_len); if (ret) { ath10k_err("could not write fw (%d)\n", ret); goto exit; Loading @@ -319,8 +296,8 @@ static int ath10k_download_fw(struct ath10k *ar) static void ath10k_core_free_firmware_files(struct ath10k *ar) { if (ar->board_data && !IS_ERR(ar->board_data)) release_firmware(ar->board_data); if (ar->board && !IS_ERR(ar->board)) release_firmware(ar->board); if (ar->otp && !IS_ERR(ar->otp)) release_firmware(ar->otp); Loading @@ -328,12 +305,20 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) if (ar->firmware && !IS_ERR(ar->firmware)) release_firmware(ar->firmware); ar->board = NULL; ar->board_data = NULL; ar->board_len = 0; ar->otp = NULL; ar->otp_data = NULL; ar->otp_len = 0; ar->firmware = NULL; ar->firmware_data = NULL; ar->firmware_len = 0; } static int ath10k_core_fetch_firmware_files(struct ath10k *ar) static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar) { int ret = 0; Loading @@ -347,15 +332,18 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) return -EINVAL; } ar->board_data = ath10k_fetch_fw_file(ar, ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.board); if (IS_ERR(ar->board_data)) { ret = PTR_ERR(ar->board_data); if (IS_ERR(ar->board)) { ret = PTR_ERR(ar->board); ath10k_err("could not fetch board data (%d)\n", ret); goto err; } ar->board_data = ar->board->data; ar->board_len = ar->board->size; ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.fw); Loading @@ -365,6 +353,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) goto err; } ar->firmware_data = ar->firmware->data; ar->firmware_len = ar->firmware->size; /* OTP may be undefined. If so, don't fetch it at all */ if (ar->hw_params.fw.otp == NULL) return 0; Loading @@ -378,6 +369,172 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) goto err; } ar->otp_data = ar->otp->data; ar->otp_len = ar->otp->size; return 0; err: ath10k_core_free_firmware_files(ar); return ret; } static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) { size_t magic_len, len, ie_len; int ie_id, i, index, bit, ret; struct ath10k_fw_ie *hdr; const u8 *data; __le32 *timestamp; /* first fetch the firmware file (firmware-*.bin) */ ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name); if (IS_ERR(ar->firmware)) { ath10k_err("Could not fetch firmware file '%s': %ld\n", name, PTR_ERR(ar->firmware)); return PTR_ERR(ar->firmware); } data = ar->firmware->data; len = ar->firmware->size; /* magic also includes the null byte, check that as well */ magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1; if (len < magic_len) { ath10k_err("firmware image too small to contain magic: %zu\n", len); ret = -EINVAL; goto err; } if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) { ath10k_err("Invalid firmware magic\n"); ret = -EINVAL; goto err; } /* jump over the padding */ magic_len = ALIGN(magic_len, 4); len -= magic_len; data += magic_len; /* loop elements */ while (len > sizeof(struct ath10k_fw_ie)) { hdr = (struct ath10k_fw_ie *)data; ie_id = le32_to_cpu(hdr->id); ie_len = le32_to_cpu(hdr->len); len -= sizeof(*hdr); data += sizeof(*hdr); if (len < ie_len) { ath10k_err("Invalid length for FW IE %d (%zu < %zu)\n", ie_id, len, ie_len); ret = -EINVAL; goto err; } switch (ie_id) { case ATH10K_FW_IE_FW_VERSION: if (ie_len > sizeof(ar->hw->wiphy->fw_version) - 1) break; memcpy(ar->hw->wiphy->fw_version, data, ie_len); ar->hw->wiphy->fw_version[ie_len] = '\0'; ath10k_dbg(ATH10K_DBG_BOOT, "found fw version %s\n", ar->hw->wiphy->fw_version); break; case ATH10K_FW_IE_TIMESTAMP: if (ie_len != sizeof(u32)) break; timestamp = (__le32 *)data; ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n", le32_to_cpup(timestamp)); break; case ATH10K_FW_IE_FEATURES: ath10k_dbg(ATH10K_DBG_BOOT, "found firmware features ie (%zd B)\n", ie_len); for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) { index = i / 8; bit = i % 8; if (index == ie_len) break; if (data[index] & (1 << bit)) __set_bit(i, ar->fw_features); } ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "", ar->fw_features, sizeof(ar->fw_features)); break; case ATH10K_FW_IE_FW_IMAGE: ath10k_dbg(ATH10K_DBG_BOOT, "found fw image ie (%zd B)\n", ie_len); ar->firmware_data = data; ar->firmware_len = ie_len; break; case ATH10K_FW_IE_OTP_IMAGE: ath10k_dbg(ATH10K_DBG_BOOT, "found otp image ie (%zd B)\n", ie_len); ar->otp_data = data; ar->otp_len = ie_len; break; default: ath10k_warn("Unknown FW IE: %u\n", le32_to_cpu(hdr->id)); break; } /* jump over the padding */ ie_len = ALIGN(ie_len, 4); len -= ie_len; data += ie_len; } if (!ar->firmware_data || !ar->firmware_len) { ath10k_warn("No ATH10K_FW_IE_FW_IMAGE found from %s, skipping\n", name); ret = -ENOMEDIUM; goto err; } /* now fetch the board file */ if (ar->hw_params.fw.board == NULL) { ath10k_err("board data file not defined"); ret = -EINVAL; goto err; } ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.board); if (IS_ERR(ar->board)) { ret = PTR_ERR(ar->board); ath10k_err("could not fetch board data (%d)\n", ret); goto err; } ar->board_data = ar->board->data; ar->board_len = ar->board->size; return 0; err: Loading @@ -385,6 +542,28 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar) return ret; } static int ath10k_core_fetch_firmware_files(struct ath10k *ar) { int ret; ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE); if (ret == 0) { ar->fw_api = 2; goto out; } ret = ath10k_core_fetch_firmware_api_1(ar); if (ret) return ret; ar->fw_api = 1; out: ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); return 0; } static int ath10k_init_download_firmware(struct ath10k *ar) { int ret; Loading Loading @@ -541,6 +720,9 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); skb_queue_head_init(&ar->offchan_tx_queue); INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work); skb_queue_head_init(&ar->wmi_mgmt_tx_queue); init_waitqueue_head(&ar->event_queue); INIT_WORK(&ar->restart_work, ath10k_core_restart); Loading @@ -555,6 +737,8 @@ EXPORT_SYMBOL(ath10k_core_create); void ath10k_core_destroy(struct ath10k *ar) { ath10k_debug_destroy(ar); flush_workqueue(ar->workqueue); destroy_workqueue(ar->workqueue); Loading @@ -566,6 +750,8 @@ int ath10k_core_start(struct ath10k *ar) { int status; lockdep_assert_held(&ar->conf_mutex); ath10k_bmi_start(ar); if (ath10k_init_configure_target(ar)) { Loading Loading @@ -616,10 +802,6 @@ int ath10k_core_start(struct ath10k *ar) ath10k_info("firmware %s booted\n", ar->hw->wiphy->fw_version); status = ath10k_check_fw_version(ar); if (status) goto err_disconnect_htc; status = ath10k_wmi_cmd_init(ar); if (status) { ath10k_err("could not send WMI init command (%d)\n", status); Loading @@ -642,6 +824,7 @@ int ath10k_core_start(struct ath10k *ar) goto err_disconnect_htc; ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; INIT_LIST_HEAD(&ar->arvifs); return 0; Loading @@ -658,6 +841,8 @@ EXPORT_SYMBOL(ath10k_core_start); void ath10k_core_stop(struct ath10k *ar) { lockdep_assert_held(&ar->conf_mutex); ath10k_debug_stop(ar); ath10k_htc_stop(&ar->htc); ath10k_htt_detach(&ar->htt); Loading Loading @@ -705,15 +890,21 @@ static int ath10k_core_probe_fw(struct ath10k *ar) return ret; } mutex_lock(&ar->conf_mutex); ret = ath10k_core_start(ar); if (ret) { ath10k_err("could not init core (%d)\n", ret); ath10k_core_free_firmware_files(ar); ath10k_hif_power_down(ar); mutex_unlock(&ar->conf_mutex); return ret; } ath10k_core_stop(ar); mutex_unlock(&ar->conf_mutex); ath10k_hif_power_down(ar); return 0; } Loading
drivers/net/wireless/ath/ath10k/core.h +44 −3 Original line number Diff line number Diff line Loading @@ -43,15 +43,17 @@ /* Antenna noise floor */ #define ATH10K_DEFAULT_NOISE_FLOOR -95 #define ATH10K_MAX_NUM_MGMT_PENDING 16 struct ath10k; struct ath10k_skb_cb { dma_addr_t paddr; bool is_mapped; bool is_aborted; u8 vdev_id; struct { u8 vdev_id; u8 tid; bool is_offchan; Loading Loading @@ -102,11 +104,26 @@ struct ath10k_bmi { bool done_sent; }; #define ATH10K_MAX_MEM_REQS 16 struct ath10k_mem_chunk { void *vaddr; dma_addr_t paddr; u32 len; u32 req_id; }; struct ath10k_wmi { enum ath10k_htc_ep_id eid; struct completion service_ready; struct completion unified_ready; wait_queue_head_t tx_credits_wq; struct wmi_cmd_map *cmd; struct wmi_vdev_param_map *vdev_param; struct wmi_pdev_param_map *pdev_param; u32 num_mem_chunks; struct ath10k_mem_chunk mem_chunks[ATH10K_MAX_MEM_REQS]; }; struct ath10k_peer_stat { Loading Loading @@ -188,6 +205,8 @@ struct ath10k_peer { #define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ) struct ath10k_vif { struct list_head list; u32 vdev_id; enum wmi_vdev_type vdev_type; enum wmi_vdev_subtype vdev_subtype; Loading @@ -198,8 +217,10 @@ struct ath10k_vif { struct ath10k *ar; struct ieee80211_vif *vif; struct work_struct wep_key_work; struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1]; u8 def_wep_key_index; u8 def_wep_key_idx; u8 def_wep_key_newidx; u16 tx_seq_no; Loading Loading @@ -268,6 +289,12 @@ enum ath10k_fw_features { /* wmi_mgmt_rx_hdr contains extra RSSI information */ ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0, /* firmware from 10X branch */ ATH10K_FW_FEATURE_WMI_10X = 1, /* firmware support tx frame management over WMI, otherwise it's HTT */ ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX = 2, /* keep last */ ATH10K_FW_FEATURE_COUNT, }; Loading Loading @@ -324,9 +351,19 @@ struct ath10k { } fw; } hw_params; const struct firmware *board_data; const struct firmware *board; const void *board_data; size_t board_len; const struct firmware *otp; const void *otp_data; size_t otp_len; const struct firmware *firmware; const void *firmware_data; size_t firmware_len; int fw_api; struct { struct completion started; Loading Loading @@ -369,6 +406,7 @@ struct ath10k { /* protects shared structure data */ spinlock_t data_lock; struct list_head arvifs; struct list_head peers; wait_queue_head_t peer_mapping_wq; Loading @@ -377,6 +415,9 @@ struct ath10k { struct completion offchan_tx_completed; struct sk_buff *offchan_tx_skb; struct work_struct wmi_mgmt_tx_work; struct sk_buff_head wmi_mgmt_tx_queue; enum ath10k_state state; struct work_struct restart_work; Loading
drivers/net/wireless/ath/ath10k/debug.c +14 −1 Original line number Diff line number Diff line Loading @@ -618,6 +618,8 @@ int ath10k_debug_start(struct ath10k *ar) { int ret; lockdep_assert_held(&ar->conf_mutex); ret = ath10k_debug_htt_stats_req(ar); if (ret) /* continue normally anyway, this isn't serious */ Loading @@ -628,7 +630,13 @@ int ath10k_debug_start(struct ath10k *ar) void ath10k_debug_stop(struct ath10k *ar) { cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); lockdep_assert_held(&ar->conf_mutex); /* Must not use _sync to avoid deadlock, we do that in * ath10k_debug_destroy(). The check for htt_stats_mask is to avoid * warning from del_timer(). */ if (ar->debug.htt_stats_mask != 0) cancel_delayed_work(&ar->debug.htt_stats_dwork); } int ath10k_debug_create(struct ath10k *ar) Loading Loading @@ -662,6 +670,11 @@ int ath10k_debug_create(struct ath10k *ar) return 0; } void ath10k_debug_destroy(struct ath10k *ar) { cancel_delayed_work_sync(&ar->debug.htt_stats_dwork); } #endif /* CONFIG_ATH10K_DEBUGFS */ #ifdef CONFIG_ATH10K_DEBUG Loading