ar71xx: use page fragment API in the ethernet driver

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

SVN-Revision: 48578
This commit is contained in:
Felix Fietkau 2016-01-31 12:29:34 +00:00
parent 8fe8360981
commit 2067f7f1de

View File

@ -13,6 +13,13 @@
#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;
}