Date: Tue, 13 Mar 2012 06:28:52 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r232914 - head/sys/mips/atheros Message-ID: <201203130628.q2D6Squg020490@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Tue Mar 13 06:28:52 2012 New Revision: 232914 URL: http://svn.freebsd.org/changeset/base/232914 Log: Fix link status handling on if_arge upon system boot to allow bootp/NFS to function. From the submitter: This patch fixes an issue I encountered using an NFS root with an ar71xx-based MikroTik RouterBoard 450G on -current where the kernel fails to contact a DHCP/BOOTP server via if_arge when it otherwise should be able to. This may be the same issue that Monthadar Al Jaberi reported against an RSPRO on 6 March, as the signature is the same: %%% DHCP/BOOTP timeout for server 255.255.255.255 DHCP/BOOTP timeout for server 255.255.255.255 DHCP/BOOTP timeout for server 255.255.255.255 . . . DHCP/BOOTP timeout for server 255.255.255.255 DHCP/BOOTP timeout for server 255.255.255.255 arge0: initialization failed: no memory for rx buffers DHCP/BOOTP timeout for server 255.255.255.255 arge0: initialization failed: no memory for rx buffers %%% The primary issue that I found is that the DHCP/BOOTP message that bootpc_call() is sending never makes it onto the wire, which I believe is due to the following: - Last December, a change was made to the ifioctl that bootpc_call() uses to adjust the netmask around the sosend(). - The new ioctl (SIOCAIFADDR) performs an if_init when invoked, whereas the old one (SIOCSIFNETMASK) did not. - if_arge maintains its own sense of link state in sc->arge_link_status. - On a single-phy interface, sc->arge_link_status is initialized to 0 in arge_init_locked(). - sc->arge_link_status remains 0 until a phy state change notification causes arge_link_task to run, notice the link is up, and set it to 1. - The inits caused by the ifioctls in bootpc_call are reinitializing the interface, but not the phy, so sc->arge_link_status goes to 0 and remains there. - arge_start_locked() always sees sc->arge_link_status == 0 and returns without queuing anything. The attached patch changes arge_init_locked() such that in the single-phy case, instead of initializing sc->arge_link_status to 0, it runs arge_link_task() to set it according to the current phy state. This change has allowed my setup to mount an NFS root successfully. Submitted by: Patrick Kelsey <kelsey@ieee.org> Reviewed by: juli Modified: head/sys/mips/atheros/if_arge.c Modified: head/sys/mips/atheros/if_arge.c ============================================================================== --- head/sys/mips/atheros/if_arge.c Tue Mar 13 06:22:49 2012 (r232913) +++ head/sys/mips/atheros/if_arge.c Tue Mar 13 06:28:52 2012 (r232914) @@ -110,6 +110,7 @@ static int arge_ioctl(struct ifnet *, u_ static void arge_init(void *); static void arge_init_locked(struct arge_softc *); static void arge_link_task(void *, int); +static void arge_update_link_locked(struct arge_softc *sc); static void arge_set_pll(struct arge_softc *, int, int); static int arge_miibus_readreg(device_t, int, int); static void arge_miibus_statchg(device_t); @@ -684,13 +685,20 @@ static void arge_link_task(void *arg, int pending) { struct arge_softc *sc; + sc = (struct arge_softc *)arg; + + ARGE_LOCK(sc); + arge_update_link_locked(sc); + ARGE_UNLOCK(sc); +} + +static void +arge_update_link_locked(struct arge_softc *sc) +{ struct mii_data *mii; struct ifnet *ifp; uint32_t media, duplex; - sc = (struct arge_softc *)arg; - - ARGE_LOCK(sc); mii = device_get_softc(sc->arge_miibus); ifp = sc->arge_ifp; if (mii == NULL || ifp == NULL || @@ -708,10 +716,10 @@ arge_link_task(void *arg, int pending) duplex = mii->mii_media_active & IFM_GMASK; arge_set_pll(sc, media, duplex); } - } else + } else { sc->arge_link_status = 0; + } - ARGE_UNLOCK(sc); } static void @@ -853,7 +861,6 @@ arge_init_locked(struct arge_softc *sc) if (sc->arge_miibus) { - sc->arge_link_status = 0; mii = device_get_softc(sc->arge_miibus); mii_mediachg(mii); } @@ -867,8 +874,10 @@ arge_init_locked(struct arge_softc *sc) ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - if (sc->arge_miibus) + if (sc->arge_miibus) { callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc); + arge_update_link_locked(sc); + } ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, ARGE_TX_RING_ADDR(sc, 0)); ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, ARGE_RX_RING_ADDR(sc, 0));
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201203130628.q2D6Squg020490>