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

Commit 146ff543 authored by Yue Ma's avatar Yue Ma
Browse files

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



Add the support to recover PCIe link after link down so that it can
try to collect firmware RAM dump to debug.

Change-Id: I227373b2285b3ea415a315ace7db907c477297e8
Signed-off-by: default avatarYue Ma <yuem@codeaurora.org>
parent 5769cd22
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -450,6 +450,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)
{
+1 −0
Original line number Diff line number Diff line
@@ -51,6 +51,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,
+9 −1
Original line number Diff line number Diff line
@@ -744,7 +744,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);
@@ -1042,6 +1042,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);
+45 −3
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@

#define FW_ASSERT_TIMEOUT		5000
#define DEV_RDDM_TIMEOUT		5000
#define WAKE_EVENT_TIMEOUT		5000

#ifdef CONFIG_CNSS_EMULATION
#define EMULATION_HW			1
@@ -776,6 +777,42 @@ int cnss_resume_pci_link(struct cnss_pci_data *pci_priv)
	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);
@@ -850,6 +887,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);
@@ -2257,23 +2295,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);
@@ -4533,6 +4573,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);

@@ -4596,6 +4637,7 @@ 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:
+2 −0
Original line number Diff line number Diff line
@@ -77,6 +77,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;
@@ -165,6 +166,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);
void cnss_pci_add_fw_prefix_name(struct cnss_pci_data *pci_priv,