|
@@ -82,6 +82,9 @@ static DEFINE_SPINLOCK(time_sync_lock);
|
|
#define WLAON_PWR_CTRL_SHUTDOWN_DELAY_MIN_US 1000
|
|
#define WLAON_PWR_CTRL_SHUTDOWN_DELAY_MIN_US 1000
|
|
#define WLAON_PWR_CTRL_SHUTDOWN_DELAY_MAX_US 2000
|
|
#define WLAON_PWR_CTRL_SHUTDOWN_DELAY_MAX_US 2000
|
|
|
|
|
|
|
|
+#define RDDM_LINK_RECOVERY_RETRY 20
|
|
|
|
+#define RDDM_LINK_RECOVERY_RETRY_DELAY_MS 20
|
|
|
|
+
|
|
#define FORCE_WAKE_DELAY_MIN_US 4000
|
|
#define FORCE_WAKE_DELAY_MIN_US 4000
|
|
#define FORCE_WAKE_DELAY_MAX_US 6000
|
|
#define FORCE_WAKE_DELAY_MAX_US 6000
|
|
#define FORCE_WAKE_DELAY_TIMEOUT_US 60000
|
|
#define FORCE_WAKE_DELAY_TIMEOUT_US 60000
|
|
@@ -1492,46 +1495,6 @@ out:
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-int cnss_pci_recover_link_down(struct cnss_pci_data *pci_priv)
|
|
|
|
-{
|
|
|
|
- int ret;
|
|
|
|
-
|
|
|
|
- switch (pci_priv->device_id) {
|
|
|
|
- case QCA6390_DEVICE_ID:
|
|
|
|
- case QCA6490_DEVICE_ID:
|
|
|
|
- case KIWI_DEVICE_ID:
|
|
|
|
- case MANGO_DEVICE_ID:
|
|
|
|
- case PEACH_DEVICE_ID:
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- return -EOPNOTSUPP;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Always wait here to avoid missing WAKE assert for RDDM
|
|
|
|
- * before link recovery
|
|
|
|
- */
|
|
|
|
- msleep(WAKE_EVENT_TIMEOUT);
|
|
|
|
-
|
|
|
|
- ret = cnss_suspend_pci_link(pci_priv);
|
|
|
|
- if (ret)
|
|
|
|
- cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
|
|
|
|
-
|
|
|
|
- ret = cnss_resume_pci_link(pci_priv);
|
|
|
|
- if (ret) {
|
|
|
|
- cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
|
|
|
|
- del_timer(&pci_priv->dev_rddm_timer);
|
|
|
|
- return ret;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- mod_timer(&pci_priv->dev_rddm_timer,
|
|
|
|
- jiffies + msecs_to_jiffies(DEV_RDDM_TIMEOUT));
|
|
|
|
-
|
|
|
|
- cnss_mhi_debug_reg_dump(pci_priv);
|
|
|
|
- cnss_pci_soc_scratch_reg_dump(pci_priv);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void cnss_pci_update_link_event(struct cnss_pci_data *pci_priv,
|
|
static void cnss_pci_update_link_event(struct cnss_pci_data *pci_priv,
|
|
enum cnss_bus_event_type type,
|
|
enum cnss_bus_event_type type,
|
|
void *data)
|
|
void *data)
|
|
@@ -1577,6 +1540,7 @@ void cnss_pci_handle_linkdown(struct cnss_pci_data *pci_priv)
|
|
cnss_pci_update_link_event(pci_priv, BUS_EVENT_PCI_LINK_DOWN, NULL);
|
|
cnss_pci_update_link_event(pci_priv, BUS_EVENT_PCI_LINK_DOWN, NULL);
|
|
|
|
|
|
cnss_fatal_err("PCI link down, schedule recovery\n");
|
|
cnss_fatal_err("PCI link down, schedule recovery\n");
|
|
|
|
+ reinit_completion(&pci_priv->wake_event_complete);
|
|
cnss_schedule_recovery(&pci_dev->dev, CNSS_REASON_LINK_DOWN);
|
|
cnss_schedule_recovery(&pci_dev->dev, CNSS_REASON_LINK_DOWN);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2893,6 +2857,7 @@ int cnss_pci_call_driver_remove(struct cnss_pci_data *pci_priv)
|
|
|
|
|
|
if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
|
|
if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state) &&
|
|
test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
|
|
test_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state)) {
|
|
|
|
+ complete(&plat_priv->rddm_complete);
|
|
pci_priv->driver_ops->shutdown(pci_priv->pci_dev);
|
|
pci_priv->driver_ops->shutdown(pci_priv->pci_dev);
|
|
} else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
|
|
} else if (test_bit(CNSS_DRIVER_UNLOADING, &plat_priv->driver_state)) {
|
|
pci_priv->driver_ops->remove(pci_priv->pci_dev);
|
|
pci_priv->driver_ops->remove(pci_priv->pci_dev);
|
|
@@ -5731,6 +5696,70 @@ static void cnss_pci_mhi_reg_dump(struct cnss_pci_data *pci_priv)
|
|
cnss_pci_dump_shadow_reg(pci_priv);
|
|
cnss_pci_dump_shadow_reg(pci_priv);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+int cnss_pci_recover_link_down(struct cnss_pci_data *pci_priv)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+ int retry = 0;
|
|
|
|
+ enum mhi_ee_type mhi_ee;
|
|
|
|
+
|
|
|
|
+ switch (pci_priv->device_id) {
|
|
|
|
+ case QCA6390_DEVICE_ID:
|
|
|
|
+ case QCA6490_DEVICE_ID:
|
|
|
|
+ case KIWI_DEVICE_ID:
|
|
|
|
+ case MANGO_DEVICE_ID:
|
|
|
|
+ case PEACH_DEVICE_ID:
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ return -EOPNOTSUPP;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Always wait here to avoid missing WAKE assert for RDDM
|
|
|
|
+ * before link recovery
|
|
|
|
+ */
|
|
|
|
+ ret = wait_for_completion_timeout(&pci_priv->wake_event_complete,
|
|
|
|
+ msecs_to_jiffies(WAKE_EVENT_TIMEOUT));
|
|
|
|
+ if (!ret)
|
|
|
|
+ cnss_pr_err("Timeout waiting for wake event after link down\n");
|
|
|
|
+
|
|
|
|
+ ret = cnss_suspend_pci_link(pci_priv);
|
|
|
|
+ if (ret)
|
|
|
|
+ cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
|
|
|
|
+
|
|
|
|
+ ret = cnss_resume_pci_link(pci_priv);
|
|
|
|
+ if (ret) {
|
|
|
|
+ cnss_pr_err("Failed to resume PCI link, err = %d\n", ret);
|
|
|
|
+ del_timer(&pci_priv->dev_rddm_timer);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+retry:
|
|
|
|
+ /*
|
|
|
|
+ * After PCIe link resumes, 20 to 400 ms delay is observerved
|
|
|
|
+ * before device moves to RDDM.
|
|
|
|
+ */
|
|
|
|
+ msleep(RDDM_LINK_RECOVERY_RETRY_DELAY_MS);
|
|
|
|
+ mhi_ee = mhi_get_exec_env(pci_priv->mhi_ctrl);
|
|
|
|
+ if (mhi_ee == MHI_EE_RDDM) {
|
|
|
|
+ del_timer(&pci_priv->dev_rddm_timer);
|
|
|
|
+ cnss_pr_info("Device in RDDM after link recovery, try to collect dump\n");
|
|
|
|
+ cnss_schedule_recovery(&pci_priv->pci_dev->dev,
|
|
|
|
+ CNSS_REASON_RDDM);
|
|
|
|
+ return 0;
|
|
|
|
+ } else if (retry++ < RDDM_LINK_RECOVERY_RETRY) {
|
|
|
|
+ cnss_pr_dbg("Wait for RDDM after link recovery, retry #%d, Device EE: %d\n",
|
|
|
|
+ retry, mhi_ee);
|
|
|
|
+ goto retry;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!cnss_pci_assert_host_sol(pci_priv))
|
|
|
|
+ return 0;
|
|
|
|
+ cnss_mhi_debug_reg_dump(pci_priv);
|
|
|
|
+ cnss_pci_soc_scratch_reg_dump(pci_priv);
|
|
|
|
+ cnss_schedule_recovery(&pci_priv->pci_dev->dev,
|
|
|
|
+ CNSS_REASON_TIMEOUT);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv)
|
|
int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv)
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
@@ -5793,6 +5822,7 @@ int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv)
|
|
cnss_pci_dump_debug_reg(pci_priv);
|
|
cnss_pci_dump_debug_reg(pci_priv);
|
|
cnss_schedule_recovery(&pci_priv->pci_dev->dev,
|
|
cnss_schedule_recovery(&pci_priv->pci_dev->dev,
|
|
CNSS_REASON_DEFAULT);
|
|
CNSS_REASON_DEFAULT);
|
|
|
|
+ ret = 0;
|
|
goto runtime_pm_put;
|
|
goto runtime_pm_put;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -5946,12 +5976,18 @@ exit:
|
|
#ifdef CONFIG_CNSS2_SSR_DRIVER_DUMP
|
|
#ifdef CONFIG_CNSS2_SSR_DRIVER_DUMP
|
|
void cnss_pci_collect_host_dump_info(struct cnss_pci_data *pci_priv)
|
|
void cnss_pci_collect_host_dump_info(struct cnss_pci_data *pci_priv)
|
|
{
|
|
{
|
|
- struct cnss_ssr_driver_dump_entry ssr_entry[CNSS_HOST_DUMP_TYPE_MAX] = {0};
|
|
|
|
|
|
+ struct cnss_ssr_driver_dump_entry *ssr_entry;
|
|
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
|
|
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
|
|
size_t num_entries_loaded = 0;
|
|
size_t num_entries_loaded = 0;
|
|
int x;
|
|
int x;
|
|
int ret = -1;
|
|
int ret = -1;
|
|
|
|
|
|
|
|
+ ssr_entry = kmalloc(sizeof(*ssr_entry) * CNSS_HOST_DUMP_TYPE_MAX, GFP_KERNEL);
|
|
|
|
+ if (!ssr_entry) {
|
|
|
|
+ cnss_pr_err("ssr_entry malloc failed");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (pci_priv->driver_ops &&
|
|
if (pci_priv->driver_ops &&
|
|
pci_priv->driver_ops->collect_driver_dump) {
|
|
pci_priv->driver_ops->collect_driver_dump) {
|
|
ret = pci_priv->driver_ops->collect_driver_dump(pci_priv->pci_dev,
|
|
ret = pci_priv->driver_ops->collect_driver_dump(pci_priv->pci_dev,
|
|
@@ -5971,6 +6007,8 @@ void cnss_pci_collect_host_dump_info(struct cnss_pci_data *pci_priv)
|
|
} else {
|
|
} else {
|
|
cnss_pr_info("Host SSR elf dump collection feature disabled\n");
|
|
cnss_pr_info("Host SSR elf dump collection feature disabled\n");
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ kfree(ssr_entry);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
@@ -6380,7 +6418,7 @@ static void cnss_dev_rddm_timeout_hdlr(struct timer_list *t)
|
|
|
|
|
|
mhi_ee = mhi_get_exec_env(pci_priv->mhi_ctrl);
|
|
mhi_ee = mhi_get_exec_env(pci_priv->mhi_ctrl);
|
|
if (mhi_ee == MHI_EE_PBL)
|
|
if (mhi_ee == MHI_EE_PBL)
|
|
- cnss_pr_err("Unable to collect ramdumps due to abrupt reset\n");
|
|
|
|
|
|
+ cnss_pr_err("Device MHI EE is PBL, unable to collect dump\n");
|
|
|
|
|
|
if (mhi_ee == MHI_EE_RDDM) {
|
|
if (mhi_ee == MHI_EE_RDDM) {
|
|
cnss_pr_info("Device MHI EE is RDDM, try to collect dump\n");
|
|
cnss_pr_info("Device MHI EE is RDDM, try to collect dump\n");
|
|
@@ -6431,6 +6469,7 @@ static int cnss_pci_handle_mhi_sys_err(struct cnss_pci_data *pci_priv)
|
|
cnss_ignore_qmi_failure(true);
|
|
cnss_ignore_qmi_failure(true);
|
|
set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
|
|
set_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state);
|
|
del_timer(&plat_priv->fw_boot_timer);
|
|
del_timer(&plat_priv->fw_boot_timer);
|
|
|
|
+ reinit_completion(&pci_priv->wake_event_complete);
|
|
mod_timer(&pci_priv->dev_rddm_timer,
|
|
mod_timer(&pci_priv->dev_rddm_timer,
|
|
jiffies + msecs_to_jiffies(DEV_RDDM_TIMEOUT));
|
|
jiffies + msecs_to_jiffies(DEV_RDDM_TIMEOUT));
|
|
cnss_pci_update_status(pci_priv, CNSS_FW_DOWN);
|
|
cnss_pci_update_status(pci_priv, CNSS_FW_DOWN);
|
|
@@ -7270,6 +7309,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
|
|
cnss_pci_get_link_status(pci_priv);
|
|
cnss_pci_get_link_status(pci_priv);
|
|
cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, true, false);
|
|
cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, true, false);
|
|
cnss_pci_wake_gpio_init(pci_priv);
|
|
cnss_pci_wake_gpio_init(pci_priv);
|
|
|
|
+ init_completion(&pci_priv->wake_event_complete);
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
cnss_pr_err("Unknown PCI device found: 0x%x\n",
|
|
cnss_pr_err("Unknown PCI device found: 0x%x\n",
|