Avoid unnecessary controller reinitialization by checking driver

running state.  fxp(4) requires controller reinitialization for the
following cases.
 o RX lockup condition on i82557
 o promiscuous mode change
 o multicast filter change
 o WOL configuration
 o TSO/VLAN hardware tagging/checksum offloading configuration
 o MAC reprogramming after speed/duplex/flow-control resolution
 o Any events that result in MAC reprogramming(link UP/DOWN,
   remote link partner's restart of auto-negotiation etc)
 o Microcode loading/unloading
Apart from above cases which come from hardware limitation, upper
stack also blindly reinitializes controller whenever an IP address
is assigned. After r194573, fxp(4) no longer needs to reinitialize
the controller to program multicast filter after upping the
interface. So keeping track of driver running state should remove
all unnecessary controller reinitializations.

This change will also address endless controller reinitialization
triggered by dhclient(8).

Tested by:	hrs, Alban Hertroys <haramrae@gmail.com>
This commit is contained in:
yongari 2013-06-10 07:31:49 +00:00
parent 4e8602cd39
commit 015913b383

View File

@ -1075,7 +1075,8 @@ fxp_suspend(device_t dev)
pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
sc->flags |= FXP_FLAG_WOL;
/* Reconfigure hardware to accept magic frames. */
fxp_init_body(sc, 1);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
fxp_init_body(sc, 0);
}
pci_write_config(sc->dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
}
@ -2141,8 +2142,10 @@ fxp_tick(void *xsc)
*/
if (sc->rx_idle_secs > FXP_MAX_RX_IDLE) {
sc->rx_idle_secs = 0;
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
fxp_init_body(sc, 1);
}
return;
}
/*
@ -2240,6 +2243,7 @@ fxp_watchdog(struct fxp_softc *sc)
device_printf(sc->dev, "device timeout\n");
sc->ifp->if_oerrors++;
sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
fxp_init_body(sc, 1);
}
@ -2274,6 +2278,10 @@ fxp_init_body(struct fxp_softc *sc, int setmedia)
int i, prm;
FXP_LOCK_ASSERT(sc, MA_OWNED);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
return;
/*
* Cancel any pending I/O
*/
@ -2813,6 +2821,7 @@ fxp_miibus_statchg(device_t dev)
*/
if (sc->revision == FXP_REV_82557)
return;
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
fxp_init_body(sc, 0);
}
@ -2836,9 +2845,10 @@ fxp_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
if (ifp->if_flags & IFF_UP) {
if (((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) &&
((ifp->if_flags ^ sc->if_flags) &
(IFF_PROMISC | IFF_ALLMULTI | IFF_LINK0)) != 0)
(IFF_PROMISC | IFF_ALLMULTI | IFF_LINK0)) != 0) {
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
fxp_init_body(sc, 0);
else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
} else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
fxp_init_body(sc, 1);
} else {
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
@ -2851,8 +2861,10 @@ fxp_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
case SIOCADDMULTI:
case SIOCDELMULTI:
FXP_LOCK(sc);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
fxp_init_body(sc, 0);
}
FXP_UNLOCK(sc);
break;
@ -2942,8 +2954,10 @@ fxp_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
~(IFCAP_VLAN_HWTSO | IFCAP_VLAN_HWCSUM);
reinit++;
}
if (reinit > 0 && ifp->if_flags & IFF_UP)
if (reinit > 0 && (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
fxp_init_body(sc, 0);
}
FXP_UNLOCK(sc);
VLAN_CAPABILITIES(ifp);
break;