ar71xx: use page fragment API in the ethernet driver
authorFelix Fietkau <nbd@openwrt.org>
Sun, 31 Jan 2016 12:29:34 +0000 (12:29 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 31 Jan 2016 12:29:34 +0000 (12:29 +0000)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
SVN-Revision: 48578

target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c

index 663941dda1f1a0c95de54a9b20e0fbbbefc9245f..6eafceef0398c85875d488dd1d19756a1dfcb156 100644 (file)
 
 #include "ag71xx.h"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)
+static inline void skb_free_frag(void *data)
+{
+       put_page(virt_to_head_page(data));
+}
+#endif
+
 #define AG71XX_DEFAULT_MSG_ENABLE      \
        (NETIF_MSG_DRV                  \
        | NETIF_MSG_PROBE               \
@@ -197,7 +204,7 @@ static void ag71xx_ring_rx_clean(struct ag71xx *ag)
                if (ring->buf[i].rx_buf) {
                        dma_unmap_single(&ag->dev->dev, ring->buf[i].dma_addr,
                                         ag->rx_buf_size, DMA_FROM_DEVICE);
-                       kfree(ring->buf[i].rx_buf);
+                       skb_free_frag(ring->buf[i].rx_buf);
                }
 }
 
@@ -217,16 +224,21 @@ static int ag71xx_buffer_offset(struct ag71xx *ag)
        return offset + NET_IP_ALIGN;
 }
 
+static int ag71xx_buffer_size(struct ag71xx *ag)
+{
+       return ag->rx_buf_size +
+              SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+}
+
 static bool ag71xx_fill_rx_buf(struct ag71xx *ag, struct ag71xx_buf *buf,
-                              int offset)
+                              int offset,
+                              void *(*alloc)(unsigned int size))
 {
        struct ag71xx_ring *ring = &ag->rx_ring;
        struct ag71xx_desc *desc = ag71xx_ring_desc(ring, buf - &ring->buf[0]);
        void *data;
 
-       data = kmalloc(ag->rx_buf_size +
-                      SKB_DATA_ALIGN(sizeof(struct skb_shared_info)),
-                      GFP_ATOMIC);
+       data = alloc(ag71xx_buffer_size(ag));
        if (!data)
                return false;
 
@@ -258,7 +270,8 @@ static int ag71xx_ring_rx_init(struct ag71xx *ag)
        for (i = 0; i < ring->size; i++) {
                struct ag71xx_desc *desc = ag71xx_ring_desc(ring, i);
 
-               if (!ag71xx_fill_rx_buf(ag, &ring->buf[i], offset)) {
+               if (!ag71xx_fill_rx_buf(ag, &ring->buf[i], offset,
+                                       netdev_alloc_frag)) {
                        ret = -ENOMEM;
                        break;
                }
@@ -290,7 +303,8 @@ static int ag71xx_ring_rx_refill(struct ag71xx *ag)
                desc = ag71xx_ring_desc(ring, i);
 
                if (!ring->buf[i].rx_buf &&
-                   !ag71xx_fill_rx_buf(ag, &ring->buf[i], offset))
+                   !ag71xx_fill_rx_buf(ag, &ring->buf[i], offset,
+                                       napi_alloc_frag))
                        break;
 
                desc->ctrl = DESC_EMPTY;
@@ -680,7 +694,7 @@ static int ag71xx_open(struct net_device *dev)
 
        netif_carrier_off(dev);
        max_frame_len = ag71xx_max_frame_len(dev->mtu);
-       ag->rx_buf_size = max_frame_len + NET_SKB_PAD + NET_IP_ALIGN;
+       ag->rx_buf_size = SKB_DATA_ALIGN(max_frame_len + NET_SKB_PAD + NET_IP_ALIGN);
 
        /* setup max frame length */
        ag71xx_wr(ag, AG71XX_REG_MAC_MFL, max_frame_len);
@@ -1012,9 +1026,9 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit)
                dev->stats.rx_packets++;
                dev->stats.rx_bytes += pktlen;
 
-               skb = build_skb(ring->buf[i].rx_buf, 0);
+               skb = build_skb(ring->buf[i].rx_buf, ag71xx_buffer_size(ag));
                if (!skb) {
-                       kfree(ring->buf[i].rx_buf);
+                       skb_free_frag(ring->buf[i].rx_buf);
                        goto next;
                }