mwifiex: flush TX ring for PCIe after disconnect or bss stop
authorAvinash Patil <patila@marvell.com>
Fri, 4 Jan 2013 05:21:31 +0000 (21:21 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 7 Jan 2013 20:18:30 +0000 (15:18 -0500)
This patch adds handler to clean PCIe TX rings after disconnect
or bss stop is called for PCIe based mwifiex driver.

Signed-off-by: Avinash Patil <patila@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/pcie.h
drivers/net/wireless/mwifiex/wmm.c

index ef02a5b..51044e3 100644 (file)
@@ -602,6 +602,7 @@ struct mwifiex_if_ops {
        int (*init_fw_port) (struct mwifiex_adapter *);
        int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
        void (*card_reset) (struct mwifiex_adapter *);
+       int (*clean_pcie_ring) (struct mwifiex_adapter *adapter);
 };
 
 struct mwifiex_adapter {
index ac20bc4..19b5a83 100644 (file)
@@ -764,6 +764,37 @@ static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter)
        return 0;
 }
 
+/* This function flushes the TX buffer descriptor ring
+ * This function defined as handler is also called while cleaning TXRX
+ * during disconnect/ bss stop.
+ */
+static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
+{
+       struct pcie_service_card *card = adapter->card;
+       u32 rdptr;
+
+       /* Read the TX ring read pointer set by firmware */
+       if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
+               dev_err(adapter->dev,
+                       "Flush TXBD: failed to read REG_TXBD_RDPTR\n");
+               return -1;
+       }
+
+       if (!mwifiex_pcie_txbd_empty(card, rdptr)) {
+               card->txbd_flush = 1;
+               /* write pointer already set at last send
+                * send dnld-rdy intr again, wait for completion.
+                */
+               if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+                                     CPU_INTR_DNLD_RDY)) {
+                       dev_err(adapter->dev,
+                               "failed to assert dnld-rdy interrupt.\n");
+                       return -1;
+               }
+       }
+       return 0;
+}
+
 /*
  * This function sends data buffer to device
  */
@@ -1995,6 +2026,7 @@ static struct mwifiex_if_ops pcie_ops = {
        .update_mp_end_port =           NULL,
        .cleanup_mpa_buf =              NULL,
        .init_fw_port =                 mwifiex_pcie_init_fw_port,
+       .clean_pcie_ring =              mwifiex_clean_pcie_ring_buf,
 };
 
 /*
index 87201f5..24a39b3 100644 (file)
@@ -114,6 +114,7 @@ struct pcie_service_card {
        struct pci_dev *dev;
        struct mwifiex_adapter *adapter;
 
+       u8 txbd_flush;
        u32 txbd_wrptr;
        u32 txbd_rdptr;
        u32 txbd_ring_size;
@@ -146,4 +147,16 @@ struct pcie_service_card {
        void __iomem *pci_mmap1;
 };
 
+static inline int
+mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr)
+{
+       if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
+                       (rdptr & MWIFIEX_TXBD_MASK)) &&
+           ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
+                       (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND)))
+               return 1;
+
+       return 0;
+}
+
 #endif /* _MWIFIEX_PCIE_H */
index 818f871..6d641cb 100644 (file)
@@ -568,6 +568,8 @@ mwifiex_clean_txrx(struct mwifiex_private *priv)
        mwifiex_wmm_delete_all_ralist(priv);
        memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
 
+       if (priv->adapter->if_ops.clean_pcie_ring)
+               priv->adapter->if_ops.clean_pcie_ring(priv->adapter);
        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
 }