static int ath10k_init_hw_params(struct ath10k *ar) { const struct ath10k_hw_params *uninitialized_var(hw_params); int i; for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) { hw_params = &ath10k_hw_params_list[i]; if (hw_params->id == ar->target_version) break; } if (i == ARRAY_SIZE(ath10k_hw_params_list)) { ath10k_err("Unsupported hardware version: 0x%x\n", ar->target_version); return -EINVAL; } ar->hw_params = *hw_params; ath10k_info("Hardware name %s version 0x%x\n", ar->hw_params.name, ar->target_version); return 0; }
/* registered target arrival callback from the HIF layer */ int ath10k_htc_init(struct ath10k *ar) { int status; struct ath10k_htc *htc = &ar->htc; struct ath10k_htc_svc_conn_req conn_req; struct ath10k_htc_svc_conn_resp conn_resp; spin_lock_init(&htc->tx_lock); ath10k_htc_reset_endpoint_states(htc); htc->ar = ar; /* setup our pseudo HTC control endpoint connection */ memset(&conn_req, 0, sizeof(conn_req)); memset(&conn_resp, 0, sizeof(conn_resp)); conn_req.ep_ops.ep_tx_complete = ath10k_htc_control_tx_complete; conn_req.ep_ops.ep_rx_complete = ath10k_htc_control_rx_complete; conn_req.max_send_queue_depth = ATH10K_NUM_CONTROL_TX_BUFFERS; conn_req.service_id = ATH10K_HTC_SVC_ID_RSVD_CTRL; /* connect fake service */ status = ath10k_htc_connect_service(htc, &conn_req, &conn_resp); if (status) { ath10k_err(ar, "could not connect to htc service (%d)\n", status); return status; } init_completion(&htc->ctl_resp); return 0; }
static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data, size_t data_len) { u32 board_data_size = ar->hw_params.fw.board_size; u32 board_ext_data_size = ar->hw_params.fw.board_ext_size; u32 board_ext_data_addr; int ret; ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr); if (ret) { ath10k_err(ar, "could not read board ext data addr (%d)\n", ret); return ret; } ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot push board extended data addr 0x%x\n", board_ext_data_addr); if (board_ext_data_addr == 0) return 0; if (data_len != (board_data_size + board_ext_data_size)) { ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n", data_len, board_data_size, board_ext_data_size); return -EINVAL; } ret = ath10k_bmi_write_memory(ar, board_ext_data_addr, data + board_data_size, board_ext_data_size); if (ret) { ath10k_err(ar, "could not write board ext data (%d)\n", ret); return ret; } ret = ath10k_bmi_write32(ar, hi_board_ext_data_config, (board_ext_data_size << 16) | 1); if (ret) { ath10k_err(ar, "could not write board ext data bit (%d)\n", ret); return ret; } return 0; }
static int ath10k_download_and_run_otp(struct ath10k *ar) { u32 result, address = ar->hw_params.patch_load_addr; u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param; 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) { ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n", ar->otp_data, ar->otp_len); return 0; } ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", address, ar->otp_len); ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); if (ret) { ath10k_err(ar, "could not write otp (%d)\n", ret); return ret; } ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); if (ret) { ath10k_err(ar, "could not execute otp (%d)\n", ret); return ret; } ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, ar->fw_features)) && result != 0) { ath10k_err(ar, "otp calibration failed: %d", result); return -EINVAL; } return 0; }
static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode) { u32 address, data_len; const char *mode_name; const void *data; int ret; address = ar->hw_params.patch_load_addr; switch (mode) { case ATH10K_FIRMWARE_MODE_NORMAL: data = ar->firmware_data; data_len = ar->firmware_len; mode_name = "normal"; ret = ath10k_swap_code_seg_configure(ar, ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW); if (ret) { ath10k_err(ar, "failed to configure fw code swap: %d\n", ret); return ret; } break; case ATH10K_FIRMWARE_MODE_UTF: data = ar->testmode.utf->data; data_len = ar->testmode.utf->size; mode_name = "utf"; break; default: ath10k_err(ar, "unknown firmware mode: %d\n", mode); return -EINVAL; } ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot uploading firmware image %p len %d mode %s\n", data, data_len, mode_name); ret = ath10k_bmi_fast_download(ar, address, data, data_len); if (ret) { ath10k_err(ar, "failed to download %s firmware: %d\n", mode_name, ret); return ret; } return ret; }
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; u32 board_ext_data_addr; int ret; ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr); if (ret) { ath10k_err(ar, "could not read board ext data addr (%d)\n", ret); return ret; } ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot push board extended data addr 0x%x\n", board_ext_data_addr); if (board_ext_data_addr == 0) return 0; if (ar->board_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); return -EINVAL; } ret = ath10k_bmi_write_memory(ar, board_ext_data_addr, ar->board_data + board_data_size, board_ext_data_size); if (ret) { ath10k_err(ar, "could not write board ext data (%d)\n", ret); return ret; } ret = ath10k_bmi_write32(ar, hi_board_ext_data_config, (board_ext_data_size << 16) | 1); if (ret) { ath10k_err(ar, "could not write board ext data bit (%d)\n", ret); return ret; } return 0; }
/* * Initialize a Copy Engine based on caller-supplied attributes. * This may be called once to initialize both source and destination * rings or it may be called twice for separate source and destination * initialization. It may be that only one side or the other is * initialized by software/firmware. */ struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar, unsigned int ce_id, const struct ce_attr *attr) { struct ath10k_ce_pipe *ce_state; u32 ctrl_addr = ath10k_ce_base_address(ce_id); int ret; ret = ath10k_pci_wake(ar); if (ret) return NULL; ce_state = ath10k_ce_init_state(ar, ce_id, attr); if (!ce_state) { ath10k_err("Failed to initialize CE state for ID: %d\n", ce_id); return NULL; } if (attr->src_nentries) { ret = ath10k_ce_init_src_ring(ar, ce_id, ce_state, attr); if (ret) { ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n", ce_id, ret); ath10k_ce_deinit(ce_state); return NULL; } } if (attr->dest_nentries) { ret = ath10k_ce_init_dest_ring(ar, ce_id, ce_state, attr); if (ret) { ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n", ce_id, ret); ath10k_ce_deinit(ce_state); return NULL; } } /* Enable CE error interrupts */ ath10k_ce_error_intr_enable(ar, ctrl_addr); ath10k_pci_sleep(ar); return ce_state; }
/* * Setup the driver side of the list allocations and insert them * all into the inactive list. */ int athp_alloc_list(struct ath10k *ar, struct athp_buf_ring *br, int count, int btype) { int i; int ret; /* Allocate initial buffer list */ br->br_list = malloc(sizeof(struct athp_buf) * count, M_ATHPDEV, M_ZERO | M_NOWAIT); br->btype = btype; if (br->br_list == NULL) { ath10k_err(ar, "%s: malloc failed!\n", __func__); return (-1); } /* Setup initial state for each entry */ for (i = 0; i < count; i++) { athp_dma_mbuf_setup(ar, &br->dh, &br->br_list[i].mb); br->br_list[i].btype = btype; if (btype == BUF_TYPE_TX) { ret = athp_descdma_alloc(ar, &br->br_list[i].txbuf_dd, "htt_txbuf", 4, sizeof (struct ath10k_htt_txbuf)); if (ret != 0) { ath10k_err(ar, "%s: descdma alloc failed: %d\n", __func__, ret); goto fail; } } } /* Lists */ TAILQ_INIT(&br->br_inactive); for (i = 0; i < count; i++) TAILQ_INSERT_HEAD(&br->br_inactive, &br->br_list[i], next); return (0); fail: athp_free_list(ar, br); return (ENXIO); }
static int ath10k_ahb_clock_enable(struct ath10k *ar) { struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); struct device *dev; int ret; dev = &ar_ahb->pdev->dev; if (IS_ERR_OR_NULL(ar_ahb->cmd_clk) || IS_ERR_OR_NULL(ar_ahb->ref_clk) || IS_ERR_OR_NULL(ar_ahb->rtc_clk)) { ath10k_err(ar, "clock(s) is/are not initialized\n"); ret = -EIO; goto out; } ret = clk_prepare_enable(ar_ahb->cmd_clk); if (ret) { ath10k_err(ar, "failed to enable cmd clk: %d\n", ret); goto out; } ret = clk_prepare_enable(ar_ahb->ref_clk); if (ret) { ath10k_err(ar, "failed to enable ref clk: %d\n", ret); goto err_cmd_clk_disable; } ret = clk_prepare_enable(ar_ahb->rtc_clk); if (ret) { ath10k_err(ar, "failed to enable rtc clk: %d\n", ret); goto err_ref_clk_disable; } return 0; err_ref_clk_disable: clk_disable_unprepare(ar_ahb->ref_clk); err_cmd_clk_disable: clk_disable_unprepare(ar_ahb->cmd_clk); out: return ret; }
static void ath10k_core_register_work(struct work_struct *work) { struct ath10k *ar = container_of(work, struct ath10k, register_work); int status; status = ath10k_core_probe_fw(ar); if (status) { ath10k_err(ar, "could not probe fw (%d)\n", status); goto err; } status = ath10k_mac_register(ar); if (status) { ath10k_err(ar, "could not register to mac80211 (%d)\n", status); goto err_release_fw; } status = ath10k_debug_register(ar); if (status) { ath10k_err(ar, "unable to initialize debugfs\n"); goto err_unregister_mac; } status = ath10k_spectral_create(ar); if (status) { ath10k_err(ar, "failed to initialize spectral\n"); goto err_debug_destroy; } set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags); return; err_debug_destroy: ath10k_debug_destroy(ar); err_unregister_mac: ath10k_mac_unregister(ar); err_release_fw: ath10k_core_free_firmware_files(ar); err: /* TODO: It's probably a good idea to release device from the driver * but calling device_release_driver() here will cause a deadlock. */ return; }
static int ath10k_download_board_data(struct ath10k *ar) { 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); goto exit; } ret = ath10k_bmi_read32(ar, hi_board_data, &address); if (ret) { ath10k_err("could not read board data addr (%d)\n", ret); goto exit; } ret = ath10k_bmi_write_memory(ar, address, fw->data, min_t(u32, board_data_size, fw->size)); if (ret) { ath10k_err("could not write board data (%d)\n", ret); goto exit; } ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1); if (ret) { ath10k_err("could not write board data bit (%d)\n", ret); goto exit; } exit: release_firmware(fw); return ret; }
static int ath10k_push_board_ext_data(struct ath10k *ar, const struct firmware *fw) { u32 board_data_size = QCA988X_BOARD_DATA_SZ; u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ; u32 board_ext_data_addr; int ret; ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr); if (ret) { ath10k_err("could not read board ext data addr (%d)\n", ret); return ret; } ath10k_dbg(ATH10K_DBG_CORE, "ath10k: Board extended Data download addr: 0x%x\n", board_ext_data_addr); if (board_ext_data_addr == 0) return 0; if (fw->size != (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); return -EINVAL; } ret = ath10k_bmi_write_memory(ar, board_ext_data_addr, fw->data + board_data_size, board_ext_data_size); if (ret) { ath10k_err("could not write board ext data (%d)\n", ret); return ret; } ret = ath10k_bmi_write32(ar, hi_board_ext_data_config, (board_ext_data_size << 16) | 1); if (ret) { ath10k_err("could not write board ext data bit (%d)\n", ret); return ret; } return 0; }
static int ath10k_ahb_clock_init(struct ath10k *ar) { struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); struct device *dev; int ret; dev = &ar_ahb->pdev->dev; ar_ahb->cmd_clk = clk_get(dev, "wifi_wcss_cmd"); if (IS_ERR_OR_NULL(ar_ahb->cmd_clk)) { ath10k_err(ar, "failed to get cmd clk: %ld\n", PTR_ERR(ar_ahb->cmd_clk)); ret = ar_ahb->cmd_clk ? PTR_ERR(ar_ahb->cmd_clk) : -ENODEV; goto out; } ar_ahb->ref_clk = clk_get(dev, "wifi_wcss_ref"); if (IS_ERR_OR_NULL(ar_ahb->ref_clk)) { ath10k_err(ar, "failed to get ref clk: %ld\n", PTR_ERR(ar_ahb->ref_clk)); ret = ar_ahb->ref_clk ? PTR_ERR(ar_ahb->ref_clk) : -ENODEV; goto err_cmd_clk_put; } ar_ahb->rtc_clk = clk_get(dev, "wifi_wcss_rtc"); if (IS_ERR_OR_NULL(ar_ahb->rtc_clk)) { ath10k_err(ar, "failed to get rtc clk: %ld\n", PTR_ERR(ar_ahb->rtc_clk)); ret = ar_ahb->rtc_clk ? PTR_ERR(ar_ahb->rtc_clk) : -ENODEV; goto err_ref_clk_put; } return 0; err_ref_clk_put: clk_put(ar_ahb->ref_clk); err_cmd_clk_put: clk_put(ar_ahb->cmd_clk); out: return ret; }
static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar) { int ret = 0; if (ar->hw_params.fw.fw == NULL) { ath10k_err(ar, "firmware file not defined\n"); return -EINVAL; } 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(ar, "could not fetch firmware (%d)\n", ret); 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; 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(ar, "could not fetch otp (%d)\n", ret); 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_files(struct ath10k *ar) { int ret; /* calibration file is optional, don't check for any errors */ ath10k_fetch_cal_file(ar); ret = ath10k_core_fetch_board_file(ar); if (ret) { ath10k_err(ar, "failed to fetch board file: %d\n", ret); return ret; } ar->fw_api = 5; ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API5_FILE); if (ret == 0) goto success; ar->fw_api = 4; ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API4_FILE); if (ret == 0) goto success; ar->fw_api = 3; ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE); if (ret == 0) goto success; ar->fw_api = 2; ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE); if (ret == 0) goto success; ar->fw_api = 1; ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api); ret = ath10k_core_fetch_firmware_api_1(ar); if (ret) return ret; success: ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api); return 0; }
static int ath10k_download_and_run_otp(struct ath10k *ar) { const struct firmware *fw; u32 address; 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)); return 0; } ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); if (ret) { ath10k_err("could not write otp (%d)\n", ret); goto exit; } exec_param = 0; ret = ath10k_bmi_execute(ar, address, &exec_param); if (ret) { ath10k_err("could not execute otp (%d)\n", ret); goto exit; } exit: release_firmware(fw); return ret; }
static int ath10k_download_and_run_otp(struct ath10k *ar) { u32 result, address = ar->hw_params.patch_load_addr; int ret; /* OTP is optional */ if (!ar->otp_data || !ar->otp_len) { ath10k_warn("Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n", ar->otp_data, ar->otp_len); return 0; } ath10k_dbg(ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", address, ar->otp_len); ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len); if (ret) { ath10k_err("could not write otp (%d)\n", ret); return ret; } ret = ath10k_bmi_execute(ar, address, 0, &result); if (ret) { ath10k_err("could not execute otp (%d)\n", ret); return ret; } ath10k_dbg(ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); if (result == 2) { ath10k_warn("otp stream is empty, using board.bin contents"); return 0; } else if (result != 0) { ath10k_err("otp calibration failed: %d", result); return -EINVAL; } return 0; }
static int ath10k_ahb_release_reset(struct ath10k *ar) { struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); int ret; if (IS_ERR_OR_NULL(ar_ahb->radio_cold_rst) || IS_ERR_OR_NULL(ar_ahb->radio_warm_rst) || IS_ERR_OR_NULL(ar_ahb->radio_srif_rst) || IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) { ath10k_err(ar, "rst ctrl(s) is/are not initialized\n"); return -EINVAL; } ret = reset_control_deassert(ar_ahb->radio_cold_rst); if (ret) { ath10k_err(ar, "failed to deassert radio cold rst: %d\n", ret); return ret; } ret = reset_control_deassert(ar_ahb->radio_warm_rst); if (ret) { ath10k_err(ar, "failed to deassert radio warm rst: %d\n", ret); return ret; } ret = reset_control_deassert(ar_ahb->radio_srif_rst); if (ret) { ath10k_err(ar, "failed to deassert radio srif rst: %d\n", ret); return ret; } ret = reset_control_deassert(ar_ahb->cpu_init_rst); if (ret) { ath10k_err(ar, "failed to deassert cpu init rst: %d\n", ret); return ret; } return 0; }
void ath10k_ce_dump_registers(struct ath10k *ar, struct ath10k_fw_crash_data *crash_data) { struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); struct ath10k_ce_crash_data ce; u32 addr, id; lockdep_assert_held(&ar->data_lock); ath10k_err(ar, "Copy Engine register dump:\n"); spin_lock_bh(&ar_pci->ce_lock); for (id = 0; id < CE_COUNT; id++) { addr = ath10k_ce_base_address(ar, id); ce.base_addr = cpu_to_le32(addr); ce.src_wr_idx = cpu_to_le32(ath10k_ce_src_ring_write_index_get(ar, addr)); ce.src_r_idx = cpu_to_le32(ath10k_ce_src_ring_read_index_get(ar, addr)); ce.dst_wr_idx = cpu_to_le32(ath10k_ce_dest_ring_write_index_get(ar, addr)); ce.dst_r_idx = cpu_to_le32(ath10k_ce_dest_ring_read_index_get(ar, addr)); if (crash_data) crash_data->ce_crash_data[id] = ce; ath10k_err(ar, "[%02d]: 0x%08x %3u %3u %3u %3u", id, le32_to_cpu(ce.base_addr), le32_to_cpu(ce.src_wr_idx), le32_to_cpu(ce.src_r_idx), le32_to_cpu(ce.dst_wr_idx), le32_to_cpu(ce.dst_r_idx)); } spin_unlock_bh(&ar_pci->ce_lock); }
static int ath10k_ahb_hif_power_up(struct ath10k *ar, enum ath10k_firmware_mode fw_mode) { int ret; ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif power up\n"); ret = ath10k_ahb_chip_reset(ar); if (ret) { ath10k_err(ar, "failed to reset chip: %d\n", ret); goto out; } ret = ath10k_pci_init_pipes(ar); if (ret) { ath10k_err(ar, "failed to initialize CE: %d\n", ret); goto out; } ret = ath10k_pci_init_config(ar); if (ret) { ath10k_err(ar, "failed to setup init config: %d\n", ret); goto err_ce_deinit; } ret = ath10k_ahb_wake_target_cpu(ar); if (ret) { ath10k_err(ar, "could not wake up target CPU: %d\n", ret); goto err_ce_deinit; } return 0; err_ce_deinit: ath10k_pci_ce_deinit(ar); out: return ret; }
int ath10k_core_register(struct ath10k *ar, u32 chip_id) { int status; ar->chip_id = chip_id; status = ath10k_core_check_chip_id(ar); if (status) { ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id); return status; } status = ath10k_core_probe_fw(ar); if (status) { ath10k_err("could not probe fw (%d)\n", status); return status; } status = ath10k_mac_register(ar); if (status) { ath10k_err("could not register to mac80211 (%d)\n", status); goto err_release_fw; } 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; }
static int ath10k_htt_verify_version(struct ath10k_htt *htt) { ath10k_dbg(ATH10K_DBG_BOOT, "htt target version %d.%d\n", htt->target_version_major, htt->target_version_minor); if (htt->target_version_major != 2 && htt->target_version_major != 3) { ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n", htt->target_version_major); return -ENOTSUPP; } return 0; }
int athp_ioctl_setup(struct ath10k *ar) { ar->sc_cdev = make_dev(&athp_cdevsw, device_get_unit(ar->sc_dev), UID_ROOT, GID_WHEEL, 0600, "%s", device_get_nameunit(ar->sc_dev)); if (ar->sc_cdev == NULL) { ath10k_err(ar, "%s: failed to create ioctl node\n", __func__); return (-1); } ar->sc_cdev->si_drv1 = ar; return (0); }
void athp_freebuf(struct ath10k *ar, struct athp_buf_ring *br, struct athp_buf *bf) { struct ath10k_skb_cb *cb = ATH10K_SKB_CB(bf); /* Complain if the buffer has a noderef left */ if (cb->ni != NULL) { ath10k_err(ar, "%s: TODO: pbuf=%p, mbuf=%p, ni is not null (%p) !\n", __func__, bf, bf->m, cb->ni); } ATHP_BUF_LOCK(ar); if (br->btype != bf->btype) { ath10k_err(ar, "%s: ERROR: bf=%p, bf btype=%d, ring btype=%d\n", __func__, bf, bf->btype, br->btype); } ath10k_dbg(ar, ATH10K_DBG_PBUF, "%s: br=%d, m=%p, bf=%p, paddr=0x%lx\n", __func__, br->btype, bf->m, bf, bf->mb.paddr); /* if there's an mbuf - unmap (if needed) and free it */ if (bf->m != NULL) _athp_free_buf(ar, br, bf); /* Push it into the inactive queue */ TAILQ_INSERT_TAIL(&br->br_inactive, bf, next); ATHP_BUF_UNLOCK(ar); }
static int ath10k_download_board_data(struct ath10k *ar, const void *data, size_t data_len) { u32 board_data_size = ar->hw_params.fw.board_size; u32 address; int ret; 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; } ret = ath10k_bmi_read32(ar, hi_board_data, &address); if (ret) { ath10k_err(ar, "could not read board data addr (%d)\n", ret); goto exit; } ret = ath10k_bmi_write_memory(ar, address, data, min_t(u32, board_data_size, data_len)); if (ret) { ath10k_err(ar, "could not write board data (%d)\n", ret); goto exit; } ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1); if (ret) { ath10k_err(ar, "could not write board data bit (%d)\n", ret); goto exit; } exit: return ret; }
static int ath10k_init_download_firmware(struct ath10k *ar) { int ret; ret = ath10k_download_board_data(ar); if (ret) { ath10k_err("failed to download board data: %d\n", ret); return ret; } ret = ath10k_download_and_run_otp(ar); if (ret) { ath10k_err("failed to run otp: %d\n", ret); return ret; } ret = ath10k_download_fw(ar); if (ret) { ath10k_err("failed to download firmware: %d\n", ret); return ret; } return ret; }
static struct ath10k_swap_code_seg_info * ath10k_swap_code_seg_alloc(struct ath10k *ar, size_t swap_bin_len) { struct ath10k_swap_code_seg_info *seg_info; void *virt_addr; dma_addr_t paddr; swap_bin_len = roundup(swap_bin_len, 2); if (swap_bin_len > ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX) { ath10k_err(ar, "refusing code swap bin because it is too big %zu > %d\n", swap_bin_len, ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX); return NULL; } seg_info = devm_kzalloc(ar->dev, sizeof(*seg_info), GFP_KERNEL); if (!seg_info) return NULL; virt_addr = dma_alloc_coherent(ar->dev, swap_bin_len, &paddr, GFP_KERNEL); if (!virt_addr) { ath10k_err(ar, "failed to allocate dma coherent memory\n"); return NULL; } seg_info->seg_hw_info.bus_addr[0] = __cpu_to_le32(paddr); seg_info->seg_hw_info.size = __cpu_to_le32(swap_bin_len); seg_info->seg_hw_info.swap_size = __cpu_to_le32(swap_bin_len); seg_info->seg_hw_info.num_segs = __cpu_to_le32(ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED); seg_info->seg_hw_info.size_log2 = __cpu_to_le32(ilog2(swap_bin_len)); seg_info->virt_address[0] = virt_addr; seg_info->paddr[0] = paddr; return seg_info; }
int ath10k_core_register(struct ath10k *ar, u32 chip_id) { int status; ar->chip_id = chip_id; status = ath10k_core_check_chip_id(ar); if (status) { ath10k_err(ar, "Unsupported chip id 0x%08x\n", ar->chip_id); return status; } queue_work(ar->workqueue, &ar->register_work); return 0; }
static int ath10k_download_fw(struct ath10k *ar) { u32 address; int ret; address = ar->hw_params.patch_load_addr; 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; } exit: return ret; }
static int ath10k_core_fetch_generic_board_file(struct ath10k *ar) { if (!ar->hw_params.fw.board) { ath10k_err(ar, "failed to find board file fw entry\n"); return -EINVAL; } ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, ar->hw_params.fw.board); if (IS_ERR(ar->board)) return PTR_ERR(ar->board); ar->board_data = ar->board->data; ar->board_len = ar->board->size; ar->spec_board_loaded = false; return 0; }