Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F164578401
D58425.id182655.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D58425.id182655.diff
View Options
diff --git a/sys/dev/e1000/if_em.h b/sys/dev/e1000/if_em.h
--- a/sys/dev/e1000/if_em.h
+++ b/sys/dev/e1000/if_em.h
@@ -469,6 +469,14 @@
struct if_irq que_irq;
};
+/* Driver-observed link state and its publication barrier. */
+enum em_link_state {
+ EM_LINK_STATE_DOWN = 0,
+ EM_LINK_STATE_DOWN_RESET_PENDING,
+ EM_LINK_STATE_UP,
+ EM_LINK_STATE_UP_RESET_PENDING,
+};
+
/* Our softc structure */
struct e1000_softc {
struct e1000_hw hw;
@@ -530,7 +538,7 @@
u32 shadow_vfta[EM_VFTA_SIZE];
/* Info about the interface */
- u16 link_active;
+ enum em_link_state link_state;
u16 fc;
u16 link_speed;
u16 link_duplex;
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -1562,6 +1562,10 @@
/* Initialize the hardware */
em_reset(ctx);
+ /* Re-arm a link-up transition deferred for this reset. */
+ if (sc->link_state == EM_LINK_STATE_DOWN_RESET_PENDING ||
+ sc->link_state == EM_LINK_STATE_UP_RESET_PENDING)
+ sc->link_state = EM_LINK_STATE_DOWN;
em_if_update_admin_status(ctx);
for (i = 0, tx_que = sc->tx_queues; i < sc->tx_num_queues;
@@ -1999,7 +2003,8 @@
ifmr->ifm_status = IFM_AVALID;
ifmr->ifm_active = IFM_ETHER;
- if (!sc->link_active) {
+ if (sc->link_state == EM_LINK_STATE_DOWN ||
+ sc->link_state == EM_LINK_STATE_DOWN_RESET_PENDING) {
return;
}
@@ -2219,7 +2224,7 @@
struct e1000_hw *hw = &sc->hw;
device_t dev = iflib_get_dev(ctx);
u32 link_check, thstat, ctrl;
- bool automasked = false;
+ bool reset_requested = false;
link_check = thstat = ctrl = 0;
/* Get the cached link value or read phy for real */
@@ -2262,7 +2267,13 @@
}
/* Now check for a transition */
- if (link_check && (sc->link_active == 0)) {
+ if (link_check &&
+ (sc->link_state == EM_LINK_STATE_DOWN ||
+ sc->link_state == EM_LINK_STATE_DOWN_RESET_PENDING)) {
+ bool reset_pending;
+
+ reset_pending =
+ sc->link_state == EM_LINK_STATE_DOWN_RESET_PENDING;
e1000_get_speed_and_duplex(hw, &sc->link_speed,
&sc->link_duplex);
/* Check if we must disable SPEED_MODE bit on PCI-E */
@@ -2279,7 +2290,7 @@
sc->link_speed,
((sc->link_duplex == FULL_DUPLEX) ?
"Full Duplex" : "Half Duplex"));
- sc->link_active = 1;
+ sc->link_state = EM_LINK_STATE_UP;
sc->smartspeed = 0;
if ((ctrl & E1000_CTRL_EXT_LINK_MODE_MASK) ==
E1000_CTRL_EXT_LINK_MODE_GMII &&
@@ -2299,17 +2310,33 @@
}
/* Only do TSO on gigabit for older chips due to errata */
if (hw->mac.type < igb_mac_min)
- automasked = em_automask_tso(ctx);
+ reset_requested = em_automask_tso(ctx);
- /* Automasking resets the interface so don't mark it up yet */
- if (!automasked)
+ if (reset_pending || reset_requested) {
+ /*
+ * The PHY is up, but publish it only after the TSO
+ * capability-change reset.
+ */
+ sc->link_state = EM_LINK_STATE_UP_RESET_PENDING;
+ } else {
iflib_link_state_change(ctx, LINK_STATE_UP,
IF_Mbps(sc->link_speed));
- } else if (!link_check && (sc->link_active == 1)) {
+ }
+ } else if (!link_check &&
+ (sc->link_state == EM_LINK_STATE_UP ||
+ sc->link_state == EM_LINK_STATE_UP_RESET_PENDING)) {
+ bool link_was_published;
+ bool reset_pending;
+
+ link_was_published = sc->link_state == EM_LINK_STATE_UP;
+ reset_pending =
+ sc->link_state == EM_LINK_STATE_UP_RESET_PENDING;
sc->link_speed = 0;
sc->link_duplex = 0;
- sc->link_active = 0;
- iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
+ sc->link_state = reset_pending ?
+ EM_LINK_STATE_DOWN_RESET_PENDING : EM_LINK_STATE_DOWN;
+ if (link_was_published)
+ iflib_link_state_change(ctx, LINK_STATE_DOWN, 0);
}
em_update_stats_counters(sc);
@@ -2758,7 +2785,9 @@
{
u16 phy_tmp;
- if (sc->link_active || (sc->hw.phy.type != e1000_phy_igp) ||
+ if (sc->link_state == EM_LINK_STATE_UP ||
+ sc->link_state == EM_LINK_STATE_UP_RESET_PENDING ||
+ (sc->hw.phy.type != e1000_phy_igp) ||
sc->hw.mac.autoneg == 0 ||
(sc->hw.phy.autoneg_advertised & ADVERTISE_1000_FULL) == 0)
return;
@@ -4342,6 +4371,8 @@
struct e1000_softc *sc = iflib_get_softc(ctx);
if_softc_ctx_t scctx = iflib_get_softc_ctx(ctx);
if_t ifp = iflib_get_ifp(ctx);
+ bool reset_needed;
+ int drvflags;
if (!em_unsupported_tso && sc->link_speed &&
sc->link_speed != SPEED_1000 &&
@@ -4351,20 +4382,32 @@
sc->tso_automasked = scctx->isc_capenable & IFCAP_TSO;
scctx->isc_capenable &= ~IFCAP_TSO;
if_setcapenablebit(ifp, 0, IFCAP_TSO);
- /* iflib_init_locked handles ifnet hwassistbits */
- iflib_request_reset(ctx);
- return true;
} else if (sc->link_speed == SPEED_1000 && sc->tso_automasked) {
device_printf(sc->dev, "Re-enabling TSO for GbE.\n");
scctx->isc_capenable |= sc->tso_automasked;
if_setcapenablebit(ifp, sc->tso_automasked, 0);
sc->tso_automasked = 0;
- /* iflib_init_locked handles ifnet hwassistbits */
- iflib_request_reset(ctx);
- return true;
+ } else {
+ return (false);
}
- return false;
+ /*
+ * Reset a running interface, or one being initialized while
+ * administratively up. OACTIVE remains set after iflib_stop(), so
+ * it alone cannot distinguish initialization from an interface that
+ * is down. In other states, the next initialization will apply the
+ * updated capabilities.
+ */
+ drvflags = if_getdrvflags(ifp);
+ reset_needed = (drvflags & IFF_DRV_RUNNING) != 0 ||
+ ((drvflags & IFF_DRV_OACTIVE) != 0 &&
+ (if_getflags(ifp) & IFF_UP) != 0);
+ if (!reset_needed)
+ return (false);
+
+ /* iflib_init_locked handles ifnet hwassistbits */
+ iflib_request_reset(ctx);
+ return (true);
}
/*
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Aug 3, 4:38 AM (15 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35505511
Default Alt Text
D58425.id182655.diff (5 KB)
Attached To
Mode
D58425: e1000: Defer link-up notification until after TSO reset
Attached
Detach File
Event Timeline
Log In to Comment