diff options
Diffstat (limited to 'target/linux/ar71xx/files/drivers/net')
-rw-r--r-- | target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c | 34 |
1 files changed, 24 insertions, 10 deletions
diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c index 663941d..6eafcee 100644 --- a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c +++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c @@ -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; } |