Module Name: src Committed By: martin Date: Wed Nov 4 11:48:26 UTC 2020
Modified Files: src/sys/dev/pci [netbsd-9]: if_wm.c if_wmvar.h Log Message: Pull up following revision(s) (requested by knakahara in ticket #1126): sys/dev/pci/if_wm.c: revision 1.694 sys/dev/pci/if_wm.c: revision 1.695 (via patch) sys/dev/pci/if_wmvar.h: revision 1.47 Add WMPHY_I350. Not used yet. Workaround for ihphy and atphy(ICH*/PCH*, 82580 and I350). These phys stop DMA while link is down which causes device timeout. Fix PR/kern 40981 Reviewed and tested by msaitoh@n.o, thanks. XXX pullup-[89] To generate a diff of this commit: cvs rdiff -u -r1.645.2.8 -r1.645.2.9 src/sys/dev/pci/if_wm.c cvs rdiff -u -r1.44.4.2 -r1.44.4.3 src/sys/dev/pci/if_wmvar.h 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.645.2.8 src/sys/dev/pci/if_wm.c:1.645.2.9 --- src/sys/dev/pci/if_wm.c:1.645.2.8 Fri Oct 16 08:03:36 2020 +++ src/sys/dev/pci/if_wm.c Wed Nov 4 11:48:26 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.645.2.8 2020/10/16 08:03:36 martin Exp $ */ +/* $NetBSD: if_wm.c,v 1.645.2.9 2020/11/04 11:48:26 martin 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.645.2.8 2020/10/16 08:03:36 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.645.2.9 2020/11/04 11:48:26 martin Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -375,7 +375,8 @@ struct wm_txqueue { * to manage Tx H/W queue's busy flag. */ int txq_flags; /* flags for H/W queue, see below */ -#define WM_TXQ_NO_SPACE 0x1 +#define WM_TXQ_NO_SPACE 0x1 +#define WM_TXQ_LINKDOWN_DISCARD 0x2 bool txq_stopping; @@ -1031,6 +1032,9 @@ static void wm_toggle_lanphypc_pch_lpt(s static int wm_platform_pm_pch_lpt(struct wm_softc *, bool); static int wm_pll_workaround_i210(struct wm_softc *); static void wm_legacy_irq_quirk_spt(struct wm_softc *); +static bool wm_phy_need_linkdown_discard(struct wm_softc *); +static void wm_set_linkdown_discard(struct wm_softc *); +static void wm_clear_linkdown_discard(struct wm_softc *); CFATTACH_DECL3_NEW(wm, sizeof(struct wm_softc), wm_match, wm_attach, wm_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); @@ -3077,6 +3081,9 @@ alloc_retry: sc->sc_txrx_use_workqueue = false; + if (wm_phy_need_linkdown_discard(sc)) + wm_set_linkdown_discard(sc); + wm_init_sysctls(sc); if (pmf_device_register(self, wm_suspend, wm_resume)) @@ -3455,6 +3462,49 @@ out: return rc; } +static bool +wm_phy_need_linkdown_discard(struct wm_softc *sc) +{ + + switch(sc->sc_phytype) { + case WMPHY_82577: /* ihphy */ + case WMPHY_82578: /* atphy */ + case WMPHY_82579: /* ihphy */ + case WMPHY_I217: /* ihphy */ + case WMPHY_82580: /* ihphy */ + case WMPHY_I350: /* ihphy */ + return true; + default: + return false; + } +} + +static void +wm_set_linkdown_discard(struct wm_softc *sc) +{ + + for (int i = 0; i < sc->sc_nqueues; i++) { + struct wm_txqueue *txq = &sc->sc_queue[i].wmq_txq; + + mutex_enter(txq->txq_lock); + txq->txq_flags |= WM_TXQ_LINKDOWN_DISCARD; + mutex_exit(txq->txq_lock); + } +} + +static void +wm_clear_linkdown_discard(struct wm_softc *sc) +{ + + for (int i = 0; i < sc->sc_nqueues; i++) { + struct wm_txqueue *txq = &sc->sc_queue[i].wmq_txq; + + mutex_enter(txq->txq_lock); + txq->txq_flags &= ~WM_TXQ_LINKDOWN_DISCARD; + mutex_exit(txq->txq_lock); + } +} + /* * wm_ioctl: [ifnet interface function] * @@ -3498,6 +3548,12 @@ wm_ioctl(struct ifnet *ifp, u_long cmd, #ifdef WM_MPSAFE splx(s); #endif + if (error == 0 && wm_phy_need_linkdown_discard(sc)) { + if (IFM_SUBTYPE(ifr->ifr_media) == IFM_NONE) + wm_set_linkdown_discard(sc); + else + wm_clear_linkdown_discard(sc); + } break; case SIOCINITIFADDR: WM_CORE_LOCK(sc); @@ -3512,8 +3568,17 @@ wm_ioctl(struct ifnet *ifp, u_long cmd, break; } WM_CORE_UNLOCK(sc); + if (((ifp->if_flags & IFF_UP) == 0) && wm_phy_need_linkdown_discard(sc)) + wm_clear_linkdown_discard(sc); /*FALLTHROUGH*/ default: + if (cmd == SIOCSIFFLAGS && wm_phy_need_linkdown_discard(sc)) { + if (((ifp->if_flags & IFF_UP) == 0) && ((ifr->ifr_flags & IFF_UP) != 0)) { + wm_clear_linkdown_discard(sc); + } else if (((ifp->if_flags & IFF_UP) != 0) && ((ifr->ifr_flags & IFF_UP) == 0)) { + wm_set_linkdown_discard(sc); + } + } #ifdef WM_MPSAFE s = splnet(); #endif @@ -7627,6 +7692,16 @@ wm_select_txqueue(struct ifnet *ifp, str return ((cpuid + ncpu - sc->sc_affinity_offset) % ncpu) % sc->sc_nqueues; } +static inline bool +wm_linkdown_discard(struct wm_txqueue *txq) +{ + + if ((txq->txq_flags & WM_TXQ_LINKDOWN_DISCARD) != 0) + return true; + + return false; +} + /* * wm_start: [ifnet interface function] * @@ -7721,6 +7796,23 @@ wm_send_common_locked(struct ifnet *ifp, if ((txq->txq_flags & WM_TXQ_NO_SPACE) != 0) return; + if (__predict_false(wm_linkdown_discard(txq))) { + do { + if (is_transmit) + m0 = pcq_get(txq->txq_interq); + else + IFQ_DEQUEUE(&ifp->if_snd, m0); + /* + * increment successed packet counter as in the case + * which the packet is discarded by link down PHY. + */ + if (m0 != NULL) + ifp->if_opackets++; + m_freem(m0); + } while (m0 != NULL); + return; + } + /* Remember the previous number of free descriptors. */ ofree = txq->txq_free; @@ -8330,6 +8422,23 @@ wm_nq_send_common_locked(struct ifnet *i if ((txq->txq_flags & WM_TXQ_NO_SPACE) != 0) return; + if (__predict_false(wm_linkdown_discard(txq))) { + do { + if (is_transmit) + m0 = pcq_get(txq->txq_interq); + else + IFQ_DEQUEUE(&ifp->if_snd, m0); + /* + * increment successed packet counter as in the case + * which the packet is discarded by link down PHY. + */ + if (m0 != NULL) + ifp->if_opackets++; + m_freem(m0); + } while (m0 != NULL); + return; + } + sent = false; /* @@ -9201,7 +9310,11 @@ wm_linkintr_gmii(struct wm_softc *sc, ui DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> up %s\n", device_xname(dev), (status & STATUS_FD) ? "FDX" : "HDX")); + if (wm_phy_need_linkdown_discard(sc)) + wm_clear_linkdown_discard(sc); } else { + if (wm_phy_need_linkdown_discard(sc)) + wm_set_linkdown_discard(sc); DPRINTF(WM_DEBUG_LINK, ("%s: LINK: LSC -> down\n", device_xname(dev))); } @@ -10251,9 +10364,12 @@ wm_gmii_setup_phytype(struct wm_softc *s new_phytype = WMPHY_I217; break; case MII_MODEL_INTEL_I82580: - case MII_MODEL_INTEL_I350: new_phytype = WMPHY_82580; break; + case MII_MODEL_INTEL_I350: + new_phytype = WMPHY_I350; + break; + break; default: break; } Index: src/sys/dev/pci/if_wmvar.h diff -u src/sys/dev/pci/if_wmvar.h:1.44.4.2 src/sys/dev/pci/if_wmvar.h:1.44.4.3 --- src/sys/dev/pci/if_wmvar.h:1.44.4.2 Wed Sep 23 08:46:54 2020 +++ src/sys/dev/pci/if_wmvar.h Wed Nov 4 11:48:26 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wmvar.h,v 1.44.4.2 2020/09/23 08:46:54 martin Exp $ */ +/* $NetBSD: if_wmvar.h,v 1.44.4.3 2020/11/04 11:48:26 martin Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -198,9 +198,10 @@ typedef enum { WMPHY_BM, /* 82567: ICH8 ICH9 ICH10 */ WMPHY_82578, /* 82578: PCH */ WMPHY_82577, /* 82577: PCH (NOTE: functionality newer than 82578) */ - WMPHY_82579, /* 82579 : PCH2 */ + WMPHY_82579, /* 82579: PCH2 */ WMPHY_I217, /* I217: _LPT, I218: _LPT, I219: _SPT _CNP */ - WMPHY_82580, /* 82580: 82580 or I350 */ + WMPHY_82580, /* 82580 */ + WMPHY_I350, /* I350 */ WMPHY_VF, WMPHY_I210 /* I210: I210 I211 */ } wm_phy_type;