--- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -573,6 +573,29 @@ static void ath11k_ahb_power_down(struct rproc_shutdown(ab->tgt_rproc); } +int ath11k_ahb_fwreset_from_cold_boot(struct ath11k_base *ab) +{ + int timeout; + + if (enable_cold_boot_cal == 0 || ab->qmi.cal_done) + return 0; + + ath11k_dbg(ab, ATH11K_DBG_AHB, "wait for cold boot done\n"); + timeout = wait_event_timeout(ab->qmi.cold_boot_waitq, (ab->qmi.cal_done == 1), + ATH11K_COLD_BOOT_FW_RESET_DELAY); + if (timeout <= 0) { + ath11k_warn(ab, "Coldboot Calibration timed out\n"); + return -ETIMEDOUT; + } + + /* reset the firmware */ + ath11k_ahb_power_down(ab); + ath11k_ahb_power_up(ab); + ath11k_dbg(ab, ATH11K_DBG_AHB, "exit wait for cold boot done\n"); + + return 0; +} + static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab) { struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; @@ -911,6 +934,8 @@ static int ath11k_ahb_probe(struct platf goto err_ce_free; } + ath11k_ahb_fwreset_from_cold_boot(ab); + return 0; err_ce_free: --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -107,8 +107,12 @@ enum ath11k_firmware_mode { /* factory tests etc */ ATH11K_FIRMWARE_MODE_FTM, + + /* Cold boot calibration */ + ATH11K_FIRMWARE_MODE_COLD_BOOT = 7, }; +extern bool enable_cold_boot_cal; #define ATH11K_IRQ_NUM_MAX 52 #define ATH11K_EXT_IRQ_NUM_MAX 16 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -12,6 +12,12 @@ #define SLEEP_CLOCK_SELECT_INTERNAL_BIT 0x02 #define HOST_CSTATE_BIT 0x04 +/* set the default max assoc sta to max supported by driver */ +bool enable_cold_boot_cal = 1; +EXPORT_SYMBOL(enable_cold_boot_cal); +module_param(enable_cold_boot_cal, bool, 0644); +MODULE_PARM_DESC(enable_cold_boot_cal, "cold boot calibration enable:1 disable:0"); + static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, @@ -1752,6 +1758,7 @@ static int ath11k_qmi_alloc_target_mem_c static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) { int i, idx; + u32 caldb_location[2] = {0, 0}; for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) { switch (ab->qmi.target_mem[i].type) { @@ -1767,9 +1774,20 @@ static int ath11k_qmi_assign_target_mem_ ath11k_warn(ab, "qmi mem size is low to load caldata\n"); return -EINVAL; } - /* TODO ath11k does not support cold boot calibration */ - ab->qmi.target_mem[idx].paddr = 0; - ab->qmi.target_mem[idx].vaddr = NULL; + + if (of_property_read_u32_array(ab->dev->of_node, "qcom,caldb-addr", + &caldb_location[0], + ARRAY_SIZE(caldb_location))) { + ath11k_warn(ab, "qmi no bdf_addr in device_tree\n"); + } + + if (enable_cold_boot_cal) { + ab->qmi.target_mem[idx].paddr = caldb_location[ab->qmi.target_mem_mode]; + ab->qmi.target_mem[idx].vaddr = caldb_location[ab->qmi.target_mem_mode]; + } else { + ab->qmi.target_mem[idx].paddr = 0; + ab->qmi.target_mem[idx].vaddr = 0; + } ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size; ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type; idx++; @@ -2331,6 +2349,30 @@ int ath11k_qmi_firmware_start(struct ath return 0; } +int ath11k_qmi_process_coldboot_calibration(struct ath11k_base *ab) +{ + int ret; + int timeout; + + ret = ath11k_qmi_wlanfw_mode_send(ab, ATH11K_FIRMWARE_MODE_COLD_BOOT); + if (ret < 0) { + ath11k_warn(ab, "qmi failed to send wlan fw mode:%d\n", ret); + return ret; + } + + ath11k_info(ab, "Coldboot calibration wait started\n"); + timeout = wait_event_timeout(ab->qmi.cold_boot_waitq, (ab->qmi.cal_done == 1), + ATH11K_COLD_BOOT_FW_RESET_DELAY); + if (timeout <= 0) { + ath11k_warn(ab, "Coldboot Calibration timed out\n"); + return -ETIMEDOUT; + } + + ath11k_info(ab, "Coldboot calibration wait ended\n"); + + return 0; +} + static int ath11k_qmi_driver_event_post(struct ath11k_qmi *qmi, enum ath11k_qmi_event_type type, @@ -2480,11 +2522,17 @@ static void ath11k_qmi_msg_fw_ready_cb(s ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_FW_READY, NULL); } -static void ath11k_qmi_msg_cold_boot_cal_done_cb(struct qmi_handle *qmi, +static void ath11k_qmi_msg_cold_boot_cal_done_cb(struct qmi_handle *qmi_hdl, struct sockaddr_qrtr *sq, struct qmi_txn *txn, const void *decoded) { + struct ath11k_qmi *qmi = container_of(qmi_hdl, struct ath11k_qmi, handle); + struct ath11k_base *ab = qmi->ab; + + ab->qmi.cal_done = 1; + wake_up(&ab->qmi.cold_boot_waitq); + ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi cold boot calibration done\n"); } static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = { @@ -2596,11 +2644,14 @@ static void ath11k_qmi_driver_event_work queue_work(ab->workqueue, &ab->restart_work); break; } - - ath11k_core_qmi_firmware_ready(ab); - ab->qmi.cal_done = 1; - set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags); - + if (enable_cold_boot_cal && ab->qmi.cal_done == 0) { + ath11k_qmi_process_coldboot_calibration(ab); + } else { + clear_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags); + clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags); + ath11k_core_qmi_firmware_ready(ab); + set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags); + } break; case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE: break; --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -33,6 +33,7 @@ #define QMI_WLANFW_MAX_DATA_SIZE_V01 6144 #define ATH11K_FIRMWARE_MODE_OFF 4 #define ATH11K_QMI_TARGET_MEM_MODE_DEFAULT 0 +#define ATH11K_COLD_BOOT_FW_RESET_DELAY (40 * HZ) struct ath11k_base; @@ -125,6 +126,7 @@ struct ath11k_qmi { struct target_info target; struct m3_mem_region m3_mem; unsigned int service_ins_id; + wait_queue_head_t cold_boot_waitq; }; #define QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN 189 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -901,6 +901,7 @@ struct ath11k_base *ath11k_core_alloc(st INIT_LIST_HEAD(&ab->peers); init_waitqueue_head(&ab->peer_mapping_wq); init_waitqueue_head(&ab->wmi_ab.tx_credits_wq); + init_waitqueue_head(&ab->qmi.cold_boot_waitq); INIT_WORK(&ab->restart_work, ath11k_core_restart); timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); ab->dev = dev;