bgmac: pass received packet to the netif instead of copying it
authorRafał Miłecki <zajec5@gmail.com>
Wed, 30 Oct 2013 07:00:00 +0000 (08:00 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 30 Oct 2013 20:58:19 +0000 (16:58 -0400)
Copying whole packets with skb_copy_from_linear_data_offset is a pretty
bad idea. CPU was spending time in __copy_user_common and network
performance was lower. With the new solution iperf-measured speed
increased from 116Mb/s to 134Mb/s.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bgmac.c

index 4f9beed54506a888d21a40c77b0db18b708f308d..a98778e3af842181acded6ed602d91ad3a0a2747 100644 (file)
@@ -315,7 +315,6 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
                struct device *dma_dev = bgmac->core->dma_dev;
                struct bgmac_slot_info *slot = &ring->slots[ring->start];
                struct sk_buff *skb = slot->skb;
-               struct sk_buff *new_skb;
                struct bgmac_rx_header *rx;
                u16 len, flags;
 
@@ -328,38 +327,51 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
                len = le16_to_cpu(rx->len);
                flags = le16_to_cpu(rx->flags);
 
-               /* Check for poison and drop or pass the packet */
-               if (len == 0xdead && flags == 0xbeef) {
-                       bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
-                                 ring->start);
-               } else {
+               do {
+                       dma_addr_t old_dma_addr = slot->dma_addr;
+                       int err;
+
+                       /* Check for poison and drop or pass the packet */
+                       if (len == 0xdead && flags == 0xbeef) {
+                               bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
+                                         ring->start);
+                               dma_sync_single_for_device(dma_dev,
+                                                          slot->dma_addr,
+                                                          BGMAC_RX_BUF_SIZE,
+                                                          DMA_FROM_DEVICE);
+                               break;
+                       }
+
                        /* Omit CRC. */
                        len -= ETH_FCS_LEN;
 
-                       new_skb = netdev_alloc_skb_ip_align(bgmac->net_dev, len);
-                       if (new_skb) {
-                               skb_put(new_skb, len);
-                               skb_copy_from_linear_data_offset(skb, BGMAC_RX_FRAME_OFFSET,
-                                                                new_skb->data,
-                                                                len);
-                               skb_checksum_none_assert(skb);
-                               new_skb->protocol =
-                                       eth_type_trans(new_skb, bgmac->net_dev);
-                               netif_receive_skb(new_skb);
-                               handled++;
-                       } else {
-                               bgmac->net_dev->stats.rx_dropped++;
-                               bgmac_err(bgmac, "Allocation of skb for copying packet failed!\n");
+                       /* Prepare new skb as replacement */
+                       err = bgmac_dma_rx_skb_for_slot(bgmac, slot);
+                       if (err) {
+                               /* Poison the old skb */
+                               rx->len = cpu_to_le16(0xdead);
+                               rx->flags = cpu_to_le16(0xbeef);
+
+                               dma_sync_single_for_device(dma_dev,
+                                                          slot->dma_addr,
+                                                          BGMAC_RX_BUF_SIZE,
+                                                          DMA_FROM_DEVICE);
+                               break;
                        }
+                       bgmac_dma_rx_setup_desc(bgmac, ring, ring->start);
 
-                       /* Poison the old skb */
-                       rx->len = cpu_to_le16(0xdead);
-                       rx->flags = cpu_to_le16(0xbeef);
-               }
+                       /* Unmap old skb, we'll pass it to the netfif */
+                       dma_unmap_single(dma_dev, old_dma_addr,
+                                        BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+
+                       skb_put(skb, BGMAC_RX_FRAME_OFFSET + len);
+                       skb_pull(skb, BGMAC_RX_FRAME_OFFSET);
 
-               /* Make it back accessible to the hardware */
-               dma_sync_single_for_device(dma_dev, slot->dma_addr,
-                                          BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
+                       skb_checksum_none_assert(skb);
+                       skb->protocol = eth_type_trans(skb, bgmac->net_dev);
+                       netif_receive_skb(skb);
+                       handled++;
+               } while (0);
 
                if (++ring->start >= BGMAC_RX_RING_SLOTS)
                        ring->start = 0;