qede: Correct XDP forward unmapping
authorMintz, Yuval <Yuval.Mintz@cavium.com>
Fri, 7 Apr 2017 08:04:58 +0000 (11:04 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 7 Apr 2017 13:26:14 +0000 (06:26 -0700)
Driver is currently using dma_unmap_single() with the address it
passed to device for the purpose of forwarding, but the XDP
transmission buffer was originally a page allocated for the rx-queue.
The mapped address is likely to differ from the original mapped
address due to the placement offset.

This difference is going to get even bigger once we support headroom.

Cache the original mapped address of the page, and use it for unmapping
of the buffer when completion arrives for the XDP forwarded packet.

Signed-off-by: Yuval Mintz <Yuval.Mintz@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qede/qede.h
drivers/net/ethernet/qlogic/qede/qede_fp.c
drivers/net/ethernet/qlogic/qede/qede_main.c

index e73a4a5165ee7a00193f249a33dd3297898e04e0..7ab2201a43b26cb325d30f7b0b1a7bdeb74f3101 100644 (file)
@@ -349,6 +349,11 @@ struct sw_tx_bd {
 #define QEDE_TSO_SPLIT_BD              BIT(0)
 };
 
+struct sw_tx_xdp {
+       struct page *page;
+       dma_addr_t mapping;
+};
+
 struct qede_tx_queue {
        u8 is_xdp;
        bool is_legacy;
@@ -372,11 +377,11 @@ struct qede_tx_queue {
 #define QEDE_TXQ_IDX_TO_XDP(edev, idx) ((idx) + QEDE_MAX_TSS_CNT(edev))
 
        /* Regular Tx requires skb + metadata for release purpose,
-        * while XDP requires only the pages themselves.
+        * while XDP requires the pages and the mapped address.
         */
        union {
                struct sw_tx_bd *skbs;
-               struct page **pages;
+               struct sw_tx_xdp *xdp;
        } sw_tx_ring;
 
        struct qed_chain tx_pbl;
index c77e6972ab48aec3c504a193d78b20f196800d01..c61cfcfbbd56ef29ea7d09154af2d732e32fc5dd 100644 (file)
@@ -360,7 +360,8 @@ static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp,
                                   metadata->mapping + padding,
                                   length, PCI_DMA_TODEVICE);
 
-       txq->sw_tx_ring.pages[idx] = metadata->data;
+       txq->sw_tx_ring.xdp[idx].page = metadata->data;
+       txq->sw_tx_ring.xdp[idx].mapping = metadata->mapping;
        txq->sw_tx_prod++;
 
        /* Mark the fastpath for future XDP doorbell */
@@ -384,19 +385,19 @@ int qede_txq_has_work(struct qede_tx_queue *txq)
 
 static void qede_xdp_tx_int(struct qede_dev *edev, struct qede_tx_queue *txq)
 {
-       struct eth_tx_1st_bd *bd;
-       u16 hw_bd_cons;
+       u16 hw_bd_cons, idx;
 
        hw_bd_cons = le16_to_cpu(*txq->hw_cons_ptr);
        barrier();
 
        while (hw_bd_cons != qed_chain_get_cons_idx(&txq->tx_pbl)) {
-               bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl);
+               qed_chain_consume(&txq->tx_pbl);
+               idx = txq->sw_tx_cons & NUM_TX_BDS_MAX;
 
-               dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(bd),
-                                PAGE_SIZE, DMA_BIDIRECTIONAL);
-               __free_page(txq->sw_tx_ring.pages[txq->sw_tx_cons &
-                                                 NUM_TX_BDS_MAX]);
+               dma_unmap_page(&edev->pdev->dev,
+                              txq->sw_tx_ring.xdp[idx].mapping,
+                              PAGE_SIZE, DMA_BIDIRECTIONAL);
+               __free_page(txq->sw_tx_ring.xdp[idx].page);
 
                txq->sw_tx_cons++;
                txq->xmit_pkts++;
index abd99109e5328229bed46d1c954c8b8b4bc9200e..fa62c37dac7a2141661784ee7c4ef87ff1fa4fe0 100644 (file)
@@ -1251,7 +1251,7 @@ static void qede_free_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq)
 {
        /* Free the parallel SW ring */
        if (txq->is_xdp)
-               kfree(txq->sw_tx_ring.pages);
+               kfree(txq->sw_tx_ring.xdp);
        else
                kfree(txq->sw_tx_ring.skbs);
 
@@ -1269,9 +1269,9 @@ static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq)
 
        /* Allocate the parallel driver ring for Tx buffers */
        if (txq->is_xdp) {
-               size = sizeof(*txq->sw_tx_ring.pages) * TX_RING_SIZE;
-               txq->sw_tx_ring.pages = kzalloc(size, GFP_KERNEL);
-               if (!txq->sw_tx_ring.pages)
+               size = sizeof(*txq->sw_tx_ring.xdp) * TX_RING_SIZE;
+               txq->sw_tx_ring.xdp = kzalloc(size, GFP_KERNEL);
+               if (!txq->sw_tx_ring.xdp)
                        goto err;
        } else {
                size = sizeof(*txq->sw_tx_ring.skbs) * TX_RING_SIZE;