Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions drivers/net/ethernet/cadence/macb.h
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,10 @@
#define MACB_CAPS_QUEUE_DISABLE 0x00000800
#define MACB_CAPS_QBV 0x00001000
#define MACB_CAPS_EEE 0x00002000
/* Register writes are posted on the parent fabric and need a non-posted
* read-back to guarantee delivery. Currently set only on RP1.
*/
#define MACB_CAPS_PCIE_POSTED_WRITES 0x00004000
#define MACB_CAPS_PCS 0x01000000
#define MACB_CAPS_HIGH_SPEED 0x02000000
#define MACB_CAPS_CLK_HW_CHG 0x04000000
Expand Down
77 changes: 50 additions & 27 deletions drivers/net/ethernet/cadence/macb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1951,12 +1951,13 @@

spin_lock(&bp->lock);
macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
/* Flush the PCIe posted-write queue so the TSTART doorbell
* reliably reaches the MAC. Without this, the write can sit
* in the fabric and the MAC never advances, causing a silent
* TX stall.
/* On PCIe-attached parts, flush the posted-write queue so the
* TSTART doorbell reliably reaches the MAC. Without this the
* write can sit in the fabric and the MAC never advances,
* causing a silent TX stall.
*/
(void)macb_readl(bp, NCR);
if (bp->caps & MACB_CAPS_PCIE_POSTED_WRITES)
(void)macb_readl(bp, NCR);
spin_unlock(&bp->lock);

out_tx_ptr_unlock:
Expand Down Expand Up @@ -2001,24 +2002,31 @@
if (work_done < budget && napi_complete_done(napi, work_done)) {
queue_writel(queue, IER, MACB_BIT(TCOMP));

/* TCOMP events that fire while the interrupt is masked do
* not re-fire when IER is re-enabled. Catch this two ways
* to avoid losing a wakeup:
/* TCOMP events that fire while masked don't re-fire when
* IER is re-enabled (HW errata), so check in software.
* macb_tx_complete_pending() inspects the descriptor at
* tx_tail; the rmb() in there orders prior CPU writes but
* does not retire in-flight peripheral DMA writes that
* may still be racing back to memory on PCIe-attached
* parts.
*
* (1) Read ISR -- catches completions the hardware flagged
* but that we did not see as an interrupt. The MMIO
* read doubles as a PCIe read barrier, flushing any
* in-flight descriptor TX_USED DMA writes into memory.
* (2) macb_tx_complete_pending() inspects the ring after
* that flush, catching a descriptor whose TX_USED is
* now visible as a result of the barrier.
* Read a side-effect-free MMIO register (IMR, the
* read-only mask mirror) to act as a PCIe read barrier
* for prior peripheral DMA writes. After this read, any
* in-flight TX_USED descriptor update has retired and
* macb_tx_complete_pending() will observe it.
*
* This can race with the interrupt handler taking the same
* path if an interrupt fires just after the IER write;
* rescheduling NAPI in that case is harmless.
* Note: an earlier form of this block read ISR directly
* to also sample a latched TCOMP bit, but that is
* destructive on silicon where MACB_CAPS_ISR_CLEAR_ON_WRITE
* is not set (raspberrypi_rp1_config among others): the
* read clears every set bit, and a masked check silently
* consumes RCOMP / ROVR / TXUBR bits the IRQ handler is
* expected to process in one pass. IMR is non-destructive
* on both read-clear and W1C silicon.
*/
if ((queue_readl(queue, ISR) & MACB_BIT(TCOMP)) ||
macb_tx_complete_pending(queue)) {
(void)queue_readl(queue, IMR);
if (macb_tx_complete_pending(queue)) {
queue_writel(queue, IDR, MACB_BIT(TCOMP));
if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
queue_writel(queue, ISR, MACB_BIT(TCOMP));
Expand Down Expand Up @@ -2067,6 +2075,16 @@
if (!netif_running(bp->dev))
return;

/* No carrier => no completion is possible. Skip the stall
* check (otherwise queue->tx_head can advance from kernel-
* queued packets between macb_open() and link autoneg
* completion while tx_tail stays unchanged, tripping a false
* positive), but keep the watchdog ticking so it picks up
* once carrier comes up.
*/
if (!netif_carrier_ok(bp->dev))
goto reschedule;

spin_lock_irqsave(&queue->tx_ptr_lock, flags);
cur_tail = queue->tx_tail;
cur_head = queue->tx_head;
Expand All @@ -2076,13 +2094,15 @@
spin_unlock_irqrestore(&queue->tx_ptr_lock, flags);

if (stalled) {
netdev_warn_once(bp->dev,
"TX stall detected on queue %u (tail=%u head=%u); re-kicking TSTART\n",
(unsigned int)(queue - bp->queues),
cur_tail, cur_head);
if (printk_ratelimit())

Check failure on line 2097 in drivers/net/ethernet/cadence/macb_main.c

View workflow job for this annotation

GitHub Actions / checkpatch review

WARNING: Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit
netdev_warn(bp->dev,
"TX stall detected on queue %u (tail=%u head=%u); re-kicking TSTART\n",
Comment thread
lukaszraczylo marked this conversation as resolved.
Outdated
(unsigned int)(queue - bp->queues),
cur_tail, cur_head);
macb_tx_restart(queue);
}

reschedule:
schedule_delayed_work(&queue->tx_stall_watchdog_work,
msecs_to_jiffies(MACB_TX_STALL_INTERVAL_MS));
}
Expand Down Expand Up @@ -2702,10 +2722,12 @@
queue->tx_pending = 1;

macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
/* Flush the PCIe posted-write queue; see the comment in
* macb_tx_restart() for the reasoning.
/* Flush PCIe posted-write queue; see comment in macb_tx_restart().
* Also flushes the preceding macb_tx_lpi_wake() NCR write and the
* TSR-read tx_pending breadcrumb above.
*/
(void)macb_readl(bp, NCR);
if (bp->caps & MACB_CAPS_PCIE_POSTED_WRITES)
(void)macb_readl(bp, NCR);
spin_unlock(&bp->lock);

if (CIRC_SPACE(queue->tx_head, queue->tx_tail, bp->tx_ring_size) < 1)
Expand Down Expand Up @@ -5810,6 +5832,7 @@
.caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_CLK_HW_CHG |
MACB_CAPS_JUMBO |
MACB_CAPS_GEM_HAS_PTP |
MACB_CAPS_PCIE_POSTED_WRITES |
MACB_CAPS_EEE,
.dma_burst_length = 16,
.clk_init = macb_clk_init,
Expand Down
Loading