Merge "cnss2: Try to recover PCIe link to collect dump after link down"

This commit is contained in:
qctecmdr 2020-08-26 13:02:18 -07:00 • committed by Gerrit - the friendly Code Review server
commit b14de778e8
5 changed files with 83 additions and 15 deletions

View file

@ -448,6 +448,21 @@ int cnss_bus_check_link_status(struct cnss_plat_data *plat_priv)
}
}
int cnss_bus_recover_link_down(struct cnss_plat_data *plat_priv)
{
if (!plat_priv)
return -ENODEV;
switch (plat_priv->bus_type) {
case CNSS_BUS_PCI:
return cnss_pci_recover_link_down(plat_priv->bus_priv);
default:
cnss_pr_dbg("Unsupported bus type: %d\n",
plat_priv->bus_type);
return -EINVAL;
}
}
int cnss_bus_debug_reg_read(struct cnss_plat_data *plat_priv, u32 offset,
u32 *val)
{

View file

@ -50,6 +50,7 @@ int cnss_bus_update_status(struct cnss_plat_data *plat_priv,
enum cnss_driver_status status);
int cnss_bus_is_device_down(struct cnss_plat_data *plat_priv);
int cnss_bus_check_link_status(struct cnss_plat_data *plat_priv);
int cnss_bus_recover_link_down(struct cnss_plat_data *plat_priv);
int cnss_bus_debug_reg_read(struct cnss_plat_data *plat_priv, u32 offset,
u32 *val);
int cnss_bus_debug_reg_write(struct cnss_plat_data *plat_priv, u32 offset,

View file

@ -732,7 +732,7 @@ int cnss_idle_shutdown(struct device *dev)
reinit_completion(&plat_priv->recovery_complete);
ret = wait_for_completion_timeout(&plat_priv->recovery_complete,
RECOVERY_TIMEOUT);
msecs_to_jiffies(RECOVERY_TIMEOUT));
if (!ret) {
cnss_pr_err("Timeout waiting for recovery to complete\n");
CNSS_ASSERT(0);
@ -1083,6 +1083,14 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv,
if (test_bit(LINK_DOWN_SELF_RECOVERY,
&plat_priv->ctrl_params.quirks))
goto self_recovery;
if (!cnss_bus_recover_link_down(plat_priv)) {
/* clear recovery bit here to avoid skipping
* the recovery work for RDDM later
*/
clear_bit(CNSS_DRIVER_RECOVERY,
&plat_priv->driver_state);
return 0;
}
break;
case CNSS_REASON_RDDM:
cnss_bus_collect_dump_info(plat_priv, false);

View file

@ -46,6 +46,7 @@
#define WAKE_MSI_NAME "WAKE"
#define DEV_RDDM_TIMEOUT 5000
#define WAKE_EVENT_TIMEOUT 5000
#ifdef CONFIG_CNSS_EMULATION
#define EMULATION_HW 1
@ -826,6 +827,42 @@ out:
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:
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));
mhi_debug_reg_dump(pci_priv->mhi_ctrl);
return 0;
}
int cnss_pci_prevent_l1(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
@ -900,6 +937,7 @@ int cnss_pci_link_down(struct device *dev)
pci_priv->pci_link_down_ind = true;
spin_unlock_irqrestore(&pci_link_down_lock, flags);
reinit_completion(&pci_priv->wake_event);
cnss_pr_err("PCI link down is detected, schedule recovery\n");
cnss_schedule_recovery(dev, CNSS_REASON_LINK_DOWN);
@ -2384,23 +2422,25 @@ static void cnss_pci_event_cb(struct msm_pcie_notify *notify)
case MSM_PCIE_EVENT_LINKDOWN:
if (test_bit(ENABLE_PCI_LINK_DOWN_PANIC,
&plat_priv->ctrl_params.quirks))
panic("cnss: PCI link is down!\n");
panic("cnss: PCI link is down\n");
spin_lock_irqsave(&pci_link_down_lock, flags);
if (pci_priv->pci_link_down_ind) {
cnss_pr_dbg("PCI link down recovery is in progress, ignore!\n");
cnss_pr_dbg("PCI link down recovery is in progress, ignore\n");
spin_unlock_irqrestore(&pci_link_down_lock, flags);
return;
}
pci_priv->pci_link_down_ind = true;
spin_unlock_irqrestore(&pci_link_down_lock, flags);
cnss_fatal_err("PCI link down, schedule recovery!\n");
reinit_completion(&pci_priv->wake_event);
cnss_fatal_err("PCI link down, schedule recovery\n");
if (pci_dev->device == QCA6174_DEVICE_ID)
disable_irq(pci_dev->irq);
cnss_schedule_recovery(&pci_dev->dev, CNSS_REASON_LINK_DOWN);
break;
case MSM_PCIE_EVENT_WAKEUP:
complete(&pci_priv->wake_event);
if (cnss_pci_get_monitor_wake_intr(pci_priv) &&
cnss_pci_get_auto_suspended(pci_priv)) {
cnss_pci_set_monitor_wake_intr(pci_priv, false);
@ -3790,18 +3830,21 @@ static int cnss_pci_enable_bus(struct cnss_pci_data *pci_priv)
goto release_region;
}
pci_set_master(pci_dev);
pci_priv->bar = pci_iomap(pci_dev, PCI_BAR_NUM, 0);
if (!pci_priv->bar) {
cnss_pr_err("Failed to do PCI IO map!\n");
ret = -EIO;
goto clear_master;
goto release_region;
}
/* Save default config space without BME enabled */
pci_save_state(pci_dev);
pci_priv->default_state = pci_store_saved_state(pci_dev);
pci_set_master(pci_dev);
return 0;
clear_master:
pci_clear_master(pci_dev);
release_region:
pci_release_region(pci_dev, PCI_BAR_NUM);
disable_device:
@ -3814,12 +3857,14 @@ static void cnss_pci_disable_bus(struct cnss_pci_data *pci_priv)
{
struct pci_dev *pci_dev = pci_priv->pci_dev;
pci_clear_master(pci_dev);
pci_load_and_free_saved_state(pci_dev, &pci_priv->saved_state);
if (pci_priv->bar) {
pci_iounmap(pci_dev, pci_priv->bar);
pci_priv->bar = NULL;
}
pci_clear_master(pci_dev);
pci_release_region(pci_dev, PCI_BAR_NUM);
if (pci_is_enabled(pci_dev))
pci_disable_device(pci_dev);
@ -4621,9 +4666,6 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
if (ret)
goto dereg_pci_event;
pci_save_state(pci_dev);
pci_priv->default_state = pci_store_saved_state(pci_dev);
switch (pci_dev->device) {
case QCA6174_DEVICE_ID:
pci_read_config_word(pci_dev, QCA6174_REV_ID_OFFSET,
@ -4640,6 +4682,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
cnss_pci_set_wlaon_pwr_ctrl(pci_priv, false, false, false);
timer_setup(&pci_priv->dev_rddm_timer,
cnss_dev_rddm_timeout_hdlr, 0);
init_completion(&pci_priv->wake_event);
INIT_DELAYED_WORK(&pci_priv->time_sync_work,
cnss_pci_time_sync_work_hdlr);
@ -4703,14 +4746,13 @@ static void cnss_pci_remove(struct pci_dev *pci_dev)
case QCA6490_DEVICE_ID:
cnss_pci_unregister_mhi(pci_priv);
cnss_pci_disable_msi(pci_priv);
complete_all(&pci_priv->wake_event);
del_timer(&pci_priv->dev_rddm_timer);
break;
default:
break;
}
pci_load_and_free_saved_state(pci_dev, &pci_priv->saved_state);
cnss_pci_disable_bus(pci_priv);
cnss_dereg_pci_event(pci_priv);
cnss_pci_deinit_smmu(pci_priv);

View file

@ -76,6 +76,7 @@ struct cnss_pci_data {
u8 drv_connected_last;
u16 def_link_speed;
u16 def_link_width;
struct completion wake_event;
u8 monitor_wake_intr;
struct iommu_domain *iommu_domain;
u8 smmu_s1_enable;
@ -164,6 +165,7 @@ static inline int cnss_pci_get_drv_connected(void *bus_priv)
int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv);
int cnss_suspend_pci_link(struct cnss_pci_data *pci_priv);
int cnss_resume_pci_link(struct cnss_pci_data *pci_priv);
int cnss_pci_recover_link_down(struct cnss_pci_data *pci_priv);
int cnss_pci_init(struct cnss_plat_data *plat_priv);
void cnss_pci_deinit(struct cnss_plat_data *plat_priv);
int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv);