Module Name: src Committed By: knakahara Date: Tue Mar 24 09:27:46 UTC 2020
Modified Files: src/sys/arch/x86/pci: if_vmx.c Log Message: fix vmx(4) cannot link up at boot time. reviewed by msaitoh@n.o, thanks. vmx(4) could call if_link_state_change(ifp, LINK_STATE_UP) from vmxnet3_init() before ifp->if_link_cansched was set, because dp->dom_if_up() (in6_if_up() for INET6) could call ifp->if_init(). And then, workqueue_enqueue() was not called at that time. As the result, the last LQ_ITEM was stuck LINK_STATE_UP, so if_link_state_change_work_schedule() was never called until if_link_state_change(ifp, LINK_STATE_DOWN) was called. To fix this issue, vmx(4) avoid calling if_link_state_change() before ifp->if_link_cansched is set. To generate a diff of this commit: cvs rdiff -u -r1.58 -r1.59 src/sys/arch/x86/pci/if_vmx.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/arch/x86/pci/if_vmx.c diff -u src/sys/arch/x86/pci/if_vmx.c:1.58 src/sys/arch/x86/pci/if_vmx.c:1.59 --- src/sys/arch/x86/pci/if_vmx.c:1.58 Sun Mar 15 23:04:50 2020 +++ src/sys/arch/x86/pci/if_vmx.c Tue Mar 24 09:27:46 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: if_vmx.c,v 1.58 2020/03/15 23:04:50 thorpej Exp $ */ +/* $NetBSD: if_vmx.c,v 1.59 2020/03/24 09:27:46 knakahara Exp $ */ /* $OpenBSD: if_vmx.c,v 1.16 2014/01/22 06:04:17 brad Exp $ */ /* @@ -19,7 +19,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_vmx.c,v 1.58 2020/03/15 23:04:50 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_vmx.c,v 1.59 2020/03/24 09:27:46 knakahara Exp $"); #include <sys/param.h> #include <sys/cpu.h> @@ -445,9 +445,10 @@ static int vmxnet3_ifflags_cb(struct eth static int vmxnet3_watchdog(struct vmxnet3_txqueue *); static void vmxnet3_refresh_host_stats(struct vmxnet3_softc *); static void vmxnet3_tick(void *); -static void vmxnet3_link_status(struct vmxnet3_softc *); -static void vmxnet3_media_status(struct ifnet *, struct ifmediareq *); -static int vmxnet3_media_change(struct ifnet *); +static void vmxnet3_if_link_status(struct vmxnet3_softc *); +static bool vmxnet3_cmd_link_status(struct ifnet *); +static void vmxnet3_ifmedia_status(struct ifnet *, struct ifmediareq *); +static int vmxnet3_ifmedia_change(struct ifnet *); static void vmxnet3_set_lladdr(struct vmxnet3_softc *); static void vmxnet3_get_lladdr(struct vmxnet3_softc *); @@ -1857,8 +1858,8 @@ vmxnet3_setup_interface(struct vmxnet3_s /* Initialize ifmedia structures. */ sc->vmx_ethercom.ec_ifmedia = &sc->vmx_media; - ifmedia_init_with_lock(&sc->vmx_media, IFM_IMASK, vmxnet3_media_change, - vmxnet3_media_status, sc->vmx_mtx); + ifmedia_init_with_lock(&sc->vmx_media, IFM_IMASK, vmxnet3_ifmedia_change, + vmxnet3_ifmedia_status, sc->vmx_mtx); ifmedia_add(&sc->vmx_media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_add(&sc->vmx_media, IFM_ETHER | IFM_10G_T | IFM_FDX, 0, NULL); ifmedia_add(&sc->vmx_media, IFM_ETHER | IFM_10G_T, 0, NULL); @@ -1870,7 +1871,7 @@ vmxnet3_setup_interface(struct vmxnet3_s if_deferred_start_init(ifp, NULL); ether_ifattach(ifp, sc->vmx_lladdr); ether_set_ifflags_cb(&sc->vmx_ethercom, vmxnet3_ifflags_cb); - vmxnet3_link_status(sc); + vmxnet3_cmd_link_status(ifp); /* should set before setting interrupts */ sc->vmx_rx_intr_process_limit = VMXNET3_RX_INTR_PROCESS_LIMIT; @@ -2069,7 +2070,7 @@ vmxnet3_evintr(struct vmxnet3_softc *sc) if (event & VMXNET3_EVENT_LINK) { sc->vmx_event_link.ev_count++; - vmxnet3_link_status(sc); + vmxnet3_if_link_status(sc); if (sc->vmx_link_active != 0) if_schedule_deferred_start(&sc->vmx_ethercom.ec_if); } @@ -2909,7 +2910,7 @@ vmxnet3_init_locked(struct vmxnet3_softc } ifp->if_flags |= IFF_RUNNING; - vmxnet3_link_status(sc); + vmxnet3_cmd_link_status(ifp); vmxnet3_enable_all_intrs(sc); callout_reset(&sc->vmx_tick, hz, vmxnet3_tick, sc); @@ -3425,6 +3426,8 @@ vmxnet3_ifflags_cb(struct ethercom *ec) vmxnet3_set_rxfilter(sc); VMXNET3_CORE_UNLOCK(sc); + vmxnet3_if_link_status(sc); + return 0; } @@ -3481,17 +3484,20 @@ vmxnet3_tick(void *xsc) VMXNET3_CORE_UNLOCK(sc); } +/* + * update link state of ifnet and softc + */ static void -vmxnet3_link_status(struct vmxnet3_softc *sc) +vmxnet3_if_link_status(struct vmxnet3_softc *sc) { struct ifnet *ifp = &sc->vmx_ethercom.ec_if; - u_int x, link, speed; + u_int x, link; + + vmxnet3_cmd_link_status(ifp); x = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_LINK); - speed = x >> 16; if (x & 1) { sc->vmx_link_active = 1; - ifp->if_baudrate = IF_Mbps(speed); link = LINK_STATE_UP; } else { sc->vmx_link_active = 0; @@ -3501,17 +3507,37 @@ vmxnet3_link_status(struct vmxnet3_softc if_link_state_change(ifp, link); } -static void -vmxnet3_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +/* + * check vmx(4) state by VMXNET3_CMD and update ifp->if_baudrate + * returns + * - true: link up + * - flase: link down + */ +static bool +vmxnet3_cmd_link_status(struct ifnet *ifp) { struct vmxnet3_softc *sc = ifp->if_softc; + u_int x, speed; + + x = vmxnet3_read_cmd(sc, VMXNET3_CMD_GET_LINK); + if ((x & 1) == 0) + return false; + + speed = x >> 16; + ifp->if_baudrate = IF_Mbps(speed); + return true; +} - vmxnet3_link_status(sc); +static void +vmxnet3_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + bool up; ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; - if (ifp->if_link_state != LINK_STATE_UP) + up = vmxnet3_cmd_link_status(ifp); + if (!up) return; ifmr->ifm_status |= IFM_ACTIVE; @@ -3521,7 +3547,7 @@ vmxnet3_media_status(struct ifnet *ifp, } static int -vmxnet3_media_change(struct ifnet *ifp) +vmxnet3_ifmedia_change(struct ifnet *ifp) { return 0; }