Skip to content

Commit 881d032

Browse files
ftang1davem330
authored andcommitted
net: alx: Work around the DMA RX overflow issue
Commit 26c5f03 uses a new skb allocator to avoid the RFD overflow issue. But from debugging without datasheet, we found the error always happen when the DMA RX address is set to 0x....fc0, which is very likely to be a HW/silicon problem. So one idea is instead of adding a new allocator, why not just hitting the right target by avaiding the error-prone DMA address? This patch will actually * Remove the commit 26c5f03 * Apply rx skb with 64 bytes longer space, and if the allocated skb has a 0x...fc0 address, it will use skb_resever(skb, 64) to advance the address, so that the RX overflow can be avoided. In theory this method should also apply to atl1c driver, which I can't find anyone who can help to test on real devices. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=70761 Signed-off-by: Feng Tang <[email protected]> Suggested-by: Eric Dumazet <[email protected]> Tested-by: Ole Lukoie <[email protected]> Acked-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b46d9f6 commit 881d032

File tree

2 files changed

+14
-51
lines changed

2 files changed

+14
-51
lines changed

drivers/net/ethernet/atheros/alx/alx.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,6 @@ struct alx_priv {
9696
unsigned int rx_ringsz;
9797
unsigned int rxbuf_size;
9898

99-
struct page *rx_page;
100-
unsigned int rx_page_offset;
101-
unsigned int rx_frag_size;
102-
10399
struct napi_struct napi;
104100
struct alx_tx_queue txq;
105101
struct alx_rx_queue rxq;

drivers/net/ethernet/atheros/alx/main.c

Lines changed: 14 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -70,35 +70,6 @@ static void alx_free_txbuf(struct alx_priv *alx, int entry)
7070
}
7171
}
7272

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-
10273
static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp)
10374
{
10475
struct alx_rx_queue *rxq = &alx->rxq;
@@ -115,9 +86,22 @@ static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp)
11586
while (!cur_buf->skb && next != rxq->read_idx) {
11687
struct alx_rfd *rfd = &rxq->rfd[cur];
11788

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);
11999
if (!skb)
120100
break;
101+
102+
if (((unsigned long)skb->data & 0xfff) == 0xfc0)
103+
skb_reserve(skb, 64);
104+
121105
dma = dma_map_single(&alx->hw.pdev->dev,
122106
skb->data, alx->rxbuf_size,
123107
DMA_FROM_DEVICE);
@@ -153,7 +137,6 @@ static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp)
153137
alx_write_mem16(&alx->hw, ALX_RFD_PIDX, cur);
154138
}
155139

156-
157140
return count;
158141
}
159142

@@ -622,11 +605,6 @@ static void alx_free_rings(struct alx_priv *alx)
622605
kfree(alx->txq.bufs);
623606
kfree(alx->rxq.bufs);
624607

625-
if (alx->rx_page) {
626-
put_page(alx->rx_page);
627-
alx->rx_page = NULL;
628-
}
629-
630608
dma_free_coherent(&alx->hw.pdev->dev,
631609
alx->descmem.size,
632610
alx->descmem.virt,
@@ -681,7 +659,6 @@ static int alx_request_irq(struct alx_priv *alx)
681659
alx->dev->name, alx);
682660
if (!err)
683661
goto out;
684-
685662
/* fall back to legacy interrupt */
686663
pci_disable_msi(alx->hw.pdev);
687664
}
@@ -725,7 +702,6 @@ static int alx_init_sw(struct alx_priv *alx)
725702
struct pci_dev *pdev = alx->hw.pdev;
726703
struct alx_hw *hw = &alx->hw;
727704
int err;
728-
unsigned int head_size;
729705

730706
err = alx_identify_hw(alx);
731707
if (err) {
@@ -741,12 +717,7 @@ static int alx_init_sw(struct alx_priv *alx)
741717

742718
hw->smb_timer = 400;
743719
hw->mtu = alx->dev->mtu;
744-
745720
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-
750721
alx->tx_ringsz = 256;
751722
alx->rx_ringsz = 512;
752723
hw->imt = 200;
@@ -848,7 +819,6 @@ static int alx_change_mtu(struct net_device *netdev, int mtu)
848819
{
849820
struct alx_priv *alx = netdev_priv(netdev);
850821
int max_frame = ALX_MAX_FRAME_LEN(mtu);
851-
unsigned int head_size;
852822

853823
if ((max_frame < ALX_MIN_FRAME_SIZE) ||
854824
(max_frame > ALX_MAX_FRAME_SIZE))
@@ -860,9 +830,6 @@ static int alx_change_mtu(struct net_device *netdev, int mtu)
860830
netdev->mtu = mtu;
861831
alx->hw.mtu = mtu;
862832
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);
866833
netdev_update_features(netdev);
867834
if (netif_running(netdev))
868835
alx_reinit(alx);

0 commit comments

Comments
 (0)