#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 \
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);
}
}
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;
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;
}
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;
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);
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;
}