|
@@ -481,10 +481,15 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
|
|
|
static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
|
|
|
struct net_device *dev)
|
|
|
{
|
|
|
+ unsigned int head_size;
|
|
|
int mtu = dev->mtu;
|
|
|
|
|
|
adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ?
|
|
|
roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE;
|
|
|
+
|
|
|
+ head_size = SKB_DATA_ALIGN(adapter->rx_buffer_len + NET_SKB_PAD) +
|
|
|
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
|
|
|
+ adapter->rx_frag_size = roundup_pow_of_two(head_size);
|
|
|
}
|
|
|
|
|
|
static netdev_features_t atl1c_fix_features(struct net_device *netdev,
|
|
@@ -952,6 +957,10 @@ static void atl1c_free_ring_resources(struct atl1c_adapter *adapter)
|
|
|
kfree(adapter->tpd_ring[0].buffer_info);
|
|
|
adapter->tpd_ring[0].buffer_info = NULL;
|
|
|
}
|
|
|
+ if (adapter->rx_page) {
|
|
|
+ put_page(adapter->rx_page);
|
|
|
+ adapter->rx_page = NULL;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1639,6 +1648,35 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
|
|
|
skb_checksum_none_assert(skb);
|
|
|
}
|
|
|
|
|
|
+static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter)
|
|
|
+{
|
|
|
+ struct sk_buff *skb;
|
|
|
+ struct page *page;
|
|
|
+
|
|
|
+ if (adapter->rx_frag_size > PAGE_SIZE)
|
|
|
+ return netdev_alloc_skb(adapter->netdev,
|
|
|
+ adapter->rx_buffer_len);
|
|
|
+
|
|
|
+ page = adapter->rx_page;
|
|
|
+ if (!page) {
|
|
|
+ adapter->rx_page = page = alloc_page(GFP_ATOMIC);
|
|
|
+ if (unlikely(!page))
|
|
|
+ return NULL;
|
|
|
+ adapter->rx_page_offset = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ skb = build_skb(page_address(page) + adapter->rx_page_offset,
|
|
|
+ adapter->rx_frag_size);
|
|
|
+ if (likely(skb)) {
|
|
|
+ adapter->rx_page_offset += adapter->rx_frag_size;
|
|
|
+ if (adapter->rx_page_offset >= PAGE_SIZE)
|
|
|
+ adapter->rx_page = NULL;
|
|
|
+ else
|
|
|
+ get_page(page);
|
|
|
+ }
|
|
|
+ return skb;
|
|
|
+}
|
|
|
+
|
|
|
static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
|
|
|
{
|
|
|
struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
|
|
@@ -1660,7 +1698,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
|
|
|
while (next_info->flags & ATL1C_BUFFER_FREE) {
|
|
|
rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
|
|
|
|
|
|
- skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len);
|
|
|
+ skb = atl1c_alloc_skb(adapter);
|
|
|
if (unlikely(!skb)) {
|
|
|
if (netif_msg_rx_err(adapter))
|
|
|
dev_warn(&pdev->dev, "alloc rx buffer failed\n");
|