qdpc-host: import from Quantenna SDK v37.4.0.46.

quantenna-sdk-v37.4.0.46.tar.gz/
  drivers/pcie2 -> drivers/net/wireless/quantenna/pcie2

Change-Id: Ief68b3bed5ca124dcc751c067276b807554c9f72
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 a648be0..e1d2454 100644
--- a/drivers/net/wireless/quantenna/pcie2/host/common/qdpc_init.c
+++ b/drivers/net/wireless/quantenna/pcie2/host/common/qdpc_init.c
@@ -56,6 +56,18 @@
 module_param(tlp_mps, uint, 0644);
 MODULE_PARM_DESC(tlp_mps, "Default PCIe Max_Payload_Size");
 
+/*
+ * Define EP state during host suspend
+ * 0 = EP does not power off
+ * 1 = EP power off
+ */
+#define EP_SUSPEND_MODE_RUNNING	0
+#define EP_SUSPEND_MODE_PWR_OFF	1
+static unsigned int suspend_mode = EP_SUSPEND_MODE_RUNNING;
+module_param(suspend_mode, uint, 0644);
+MODULE_PARM_DESC(suspend_mode, "Default suspend behavior");
+static unsigned int suspend_flag = 0;
+
 /* Quantenna PCIE vendor and device identifiers  */
 static struct pci_device_id qdpc_pcie_ids[] = {
 	{PCI_DEVICE(QDPC_VENDOR_ID, QDPC_DEVICE_ID),},
@@ -70,6 +82,8 @@
 static void qdpc_nl_recv_msg(struct sk_buff *skb);
 int qdpc_init_netdev(struct net_device  **net_dev, struct pci_dev *pdev);
 pci_ers_result_t qdpc_pcie_slot_reset(struct pci_dev *dev);
+static void qdpc_pcie_shutdown(struct pci_dev *pdev);
+
 
 char qdpc_pcie_driver_name[] = "qdpc_host";
 
@@ -87,6 +101,7 @@
 	.resume  = qdpc_pcie_resume,
 #endif
         .err_handler = &qdpc_err_hdl,
+	.shutdown = qdpc_pcie_shutdown,
 };
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
@@ -484,7 +499,7 @@
 #endif
 	pci_disable_device(pdev);
 
-	writel(TOPAZ_SET_INT(IPC_RESET_EP), vmp->ep_ipc_reg);
+	writel(TOPAZ_SET_INT(IPC_RESET_EP), (volatile void *)(vmp->ep_ipc_reg));
 	qdpc_unmap_iomem(vmp);
 
 	free_netdev(ndev);
@@ -536,13 +551,16 @@
 	ndev->flags &= ~IFF_RUNNING;
 	*priv->ep_pmstate = cpu_to_le32(PCI_D3hot);
 	barrier();
-	writel(TOPAZ_SET_INT(IPC_EP_PM_CTRL), priv->ep_ipc_reg);
+	writel(TOPAZ_SET_INT(IPC_EP_PM_CTRL), (volatile void *)(priv->ep_ipc_reg));
 
 	msleep(100);
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
 	qdpc_pcie_set_power_state(pdev, PCI_D3hot);
 
+	if (suspend_mode == EP_SUSPEND_MODE_PWR_OFF)
+		suspend_flag = 1;
+
 	return 0;
 }
 
@@ -552,12 +570,15 @@
 	struct vmac_priv *priv;
 	int ret;
 
-	if (ndev == NULL)
-		return -EINVAL;
+	if (ndev == NULL) {
+		ret = -EINVAL;
+		goto out;
+	}
 
 	priv = netdev_priv(ndev);
 	if (le32_to_cpu(*priv->ep_pmstate) == PCI_D0) {
-		return 0;
+		ret = 0;
+		goto out;
 	}
 
 	printk("%s start power management resume\n", qdpc_pcie_driver_name);
@@ -565,25 +586,41 @@
 	ret = pci_enable_device(pdev);
 	if (ret) {
 		PRINT_ERROR("%s: pci_enable_device failed on resume\n", __func__);
-		return ret;
+		goto out;
 	}
 
 	pci_restore_state(pdev);
+	pdev->state_saved = true;
 	qdpc_pcie_set_power_state(pdev, PCI_D0);
 
 	{
 		*priv->ep_pmstate = cpu_to_le32(PCI_D0);
 		barrier();
-		writel(TOPAZ_SET_INT(IPC_EP_PM_CTRL), priv->ep_ipc_reg);
+		writel(TOPAZ_SET_INT(IPC_EP_PM_CTRL), (volatile void *)(priv->ep_ipc_reg));
 
 		msleep(5000);
 	}
 
