Skip to content

Commit f027418

Browse files
robhancocksedclaudiubeznea
authored andcommitted
net: macb: Fix lost RX packet wakeup race in NAPI receive
There is an oddity in the way the RSR register flags propagate to the ISR register (and the actual interrupt output) on this hardware: it appears that RSR register bits only result in ISR being asserted if the interrupt was actually enabled at the time, so enabling interrupts with RSR bits already set doesn't trigger an interrupt to be raised. There was already a partial fix for this race in the macb_poll function where it checked for RSR bits being set and re-triggered NAPI receive. However, there was a still a race window between checking RSR and actually enabling interrupts, where a lost wakeup could happen. It's necessary to check again after enabling interrupts to see if RSR was set just prior to the interrupt being enabled, and re-trigger receive in that case. This issue was noticed in a point-to-point UDP request-response protocol which periodically saw timeouts or abnormally high response times due to received packets not being processed in a timely fashion. In many applications, more packets arriving, including TCP retransmissions, would cause the original packet to be processed, thus masking the issue. Fixes: 02f7a34 ("net: macb: Re-enable RX interrupt only when RX is done") Cc: stable@vger.kernel.org Co-developed-by: Scott McNutt <scott.mcnutt@siriusxm.com> Signed-off-by: Scott McNutt <scott.mcnutt@siriusxm.com> Signed-off-by: Robert Hancock <robert.hancock@calian.com> Tested-by: Claudiu Beznea <claudiu.beznea@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent b01183a commit f027418

1 file changed

Lines changed: 24 additions & 1 deletion

File tree

drivers/net/ethernet/cadence/macb_main.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1621,14 +1621,37 @@ static int macb_poll(struct napi_struct *napi, int budget)
16211621
if (work_done < budget) {
16221622
napi_complete_done(napi, work_done);
16231623

1624-
/* Packets received while interrupts were disabled */
1624+
/* RSR bits only seem to propagate to raise interrupts when
1625+
* interrupts are enabled at the time, so if bits are already
1626+
* set due to packets received while interrupts were disabled,
1627+
* they will not cause another interrupt to be generated when
1628+
* interrupts are re-enabled.
1629+
* Check for this case here. This has been seen to happen
1630+
* around 30% of the time under heavy network load.
1631+
*/
16251632
status = macb_readl(bp, RSR);
16261633
if (status) {
16271634
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
16281635
queue_writel(queue, ISR, MACB_BIT(RCOMP));
16291636
napi_reschedule(napi);
16301637
} else {
16311638
queue_writel(queue, IER, bp->rx_intr_mask);
1639+
1640+
/* In rare cases, packets could have been received in
1641+
* the window between the check above and re-enabling
1642+
* interrupts. Therefore, a double-check is required
1643+
* to avoid losing a wakeup. This can potentially race
1644+
* with the interrupt handler doing the same actions
1645+
* if an interrupt is raised just after enabling them,
1646+
* but this should be harmless.
1647+
*/
1648+
status = macb_readl(bp, RSR);
1649+
if (unlikely(status)) {
1650+
queue_writel(queue, IDR, bp->rx_intr_mask);
1651+
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
1652+
queue_writel(queue, ISR, MACB_BIT(RCOMP));
1653+
napi_schedule(napi);
1654+
}
16321655
}
16331656
}
16341657

0 commit comments

Comments
 (0)