Loading drivers/net/wireless/ath/ath10k/bmi.c +10 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,12 @@ #include "debug.h" #include "htc.h" void ath10k_bmi_start(struct ath10k *ar) { ath10k_dbg(ATH10K_DBG_CORE, "BMI started\n"); ar->bmi.done_sent = false; } int ath10k_bmi_done(struct ath10k *ar) { struct bmi_cmd cmd; Loading Loading @@ -105,7 +111,8 @@ int ath10k_bmi_read_memory(struct ath10k *ar, ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &rxlen); if (ret) { ath10k_warn("unable to read from the device\n"); ath10k_warn("unable to read from the device (%d)\n", ret); return ret; } Loading Loading @@ -149,7 +156,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar, ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen, NULL, NULL); if (ret) { ath10k_warn("unable to write to the device\n"); ath10k_warn("unable to write to the device (%d)\n", ret); return ret; } Loading drivers/net/wireless/ath/ath10k/bmi.h +1 −0 Original line number Diff line number Diff line Loading @@ -184,6 +184,7 @@ struct bmi_target_info { #define BMI_CE_NUM_TO_TARG 0 #define BMI_CE_NUM_TO_HOST 1 void ath10k_bmi_start(struct ath10k *ar); int ath10k_bmi_done(struct ath10k *ar); int ath10k_bmi_get_target_info(struct ath10k *ar, struct bmi_target_info *target_info); Loading drivers/net/wireless/ath/ath10k/ce.c +1 −1 Original line number Diff line number Diff line Loading @@ -79,7 +79,7 @@ static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar, struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); void __iomem *indicator_addr; if (!test_bit(ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND, ar_pci->features)) { if (!test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) { ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); return; } Loading drivers/net/wireless/ath/ath10k/core.c +210 −111 Original line number Diff line number Diff line Loading @@ -100,7 +100,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar) goto conn_fail; /* Start HTC */ status = ath10k_htc_start(ar->htc); status = ath10k_htc_start(&ar->htc); if (status) goto conn_fail; Loading @@ -116,7 +116,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar) return 0; timeout: ath10k_htc_stop(ar->htc); ath10k_htc_stop(&ar->htc); conn_fail: return status; } Loading Loading @@ -247,19 +247,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; const struct firmware *fw; int ret; fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.board); if (IS_ERR(fw)) { ath10k_err("could not fetch board data fw file (%ld)\n", PTR_ERR(fw)); return PTR_ERR(fw); } ret = ath10k_push_board_ext_data(ar, fw); if (ret) { ath10k_err("could not push board ext data (%d)\n", ret); Loading @@ -286,32 +278,20 @@ static int ath10k_download_board_data(struct ath10k *ar) } exit: release_firmware(fw); return ret; } static int ath10k_download_and_run_otp(struct ath10k *ar) { const struct firmware *fw; u32 address; const struct firmware *fw = ar->otp; u32 address = ar->hw_params.patch_load_addr; u32 exec_param; int ret; /* OTP is optional */ if (ar->hw_params.fw.otp == NULL) { ath10k_info("otp file not defined\n"); return 0; } address = ar->hw_params.patch_load_addr; fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.otp); if (IS_ERR(fw)) { ath10k_warn("could not fetch otp (%ld)\n", PTR_ERR(fw)); if (!ar->otp) return 0; } ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); if (ret) { Loading @@ -327,28 +307,17 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) } exit: release_firmware(fw); return ret; } static int ath10k_download_fw(struct ath10k *ar) { const struct firmware *fw; const struct firmware *fw = ar->firmware; u32 address; int ret; if (ar->hw_params.fw.fw == NULL) return -EINVAL; address = ar->hw_params.patch_load_addr; fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.fw); if (IS_ERR(fw)) { ath10k_err("could not fetch fw (%ld)\n", PTR_ERR(fw)); return PTR_ERR(fw); } ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); if (ret) { ath10k_err("could not write fw (%d)\n", ret); Loading @@ -356,7 +325,74 @@ static int ath10k_download_fw(struct ath10k *ar) } exit: release_firmware(fw); return ret; } 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->otp && !IS_ERR(ar->otp)) release_firmware(ar->otp); if (ar->firmware && !IS_ERR(ar->firmware)) release_firmware(ar->firmware); ar->board_data = NULL; ar->otp = NULL; ar->firmware = NULL; } static int ath10k_core_fetch_firmware_files(struct ath10k *ar) { int ret = 0; if (ar->hw_params.fw.fw == NULL) { ath10k_err("firmware file not defined\n"); return -EINVAL; } if (ar->hw_params.fw.board == NULL) { ath10k_err("board data file not defined"); return -EINVAL; } ar->board_data = 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); ath10k_err("could not fetch board data (%d)\n", ret); goto err; } ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.fw); if (IS_ERR(ar->firmware)) { ret = PTR_ERR(ar->firmware); ath10k_err("could not fetch firmware (%d)\n", ret); goto err; } /* OTP may be undefined. If so, don't fetch it at all */ if (ar->hw_params.fw.otp == NULL) return 0; ar->otp = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.otp); if (IS_ERR(ar->otp)) { ret = PTR_ERR(ar->otp); ath10k_err("could not fetch otp (%d)\n", ret); goto err; } return 0; err: ath10k_core_free_firmware_files(ar); return ret; } Loading Loading @@ -440,8 +476,35 @@ static int ath10k_init_hw_params(struct ath10k *ar) return 0; } static void ath10k_core_restart(struct work_struct *work) { struct ath10k *ar = container_of(work, struct ath10k, restart_work); mutex_lock(&ar->conf_mutex); switch (ar->state) { case ATH10K_STATE_ON: ath10k_halt(ar); ar->state = ATH10K_STATE_RESTARTING; ieee80211_restart_hw(ar->hw); break; case ATH10K_STATE_OFF: /* this can happen if driver is being unloaded */ ath10k_warn("cannot restart a device that hasn't been started\n"); break; case ATH10K_STATE_RESTARTING: case ATH10K_STATE_RESTARTED: ar->state = ATH10K_STATE_WEDGED; /* fall through */ case ATH10K_STATE_WEDGED: ath10k_warn("device is wedged, will not restart\n"); break; } mutex_unlock(&ar->conf_mutex); } struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, enum ath10k_bus bus, const struct ath10k_hif_ops *hif_ops) { struct ath10k *ar; Loading @@ -458,9 +521,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ar->hif.priv = hif_priv; ar->hif.ops = hif_ops; ar->hif.bus = bus; ar->free_vdev_map = 0xFF; /* 8 vdevs */ init_completion(&ar->scan.started); init_completion(&ar->scan.completed); Loading @@ -487,6 +547,8 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, init_waitqueue_head(&ar->event_queue); INIT_WORK(&ar->restart_work, ath10k_core_restart); return ar; err_wq: Loading @@ -504,24 +566,11 @@ void ath10k_core_destroy(struct ath10k *ar) } EXPORT_SYMBOL(ath10k_core_destroy); int ath10k_core_register(struct ath10k *ar) int ath10k_core_start(struct ath10k *ar) { struct ath10k_htc_ops htc_ops; struct bmi_target_info target_info; int status; memset(&target_info, 0, sizeof(target_info)); status = ath10k_bmi_get_target_info(ar, &target_info); if (status) goto err; ar->target_version = target_info.version; ar->hw->wiphy->hw_version = target_info.version; status = ath10k_init_hw_params(ar); if (status) goto err; ath10k_bmi_start(ar); if (ath10k_init_configure_target(ar)) { status = -EINVAL; Loading @@ -536,32 +585,32 @@ int ath10k_core_register(struct ath10k *ar) if (status) goto err; htc_ops.target_send_suspend_complete = ath10k_send_suspend_complete; ar->htc.htc_ops.target_send_suspend_complete = ath10k_send_suspend_complete; ar->htc = ath10k_htc_create(ar, &htc_ops); if (IS_ERR(ar->htc)) { status = PTR_ERR(ar->htc); ath10k_err("could not create HTC (%d)\n", status); status = ath10k_htc_init(ar); if (status) { ath10k_err("could not init HTC (%d)\n", status); goto err; } status = ath10k_bmi_done(ar); if (status) goto err_htc_destroy; goto err; status = ath10k_wmi_attach(ar); if (status) { ath10k_err("WMI attach failed: %d\n", status); goto err_htc_destroy; goto err; } status = ath10k_htc_wait_target(ar->htc); status = ath10k_htc_wait_target(&ar->htc); if (status) goto err_wmi_detach; ar->htt = ath10k_htt_attach(ar); if (!ar->htt) { status = -ENOMEM; status = ath10k_htt_attach(ar); if (status) { ath10k_err("could not attach htt (%d)\n", status); goto err_wmi_detach; } Loading @@ -588,77 +637,127 @@ int ath10k_core_register(struct ath10k *ar) goto err_disconnect_htc; } status = ath10k_htt_attach_target(ar->htt); if (status) goto err_disconnect_htc; status = ath10k_mac_register(ar); status = ath10k_htt_attach_target(&ar->htt); if (status) goto err_disconnect_htc; status = ath10k_debug_create(ar); if (status) { ath10k_err("unable to initialize debugfs\n"); goto err_unregister_mac; } ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; return 0; err_unregister_mac: ath10k_mac_unregister(ar); err_disconnect_htc: ath10k_htc_stop(ar->htc); ath10k_htc_stop(&ar->htc); err_htt_detach: ath10k_htt_detach(ar->htt); ath10k_htt_detach(&ar->htt); err_wmi_detach: ath10k_wmi_detach(ar); err_htc_destroy: ath10k_htc_destroy(ar->htc); err: return status; } EXPORT_SYMBOL(ath10k_core_register); EXPORT_SYMBOL(ath10k_core_start); void ath10k_core_unregister(struct ath10k *ar) void ath10k_core_stop(struct ath10k *ar) { /* We must unregister from mac80211 before we stop HTC and HIF. * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ ath10k_mac_unregister(ar); ath10k_htc_stop(ar->htc); ath10k_htt_detach(ar->htt); ath10k_htc_stop(&ar->htc); ath10k_htt_detach(&ar->htt); ath10k_wmi_detach(ar); ath10k_htc_destroy(ar->htc); } EXPORT_SYMBOL(ath10k_core_unregister); EXPORT_SYMBOL(ath10k_core_stop); int ath10k_core_target_suspend(struct ath10k *ar) /* mac80211 manages fw/hw initialization through start/stop hooks. However in * order to know what hw capabilities should be advertised to mac80211 it is * necessary to load the firmware (and tear it down immediately since start * hook will try to init it again) before registering */ static int ath10k_core_probe_fw(struct ath10k *ar) { int ret; struct bmi_target_info target_info; int ret = 0; ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__); ret = ath10k_hif_power_up(ar); if (ret) { ath10k_err("could not start pci hif (%d)\n", ret); return ret; } ret = ath10k_wmi_pdev_suspend_target(ar); if (ret) ath10k_warn("could not suspend target (%d)\n", ret); memset(&target_info, 0, sizeof(target_info)); ret = ath10k_bmi_get_target_info(ar, &target_info); if (ret) { ath10k_err("could not get target info (%d)\n", ret); ath10k_hif_power_down(ar); return ret; } ar->target_version = target_info.version; ar->hw->wiphy->hw_version = target_info.version; ret = ath10k_init_hw_params(ar); if (ret) { ath10k_err("could not get hw params (%d)\n", ret); ath10k_hif_power_down(ar); return ret; } ret = ath10k_core_fetch_firmware_files(ar); if (ret) { ath10k_err("could not fetch firmware files (%d)\n", ret); ath10k_hif_power_down(ar); return ret; } 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); return ret; } EXPORT_SYMBOL(ath10k_core_target_suspend); int ath10k_core_target_resume(struct ath10k *ar) ath10k_core_stop(ar); ath10k_hif_power_down(ar); return 0; } int ath10k_core_register(struct ath10k *ar) { int ret; int status; ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__); status = ath10k_core_probe_fw(ar); if (status) { ath10k_err("could not probe fw (%d)\n", status); return status; } ret = ath10k_wmi_pdev_resume_target(ar); if (ret) ath10k_warn("could not resume target (%d)\n", ret); status = ath10k_mac_register(ar); if (status) { ath10k_err("could not register to mac80211 (%d)\n", status); goto err_release_fw; } return ret; status = ath10k_debug_create(ar); if (status) { ath10k_err("unable to initialize debugfs\n"); goto err_unregister_mac; } return 0; err_unregister_mac: ath10k_mac_unregister(ar); err_release_fw: ath10k_core_free_firmware_files(ar); return status; } EXPORT_SYMBOL(ath10k_core_target_resume); EXPORT_SYMBOL(ath10k_core_register); void ath10k_core_unregister(struct ath10k *ar) { /* We must unregister from mac80211 before we stop HTC and HIF. * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ ath10k_mac_unregister(ar); ath10k_core_free_firmware_files(ar); } EXPORT_SYMBOL(ath10k_core_unregister); MODULE_AUTHOR("Qualcomm Atheros"); MODULE_DESCRIPTION("Core module for QCA988X PCIe devices."); Loading drivers/net/wireless/ath/ath10k/core.h +36 −14 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/types.h> #include <linux/pci.h> #include "htt.h" #include "htc.h" #include "hw.h" #include "targaddrs.h" Loading @@ -43,10 +44,6 @@ struct ath10k; enum ath10k_bus { ATH10K_BUS_PCI, }; struct ath10k_skb_cb { dma_addr_t paddr; bool is_mapped; Loading Loading @@ -250,6 +247,28 @@ struct ath10k_debug { struct completion event_stats_compl; }; enum ath10k_state { ATH10K_STATE_OFF = 0, ATH10K_STATE_ON, /* When doing firmware recovery the device is first powered down. * mac80211 is supposed to call in to start() hook later on. It is * however possible that driver unloading and firmware crash overlap. * mac80211 can wait on conf_mutex in stop() while the device is * 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(). */ ATH10K_STATE_RESTARTING, ATH10K_STATE_RESTARTED, /* The device has crashed while restarting hw. This state is like ON * but commands are blocked in HTC and -ECOMM response is given. This * prevents completion timeouts and makes the driver more responsive to * userspace commands. This is also prevents recursive recovery. */ ATH10K_STATE_WEDGED, }; struct ath10k { struct ath_common ath_common; struct ieee80211_hw *hw; Loading @@ -274,19 +293,16 @@ struct ath10k { struct { void *priv; enum ath10k_bus bus; const struct ath10k_hif_ops *ops; } hif; struct ath10k_wmi wmi; wait_queue_head_t event_queue; bool is_target_paused; struct ath10k_bmi bmi; struct ath10k_htc *htc; struct ath10k_htt *htt; struct ath10k_wmi wmi; struct ath10k_htc htc; struct ath10k_htt htt; struct ath10k_hw_params { u32 id; Loading @@ -301,6 +317,10 @@ struct ath10k { } fw; } hw_params; const struct firmware *board_data; const struct firmware *otp; const struct firmware *firmware; struct { struct completion started; struct completion completed; Loading Loading @@ -350,20 +370,22 @@ struct ath10k { struct completion offchan_tx_completed; struct sk_buff *offchan_tx_skb; enum ath10k_state state; struct work_struct restart_work; #ifdef CONFIG_ATH10K_DEBUGFS struct ath10k_debug debug; #endif }; struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, enum ath10k_bus bus, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); int ath10k_core_start(struct ath10k *ar); void ath10k_core_stop(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar); void ath10k_core_unregister(struct ath10k *ar); int ath10k_core_target_suspend(struct ath10k *ar); int ath10k_core_target_resume(struct ath10k *ar); #endif /* _CORE_H_ */ Loading
drivers/net/wireless/ath/ath10k/bmi.c +10 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,12 @@ #include "debug.h" #include "htc.h" void ath10k_bmi_start(struct ath10k *ar) { ath10k_dbg(ATH10K_DBG_CORE, "BMI started\n"); ar->bmi.done_sent = false; } int ath10k_bmi_done(struct ath10k *ar) { struct bmi_cmd cmd; Loading Loading @@ -105,7 +111,8 @@ int ath10k_bmi_read_memory(struct ath10k *ar, ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &rxlen); if (ret) { ath10k_warn("unable to read from the device\n"); ath10k_warn("unable to read from the device (%d)\n", ret); return ret; } Loading Loading @@ -149,7 +156,8 @@ int ath10k_bmi_write_memory(struct ath10k *ar, ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen, NULL, NULL); if (ret) { ath10k_warn("unable to write to the device\n"); ath10k_warn("unable to write to the device (%d)\n", ret); return ret; } Loading
drivers/net/wireless/ath/ath10k/bmi.h +1 −0 Original line number Diff line number Diff line Loading @@ -184,6 +184,7 @@ struct bmi_target_info { #define BMI_CE_NUM_TO_TARG 0 #define BMI_CE_NUM_TO_HOST 1 void ath10k_bmi_start(struct ath10k *ar); int ath10k_bmi_done(struct ath10k *ar); int ath10k_bmi_get_target_info(struct ath10k *ar, struct bmi_target_info *target_info); Loading
drivers/net/wireless/ath/ath10k/ce.c +1 −1 Original line number Diff line number Diff line Loading @@ -79,7 +79,7 @@ static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar, struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); void __iomem *indicator_addr; if (!test_bit(ATH10K_PCI_FEATURE_HW_1_0_WARKAROUND, ar_pci->features)) { if (!test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) { ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n); return; } Loading
drivers/net/wireless/ath/ath10k/core.c +210 −111 Original line number Diff line number Diff line Loading @@ -100,7 +100,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar) goto conn_fail; /* Start HTC */ status = ath10k_htc_start(ar->htc); status = ath10k_htc_start(&ar->htc); if (status) goto conn_fail; Loading @@ -116,7 +116,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar) return 0; timeout: ath10k_htc_stop(ar->htc); ath10k_htc_stop(&ar->htc); conn_fail: return status; } Loading Loading @@ -247,19 +247,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; const struct firmware *fw; int ret; fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.board); if (IS_ERR(fw)) { ath10k_err("could not fetch board data fw file (%ld)\n", PTR_ERR(fw)); return PTR_ERR(fw); } ret = ath10k_push_board_ext_data(ar, fw); if (ret) { ath10k_err("could not push board ext data (%d)\n", ret); Loading @@ -286,32 +278,20 @@ static int ath10k_download_board_data(struct ath10k *ar) } exit: release_firmware(fw); return ret; } static int ath10k_download_and_run_otp(struct ath10k *ar) { const struct firmware *fw; u32 address; const struct firmware *fw = ar->otp; u32 address = ar->hw_params.patch_load_addr; u32 exec_param; int ret; /* OTP is optional */ if (ar->hw_params.fw.otp == NULL) { ath10k_info("otp file not defined\n"); return 0; } address = ar->hw_params.patch_load_addr; fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.otp); if (IS_ERR(fw)) { ath10k_warn("could not fetch otp (%ld)\n", PTR_ERR(fw)); if (!ar->otp) return 0; } ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); if (ret) { Loading @@ -327,28 +307,17 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) } exit: release_firmware(fw); return ret; } static int ath10k_download_fw(struct ath10k *ar) { const struct firmware *fw; const struct firmware *fw = ar->firmware; u32 address; int ret; if (ar->hw_params.fw.fw == NULL) return -EINVAL; address = ar->hw_params.patch_load_addr; fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.fw); if (IS_ERR(fw)) { ath10k_err("could not fetch fw (%ld)\n", PTR_ERR(fw)); return PTR_ERR(fw); } ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); if (ret) { ath10k_err("could not write fw (%d)\n", ret); Loading @@ -356,7 +325,74 @@ static int ath10k_download_fw(struct ath10k *ar) } exit: release_firmware(fw); return ret; } 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->otp && !IS_ERR(ar->otp)) release_firmware(ar->otp); if (ar->firmware && !IS_ERR(ar->firmware)) release_firmware(ar->firmware); ar->board_data = NULL; ar->otp = NULL; ar->firmware = NULL; } static int ath10k_core_fetch_firmware_files(struct ath10k *ar) { int ret = 0; if (ar->hw_params.fw.fw == NULL) { ath10k_err("firmware file not defined\n"); return -EINVAL; } if (ar->hw_params.fw.board == NULL) { ath10k_err("board data file not defined"); return -EINVAL; } ar->board_data = 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); ath10k_err("could not fetch board data (%d)\n", ret); goto err; } ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.fw); if (IS_ERR(ar->firmware)) { ret = PTR_ERR(ar->firmware); ath10k_err("could not fetch firmware (%d)\n", ret); goto err; } /* OTP may be undefined. If so, don't fetch it at all */ if (ar->hw_params.fw.otp == NULL) return 0; ar->otp = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.otp); if (IS_ERR(ar->otp)) { ret = PTR_ERR(ar->otp); ath10k_err("could not fetch otp (%d)\n", ret); goto err; } return 0; err: ath10k_core_free_firmware_files(ar); return ret; } Loading Loading @@ -440,8 +476,35 @@ static int ath10k_init_hw_params(struct ath10k *ar) return 0; } static void ath10k_core_restart(struct work_struct *work) { struct ath10k *ar = container_of(work, struct ath10k, restart_work); mutex_lock(&ar->conf_mutex); switch (ar->state) { case ATH10K_STATE_ON: ath10k_halt(ar); ar->state = ATH10K_STATE_RESTARTING; ieee80211_restart_hw(ar->hw); break; case ATH10K_STATE_OFF: /* this can happen if driver is being unloaded */ ath10k_warn("cannot restart a device that hasn't been started\n"); break; case ATH10K_STATE_RESTARTING: case ATH10K_STATE_RESTARTED: ar->state = ATH10K_STATE_WEDGED; /* fall through */ case ATH10K_STATE_WEDGED: ath10k_warn("device is wedged, will not restart\n"); break; } mutex_unlock(&ar->conf_mutex); } struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, enum ath10k_bus bus, const struct ath10k_hif_ops *hif_ops) { struct ath10k *ar; Loading @@ -458,9 +521,6 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, ar->hif.priv = hif_priv; ar->hif.ops = hif_ops; ar->hif.bus = bus; ar->free_vdev_map = 0xFF; /* 8 vdevs */ init_completion(&ar->scan.started); init_completion(&ar->scan.completed); Loading @@ -487,6 +547,8 @@ struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, init_waitqueue_head(&ar->event_queue); INIT_WORK(&ar->restart_work, ath10k_core_restart); return ar; err_wq: Loading @@ -504,24 +566,11 @@ void ath10k_core_destroy(struct ath10k *ar) } EXPORT_SYMBOL(ath10k_core_destroy); int ath10k_core_register(struct ath10k *ar) int ath10k_core_start(struct ath10k *ar) { struct ath10k_htc_ops htc_ops; struct bmi_target_info target_info; int status; memset(&target_info, 0, sizeof(target_info)); status = ath10k_bmi_get_target_info(ar, &target_info); if (status) goto err; ar->target_version = target_info.version; ar->hw->wiphy->hw_version = target_info.version; status = ath10k_init_hw_params(ar); if (status) goto err; ath10k_bmi_start(ar); if (ath10k_init_configure_target(ar)) { status = -EINVAL; Loading @@ -536,32 +585,32 @@ int ath10k_core_register(struct ath10k *ar) if (status) goto err; htc_ops.target_send_suspend_complete = ath10k_send_suspend_complete; ar->htc.htc_ops.target_send_suspend_complete = ath10k_send_suspend_complete; ar->htc = ath10k_htc_create(ar, &htc_ops); if (IS_ERR(ar->htc)) { status = PTR_ERR(ar->htc); ath10k_err("could not create HTC (%d)\n", status); status = ath10k_htc_init(ar); if (status) { ath10k_err("could not init HTC (%d)\n", status); goto err; } status = ath10k_bmi_done(ar); if (status) goto err_htc_destroy; goto err; status = ath10k_wmi_attach(ar); if (status) { ath10k_err("WMI attach failed: %d\n", status); goto err_htc_destroy; goto err; } status = ath10k_htc_wait_target(ar->htc); status = ath10k_htc_wait_target(&ar->htc); if (status) goto err_wmi_detach; ar->htt = ath10k_htt_attach(ar); if (!ar->htt) { status = -ENOMEM; status = ath10k_htt_attach(ar); if (status) { ath10k_err("could not attach htt (%d)\n", status); goto err_wmi_detach; } Loading @@ -588,77 +637,127 @@ int ath10k_core_register(struct ath10k *ar) goto err_disconnect_htc; } status = ath10k_htt_attach_target(ar->htt); if (status) goto err_disconnect_htc; status = ath10k_mac_register(ar); status = ath10k_htt_attach_target(&ar->htt); if (status) goto err_disconnect_htc; status = ath10k_debug_create(ar); if (status) { ath10k_err("unable to initialize debugfs\n"); goto err_unregister_mac; } ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1; return 0; err_unregister_mac: ath10k_mac_unregister(ar); err_disconnect_htc: ath10k_htc_stop(ar->htc); ath10k_htc_stop(&ar->htc); err_htt_detach: ath10k_htt_detach(ar->htt); ath10k_htt_detach(&ar->htt); err_wmi_detach: ath10k_wmi_detach(ar); err_htc_destroy: ath10k_htc_destroy(ar->htc); err: return status; } EXPORT_SYMBOL(ath10k_core_register); EXPORT_SYMBOL(ath10k_core_start); void ath10k_core_unregister(struct ath10k *ar) void ath10k_core_stop(struct ath10k *ar) { /* We must unregister from mac80211 before we stop HTC and HIF. * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ ath10k_mac_unregister(ar); ath10k_htc_stop(ar->htc); ath10k_htt_detach(ar->htt); ath10k_htc_stop(&ar->htc); ath10k_htt_detach(&ar->htt); ath10k_wmi_detach(ar); ath10k_htc_destroy(ar->htc); } EXPORT_SYMBOL(ath10k_core_unregister); EXPORT_SYMBOL(ath10k_core_stop); int ath10k_core_target_suspend(struct ath10k *ar) /* mac80211 manages fw/hw initialization through start/stop hooks. However in * order to know what hw capabilities should be advertised to mac80211 it is * necessary to load the firmware (and tear it down immediately since start * hook will try to init it again) before registering */ static int ath10k_core_probe_fw(struct ath10k *ar) { int ret; struct bmi_target_info target_info; int ret = 0; ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__); ret = ath10k_hif_power_up(ar); if (ret) { ath10k_err("could not start pci hif (%d)\n", ret); return ret; } ret = ath10k_wmi_pdev_suspend_target(ar); if (ret) ath10k_warn("could not suspend target (%d)\n", ret); memset(&target_info, 0, sizeof(target_info)); ret = ath10k_bmi_get_target_info(ar, &target_info); if (ret) { ath10k_err("could not get target info (%d)\n", ret); ath10k_hif_power_down(ar); return ret; } ar->target_version = target_info.version; ar->hw->wiphy->hw_version = target_info.version; ret = ath10k_init_hw_params(ar); if (ret) { ath10k_err("could not get hw params (%d)\n", ret); ath10k_hif_power_down(ar); return ret; } ret = ath10k_core_fetch_firmware_files(ar); if (ret) { ath10k_err("could not fetch firmware files (%d)\n", ret); ath10k_hif_power_down(ar); return ret; } 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); return ret; } EXPORT_SYMBOL(ath10k_core_target_suspend); int ath10k_core_target_resume(struct ath10k *ar) ath10k_core_stop(ar); ath10k_hif_power_down(ar); return 0; } int ath10k_core_register(struct ath10k *ar) { int ret; int status; ath10k_dbg(ATH10K_DBG_CORE, "%s: called", __func__); status = ath10k_core_probe_fw(ar); if (status) { ath10k_err("could not probe fw (%d)\n", status); return status; } ret = ath10k_wmi_pdev_resume_target(ar); if (ret) ath10k_warn("could not resume target (%d)\n", ret); status = ath10k_mac_register(ar); if (status) { ath10k_err("could not register to mac80211 (%d)\n", status); goto err_release_fw; } return ret; status = ath10k_debug_create(ar); if (status) { ath10k_err("unable to initialize debugfs\n"); goto err_unregister_mac; } return 0; err_unregister_mac: ath10k_mac_unregister(ar); err_release_fw: ath10k_core_free_firmware_files(ar); return status; } EXPORT_SYMBOL(ath10k_core_target_resume); EXPORT_SYMBOL(ath10k_core_register); void ath10k_core_unregister(struct ath10k *ar) { /* We must unregister from mac80211 before we stop HTC and HIF. * Otherwise we will fail to submit commands to FW and mac80211 will be * unhappy about callback failures. */ ath10k_mac_unregister(ar); ath10k_core_free_firmware_files(ar); } EXPORT_SYMBOL(ath10k_core_unregister); MODULE_AUTHOR("Qualcomm Atheros"); MODULE_DESCRIPTION("Core module for QCA988X PCIe devices."); Loading
drivers/net/wireless/ath/ath10k/core.h +36 −14 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <linux/types.h> #include <linux/pci.h> #include "htt.h" #include "htc.h" #include "hw.h" #include "targaddrs.h" Loading @@ -43,10 +44,6 @@ struct ath10k; enum ath10k_bus { ATH10K_BUS_PCI, }; struct ath10k_skb_cb { dma_addr_t paddr; bool is_mapped; Loading Loading @@ -250,6 +247,28 @@ struct ath10k_debug { struct completion event_stats_compl; }; enum ath10k_state { ATH10K_STATE_OFF = 0, ATH10K_STATE_ON, /* When doing firmware recovery the device is first powered down. * mac80211 is supposed to call in to start() hook later on. It is * however possible that driver unloading and firmware crash overlap. * mac80211 can wait on conf_mutex in stop() while the device is * 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(). */ ATH10K_STATE_RESTARTING, ATH10K_STATE_RESTARTED, /* The device has crashed while restarting hw. This state is like ON * but commands are blocked in HTC and -ECOMM response is given. This * prevents completion timeouts and makes the driver more responsive to * userspace commands. This is also prevents recursive recovery. */ ATH10K_STATE_WEDGED, }; struct ath10k { struct ath_common ath_common; struct ieee80211_hw *hw; Loading @@ -274,19 +293,16 @@ struct ath10k { struct { void *priv; enum ath10k_bus bus; const struct ath10k_hif_ops *ops; } hif; struct ath10k_wmi wmi; wait_queue_head_t event_queue; bool is_target_paused; struct ath10k_bmi bmi; struct ath10k_htc *htc; struct ath10k_htt *htt; struct ath10k_wmi wmi; struct ath10k_htc htc; struct ath10k_htt htt; struct ath10k_hw_params { u32 id; Loading @@ -301,6 +317,10 @@ struct ath10k { } fw; } hw_params; const struct firmware *board_data; const struct firmware *otp; const struct firmware *firmware; struct { struct completion started; struct completion completed; Loading Loading @@ -350,20 +370,22 @@ struct ath10k { struct completion offchan_tx_completed; struct sk_buff *offchan_tx_skb; enum ath10k_state state; struct work_struct restart_work; #ifdef CONFIG_ATH10K_DEBUGFS struct ath10k_debug debug; #endif }; struct ath10k *ath10k_core_create(void *hif_priv, struct device *dev, enum ath10k_bus bus, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); int ath10k_core_start(struct ath10k *ar); void ath10k_core_stop(struct ath10k *ar); int ath10k_core_register(struct ath10k *ar); void ath10k_core_unregister(struct ath10k *ar); int ath10k_core_target_suspend(struct ath10k *ar); int ath10k_core_target_resume(struct ath10k *ar); #endif /* _CORE_H_ */