Skip to content

Commit 6fc937d

Browse files
xiaoleiwang123456pelwell
authored andcommitted
net: macb: Fix RX ring refill issue after link up
When the link goes down, the receive pipeline is cleared but the RX queue pointer register remains unchanged. This causes a critical issue where some RX ring entries may contain invalid addresses after link up. The problem manifests when: 1. An entry with an invalid address prevents rx_tail from advancing (gem_rx() checks rxused as 0) 2. No gap exists between rx_prepared_head and rx_tail from previous refill operations 3. gem_rx_refill() cannot refill entries because CIRC_SPACE() always returns 0 4. RSR register reports exception with value 0x7 5. The hardware detected that the buffer was unavailable. The DMA will reread the pointer each time it receives an end-of-frame signal until a valid pointer is found, but the software cannot fill it. This regression was introduced by commit 99537d5 which moved mog_init_rings() from macb_mac_link_up() to macb_open(), leaving the RX ring in an inconsistent state after link transitions. Fix this by: - Reinitializing RX rings on link up via mog_init_rings() - Adding full_refill atomic counter to force complete ring refill - Ensuring all entries are traversed and refilled after link up - Resetting rx_tail and rx_prepared_head to 0 Fixes: 99537d5 ("net: macb: Relocate mog_init_rings() callback from macb_mac_link_up() to macb_open()") Closes: #7200 (comment) Signed-off-by: Xiaolei Wang <xiaolei.wang@windriver.com>
1 parent 5aa2f4e commit 6fc937d

File tree

2 files changed

+13
-3
lines changed

2 files changed

+13
-3
lines changed

drivers/net/ethernet/cadence/macb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,7 @@ struct macb_queue {
12591259
void *rx_buffers;
12601260
struct napi_struct napi_rx;
12611261
struct queue_stats stats;
1262+
atomic_t full_refill;
12621263
};
12631264

12641265
struct ethtool_rx_fs_item {

drivers/net/ethernet/cadence/macb_main.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -775,11 +775,18 @@ static void macb_mac_link_up(struct phylink_config *config,
775775
/* Initialize rings & buffers as clearing MACB_BIT(TE) in link down
776776
* cleared the pipeline and control registers.
777777
*/
778-
macb_init_buffers(bp);
779778

780779
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue)
780+
atomic_set(&queue->full_refill, -1);
781+
782+
bp->macbgem_ops.mog_init_rings(bp);
783+
macb_init_buffers(bp);
784+
785+
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
786+
atomic_set(&queue->full_refill, bp->rx_ring_size);
781787
queue_writel(queue, IER,
782788
bp->rx_intr_mask | MACB_TX_INT_FLAGS | MACB_BIT(HRESP));
789+
}
783790
}
784791

785792
macb_or_gem_writel(bp, NCFGR, ctrl);
@@ -1327,8 +1334,9 @@ static void gem_rx_refill(struct macb_queue *queue)
13271334
struct macb *bp = queue->bp;
13281335
struct macb_dma_desc *desc;
13291336

1330-
while (CIRC_SPACE(queue->rx_prepared_head, queue->rx_tail,
1331-
bp->rx_ring_size) > 0) {
1337+
while (atomic_dec_if_positive(&queue->full_refill) >= 0 ||
1338+
((CIRC_SPACE(queue->rx_prepared_head, queue->rx_tail, bp->rx_ring_size) > 0) &&
1339+
(atomic_read(&queue->full_refill) != -1))) {
13321340
entry = macb_rx_ring_wrap(bp, queue->rx_prepared_head);
13331341

13341342
/* Make hw descriptor updates visible to CPU */
@@ -1453,6 +1461,7 @@ static int gem_rx(struct macb_queue *queue, struct napi_struct *napi,
14531461
queue->stats.rx_dropped++;
14541462
break;
14551463
}
1464+
14561465
/* now everything is ready for receiving packet */
14571466
queue->rx_skbuff[entry] = NULL;
14581467
len = ctrl & bp->rx_frm_len_mask;

0 commit comments

Comments
 (0)