Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6efedba authored by Manikandan Mohan's avatar Manikandan Mohan
Browse files

cnss2: Allow WLAN driver register after cold boot calibration



When cold boot calibration is enabled, it is the first step in
WLAN initialization. Cold boot calibration is started post file
system mount from init.target.rc and wlan driver is
loaded after that.
This update is to reject wlan driver register if it is loaded
before cold boot calibration is complete. This ensures WLAN
init sequence triggered from init.target.rc is followed and wlan
driver load from early boot is rejected.

Change-Id: Id2d7b6f9ceed0d6d648012ad6d0c24bba4d09854
Signed-off-by: default avatarManikandan Mohan <manikand@codeaurora.org>
parent bf4eaa44
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -71,8 +71,8 @@ static int cnss_stats_show_state(struct seq_file *s,
		case CNSS_FW_READY:
			seq_puts(s, "FW_READY");
			continue;
		case CNSS_COLD_BOOT_CAL:
			seq_puts(s, "COLD_BOOT_CAL");
		case CNSS_IN_COLD_BOOT_CAL:
			seq_puts(s, "IN_COLD_BOOT_CAL");
			continue;
		case CNSS_DRIVER_LOADING:
			seq_puts(s, "DRIVER_LOADING");
@@ -113,6 +113,9 @@ static int cnss_stats_show_state(struct seq_file *s,
		case CNSS_IN_REBOOT:
			seq_puts(s, "IN_REBOOT");
			continue;
		case CNSS_COLD_BOOT_CAL_DONE:
			seq_puts(s, "COLD_BOOT_CAL_DONE");
			continue;
		}

		seq_printf(s, "UNKNOWN-%d", i);
+29 −11
Original line number Diff line number Diff line
@@ -390,6 +390,7 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
	if (!plat_priv)
		return -ENODEV;

	cnss_pr_dbg("Processing FW Init Done..\n");
	del_timer(&plat_priv->fw_boot_timer);
	set_bit(CNSS_FW_READY, &plat_priv->driver_state);
	clear_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
@@ -402,7 +403,7 @@ static int cnss_fw_ready_hdlr(struct cnss_plat_data *plat_priv)
	if (test_bit(ENABLE_WALTEST, &plat_priv->ctrl_params.quirks)) {
		ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
						    CNSS_WALTEST);
	} else if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state)) {
	} else if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state)) {
		cnss_request_antenna_sharing(plat_priv);
		ret = cnss_wlfw_wlan_mode_send_sync(plat_priv,
						    CNSS_CALIBRATION);
@@ -1273,19 +1274,30 @@ static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv)
{
	int ret = 0;

	if (test_bit(CNSS_FW_READY, &plat_priv->driver_state) ||
	    test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
	    test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
		cnss_pr_dbg("Device is already active, ignore calibration\n");
	if (test_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state)) {
		cnss_pr_dbg("Calibration complete. Ignore calibration req\n");
		goto out;
	}

	set_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
	if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state) ||
	    test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state) ||
	    test_bit(CNSS_FW_READY, &plat_priv->driver_state)) {
		cnss_pr_err("WLAN in mission mode before cold boot calibration\n");
		CNSS_ASSERT(0);
		return -EINVAL;
	}

	set_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state);
	reinit_completion(&plat_priv->cal_complete);
	ret = cnss_bus_dev_powerup(plat_priv);
	if (ret) {
		complete(&plat_priv->cal_complete);
		clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
		clear_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state);
		/* Set CBC done in driver state to mark attempt and note error
		 * since calibration cannot be retried at boot.
		 */
		plat_priv->cal_done = CNSS_CAL_FAILURE;
		set_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state);
	}

out:
@@ -1297,7 +1309,7 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv,
{
	struct cnss_cal_info *cal_info = data;

	if (!test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state))
	if (!test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state))
		goto out;

	switch (cal_info->cal_status) {
@@ -1306,7 +1318,9 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv,
		plat_priv->cal_done = true;
		break;
	case CNSS_CAL_TIMEOUT:
		cnss_pr_dbg("Calibration timed out, force shutdown\n");
	case CNSS_CAL_FAILURE:
		cnss_pr_dbg("Calibration failed. Status: %d, force shutdown\n",
			    cal_info->cal_status);
		break;
	default:
		cnss_pr_err("Unknown calibration status: %u\n",
@@ -1320,7 +1334,8 @@ static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv,
	cnss_bus_dev_shutdown(plat_priv);
	msleep(COLD_BOOT_CAL_SHUTDOWN_DELAY_MS);
	complete(&plat_priv->cal_complete);
	clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
	clear_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state);
	set_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state);

out:
	kfree(data);
