qdpc-host: import from Quantenna SDK v37.4.15.62.
quantenna-sdk-v37.4.15.62.tar.gz/
drivers/pcie2 -> drivers/net/wireless/quantenna/pcie2
Change-Id: I2a9702e392d4cb4560ebe14a520796e1d98919ae
diff --git a/drivers/net/wireless/quantenna/pcie2/host/common/qdpc_init.c b/drivers/net/wireless/quantenna/pcie2/host/common/qdpc_init.c
index e1d2454..13da8ed 100644
--- a/drivers/net/wireless/quantenna/pcie2/host/common/qdpc_init.c
+++ b/drivers/net/wireless/quantenna/pcie2/host/common/qdpc_init.c
@@ -84,12 +84,19 @@
pci_ers_result_t qdpc_pcie_slot_reset(struct pci_dev *dev);
static void qdpc_pcie_shutdown(struct pci_dev *pdev);
+#ifdef QTN_LINK_MONITOR
+static bool is_ep_reset = false;
+static int link_monitor(void *data);
+static struct task_struct *link_monitor_thread = NULL;
+#endif
char qdpc_pcie_driver_name[] = "qdpc_host";
+#ifdef PCIE_HOTPLUG_SUPPORTED
static struct pci_error_handlers qdpc_err_hdl = {
.slot_reset = qdpc_pcie_slot_reset,
};
+#endif
static struct pci_driver qdpc_pcie_driver = {
.name = qdpc_pcie_driver_name,
@@ -100,7 +107,9 @@
.suspend = qdpc_pcie_suspend,
.resume = qdpc_pcie_resume,
#endif
+#ifdef PCIE_HOTPLUG_SUPPORTED
.err_handler = &qdpc_err_hdl,
+#endif
.shutdown = qdpc_pcie_shutdown,
};
@@ -601,7 +610,8 @@
msleep(5000);
}
- if ( (suspend_mode == EP_SUSPEND_MODE_PWR_OFF) &&
+#ifdef PCIE_HOTPLUG_SUPPORTED
+ if ( (suspend_mode == EP_SUSPEND_MODE_PWR_OFF) &&
(pdev->driver && pdev->driver->err_handler && pdev->driver->err_handler->slot_reset) ) {
printk("slot_reset in %s(), Device name: %s\n", __FUNCTION__, dev_name(&pdev->dev));
if(pdev->driver->err_handler->slot_reset(pdev) == PCI_ERS_RESULT_RECOVERED)
@@ -612,6 +622,7 @@
goto out;
}
}
+#endif
/* Set ep_ready to resume tx traffic */
priv->ep_ready = 1;
@@ -642,6 +653,10 @@
return ret;
}
+#ifdef QTN_LINK_MONITOR
+ link_monitor_thread = kthread_run(link_monitor, NULL, "link_monitor");
+#endif
+
return ret;
}
@@ -650,6 +665,11 @@
/* Release netlink */
qdpc_platform_exit();
+#ifdef QTN_LINK_MONITOR
+ kthread_stop(link_monitor_thread);
+ link_monitor_thread = NULL;
+#endif
+
/* Unregister the pci driver with the device */
pci_unregister_driver(&qdpc_pcie_driver);
@@ -768,6 +788,99 @@
return;
}
+#ifdef QTN_LINK_MONITOR
+static inline bool is_pcie_linkup(struct pci_dev *pdev)
+{
+ uint32_t cs = 0;
+
+ pci_read_config_dword(pdev, QDPC_VENDOR_ID_OFFSET, &cs);
+ if (cs == QDPC_LINK_UP) {
+ msleep(10000);
+ printk("%s: PCIe link up!\n", __func__);
+ return true;
+ }
+
+ return false;
+}
+
+static inline void qdpc_pcie_print_config_space(struct pci_dev *pdev)
+{
+ int i = 0;
+ uint32_t cs = 0;
+
+ /* Read PCIe configuration space header */
+ for (i = QDPC_VENDOR_ID_OFFSET; i <= QDPC_INT_LINE_OFFSET; i += QDPC_ROW_INCR_OFFSET) {
+ pci_read_config_dword(pdev, i, &cs);
+ printk("%s: pdev:0x%p config_space offset:0x%02x value:0x%08x\n", __func__, pdev, i, cs);
+ }
+ printk("\n");
+}
+
+static inline void qdpc_pcie_check_link(struct pci_dev *pdev, struct vmac_priv *priv)
+{
+ __iomem qdpc_pcie_bda_t *bda = priv->bda;
+ uint32_t cs = 0;
+
+ pci_read_config_dword(pdev, QDPC_VENDOR_ID_OFFSET, &cs);
+ /* Endian value will be all 1s if link went down */
+ if (readl(&bda->bda_pci_endian) == QDPC_LINK_DOWN) {
+ is_ep_reset = true;
+ printk("Reset detected\n");
+ }
+}
+
+static int link_monitor(void *data)
+{
+ struct net_device *ndev = NULL;
+ struct vmac_priv *priv = NULL;
+ __iomem qdpc_pcie_bda_t *bda = NULL;
+ struct pci_dev *pdev = NULL;
+ uint32_t cs = 0;
+
+ set_current_state(TASK_RUNNING);
+ while (!kthread_should_stop()) {
+ __set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ set_current_state(TASK_RUNNING);
+
+ ndev = g_ndev;
+ priv = netdev_priv(ndev);
+ bda = priv->bda;
+ pdev = priv->pdev;
+
+#ifdef QDPC_CS_DEBUG
+ qdpc_pcie_print_config_space(pdev);
+ msleep(5000);
+#endif
+ /* Check if reset to EP occurred */
+ while (!pci_read_config_dword(pdev, QDPC_VENDOR_ID_OFFSET, &cs)) {
+
+ if (kthread_should_stop())
+ do_exit(0);
+
+ qdpc_pcie_check_link(pdev, priv);
+ if (is_ep_reset) {
+ is_ep_reset = false;
+ qdpc_pcie_remove(pdev);
+ printk("%s: Attempting to recover from EP reset\n", __func__);
+ break;
+ }
+ msleep(500);
+ }
+
+ while(!is_pcie_linkup(pdev)) {
+ }
+
+#ifdef QDPC_CS_DEBUG
+ qdpc_pcie_print_config_space(pdev);
+#endif
+
+ qdpc_pcie_probe(pdev, NULL);
+ }
+ do_exit(0);
+}
+#endif
+
static int qdpc_bringup_fw(struct vmac_priv *priv)
{
__iomem qdpc_pcie_bda_t *bda = priv->bda;
@@ -841,6 +954,11 @@
PRINT_INFO("Connection established with Target BBIC4 board\n");
+#ifdef QTN_LINK_MONITOR
+ if (link_monitor_thread)
+ wake_up_process(link_monitor_thread);
+#endif
+
priv->init_thread = NULL;
do_exit(0);
}
diff --git a/drivers/net/wireless/quantenna/pcie2/host/common/qdpc_init.h b/drivers/net/wireless/quantenna/pcie2/host/common/qdpc_init.h
index 3d39181..13c2548 100644
--- a/drivers/net/wireless/quantenna/pcie2/host/common/qdpc_init.h
+++ b/drivers/net/wireless/quantenna/pcie2/host/common/qdpc_init.h
@@ -35,6 +35,8 @@
#define QDPC_PCIE_NUM_BARS 6
/* PCIe Configuration Space Defines */
+/* Used to indicate CS is valid and link is up */
+#define QDPC_LINK_UP ((QDPC_DEVICE_ID << 16) | QDPC_VENDOR_ID)
#define QDPC_LINK_DOWN 0xffffffff /* Used to indicate link went down */
#define QDPC_VENDOR_ID_OFFSET 0x00
#define QDPC_INT_LINE_OFFSET 0x3C
diff --git a/drivers/net/wireless/quantenna/pcie2/include/qdpc_version.h b/drivers/net/wireless/quantenna/pcie2/include/qdpc_version.h
index 3e81707..c99bfeb 100644
--- a/drivers/net/wireless/quantenna/pcie2/include/qdpc_version.h
+++ b/drivers/net/wireless/quantenna/pcie2/include/qdpc_version.h
@@ -1 +1 @@
-#define DRV_VERSION "v37.4.0.46"
+#define DRV_VERSION "v37.4.15.62"