diff --git a/drivers/net/wireless/cnss2/debug.c b/drivers/net/wireless/cnss2/debug.c index 1d6c3748ff8c..4d10d1aa25a9 100644 --- a/drivers/net/wireless/cnss2/debug.c +++ b/drivers/net/wireless/cnss2/debug.c @@ -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); diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 7a273f69e892..eef8058e4638 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -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; diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index 0302ea83a7b7..8d0a94092b19 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -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; diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 25fe5bd732b5..7310d1aa455c 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -1497,7 +1497,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"); @@ -1843,10 +1843,12 @@ retry: 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; @@ -2133,14 +2135,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; - cnss_pr_dbg("Start to wait for calibration to complete\n"); + /* 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)) @@ -2156,12 +2170,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, @@ -3222,7 +3235,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; } diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 4c26d37ffa26..c4f3f42a38ab 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -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;