Browse Source

cnss2: Add support for conditional powering off

It is observed during some stress tests under very bad thermal
conditions that wlan re-probe can fail after cnss2 probes the
device for the 1st time and then powers it off.

When this happens, the SW_CTRL signal doesn't go high after
cnss2 toggles WLAN_EN.

To avoid such issue, add support for conditional device power
off so power supply will be retained for certain chipsets after
cnss2 probes it for the 1st time.

Change-Id: I81d508f2a69fcbc6f8761988981ec432af059fac
CRs-Fixed: 3241179
Wade Song 2 years ago
parent
commit
f0ec361d6a
3 changed files with 60 additions and 4 deletions
  1. 4 0
      Kbuild
  2. 13 0
      cnss2/Kconfig
  3. 43 4
      cnss2/pci.c

+ 4 - 0
Kbuild

@@ -28,6 +28,10 @@ ifeq ($(CONFIG_CNSS_HW_SECURE_DISABLE), y)
 KBUILD_CPPFLAGS += -DCONFIG_CNSS_HW_SECURE_DISABLE
 endif
 
+ifeq ($(CONFIG_CNSS2_CONDITIONAL_POWEROFF),y)
+KBUILD_CPPFLAGS += -DCONFIG_CNSS2_CONDITIONAL_POWEROFF
+endif
+
 obj-$(CONFIG_CNSS2) += cnss2/
 obj-$(CONFIG_ICNSS2) += icnss2/
 obj-$(CONFIG_CNSS_GENL) += cnss_genl/

+ 13 - 0
cnss2/Kconfig

@@ -96,3 +96,16 @@ config CNSS_REQ_FW_DIRECT
 	  This enables calling request_firmware_direct for firmware or
 	  configuration file to avoid 60s timeout while search file under user
 	  space failure.
+
+config CNSS2_CONDITIONAL_POWEROFF
+	bool "Enable/Disable conditional bus suspend and device power off"
+	depends on CNSS2
+	depends on PCI
+	help
+	  Conditional pcie bus suspend and device powering off for wlan after
+	  driver probe for the first time.
+	  With this feature enabled, pcie bus suspend and device powering off
+	  will not take place for certain wlan chipsets after driver probing
+	  for the first time to avoid potential subsequent failures during
+	  device re-probe(after wlan function driver loaded) under very bad
+	  thermal conditions.

+ 43 - 4
cnss2/pci.c

@@ -5789,6 +5789,48 @@ static struct dev_pm_domain cnss_pm_domain = {
 	}
 };
 
+#ifdef CONFIG_CNSS2_CONDITIONAL_POWEROFF
+static bool cnss_should_suspend_pwroff(struct pci_dev *pci_dev)
+{
+	bool suspend_pwroff;
+
+	switch (pci_dev->device) {
+	case QCA6390_DEVICE_ID:
+	case QCA6490_DEVICE_ID:
+		suspend_pwroff = false;
+		break;
+	default:
+		suspend_pwroff = true;
+	}
+
+	return suspend_pwroff;
+}
+#else
+static bool cnss_should_suspend_pwroff(struct pci_dev *pci_dev)
+{
+	return true;
+}
+#endif
+
+static void cnss_pci_suspend_pwroff(struct pci_dev *pci_dev)
+{
+	struct cnss_pci_data *pci_priv = cnss_get_pci_priv(pci_dev);
+	struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(NULL);
+	int ret = 0;
+	bool suspend_pwroff = cnss_should_suspend_pwroff(pci_dev);
+
+	if (suspend_pwroff) {
+		ret = cnss_suspend_pci_link(pci_priv);
+		if (ret)
+			cnss_pr_err("Failed to suspend PCI link, err = %d\n",
+				    ret);
+		cnss_power_off_device(plat_priv);
+	} else {
+		cnss_pr_dbg("bus suspend and dev power off disabled for device [0x%x]\n",
+			    pci_dev->device);
+	}
+}
+
 static int cnss_pci_probe(struct pci_dev *pci_dev,
 			  const struct pci_device_id *id)
 {
@@ -5881,10 +5923,7 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
 	cnss_pci_config_regs(pci_priv);
 	if (EMULATION_HW)
 		goto out;
-	ret = cnss_suspend_pci_link(pci_priv);
-	if (ret)
-		cnss_pr_err("Failed to suspend PCI link, err = %d\n", ret);
-	cnss_power_off_device(plat_priv);
+	cnss_pci_suspend_pwroff(pci_dev);
 	set_bit(CNSS_PCI_PROBE_DONE, &plat_priv->driver_state);
 
 	return 0;