@@ -2022,7 +2037,7 @@ static ssize_t fs_ready_store(struct device *dev,
		return count;
	}

	if (fs_ready == FILE_SYSTEM_READY) {
	if (fs_ready == FILE_SYSTEM_READY && plat_priv->cbc_enabled) {
		cnss_driver_event_post(plat_priv,
				       CNSS_DRIVER_EVENT_COLD_BOOT_CAL_START,
				       0, NULL);
@@ -2179,6 +2194,9 @@ static void cnss_init_control_params(struct cnss_plat_data *plat_priv)
				  "cnss-daemon-support"))
		plat_priv->ctrl_params.quirks |= BIT(ENABLE_DAEMON_SUPPORT);

	plat_priv->cbc_enabled =
		of_property_read_bool(plat_priv->plat_dev->dev.of_node,
				      "qcom,wlan-cbc-enabled");
	plat_priv->ctrl_params.mhi_timeout = CNSS_MHI_TIMEOUT_DEFAULT;
	plat_priv->ctrl_params.mhi_m2_timeout = CNSS_MHI_M2_TIMEOUT_DEFAULT;
	plat_priv->ctrl_params.qmi_timeout = CNSS_QMI_TIMEOUT_DEFAULT;
+10 −5
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@
#define CNSS_RDDM_TIMEOUT_MS		20000
#define RECOVERY_TIMEOUT		60000
#define WLAN_WD_TIMEOUT_MS		60000
#define WLAN_COLD_BOOT_CAL_TIMEOUT	60000
#define WLAN_DRIVER_LOAD_TIMEOUT	90000
#define TIME_CLOCK_FREQ_HZ		19200000
#define CNSS_RAMDUMP_MAGIC		0x574C414E
#define CNSS_RAMDUMP_VERSION		0
@@ -218,23 +220,24 @@ enum cnss_driver_event_type {
};

enum cnss_driver_state {
	CNSS_QMI_WLFW_CONNECTED,
	CNSS_QMI_WLFW_CONNECTED = 0,
	CNSS_FW_MEM_READY,
	CNSS_FW_READY,
	CNSS_COLD_BOOT_CAL,
	CNSS_IN_COLD_BOOT_CAL,
	CNSS_DRIVER_LOADING,
	CNSS_DRIVER_UNLOADING,
	CNSS_DRIVER_UNLOADING = 5,
	CNSS_DRIVER_IDLE_RESTART,
	CNSS_DRIVER_IDLE_SHUTDOWN,
	CNSS_DRIVER_PROBED,
	CNSS_DRIVER_RECOVERY,
	CNSS_FW_BOOT_RECOVERY,
	CNSS_FW_BOOT_RECOVERY = 10,
	CNSS_DEV_ERR_NOTIFY,
	CNSS_DRIVER_DEBUG,
	CNSS_COEX_CONNECTED,
	CNSS_IMS_CONNECTED,
	CNSS_IN_SUSPEND_RESUME,
	CNSS_IN_SUSPEND_RESUME = 15,
	CNSS_IN_REBOOT,
	CNSS_COLD_BOOT_CAL_DONE,
};

struct cnss_recovery_data {
@@ -285,6 +288,7 @@ enum cnss_bdf_type {
enum cnss_cal_status {
	CNSS_CAL_DONE,
	CNSS_CAL_TIMEOUT,
	CNSS_CAL_FAILURE,
};

struct cnss_cal_info {
@@ -393,6 +397,7 @@ struct cnss_plat_data {
	u64 dynamic_feature;
	void *get_info_cb_ctx;
	int (*get_info_cb)(void *ctx, void *event, int event_len);
	bool cbc_enabled;
	u8 use_nv_mac;
	u8 set_wlaon_pwr_ctrl;
	struct kobject *shutdown_kobj;
+23 −10
Original line number Diff line number Diff line
@@ -1493,7 +1493,7 @@ int cnss_pci_call_driver_remove(struct cnss_pci_data *pci_priv)

	plat_priv = pci_priv->plat_priv;

	if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state) ||
	if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state) ||
	    test_bit(CNSS_FW_BOOT_RECOVERY, &plat_priv->driver_state) ||
	    test_bit(CNSS_DRIVER_DEBUG, &plat_priv->driver_state)) {
		cnss_pr_dbg("Skip driver remove\n");
@@ -1839,10 +1839,12 @@ static int cnss_qca6290_powerup(struct cnss_pci_data *pci_priv)
		if (ret)
			goto stop_mhi;
	} else if (timeout) {
		if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state))
			timeout = timeout << 1;
		if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state))
			timeout += WLAN_COLD_BOOT_CAL_TIMEOUT;
		else
			timeout += WLAN_DRIVER_LOAD_TIMEOUT;
		mod_timer(&plat_priv->fw_boot_timer,
			  jiffies + msecs_to_jiffies(timeout << 1));
			  jiffies + msecs_to_jiffies(timeout));
	}

	return 0;
@@ -2129,14 +2131,26 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
		return -EEXIST;
	}

	if (!test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state))
	if (!plat_priv->cbc_enabled ||
	    test_bit(CNSS_COLD_BOOT_CAL_DONE, &plat_priv->driver_state))
		goto register_driver;

	/* If enabled Cold Boot Calibration is the 1st step in init sequence.
	 * CBC is done on file system_ready trigger. Qcacld should be loaded
	 * from init.target.rc after that. Reject qcacld load from
	 * vendor_modprobe.sh at early boot to satisfy this requirement.
	 */
	if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state)) {
		cnss_pr_dbg("Start to wait for calibration to complete\n");
	} else {
		cnss_pr_err("Reject WLAN Driver insmod before CBC\n");
		return -EPERM;
	}

	timeout = cnss_get_boot_timeout(&pci_priv->pci_dev->dev);
	ret = wait_for_completion_timeout(&plat_priv->cal_complete,
					  msecs_to_jiffies(timeout) << 2);
					  WLAN_COLD_BOOT_CAL_TIMEOUT +
					  msecs_to_jiffies(timeout));
	if (!ret) {
		cnss_pr_err("Timeout waiting for calibration to complete\n");
		if (!test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state))
@@ -2152,12 +2166,11 @@ int cnss_wlan_register_driver(struct cnss_wlan_driver *driver_ops)
				       0, cal_info);
	}

register_driver:
	if (test_bit(CNSS_IN_REBOOT, &plat_priv->driver_state)) {
		cnss_pr_dbg("Reboot or shutdown is in progress, ignore register driver\n");
		return -EINVAL;
	}

register_driver:
	reinit_completion(&plat_priv->power_up_complete);
	ret = cnss_driver_event_post(plat_priv,
				     CNSS_DRIVER_EVENT_REGISTER_DRIVER,
@@ -3218,7 +3231,7 @@ void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv)
	if (!plat_priv)
		return;

	if (test_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state)) {
	if (test_bit(CNSS_IN_COLD_BOOT_CAL, &plat_priv->driver_state)) {
		cnss_pr_dbg("Ignore FW ready timeout for calibration mode\n");
		return;
	}
+14 −4
Original line number Diff line number Diff line
@@ -78,12 +78,11 @@ static int cnss_wlfw_ind_register_send_sync(struct cnss_plat_data *plat_priv)

	req->client_id_valid = 1;
	req->client_id = WLFW_CLIENT_ID;
	req->fw_ready_enable_valid = 1;
	req->fw_ready_enable = 1;
	req->request_mem_enable_valid = 1;
	req->request_mem_enable = 1;
	req->fw_mem_ready_enable_valid = 1;
	req->fw_mem_ready_enable = 1;
	/* fw_ready indication is replaced by fw_init_done in HST/HSP */
	req->fw_init_done_enable_valid = 1;
	req->fw_init_done_enable = 1;
	req->pin_connect_result_enable_valid = 1;
@@ -1776,6 +1775,12 @@ static void cnss_wlfw_fw_mem_ready_ind_cb(struct qmi_handle *qmi_wlfw,
			       0, NULL);
}

/**
 * cnss_wlfw_fw_ready_ind_cb: FW ready indication handler (Helium arch)
 *
 * This event is not required for HST/ HSP as FW calibration done is
 * provided in QMI_WLFW_CAL_DONE_IND_V01
 */
static void cnss_wlfw_fw_ready_ind_cb(struct qmi_handle *qmi_wlfw,
				      struct sockaddr_qrtr *sq,
				      struct qmi_txn *txn, const void *data)
@@ -1784,13 +1789,18 @@ static void cnss_wlfw_fw_ready_ind_cb(struct qmi_handle *qmi_wlfw,
		container_of(qmi_wlfw, struct cnss_plat_data, qmi_wlfw);
	struct cnss_cal_info *cal_info;

	cnss_pr_dbg("Received QMI WLFW FW ready indication\n");

	if (!txn) {
		cnss_pr_err("Spurious indication\n");
		return;
	}

	if (plat_priv->device_id == QCA6390_DEVICE_ID ||
	    plat_priv->device_id == QCA6490_DEVICE_ID) {
		cnss_pr_dbg("Ignore FW Ready Indication for HST/HSP");
		return;
	}

	cnss_pr_dbg("Received QMI WLFW FW ready indication.\n");
	cal_info = kzalloc(sizeof(*cal_info), GFP_KERNEL);
	if (!cal_info)
		return;