Module Name: src Committed By: knakahara Date: Tue Aug 3 01:08:18 UTC 2021
Modified Files: src/sys/dev/pci: if_wm.c Log Message: Fix locking against myself reported by rin@n.o. In some machine, INTx interrupts occurs for some reason while holding txq_lock in softint context. e.g. https://dmesgd.nycbug.org/index.cgi?do=view&id=6139 The panic message is the following. ==================== [ 50.1699480] panic: LOCKDEBUG: Mutex error: mutex_vector_enter,467: locking against myself [ 50.1800188] cpu0: Begin traceback... [ 50.1800188] 0xc7a29ac4: netbsd:db_panic+0xc [ 50.1900018] 0xc7a29adc: netbsd:vpanic+0x120 [ 50.1999533] 0xc7a29af4: netbsd:aprint_debug [ 50.1999533] 0xc7a29b34: netbsd:lockdebug_abort1+0x18c [ 50.2099719] 0xc7a29b74: netbsd:lockdebug_wantlock+0x1e8 [ 50.2199525] 0xc7a29bb4: netbsd:mutex_enter+0x288 [ 50.2299642] 0xc7a29be4: netbsd:wm_intr_legacy+0x9c [ 50.2299642] 0xc7a29c2c: netbsd:i80321_intr_dispatch+0x138 [ 50.2399631] 0xc7a29de4: netbsd:irq_entry+0x98 [ 50.2499452] 0xc7a29e24: netbsd:entropy_enter+0x88 [ 50.2599996] 0xc7a29e6c: netbsd:rnd_add_data_1+0x50 [ 50.2699565] 0xc7a29ebc: netbsd:rnd_add_data+0x10c [ 50.2699565] 0xc7a29ed4: netbsd:rnd_add_uint32+0x28 [ 50.2799524] 0xc7a29f1c: netbsd:wm_txeof+0x2c0 [ 50.2899527] 0xc7a29f5c: netbsd:wm_handle_queue+0x44 [ 50.3000257] 0xc7a29fac: netbsd:softint_thread+0x130 [ 50.3100119] cpu0: End traceback... ==================== To fix this panic, stop wm(4) interrupts before calling softint. This behavior is similar to MSI-X polling mode. Reviewed by msaitoh@n.o, tested by rin@n.o, thanks. To generate a diff of this commit: cvs rdiff -u -r1.705 -r1.706 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.705 src/sys/dev/pci/if_wm.c:1.706 --- src/sys/dev/pci/if_wm.c:1.705 Wed Jun 16 00:21:18 2021 +++ src/sys/dev/pci/if_wm.c Tue Aug 3 01:08:18 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.705 2021/06/16 00:21:18 riastradh Exp $ */ +/* $NetBSD: if_wm.c,v 1.706 2021/08/03 01:08:18 knakahara 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.705 2021/06/16 00:21:18 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.706 2021/08/03 01:08:18 knakahara Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -9774,6 +9774,20 @@ wm_sched_handle_queue(struct wm_softc *s softint_schedule(wmq->wmq_si); } +static inline void +wm_legacy_intr_disable(struct wm_softc *sc) +{ + + CSR_WRITE(sc, WMREG_IMC, 0xffffffffU); +} + +static inline void +wm_legacy_intr_enable(struct wm_softc *sc) +{ + + CSR_WRITE(sc, WMREG_IMS, sc->sc_icr); +} + /* * wm_intr_legacy: * @@ -9788,6 +9802,7 @@ wm_intr_legacy(void *arg) struct wm_rxqueue *rxq = &wmq->wmq_rxq; uint32_t icr, rndval = 0; int handled = 0; + bool more = false; while (1 /* CONSTCOND */) { icr = CSR_READ(sc, WMREG_ICR); @@ -9822,7 +9837,7 @@ wm_intr_legacy(void *arg) * as if_percpuq_enqueue() just call softint_schedule(). * So, we can call wm_rxeof() in interrupt context. */ - wm_rxeof(rxq, UINT_MAX); + more = wm_rxeof(rxq, UINT_MAX); mutex_exit(rxq->rxq_lock); mutex_enter(txq->txq_lock); @@ -9840,7 +9855,7 @@ wm_intr_legacy(void *arg) WM_Q_EVCNT_INCR(txq, txdw); } #endif - wm_txeof(txq, UINT_MAX); + more |= wm_txeof(txq, UINT_MAX); mutex_exit(txq->txq_lock); WM_CORE_LOCK(sc); @@ -9869,8 +9884,9 @@ wm_intr_legacy(void *arg) rnd_add_uint32(&sc->rnd_source, rndval); - if (handled) { + if (more) { /* Try to get more packets going. */ + wm_legacy_intr_disable(sc); wmq->wmq_txrx_use_workqueue = sc->sc_txrx_use_workqueue; wm_sched_handle_queue(sc, wmq); } @@ -9883,6 +9899,10 @@ wm_txrxintr_disable(struct wm_queue *wmq { struct wm_softc *sc = wmq->wmq_txq.txq_sc; + if (__predict_false(!wm_is_using_msix(sc))) { + return wm_legacy_intr_disable(sc); + } + if (sc->sc_type == WM_T_82574) CSR_WRITE(sc, WMREG_IMC, ICR_TXQ(wmq->wmq_id) | ICR_RXQ(wmq->wmq_id)); @@ -9900,6 +9920,10 @@ wm_txrxintr_enable(struct wm_queue *wmq) wm_itrs_calculate(sc, wmq); + if (__predict_false(!wm_is_using_msix(sc))) { + return wm_legacy_intr_enable(sc); + } + /* * ICR_OTHER which is disabled in wm_linkintr_msix() is enabled here. * There is no need to care about which of RXQ(0) and RXQ(1) enable