Commit 02f9d3c1 authored by Govindaraj Saminathan's avatar Govindaraj Saminathan Committed by Kalle Valo
Browse files

ath11k: cold boot calibration support



cold boot calibration is the process to calibrate all the channels
during the boot-up to avoid the calibration delay during the
channel change.
During the boot-up, firmware started in cold boot calibration mode
Firmware calibrate all channels and generate CalDb(DDR).
Subsequent wifi bringup will reuse the same CalDb.
Firmware is restarted in normal mode to continue the normal operation.

caldb memory address send to firmware through the QMI message.Firmware
use this address to store the caldb data and use it until next reboot.

This will give the improvement during the channel change. But it is
increasing the boot-up time(up to 15sec depend on number of radios).
So if the user want to reduce the boot-up time and accepting for channel
change delay, user can disable this feature using the module param
cold_boot_cal=0.

Tested-on: IPQ8074 WLAN.HK.2.4.0.1-01162-QCAHKSWPL_SILICONZ-1

Signed-off-by: default avatarGovindaraj Saminathan <gsamin@codeaurora.org>
Co-developed-by: default avatarSowmiya Sree Elavalagan <ssreeela@codeaurora.org>
Signed-off-by: default avatarSowmiya Sree Elavalagan <ssreeela@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/1602862111-14063-1-git-send-email-ssreeela@codeaurora.org
parent 14f43c5f
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -340,6 +340,31 @@ static void ath11k_ahb_power_down(struct ath11k_base *ab)
	rproc_shutdown(ab_ahb->tgt_rproc);
}

static int ath11k_ahb_fwreset_from_cold_boot(struct ath11k_base *ab)
{
	int timeout;

	if (ath11k_cold_boot_cal == 0 || ab->qmi.cal_done ||
	    ab->hw_params.cold_boot_calib == 0)
		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_cold_boot_cal = 0;
		ath11k_warn(ab, "Coldboot Calibration failed timed out\n");
	}

	/* reset the firmware */
	ath11k_ahb_power_down(ab);
	ath11k_ahb_power_up(ab);

	ath11k_dbg(ab, ATH11K_DBG_AHB, "exited from cold boot mode\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;
@@ -700,6 +725,8 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
		goto err_ce_free;
	}

	ath11k_ahb_fwreset_from_cold_boot(ab);

	return 0;

err_ce_free:
+4 −0
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
		.supports_monitor = true,
		.supports_shadow_regs = false,
		.idle_ps = false,
		.cold_boot_calib = true,
	},
	{
		.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -103,6 +104,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
		.supports_monitor = true,
		.supports_shadow_regs = false,
		.idle_ps = false,
		.cold_boot_calib = true,
	},
	{
		.name = "qca6390 hw2.0",
@@ -139,6 +141,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
		.supports_monitor = false,
		.supports_shadow_regs = true,
		.idle_ps = true,
		.cold_boot_calib = false,
	},
};

@@ -954,6 +957,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
	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;
+5 −0
Original line number Diff line number Diff line
@@ -111,8 +111,13 @@ enum ath11k_firmware_mode {

	/* factory tests etc */
	ATH11K_FIRMWARE_MODE_FTM,

	/* Cold boot calibration */
	ATH11K_FIRMWARE_MODE_COLD_BOOT = 7,
};

extern bool ath11k_cold_boot_cal;

#define ATH11K_IRQ_NUM_MAX 52
#define ATH11K_EXT_IRQ_NUM_MAX	16

+1 −0
Original line number Diff line number Diff line
@@ -161,6 +161,7 @@ struct ath11k_hw_params {
	bool supports_monitor;
	bool supports_shadow_regs;
	bool idle_ps;
	bool cold_boot_calib;
};

struct ath11k_hw_ops {
+60 −7
Original line number Diff line number Diff line
@@ -14,6 +14,12 @@
#define SLEEP_CLOCK_SELECT_INTERNAL_BIT	0x02
#define HOST_CSTATE_BIT			0x04

bool ath11k_cold_boot_cal = 1;
EXPORT_SYMBOL(ath11k_cold_boot_cal);
module_param_named(cold_boot_cal, ath11k_cold_boot_cal, bool, 0644);
MODULE_PARM_DESC(cold_boot_cal,
		 "Decrease the channel switch time but increase the driver load time (Default: true)");

static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = {
	{
		.data_type	= QMI_OPT_FLAG,
@@ -1769,9 +1775,16 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
				ath11k_warn(ab, "qmi mem size is low to load caldata\n");
				return -EINVAL;
			}
			/* TODO ath11k does not support cold boot calibration */

			if (ath11k_cold_boot_cal && ab->hw_params.cold_boot_calib) {
				ab->qmi.target_mem[idx].paddr =
						     ATH11K_QMI_CALDB_ADDRESS;
				ab->qmi.target_mem[idx].vaddr =
						     (void *)ATH11K_QMI_CALDB_ADDRESS;
			} else {
				ab->qmi.target_mem[idx].paddr = 0;
				ab->qmi.target_mem[idx].vaddr = NULL;
			}
			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++;
@@ -2357,6 +2370,32 @@ int ath11k_qmi_firmware_start(struct ath11k_base *ab,
	return 0;
}

static int ath11k_qmi_process_coldboot_calibration(struct ath11k_base *ab)
{
	int timeout;
	int ret;

	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_dbg(ab, ATH11K_DBG_QMI, "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 failed - wait ended\n");
		return 0;
	}

	ath11k_dbg(ab, ATH11K_DBG_QMI, "Coldboot calibration done\n");

	return 0;
}

static int
ath11k_qmi_driver_event_post(struct ath11k_qmi *qmi,
			     enum ath11k_qmi_event_type type,
@@ -2506,11 +2545,18 @@ static void ath11k_qmi_msg_fw_ready_cb(struct qmi_handle *qmi_hdl,
	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[] = {
@@ -2623,9 +2669,16 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
				break;
			}

			if (ath11k_cold_boot_cal && ab->qmi.cal_done == 0 &&
			    ab->hw_params.cold_boot_calib) {
				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);
			ab->qmi.cal_done = 1;
				set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
			}

			break;
		case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE:
Loading