diff options
Diffstat (limited to 'drivers/net/ethernet/atheros/atl1c')
-rw-r--r-- | drivers/net/ethernet/atheros/atl1c/atl1c.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/atheros/atl1c/atl1c_main.c | 40 |
2 files changed, 42 insertions, 1 deletions
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c.h b/drivers/net/ethernet/atheros/atl1c/atl1c.h index b2bf324631dc..0f0556526ba9 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c.h +++ b/drivers/net/ethernet/atheros/atl1c/atl1c.h | |||
@@ -520,6 +520,9 @@ struct atl1c_adapter { | |||
520 | struct net_device *netdev; | 520 | struct net_device *netdev; |
521 | struct pci_dev *pdev; | 521 | struct pci_dev *pdev; |
522 | struct napi_struct napi; | 522 | struct napi_struct napi; |
523 | struct page *rx_page; | ||
524 | unsigned int rx_page_offset; | ||
525 | unsigned int rx_frag_size; | ||
523 | struct atl1c_hw hw; | 526 | struct atl1c_hw hw; |
524 | struct atl1c_hw_stats hw_stats; | 527 | struct atl1c_hw_stats hw_stats; |
525 | struct mii_if_info mii; /* MII interface info */ | 528 | struct mii_if_info mii; /* MII interface info */ |
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 786a87483298..a36a760ada28 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c | |||
@@ -481,10 +481,15 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p) | |||
481 | static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter, | 481 | static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter, |
482 | struct net_device *dev) | 482 | struct net_device *dev) |
483 | { | 483 | { |
484 | unsigned int head_size; | ||
484 | int mtu = dev->mtu; | 485 | int mtu = dev->mtu; |
485 | 486 | ||
486 | adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ? | 487 | adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ? |
487 | roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE; | 488 | roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE; |
489 | |||
490 | head_size = SKB_DATA_ALIGN(adapter->rx_buffer_len + NET_SKB_PAD) + | ||
491 | SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); | ||
492 | adapter->rx_frag_size = roundup_pow_of_two(head_size); | ||
488 | } | 493 | } |
489 | 494 | ||
490 | static netdev_features_t atl1c_fix_features(struct net_device *netdev, | 495 | 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) | |||
952 | kfree(adapter->tpd_ring[0].buffer_info); | 957 | kfree(adapter->tpd_ring[0].buffer_info); |
953 | adapter->tpd_ring[0].buffer_info = NULL; | 958 | adapter->tpd_ring[0].buffer_info = NULL; |
954 | } | 959 | } |
960 | if (adapter->rx_page) { | ||
961 | put_page(adapter->rx_page); | ||
962 | adapter->rx_page = NULL; | ||
963 | } | ||
955 | } | 964 | } |
956 | 965 | ||
957 | /** | 966 | /** |
@@ -1639,6 +1648,35 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter, | |||
1639 | skb_checksum_none_assert(skb); | 1648 | skb_checksum_none_assert(skb); |
1640 | } | 1649 | } |
1641 | 1650 | ||
1651 | static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter) | ||
1652 | { | ||
1653 | struct sk_buff *skb; | ||
1654 | struct page *page; | ||
1655 | |||
1656 | if (adapter->rx_frag_size > PAGE_SIZE) | ||
1657 | return netdev_alloc_skb(adapter->netdev, | ||
1658 | adapter->rx_buffer_len); | ||
1659 | |||
1660 | page = adapter->rx_page; | ||
1661 | if (!page) { | ||
1662 | adapter->rx_page = page = alloc_page(GFP_ATOMIC); | ||
1663 | if (unlikely(!page)) | ||
1664 | return NULL; | ||
1665 | adapter->rx_page_offset = 0; | ||
1666 | } | ||
1667 | |||
1668 | skb = build_skb(page_address(page) + adapter->rx_page_offset, | ||
1669 | adapter->rx_frag_size); | ||
1670 | if (likely(skb)) { | ||
1671 | adapter->rx_page_offset += adapter->rx_frag_size; | ||
1672 | if (adapter->rx_page_offset >= PAGE_SIZE) | ||
1673 | adapter->rx_page = NULL; | ||
1674 | else | ||
1675 | get_page(page); | ||
1676 | } | ||
1677 | return skb; | ||
1678 | } | ||
1679 | |||
1642 | static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) | 1680 | static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) |
1643 | { | 1681 | { |
1644 | struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; | 1682 | struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring; |
@@ -1660,7 +1698,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter) | |||
1660 | while (next_info->flags & ATL1C_BUFFER_FREE) { | 1698 | while (next_info->flags & ATL1C_BUFFER_FREE) { |
1661 | rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use); | 1699 | rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use); |
1662 | 1700 | ||
1663 | skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len); | 1701 | skb = atl1c_alloc_skb(adapter); |
1664 | if (unlikely(!skb)) { | 1702 | if (unlikely(!skb)) { |
1665 | if (netif_msg_rx_err(adapter)) | 1703 | if (netif_msg_rx_err(adapter)) |
1666 | dev_warn(&pdev->dev, "alloc rx buffer failed\n"); | 1704 | dev_warn(&pdev->dev, "alloc rx buffer failed\n"); |