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]
This commit is contained in:
parent
78689e4e66
commit
b84348e857
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: if_wm.c,v 1.694 2020/10/30 06:29:47 msaitoh Exp $ */
|
||||
/* $NetBSD: if_wm.c,v 1.695 2020/11/02 09:21:50 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.694 2020/10/30 06:29:47 msaitoh Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.695 2020/11/02 09:21:50 knakahara Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_net_mpsafe.h"
|
||||
|
@ -384,7 +384,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;
|
||||
|
||||
|
@ -1044,6 +1045,9 @@ static void wm_toggle_lanphypc_pch_lpt(struct wm_softc *);
|
|||
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 *);
|
||||
|
||||
#ifdef WM_DEBUG
|
||||
static int wm_sysctl_debug(SYSCTLFN_PROTO);
|
||||
|
@ -3100,6 +3104,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))
|
||||
|
@ -3483,6 +3490,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]
|
||||
*
|
||||
|
@ -3520,6 +3570,12 @@ wm_ioctl(struct ifnet *ifp, u_long cmd, void *data)
|
|||
}
|
||||
WM_CORE_UNLOCK(sc);
|
||||
error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
|
||||
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);
|
||||
|
@ -3534,8 +3590,17 @@ wm_ioctl(struct ifnet *ifp, u_long cmd, void *data)
|
|||
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
|
||||
|
@ -7674,6 +7739,16 @@ wm_select_txqueue(struct ifnet *ifp, struct mbuf *m)
|
|||
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]
|
||||
*
|
||||
|
@ -7767,6 +7842,23 @@ wm_send_common_locked(struct ifnet *ifp, struct wm_txqueue *txq,
|
|||
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)
|
||||
if_statinc(ifp, if_opackets);
|
||||
m_freem(m0);
|
||||
} while (m0 != NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remember the previous number of free descriptors. */
|
||||
ofree = txq->txq_free;
|
||||
|
||||
|
@ -8367,6 +8459,23 @@ wm_nq_send_common_locked(struct ifnet *ifp, struct wm_txqueue *txq,
|
|||
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)
|
||||
if_statinc(ifp, if_opackets);
|
||||
m_freem(m0);
|
||||
} while (m0 != NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
sent = false;
|
||||
|
||||
/*
|
||||
|
@ -9234,9 +9343,13 @@ wm_linkintr_gmii(struct wm_softc *sc, uint32_t icr)
|
|||
DPRINTF(sc, 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 {
|
||||
DPRINTF(sc, WM_DEBUG_LINK, ("%s: LINK: LSC -> down\n",
|
||||
device_xname(dev)));
|
||||
if (wm_phy_need_linkdown_discard(sc))
|
||||
wm_set_linkdown_discard(sc);
|
||||
}
|
||||
if ((sc->sc_type == WM_T_ICH8) && (link == false))
|
||||
wm_gig_downshift_workaround_ich8lan(sc);
|
||||
|
|
Loading…
Reference in New Issue