+	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)
+			printk("Recovery OK\n");
+		else {
+			printk("Recovery Error");
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
 	/* Set ep_ready to resume tx traffic */
 	priv->ep_ready = 1;
 	ndev->flags |= IFF_RUNNING;
 
-	return 0;
+out:
+	if (suspend_mode == EP_SUSPEND_MODE_PWR_OFF)
+		suspend_flag = 0;
+	return ret;
 }
 
 static int __init qdpc_init_module(void)
@@ -643,12 +680,16 @@
 {
 	struct vmac_priv *priv = NULL;
 
-	if (pdev->state_saved == true) {
-		pci_restore_state(pdev);
-		pdev->state_saved = true;
-	} else {
-		printk("Recovery Error: No saved state\n");
-		goto out;
+	if (suspend_mode == EP_SUSPEND_MODE_PWR_OFF && suspend_flag)
+		suspend_flag = 0;
+	else {
+		if (pdev->state_saved == true) {
+			pci_restore_state(pdev);
+			pdev->state_saved = true;
+		} else {
+			printk("Recovery Error: No saved state\n");
+			goto out;
+		}
 	}
 
 	if (pci_enable_device(pdev)) {
@@ -720,6 +761,13 @@
 		return PCI_ERS_RESULT_DISCONNECT;
 }
 
+static void qdpc_pcie_shutdown(struct pci_dev *pdev)
+{
+	qdpc_pcie_remove(pdev);
+
+	return;
+}
+
 static int qdpc_bringup_fw(struct vmac_priv *priv)
 {
 	__iomem qdpc_pcie_bda_t  *bda = priv->bda;
diff --git a/drivers/net/wireless/quantenna/pcie2/host/common/topaz_vnet.c b/drivers/net/wireless/quantenna/pcie2/host/common/topaz_vnet.c
index 29835d9..fc20336 100644
--- a/drivers/net/wireless/quantenna/pcie2/host/common/topaz_vnet.c
+++ b/drivers/net/wireless/quantenna/pcie2/host/common/topaz_vnet.c
@@ -775,7 +775,7 @@
 			}
 		}
 		if ((ndev->stats.rx_packets & RX_DONE_INTR_MSK) == 0)
-			writel(TOPAZ_SET_INT(IPC_RC_RX_DONE), vmp->ep_ipc_reg);
+			writel(TOPAZ_SET_INT(IPC_RC_RX_DONE), (volatile void *)(vmp->ep_ipc_reg));
 
 		dump_rx_bd(vmp);
 
@@ -870,12 +870,11 @@
 	i = vmp->tx_reclaim_start;
 
 	while (i != end_idx) {
-		tbdp = &vmp->tx_bd_base[i];
 		struct sk_buff *skb;
 		skb = vmp->tx_skb[i];
 		if (!skb)
 			break;
-
+		tbdp = &vmp->tx_bd_base[i];
 		ndev->stats.tx_packets++;
 
 		ndev->stats.tx_bytes +=  skb->len;
@@ -990,7 +989,7 @@
 		vmp->txqueue_stopped = 1;
 		*vmp->txqueue_wake = 0;
 		barrier();
-		writel(TOPAZ_SET_INT(IPC_RC_STOP_TX), vmp->ep_ipc_reg);
+		writel(TOPAZ_SET_INT(IPC_RC_STOP_TX), (volatile void *)(vmp->ep_ipc_reg));
 		vmp->tx_stop_queue_cnt++;
 		netif_stop_queue(ndev);
 	}
@@ -1088,7 +1087,7 @@
 
 	dump_tx_bd(vmp);
 
-	writel(TOPAZ_SET_INT(IPC_EP_RX_PKT), vmp->ep_ipc_reg);
+	writel(TOPAZ_SET_INT(IPC_EP_RX_PKT), (volatile void *)(vmp->ep_ipc_reg));
 
 #ifdef RC_TXDONE_TIMER
 	vmac_tx_teardown(ndev, bda);
@@ -1143,7 +1142,7 @@
 	if (vmp->tx_skb[vmp->tx_reclaim_start] == NULL) {
 		del_timer(&vmp->tx_timer);
 	} else {
-		writel(TOPAZ_SET_INT(IPC_EP_RX_PKT), vmp->ep_ipc_reg);
+		writel(TOPAZ_SET_INT(IPC_EP_RX_PKT), (volatile void *)(vmp->ep_ipc_reg));
 		mod_timer(&vmp->tx_timer, jiffies + 1);
 	}
 	spin_unlock(&vmp->tx_lock);
diff --git a/drivers/net/wireless/quantenna/pcie2/include/qdpc_version.h b/drivers/net/wireless/quantenna/pcie2/include/qdpc_version.h
index 3b01b8e..3e81707 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.38"
+#define DRV_VERSION "v37.4.0.46"