Module Name:    src
Committed By:   msaitoh
Date:           Wed Oct 20 08:02:08 UTC 2021

Modified Files:
        src/sys/dev/pci: if_wm.c

Log Message:
Change DMA physical address in wm_flush_desc_rings() to match other OSes.

 - Even without this change, the workaround works with my machines.
 - Add comment.


To generate a diff of this commit:
cvs rdiff -u -r1.712 -r1.713 src/sys/dev/pci/if_wm.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/pci/if_wm.c
diff -u src/sys/dev/pci/if_wm.c:1.712 src/sys/dev/pci/if_wm.c:1.713
--- src/sys/dev/pci/if_wm.c:1.712	Wed Oct 20 07:04:28 2021
+++ src/sys/dev/pci/if_wm.c	Wed Oct 20 08:02:07 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_wm.c,v 1.712 2021/10/20 07:04:28 knakahara Exp $	*/
+/*	$NetBSD: if_wm.c,v 1.713 2021/10/20 08:02:07 msaitoh Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc.
@@ -82,7 +82,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.712 2021/10/20 07:04:28 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.713 2021/10/20 08:02:07 msaitoh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_net_mpsafe.h"
@@ -4852,8 +4852,15 @@ wm_reset_phy(struct wm_softc *sc)
 }
 
 /*
- * Only used by WM_T_PCH_SPT which does not use multiqueue,
- * so it is enough to check sc->sc_queue[0] only.
+ * wm_flush_desc_rings - remove all descriptors from the descriptor rings.
+ *
+ * In i219, the descriptor rings must be emptied before resetting the HW
+ * or before changing the device state to D3 during runtime (runtime PM).
+ *
+ * Failure to do this will cause the HW to enter a unit hang state which can
+ * only be released by PCI reset on the device.
+ *
+ * I219 does not use multiqueue, so it is enough to check sc->sc_queue[0] only.
  */
 static void
 wm_flush_desc_rings(struct wm_softc *sc)
@@ -4875,7 +4882,14 @@ wm_flush_desc_rings(struct wm_softc *sc)
 	if (((preg & DESCRING_STATUS_FLUSH_REQ) == 0) || (reg == 0))
 		return;
 
-	/* TX */
+	/*
+	 * Remove all descriptors from the tx_ring.
+	 *
+	 * We want to clear all pending descriptors from the TX ring. Zeroing
+	 * happens when the HW reads the regs. We  assign the ring itself as
+	 * the data of the next descriptor. We don't care about the data we are
+	 * about to reset the HW.
+	 */
 	device_printf(sc->sc_dev, "Need TX flush (reg = %08x, len = %u)\n",
 	    preg, reg);
 	reg = CSR_READ(sc, WMREG_TCTL);
@@ -4884,7 +4898,7 @@ wm_flush_desc_rings(struct wm_softc *sc)
 	txq = &sc->sc_queue[0].wmq_txq;
 	nexttx = txq->txq_next;
 	txd = &txq->txq_descs[nexttx];
-	wm_set_dma_addr(&txd->wtx_addr, WM_CDTXADDR(txq, nexttx));
+	wm_set_dma_addr(&txd->wtx_addr, txq->txq_desc_dma);
 	txd->wtx_cmdlen = htole32(WTX_CMD_IFCS | 512);
 	txd->wtx_fields.wtxu_status = 0;
 	txd->wtx_fields.wtxu_options = 0;
@@ -4903,7 +4917,10 @@ wm_flush_desc_rings(struct wm_softc *sc)
 	if ((preg & DESCRING_STATUS_FLUSH_REQ) == 0)
 		return;
 
-	/* RX */
+	/*
+	 * Mark all descriptors in the RX ring as consumed and disable the
+	 * rx ring.
+	 */
 	device_printf(sc->sc_dev, "Need RX flush (reg = %08x)\n", preg);
 	rctl = CSR_READ(sc, WMREG_RCTL);
 	CSR_WRITE(sc, WMREG_RCTL, rctl & ~RCTL_EN);

Reply via email to