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 [email protected], 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;
}