ar71xx: use page fragment API in the ethernet driver

Signed-off-by: Felix Fietkau <nbd@openwrt.org>

SVN-Revision: 48578
master
Felix Fietkau 9 years ago
parent 8fe8360981
commit 2067f7f1de
  1. 34
      target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c

@ -13,6 +13,13 @@
#include "ag71xx.h" #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 \ #define AG71XX_DEFAULT_MSG_ENABLE \
(NETIF_MSG_DRV \ (NETIF_MSG_DRV \
| NETIF_MSG_PROBE \ | NETIF_MSG_PROBE \
@ -197,7 +204,7 @@ static void ag71xx_ring_rx_clean(struct ag71xx *ag)
if (ring->buf[i].rx_buf) { if (ring->buf[i].rx_buf) {
dma_unmap_single(&ag->dev->dev, ring->buf[i].dma_addr, dma_unmap_single(&ag->dev->dev, ring->buf[i].dma_addr,
ag->rx_buf_size, DMA_FROM_DEVICE); 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; 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, 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_ring *ring = &ag->rx_ring;
struct ag71xx_desc *desc = ag71xx_ring_desc(ring, buf - &ring->buf[0]); struct ag71xx_desc *desc = ag71xx_ring_desc(ring, buf - &ring->buf[0]);
void *data; void *data;
data = kmalloc(ag->rx_buf_size + data = alloc(ag71xx_buffer_size(ag));
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)),
GFP_ATOMIC);
if (!data) if (!data)
return false; return false;
@ -258,7 +270,8 @@ static int ag71xx_ring_rx_init(struct ag71xx *ag)
for (i = 0; i < ring->size; i++) { for (i = 0; i < ring->size; i++) {
struct ag71xx_desc *desc = ag71xx_ring_desc(ring, 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; ret = -ENOMEM;
break; break;
} }
@ -290,7 +303,8 @@ static int ag71xx_ring_rx_refill(struct ag71xx *ag)
desc = ag71xx_ring_desc(ring, i); desc = ag71xx_ring_desc(ring, i);
if (!ring->buf[i].rx_buf && 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; break;
desc->ctrl = DESC_EMPTY; desc->ctrl = DESC_EMPTY;
@ -680,7 +694,7 @@ static int ag71xx_open(struct net_device *dev)
netif_carrier_off(dev); netif_carrier_off(dev);
max_frame_len = ag71xx_max_frame_len(dev->mtu); 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 */ /* setup max frame length */
ag71xx_wr(ag, AG71XX_REG_MAC_MFL, max_frame_len); 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_packets++;
dev->stats.rx_bytes += pktlen; 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) { if (!skb) {
kfree(ring->buf[i].rx_buf); skb_free_frag(ring->buf[i].rx_buf);
goto next; goto next;
} }

Loading…
Cancel
Save