diff options
Diffstat (limited to 'drivers/net/ethernet/atheros/alx/main.c')
-rw-r--r-- | drivers/net/ethernet/atheros/alx/main.c | 61 |
1 files changed, 14 insertions, 47 deletions
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index c98acdc0d14f..e708e360a9e3 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c | |||
@@ -70,35 +70,6 @@ static void alx_free_txbuf(struct alx_priv *alx, int entry) | |||
70 | } | 70 | } |
71 | } | 71 | } |
72 | 72 | ||
73 | static struct sk_buff *alx_alloc_skb(struct alx_priv *alx, gfp_t gfp) | ||
74 | { | ||
75 | struct sk_buff *skb; | ||
76 | struct page *page; | ||
77 | |||
78 | if (alx->rx_frag_size > PAGE_SIZE) | ||
79 | return __netdev_alloc_skb(alx->dev, alx->rxbuf_size, gfp); | ||
80 | |||
81 | page = alx->rx_page; | ||
82 | if (!page) { | ||
83 | alx->rx_page = page = alloc_page(gfp); | ||
84 | if (unlikely(!page)) | ||
85 | return NULL; | ||
86 | alx->rx_page_offset = 0; | ||
87 | } | ||
88 | |||
89 | skb = build_skb(page_address(page) + alx->rx_page_offset, | ||
90 | alx->rx_frag_size); | ||
91 | if (likely(skb)) { | ||
92 | alx->rx_page_offset += alx->rx_frag_size; | ||
93 | if (alx->rx_page_offset >= PAGE_SIZE) | ||
94 | alx->rx_page = NULL; | ||
95 | else | ||
96 | get_page(page); | ||
97 | } | ||
98 | return skb; | ||
99 | } | ||
100 | |||
101 | |||
102 | static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp) | 73 | static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp) |
103 | { | 74 | { |
104 | struct alx_rx_queue *rxq = &alx->rxq; | 75 | struct alx_rx_queue *rxq = &alx->rxq; |
@@ -115,9 +86,22 @@ static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp) | |||
115 | while (!cur_buf->skb && next != rxq->read_idx) { | 86 | while (!cur_buf->skb && next != rxq->read_idx) { |
116 | struct alx_rfd *rfd = &rxq->rfd[cur]; | 87 | struct alx_rfd *rfd = &rxq->rfd[cur]; |
117 | 88 | ||
118 | skb = alx_alloc_skb(alx, gfp); | 89 | /* |
90 | * When DMA RX address is set to something like | ||
91 | * 0x....fc0, it will be very likely to cause DMA | ||
92 | * RFD overflow issue. | ||
93 | * | ||
94 | * To work around it, we apply rx skb with 64 bytes | ||
95 | * longer space, and offset the address whenever | ||
96 | * 0x....fc0 is detected. | ||
97 | */ | ||
98 | skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size + 64, gfp); | ||
119 | if (!skb) | 99 | if (!skb) |
120 | break; | 100 | break; |
101 | |||
102 | if (((unsigned long)skb->data & 0xfff) == 0xfc0) | ||
103 | skb_reserve(skb, 64); | ||
104 | |||
121 | dma = dma_map_single(&alx->hw.pdev->dev, | 105 | dma = dma_map_single(&alx->hw.pdev->dev, |
122 | skb->data, alx->rxbuf_size, | 106 | skb->data, alx->rxbuf_size, |
123 | DMA_FROM_DEVICE); | 107 | DMA_FROM_DEVICE); |
@@ -153,7 +137,6 @@ static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp) | |||
153 | alx_write_mem16(&alx->hw, ALX_RFD_PIDX, cur); | 137 | alx_write_mem16(&alx->hw, ALX_RFD_PIDX, cur); |
154 | } | 138 | } |
155 | 139 | ||
156 | |||
157 | return count; | 140 | return count; |
158 | } | 141 | } |
159 | 142 | ||
@@ -622,11 +605,6 @@ static void alx_free_rings(struct alx_priv *alx) | |||
622 | kfree(alx->txq.bufs); | 605 | kfree(alx->txq.bufs); |
623 | kfree(alx->rxq.bufs); | 606 | kfree(alx->rxq.bufs); |
624 | 607 | ||
625 | if (alx->rx_page) { | ||
626 | put_page(alx->rx_page); | ||
627 | alx->rx_page = NULL; | ||
628 | } | ||
629 | |||
630 | dma_free_coherent(&alx->hw.pdev->dev, | 608 | dma_free_coherent(&alx->hw.pdev->dev, |
631 | alx->descmem.size, | 609 | alx->descmem.size, |
632 | alx->descmem.virt, | 610 | alx->descmem.virt, |
@@ -681,7 +659,6 @@ static int alx_request_irq(struct alx_priv *alx) | |||
681 | alx->dev->name, alx); | 659 | alx->dev->name, alx); |
682 | if (!err) | 660 | if (!err) |
683 | goto out; | 661 | goto out; |
684 | |||
685 | /* fall back to legacy interrupt */ | 662 | /* fall back to legacy interrupt */ |
686 | pci_disable_msi(alx->hw.pdev); | 663 | pci_disable_msi(alx->hw.pdev); |
687 | } | 664 | } |
@@ -725,7 +702,6 @@ static int alx_init_sw(struct alx_priv *alx) | |||
725 | struct pci_dev *pdev = alx->hw.pdev; | 702 | struct pci_dev *pdev = alx->hw.pdev; |
726 | struct alx_hw *hw = &alx->hw; | 703 | struct alx_hw *hw = &alx->hw; |
727 | int err; | 704 | int err; |
728 | unsigned int head_size; | ||
729 | 705 | ||
730 | err = alx_identify_hw(alx); | 706 | err = alx_identify_hw(alx); |
731 | if (err) { | 707 | if (err) { |
@@ -741,12 +717,7 @@ static int alx_init_sw(struct alx_priv *alx) | |||
741 | 717 | ||
742 | hw->smb_timer = 400; | 718 | hw->smb_timer = 400; |
743 | hw->mtu = alx->dev->mtu; | 719 | hw->mtu = alx->dev->mtu; |
744 | |||
745 | alx->rxbuf_size = ALX_MAX_FRAME_LEN(hw->mtu); | 720 | alx->rxbuf_size = ALX_MAX_FRAME_LEN(hw->mtu); |
746 | head_size = SKB_DATA_ALIGN(alx->rxbuf_size + NET_SKB_PAD) + | ||
747 | SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); | ||
748 | alx->rx_frag_size = roundup_pow_of_two(head_size); | ||
749 | |||
750 | alx->tx_ringsz = 256; | 721 | alx->tx_ringsz = 256; |
751 | alx->rx_ringsz = 512; | 722 | alx->rx_ringsz = 512; |
752 | hw->imt = 200; | 723 | hw->imt = 200; |
@@ -848,7 +819,6 @@ static int alx_change_mtu(struct net_device *netdev, int mtu) | |||
848 | { | 819 | { |
849 | struct alx_priv *alx = netdev_priv(netdev); | 820 | struct alx_priv *alx = netdev_priv(netdev); |
850 | int max_frame = ALX_MAX_FRAME_LEN(mtu); | 821 | int max_frame = ALX_MAX_FRAME_LEN(mtu); |
851 | unsigned int head_size; | ||
852 | 822 | ||
853 | if ((max_frame < ALX_MIN_FRAME_SIZE) || | 823 | if ((max_frame < ALX_MIN_FRAME_SIZE) || |
854 | (max_frame > ALX_MAX_FRAME_SIZE)) | 824 | (max_frame > ALX_MAX_FRAME_SIZE)) |
@@ -860,9 +830,6 @@ static int alx_change_mtu(struct net_device *netdev, int mtu) | |||
860 | netdev->mtu = mtu; | 830 | netdev->mtu = mtu; |
861 | alx->hw.mtu = mtu; | 831 | alx->hw.mtu = mtu; |
862 | alx->rxbuf_size = max(max_frame, ALX_DEF_RXBUF_SIZE); | 832 | alx->rxbuf_size = max(max_frame, ALX_DEF_RXBUF_SIZE); |
863 | head_size = SKB_DATA_ALIGN(alx->rxbuf_size + NET_SKB_PAD) + | ||
864 | SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); | ||
865 | alx->rx_frag_size = roundup_pow_of_two(head_size); | ||
866 | netdev_update_features(netdev); | 833 | netdev_update_features(netdev); |
867 | if (netif_running(netdev)) | 834 | if (netif_running(netdev)) |
868 | alx_reinit(alx); | 835 | alx_reinit(alx); |