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;
 }

Reply via email to