Signed-off-by: Michal Kazior <michal.kaz...@tieto.com> --- drivers/net/wireless/ath/ath10k/core.c | 358 +++++++++++++++++--------------- 1 file changed, 190 insertions(+), 168 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index bf6db39..6b83d29 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -37,12 +37,6 @@ MODULE_PARM_DESC(debug_mask, "Debugging mask"); MODULE_PARM_DESC(uart_print, "Uart target debugging"); MODULE_PARM_DESC(ath10k_p2p, "Enable ath10k P2P support"); -enum ath10k_file { - ATH10K_FILE_OTP, - ATH10K_FILE_FIRMWARE, - ATH10K_FILE_BOARD_DATA, -}; - static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA988X_HW_1_0_VERSION, @@ -183,188 +177,213 @@ static int ath10k_init_configure_target(struct ath10k *ar) return 0; } -static int ath10k_init_transfer_bin_file(struct ath10k *ar, - enum ath10k_file file, - u32 address, bool compressed) +static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar, + const char *dir, + const char *file) { - int status = 0; char filename[100]; - const struct firmware *fw_entry; - u32 fw_entry_size; - u8 *temp_eeprom = NULL, *fw_buf = NULL; - - switch (file) { - default: - ath10k_err("%s: unknown file type\n", __func__); - return -1; - - case ATH10K_FILE_OTP: - if (!ar->hw_params.fw.otp) { - ath10k_err("%s: OTP file not defined\n", __func__); - return -ENOENT; - } - snprintf(filename, sizeof(filename), "%s/%s", - ar->hw_params.fw.dir, ar->hw_params.fw.otp); - break; - - case ATH10K_FILE_FIRMWARE: - if (!ar->hw_params.fw.fw) { - ath10k_err("%s: FW file not defined\n", __func__); - return -ENOENT; - } - snprintf(filename, sizeof(filename), "%s/%s", - ar->hw_params.fw.dir, ar->hw_params.fw.fw); - break; - - case ATH10K_FILE_BOARD_DATA: - if (!ar->hw_params.fw.board) { - ath10k_err("%s: board file not defined\n", __func__); - return -ENOENT; - } - snprintf(filename, sizeof(filename), "%s/%s", - ar->hw_params.fw.dir, ar->hw_params.fw.board); - break; - - } - - if (request_firmware(&fw_entry, filename, ar->dev) != 0) { - if (file == ATH10K_FILE_OTP) - return -ENOENT; - - ath10k_err("%s: failed to get %s\n", __func__, filename); - return -1; - } - - fw_entry_size = fw_entry->size; - fw_buf = (u8 *)fw_entry->data; - - if (file == ATH10K_FILE_BOARD_DATA && fw_entry->data) { - u32 board_ext_address; - - temp_eeprom = kmalloc(fw_entry_size, GFP_ATOMIC); - if (!temp_eeprom) { - ath10k_err("%s: memory allocation failed\n", __func__); - status = -ENOMEM; - goto exit_fw; - } - - memcpy(temp_eeprom, fw_buf, fw_entry_size); - - /* Determine where in Target RAM to write Board Data */ - ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_address); - - ath10k_dbg(ATH10K_DBG_CORE, - "ath10k: Board extended Data download addr: 0x%x\n", - board_ext_address); - - /* - * Check whether the target has allocated memory for extended - * board data and file contains extended board data - */ - if (board_ext_address && (fw_entry_size == (QCA988X_BOARD_DATA_SZ + QCA988X_BOARD_EXT_DATA_SZ))) { - status = ath10k_bmi_write_memory(ar, board_ext_address, - (u8 *)(((unsigned long)temp_eeprom) + QCA988X_BOARD_DATA_SZ), - QCA988X_BOARD_EXT_DATA_SZ); - - if (status != 0) { - ath10k_err("ath10k: BMI operation failed\n"); - goto exit_buf; - } - - /* - * Record the fact that extended board Data IS - * initialized - */ - ath10k_bmi_write32(ar, hi_board_ext_data_config, - (QCA988X_BOARD_EXT_DATA_SZ << 16) | 1); - - fw_entry_size = QCA988X_BOARD_DATA_SZ; - } - } - - if (compressed) - status = ath10k_bmi_fast_download(ar, address, - fw_buf, fw_entry_size); - else { - if (file == ATH10K_FILE_BOARD_DATA && fw_entry->data) - status = ath10k_bmi_write_memory(ar, address, - temp_eeprom, - fw_entry_size); - else - status = ath10k_bmi_write_memory(ar, address, - fw_buf, - fw_entry_size); - } - -exit_buf: - kfree(temp_eeprom); - - if (status != 0) - ath10k_err("BMI operation failed: %d\n", __LINE__); -exit_fw: - release_firmware(fw_entry); - return status; + const struct firmware *fw; + int ret; + + if (file == NULL) + return ERR_PTR(-ENOENT); + + if (dir == NULL) + dir = "."; + + snprintf(filename, sizeof(filename), "%s/%s", dir, file); + ret = request_firmware(&fw, filename, ar->dev); + if (ret) + return ERR_PTR(ret); + + return fw; } -static int ath10k_init_download_firmware(struct ath10k *ar) +static int ath10k_push_board_ext_data(struct ath10k *ar, + const struct firmware *fw) { - u32 param_host, address = 0; - int status; + 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; + } - /* Transfer Board Data from Target EEPROM to Target RAM */ - /* Determine where in Target RAM to write Board Data */ - ath10k_bmi_read32(ar, hi_board_data, &address); + ath10k_dbg(ATH10K_DBG_CORE, + "ath10k: Board extended Data download addr: 0x%x\n", + board_ext_data_addr); - if (!address) { - ath10k_err("Target address not known!\n"); - return -1; + 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 %lu != %d+%d\n", + fw->size, board_data_size, board_ext_data_size); + return -EINVAL; } - /* Write EEPROM data to Target RAM */ - status = ath10k_init_transfer_bin_file(ar, ATH10K_FILE_BOARD_DATA, - address, false); - if (status) { - ath10k_err("boardData file upload failed!\n"); - return status; + 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; } - /* Record the fact that Board Data is initialized */ - ath10k_bmi_write32(ar, hi_board_data_initialized, 1); + return 0; +} + +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_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; + } - /* Transfer One Time Programmable data */ address = ar->hw_params.patch_load_addr; - ath10k_dbg(ATH10K_DBG_CORE, - "Using 0x%x for the remainder of init\n", address); - status = ath10k_init_transfer_bin_file(ar, ATH10K_FILE_OTP, - address, true); - if (status == 0) { - /* Execute the OTP code only if entry found and downloaded */ - param_host = 0; - ath10k_bmi_execute(ar, address, ¶m_host); - } else if (status == -1) - return status; + 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; + } - /* - * Download Target firmware - */ - status = ath10k_init_transfer_bin_file(ar, ATH10K_FILE_FIRMWARE, - address, true); - if (status) { - ath10k_err("firmware upload failed\n"); - return status; + ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size); + if (ret) { + ath10k_err("could not write otp (%d)\n", ret); + goto exit; } - ath10k_dbg(ATH10K_DBG_CORE, "Firmware downloaded\n"); - return 0; + 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_fw(struct ath10k *ar) +{ + const struct firmware *fw; + 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); + goto exit; + } + +exit: + release_firmware(fw); + return ret; +} + +static int ath10k_init_download_firmware(struct ath10k *ar) +{ + int ret; + + ret = ath10k_download_board_data(ar); + if (ret) + return ret; + + ret = ath10k_download_and_run_otp(ar); + if (ret) + return ret; + + ret = ath10k_download_fw(ar); + if (ret) + return ret; + + ath10k_info("firmware downloaded\n"); + return ret; } static int ath10k_init_uart(struct ath10k *ar) { int ret; - /* Explicitly setting UART prints to zero as target turns it on - * based on scratch registers. */ + /* + * Explicitly setting UART prints to zero as target turns it on + * based on scratch registers. + */ ret = ath10k_bmi_write32(ar, hi_serial_enable, 0); if (ret) { ath10k_warn("could not disable UART prints (%d)\n", ret); @@ -507,10 +526,13 @@ int ath10k_core_register(struct ath10k *ar) goto err; } - if (ath10k_init_download_firmware(ar)) { - status = -EIO; + status = ath10k_init_download_firmware(ar); + if (status) + goto err; + + status = ath10k_init_uart(ar); + if (status) goto err; - } status = ath10k_init_uart(ar); if (status) -- 1.7.9.5 _______________________________________________ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel