mwifiex: use map/unmap APIs in TX and RX to reduce memcpy
authorAvinash Patil <patila@marvell.com>
Fri, 4 Jan 2013 05:21:32 +0000 (21:21 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 7 Jan 2013 20:18:30 +0000 (15:18 -0500)
This patch is an enhacement to mwifiex_pcie driver to use
map/unmap PCI memory APIs. This reduces one memcpy each in TX
path and RX path, and enhances throughput.

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/11n_aggr.c
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/pcie.h
drivers/net/wireless/mwifiex/txrx.c
drivers/net/wireless/mwifiex/wmm.c

index 68d52cfc1ebd250a55a43c8b641344d7d6999461..af8fe6352eed143baca5fbeb5fee807c2964dc99 100644 (file)
@@ -278,14 +278,16 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
                break;
        case -1:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
                dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",
                        __func__, ret);
                adapter->dbg.num_tx_host_to_card_failure++;
                mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
                return 0;
        case -EINPROGRESS:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
                break;
        case 0:
                mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
index 19b5a83f4e7f9f75a1caf720ab36282e70da48fe..3da89b456c13e7231bddb89f0a0f11b388c8535b 100644 (file)
@@ -796,15 +796,15 @@ static int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
 }
 
 /*
- * This function sends data buffer to device
+ * This function unmaps and frees downloaded data buffer
  */
-static int
-mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+static int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
 {
+       const u32 num_tx_buffs = MWIFIEX_MAX_TXRX_BD;
+       struct sk_buff *skb;
+       dma_addr_t buf_pa;
+       u32 wrdoneidx, rdptr, unmap_count = 0;
        struct pcie_service_card *card = adapter->card;
-       u32 wrindx, rdptr;
-       phys_addr_t buf_pa;
-       __le16 *tmp;
 
        if (!mwifiex_pcie_ok_to_access_hw(adapter))
                mwifiex_pm_wakeup_card(adapter);
@@ -812,34 +812,112 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
        /* Read the TX ring read pointer set by firmware */
        if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) {
                dev_err(adapter->dev,
-                       "SEND DATA: failed to read REG_TXBD_RDPTR\n");
+                       "SEND COMP: failed to read REG_TXBD_RDPTR\n");
                return -1;
        }
 
-       wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
+       dev_dbg(adapter->dev, "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
+               card->txbd_rdptr, rdptr);
 
-       dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr,
-               card->txbd_wrptr);
-       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))) {
-               struct sk_buff *skb_data;
+       /* free from previous txbd_rdptr to current txbd_rdptr */
+       while (((card->txbd_rdptr & MWIFIEX_TXBD_MASK) !=
+               (rdptr & MWIFIEX_TXBD_MASK)) ||
+              ((card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
+               (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
+               wrdoneidx = card->txbd_rdptr & MWIFIEX_TXBD_MASK;
+
+               skb = card->tx_buf_list[wrdoneidx];
+               if (skb) {
+                       dev_dbg(adapter->dev,
+                               "SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
+                               skb, wrdoneidx);
+                       MWIFIEX_SKB_PACB(skb, &buf_pa);
+                       pci_unmap_single(card->dev, buf_pa, skb->len,
+                                        PCI_DMA_TODEVICE);
+
+                       unmap_count++;
+
+                       if (card->txbd_flush)
+                               mwifiex_write_data_complete(adapter, skb, 0,
+                                                           -1);
+                       else
+                               mwifiex_write_data_complete(adapter, skb, 0, 0);
+               }
+
+               card->tx_buf_list[wrdoneidx] = NULL;
+               card->txbd_ring[wrdoneidx]->paddr = 0;
+               card->rxbd_ring[wrdoneidx]->len = 0;
+               card->rxbd_ring[wrdoneidx]->flags = 0;
+               card->txbd_rdptr++;
+
+               if ((card->txbd_rdptr & MWIFIEX_TXBD_MASK) == num_tx_buffs)
+                       card->txbd_rdptr = ((card->txbd_rdptr &
+                                           MWIFIEX_BD_FLAG_ROLLOVER_IND) ^
+                                           MWIFIEX_BD_FLAG_ROLLOVER_IND);
+       }
+
+       if (unmap_count)
+               adapter->data_sent = false;
+
+       if (card->txbd_flush) {
+               if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) ==
+                    (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) &&
+                   ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
+                    (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND)))
+                       card->txbd_flush = 0;
+               else
+                       mwifiex_clean_pcie_ring_buf(adapter);
+       }
+
+       return 0;
+}
+
+/* This function sends data buffer to device. First 4 bytes of payload
+ * are filled with payload length and payload type. Then this payload
+ * is mapped to PCI device memory. Tx ring pointers are advanced accordingly.
+ * Download ready interrupt to FW is deffered if Tx ring is not full and
+ * additional payload can be accomodated.
+ */
+static int
+mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
+                      struct mwifiex_tx_param *tx_param)
+{
+       struct pcie_service_card *card = adapter->card;
+       u32 wrindx;
+       int ret;
+       dma_addr_t buf_pa;
+       __le16 *tmp;
+
+       if (!(skb->data && skb->len)) {
+               dev_err(adapter->dev, "%s(): invalid parameter <%p, %#x>\n",
+                       __func__, skb->data, skb->len);
+               return -1;
+       }
+
+       if (!mwifiex_pcie_ok_to_access_hw(adapter))
+               mwifiex_pm_wakeup_card(adapter);
+
+       dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
+               card->txbd_rdptr, card->txbd_wrptr);
+       if (mwifiex_pcie_txbd_not_full(card)) {
                u8 *payload;
 
                adapter->data_sent = true;
-               skb_data = card->tx_buf_list[wrindx];
-               memcpy(skb_data->data, skb->data, skb->len);
-               payload = skb_data->data;
+               payload = skb->data;
                tmp = (__le16 *)&payload[0];
                *tmp = cpu_to_le16((u16)skb->len);
                tmp = (__le16 *)&payload[2];
                *tmp = cpu_to_le16(MWIFIEX_TYPE_DATA);
-               skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len);
-               skb_trim(skb_data, skb->len);
-               MWIFIEX_SKB_PACB(skb_data, &buf_pa);
+
+               if (mwifiex_map_pci_memory(adapter, skb, skb->len ,
+                                          PCI_DMA_TODEVICE))
+                       return -1;
+
+               wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK;
+               MWIFIEX_SKB_PACB(skb, &buf_pa);
+               card->tx_buf_list[wrindx] = skb;
                card->txbd_ring[wrindx]->paddr = buf_pa;
-               card->txbd_ring[wrindx]->len = (u16)skb_data->len;
+               card->txbd_ring[wrindx]->len = (u16)skb->len;
                card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
                                                MWIFIEX_BD_FLAG_LAST_DESC;
 
@@ -854,19 +932,28 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
                                      card->txbd_wrptr)) {
                        dev_err(adapter->dev,
                                "SEND DATA: failed to write REG_TXBD_WRPTR\n");
-                       return 0;
+                       ret = -1;
+                       goto done_unmap;
                }
-
-               /* Send the TX ready interrupt */
-               if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
-                                     CPU_INTR_DNLD_RDY)) {
-                       dev_err(adapter->dev,
-                               "SEND DATA: failed to assert door-bell intr\n");
-                       return -1;
+               if ((mwifiex_pcie_txbd_not_full(card)) &&
+                   tx_param->next_pkt_len) {
+                       /* have more packets and TxBD still can hold more */
+                       dev_dbg(adapter->dev,
+                               "SEND DATA: delay dnld-rdy interrupt.\n");
+                       adapter->data_sent = false;
+               } else {
+                       /* Send the TX ready interrupt */
+                       if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
+                                             CPU_INTR_DNLD_RDY)) {
+                               dev_err(adapter->dev,
+                                       "SEND DATA: failed to assert dnld-rdy interrupt.\n");
+                               ret = -1;
+                               goto done_unmap;
+                       }
                }
                dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: "
                        "%#x> and sent packet to firmware successfully\n",
-                       rdptr, card->txbd_wrptr);
+                       card->txbd_rdptr, card->txbd_wrptr);
        } else {
                dev_dbg(adapter->dev,
                        "info: TX Ring full, can't send packets to fw\n");
@@ -879,7 +966,15 @@ mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb)
                return -EBUSY;
        }
 
-       return 0;
+       return -EINPROGRESS;
+done_unmap:
+       MWIFIEX_SKB_PACB(skb, &buf_pa);
+       pci_unmap_single(card->dev, buf_pa, skb->len, PCI_DMA_TODEVICE);
+       card->tx_buf_list[wrindx] = NULL;
+       card->txbd_ring[wrindx]->paddr = 0;
+       card->txbd_ring[wrindx]->len = 0;
+       card->txbd_ring[wrindx]->flags = 0;
+       return ret;
 }
 
 /*
@@ -890,9 +985,13 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
 {
        struct pcie_service_card *card = adapter->card;
        u32 wrptr, rd_index;
+       dma_addr_t buf_pa;
        int ret = 0;
        struct sk_buff *skb_tmp = NULL;
 
+       if (!mwifiex_pcie_ok_to_access_hw(adapter))
+               mwifiex_pm_wakeup_card(adapter);
+
        /* Read the RX ring Write pointer set by firmware */
        if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) {
                dev_err(adapter->dev,
@@ -900,6 +999,7 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
                ret = -1;
                goto done;
        }
+       card->rxbd_wrptr = wrptr;
 
        while (((wrptr & MWIFIEX_RXBD_MASK) !=
                (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) ||
@@ -907,27 +1007,50 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
                (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) {
                struct sk_buff *skb_data;
                u16 rx_len;
+               __le16 pkt_len;
 
                rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK;
                skb_data = card->rx_buf_list[rd_index];
 
+               MWIFIEX_SKB_PACB(skb_data, &buf_pa);
+               pci_unmap_single(card->dev, buf_pa, MWIFIEX_RX_DATA_BUF_SIZE,
+                                PCI_DMA_FROMDEVICE);
+               card->rx_buf_list[rd_index] = NULL;
+
                /* Get data length from interface header -
-                  first byte is len, second byte is type */
-               rx_len = *((u16 *)skb_data->data);
+                * first 2 bytes for len, next 2 bytes is for type
+                */
+               pkt_len = *((__le16 *)skb_data->data);
+               rx_len = le16_to_cpu(pkt_len);
+               skb_put(skb_data, rx_len);
                dev_dbg(adapter->dev,
                        "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
                        card->rxbd_rdptr, wrptr, rx_len);
-               skb_tmp = dev_alloc_skb(rx_len);
+               skb_pull(skb_data, INTF_HEADER_LEN);
+               mwifiex_handle_rx_packet(adapter, skb_data);
+
+               skb_tmp = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE);
                if (!skb_tmp) {
-                       dev_dbg(adapter->dev,
-                               "info: Failed to alloc skb for RX\n");
-                       ret = -EBUSY;
-                       goto done;
+                       dev_err(adapter->dev,
+                               "Unable to allocate skb.\n");
+                       return -ENOMEM;
                }
 
-               skb_put(skb_tmp, rx_len);
+               if (mwifiex_map_pci_memory(adapter, skb_tmp,
+                                          MWIFIEX_RX_DATA_BUF_SIZE,
+                                          PCI_DMA_FROMDEVICE))
+                       return -1;
+
+               MWIFIEX_SKB_PACB(skb_tmp, &buf_pa);
+
+               dev_dbg(adapter->dev,
+                       "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
+                       skb_tmp, rd_index);
+               card->rx_buf_list[rd_index] = skb_tmp;
+               card->rxbd_ring[rd_index]->paddr = buf_pa;
+               card->rxbd_ring[rd_index]->len = skb_tmp->len;
+               card->rxbd_ring[rd_index]->flags = 0;
 
-               memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len);
                if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) ==
                                                        MWIFIEX_MAX_TXRX_BD) {
                        card->rxbd_rdptr = ((card->rxbd_rdptr &
@@ -955,12 +1078,10 @@ static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
                }
                dev_dbg(adapter->dev,
                        "info: RECV DATA: Rcvd packet from fw successfully\n");
-               mwifiex_handle_rx_packet(adapter, skb_tmp);
+               card->rxbd_wrptr = wrptr;
        }
 
 done:
-       if (ret && skb_tmp)
-               dev_kfree_skb_any(skb_tmp);
        return ret;
 }
 
@@ -1732,10 +1853,10 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
        while (pcie_ireg & HOST_INTR_MASK) {
                if (pcie_ireg & HOST_INTR_DNLD_DONE) {
                        pcie_ireg &= ~HOST_INTR_DNLD_DONE;
-                       if (adapter->data_sent) {
-                               dev_dbg(adapter->dev, "info: DATA sent intr\n");
-                               adapter->data_sent = false;
-                       }
+                       dev_dbg(adapter->dev, "info: TX DNLD Done\n");
+                       ret = mwifiex_pcie_send_data_complete(adapter);
+                       if (ret)
+                               return ret;
                }
                if (pcie_ireg & HOST_INTR_UPLD_RDY) {
                        pcie_ireg &= ~HOST_INTR_UPLD_RDY;
@@ -1812,7 +1933,7 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
        }
 
        if (type == MWIFIEX_TYPE_DATA)
-               return mwifiex_pcie_send_data(adapter, skb);
+               return mwifiex_pcie_send_data(adapter, skb, tx_param);
        else if (type == MWIFIEX_TYPE_CMD)
                return mwifiex_pcie_send_cmd(adapter, skb);
 
index 24a39b32a222dc4c400e18f57e1cbb86ce5d3e41..37eeb2ca6b298654adc603dc9be0e3deca27a9f1 100644 (file)
@@ -159,4 +159,15 @@ mwifiex_pcie_txbd_empty(struct pcie_service_card *card, u32 rdptr)
        return 0;
 }
 
+static inline int
+mwifiex_pcie_txbd_not_full(struct pcie_service_card *card)
+{
+       if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) !=
+            (card->txbd_rdptr & MWIFIEX_TXBD_MASK)) ||
+           ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) !=
+            (card->txbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND)))
+               return 1;
+
+       return 0;
+}
 #endif /* _MWIFIEX_PCIE_H */
index 8c80024c30ff6345399d53e7132bed310a6c12a6..296faec143657bde52c6304f429f4b0b231221a3 100644 (file)
@@ -117,14 +117,16 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
                dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
                break;
        case -1:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
                dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
                        ret);
                adapter->dbg.num_tx_host_to_card_failure++;
                mwifiex_write_data_complete(adapter, skb, 0, ret);
                break;
        case -EINPROGRESS:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
                break;
        case 0:
                mwifiex_write_data_complete(adapter, skb, 0, ret);
index 6d641cbce7265968dfac09c3eeb80306a69885e4..135d96df2063a976ca107841b6d4f494abb1702a 100644 (file)
@@ -1208,13 +1208,15 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
                                       ra_list_flags);
                break;
        case -1:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
                dev_err(adapter->dev, "host_to_card failed: %#x\n", ret);
                adapter->dbg.num_tx_host_to_card_failure++;
                mwifiex_write_data_complete(adapter, skb, 0, ret);
                break;
        case -EINPROGRESS:
-               adapter->data_sent = false;
+               if (adapter->iface_type != MWIFIEX_PCIE)
+                       adapter->data_sent = false;
        default:
                break;
        }