summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzhefeng xu - Sun Microsystems - Beijing China <Jason.Xu@Sun.COM>2009-12-21 14:33:26 +0800
committerzhefeng xu - Sun Microsystems - Beijing China <Jason.Xu@Sun.COM>2009-12-21 14:33:26 +0800
commitcf8dcc9bbabedca41ecfee13dec8172104e99968 (patch)
treebd3f6c50709bc5dd51d8577ce2f70187506d0306
parented11b5015754f34571b1ea0fef3f0faad03a1e45 (diff)
downloadillumos-gate-cf8dcc9bbabedca41ecfee13dec8172104e99968.tar.gz
6890117 igb driver reports link status as down before auto neg has had time to complete
6902785 igb should return failure immediately when finding error with dma handle 6882523 igb.conf configuration inconsistent with igb driver
-rw-r--r--usr/src/uts/common/io/igb/igb.conf6
-rw-r--r--usr/src/uts/common/io/igb/igb_gld.c10
-rw-r--r--usr/src/uts/common/io/igb/igb_main.c159
-rw-r--r--usr/src/uts/common/io/igb/igb_ndd.c19
-rw-r--r--usr/src/uts/common/io/igb/igb_rx.c16
-rw-r--r--usr/src/uts/common/io/igb/igb_stat.c6
-rw-r--r--usr/src/uts/common/io/igb/igb_sw.h4
-rw-r--r--usr/src/uts/common/io/igb/igb_tx.c12
8 files changed, 189 insertions, 43 deletions
diff --git a/usr/src/uts/common/io/igb/igb.conf b/usr/src/uts/common/io/igb/igb.conf
index 93860209f0..8914b31189 100644
--- a/usr/src/uts/common/io/igb/igb.conf
+++ b/usr/src/uts/common/io/igb/igb.conf
@@ -19,9 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright(c) 2007-2008 Intel Corporation. All rights reserved.
+# Copyright(c) 2007-2009 Intel Corporation. All rights reserved.
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#
@@ -133,7 +133,7 @@
# mr_enable
# Enable multiple rx queues and tx queues
# Allowed values: 0, 1
-# Default value: 1
+# Default value: 0
#
# rx_group_number
# The number of the receive ring groups
diff --git a/usr/src/uts/common/io/igb/igb_gld.c b/usr/src/uts/common/io/igb/igb_gld.c
index 539b1992cc..9fddd30f61 100644
--- a/usr/src/uts/common/io/igb/igb_gld.c
+++ b/usr/src/uts/common/io/igb/igb_gld.c
@@ -427,8 +427,10 @@ igb_m_stat(void *arg, uint_t stat, uint64_t *val)
mutex_exit(&igb->gen_lock);
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_UNAFFECTED);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ return (EIO);
+ }
return (0);
}
@@ -454,7 +456,7 @@ igb_m_start(void *arg)
return (EIO);
}
- igb->igb_state |= IGB_STARTED;
+ atomic_or_32(&igb->igb_state, IGB_STARTED);
mutex_exit(&igb->gen_lock);
@@ -482,7 +484,7 @@ igb_m_stop(void *arg)
return;
}
- igb->igb_state &= ~IGB_STARTED;
+ atomic_and_32(&igb->igb_state, ~IGB_STARTED);
igb_stop(igb);
diff --git a/usr/src/uts/common/io/igb/igb_main.c b/usr/src/uts/common/io/igb/igb_main.c
index e2137ae44c..5939625e28 100644
--- a/usr/src/uts/common/io/igb/igb_main.c
+++ b/usr/src/uts/common/io/igb/igb_main.c
@@ -29,7 +29,7 @@
#include "igb_sw.h"
static char ident[] = "Intel 1Gb Ethernet";
-static char igb_version[] = "igb 1.1.9";
+static char igb_version[] = "igb 1.1.10";
/*
* Local function protoypes
@@ -67,10 +67,13 @@ static int igb_get_prop(igb_t *, char *, int, int, int);
static boolean_t igb_is_link_up(igb_t *);
static boolean_t igb_link_check(igb_t *);
static void igb_local_timer(void *);
+static void igb_link_timer(void *);
static void igb_arm_watchdog_timer(igb_t *);
static void igb_start_watchdog_timer(igb_t *);
static void igb_restart_watchdog_timer(igb_t *);
static void igb_stop_watchdog_timer(igb_t *);
+static void igb_start_link_timer(igb_t *);
+static void igb_stop_link_timer(igb_t *);
static void igb_disable_adapter_interrupts(igb_t *);
static void igb_enable_adapter_interrupts_82575(igb_t *);
static void igb_enable_adapter_interrupts_82576(igb_t *);
@@ -507,7 +510,7 @@ igb_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
igb->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
igb_log(igb, "%s", igb_version);
- igb->igb_state |= IGB_INITIALIZED;
+ atomic_or_32(&igb->igb_state, IGB_INITIALIZED);
return (DDI_SUCCESS);
@@ -575,7 +578,7 @@ igb_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
*/
mutex_enter(&igb->gen_lock);
if (igb->igb_state & IGB_STARTED) {
- igb->igb_state &= ~IGB_STARTED;
+ atomic_and_32(&igb->igb_state, ~IGB_STARTED);
igb_stop(igb);
mutex_exit(&igb->gen_lock);
/* Disable and stop the watchdog timer */
@@ -1027,6 +1030,9 @@ igb_init_locks(igb_t *igb)
mutex_init(&igb->watchdog_lock, NULL,
MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
+
+ mutex_init(&igb->link_lock, NULL,
+ MUTEX_DRIVER, DDI_INTR_PRI(igb->intr_pri));
}
/*
@@ -1055,6 +1061,7 @@ igb_destroy_locks(igb_t *igb)
mutex_destroy(&igb->gen_lock);
mutex_destroy(&igb->watchdog_lock);
+ mutex_destroy(&igb->link_lock);
}
static int
@@ -1080,7 +1087,7 @@ igb_resume(dev_info_t *devinfo)
igb_enable_watchdog_timer(igb);
}
- igb->igb_state &= ~IGB_SUSPENDED;
+ atomic_and_32(&igb->igb_state, ~IGB_SUSPENDED);
mutex_exit(&igb->gen_lock);
@@ -1098,7 +1105,7 @@ igb_suspend(dev_info_t *devinfo)
mutex_enter(&igb->gen_lock);
- igb->igb_state |= IGB_SUSPENDED;
+ atomic_or_32(&igb->igb_state, IGB_SUSPENDED);
if (!(igb->igb_state & IGB_STARTED)) {
mutex_exit(&igb->gen_lock);
@@ -1149,6 +1156,11 @@ igb_init(igb_t *igb)
for (i = igb->num_rx_rings - 1; i >= 0; i--)
mutex_exit(&igb->rx_rings[i].rx_lock);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
+ return (IGB_FAILURE);
+ }
+
mutex_exit(&igb->gen_lock);
return (IGB_SUCCESS);
@@ -1325,6 +1337,11 @@ igb_init_adapter(igb_t *igb)
}
/*
+ * Start the link setup timer
+ */
+ igb_start_link_timer(igb);
+
+ /*
* Disable wakeup control by default
*/
E1000_WRITE_REG(hw, E1000_WUC, 0);
@@ -1394,6 +1411,9 @@ igb_stop_adapter(igb_t *igb)
ASSERT(mutex_owned(&igb->gen_lock));
+ /* Stop the link setup timer */
+ igb_stop_link_timer(igb);
+
/* Tell firmware driver is no longer in control */
igb_release_driver_control(hw);
@@ -1424,6 +1444,7 @@ igb_reset(igb_t *igb)
mutex_enter(&igb->gen_lock);
ASSERT(igb->igb_state & IGB_STARTED);
+ atomic_and_32(&igb->igb_state, ~IGB_STARTED);
/*
* Disable the adapter interrupts to stop any rx/tx activities
@@ -1464,6 +1485,8 @@ igb_reset(igb_t *igb)
*/
igb_setup_rings(igb);
+ atomic_and_32(&igb->igb_state, ~(IGB_ERROR | IGB_STALL));
+
/*
* Enable adapter interrupts
* The interrupts must be enabled after the driver state is START
@@ -1481,6 +1504,8 @@ igb_reset(igb_t *igb)
for (i = igb->num_rx_rings - 1; i >= 0; i--)
mutex_exit(&igb->rx_rings[i].rx_lock);
+ atomic_or_32(&igb->igb_state, IGB_STARTED);
+
mutex_exit(&igb->gen_lock);
return (IGB_SUCCESS);
@@ -1840,9 +1865,6 @@ igb_setup_rings(igb_t *igb)
igb_setup_rx(igb);
igb_setup_tx(igb);
-
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
}
static void
@@ -2397,9 +2419,6 @@ igb_init_unicst(igb_t *igb)
igb->unicst_addr[slot].mac.group_index);
}
}
-
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
}
/*
@@ -2982,8 +3001,10 @@ igb_link_check(igb_t *igb)
igb->link_state = LINK_STATE_UP;
igb->link_down_timeout = 0;
link_changed = B_TRUE;
+ if (!igb->link_complete)
+ igb_stop_link_timer(igb);
}
- } else {
+ } else if (igb->link_complete) {
if (igb->link_state != LINK_STATE_DOWN) {
igb->link_speed = 0;
igb->link_duplex = 0;
@@ -3002,8 +3023,10 @@ igb_link_check(igb_t *igb)
}
}
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ return (B_FALSE);
+ }
return (link_changed);
}
@@ -3020,17 +3043,24 @@ igb_local_timer(void *arg)
igb_t *igb = (igb_t *)arg;
boolean_t link_changed = B_FALSE;
- if (igb_stall_check(igb))
- igb->igb_state |= IGB_STALL;
+ if (igb->igb_state & IGB_ERROR) {
+ igb->reset_count++;
+ if (igb_reset(igb) == IGB_SUCCESS)
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_RESTORED);
- if (igb->igb_state & IGB_STALL) {
+ igb_restart_watchdog_timer(igb);
+ return;
+ }
+
+ if (igb_stall_check(igb) || (igb->igb_state & IGB_STALL)) {
igb_fm_ereport(igb, DDI_FM_DEVICE_STALL);
ddi_fm_service_impact(igb->dip, DDI_SERVICE_LOST);
igb->reset_count++;
- igb->igb_state &= ~IGB_STALL;
if (igb_reset(igb) == IGB_SUCCESS)
- ddi_fm_service_impact(igb->dip,
- DDI_SERVICE_RESTORED);
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_RESTORED);
+
+ igb_restart_watchdog_timer(igb);
+ return;
}
mutex_enter(&igb->gen_lock);
@@ -3041,13 +3071,30 @@ igb_local_timer(void *arg)
if (link_changed)
mac_link_update(igb->mac_hdl, igb->link_state);
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
-
igb_restart_watchdog_timer(igb);
}
/*
+ * igb_link_timer - link setup timer function
+ *
+ * It is called when the timer for link setup is expired, which indicates
+ * the completion of the link setup. The link state will not be updated
+ * until the link setup is completed. And the link state will not be sent
+ * to the upper layer through mac_link_update() in this function. It will
+ * be updated in the local timer routine or the interrupts service routine
+ * after the interface is started (plumbed).
+ */
+static void
+igb_link_timer(void *arg)
+{
+ igb_t *igb = (igb_t *)arg;
+
+ mutex_enter(&igb->link_lock);
+ igb->link_complete = B_TRUE;
+ igb->link_tid = 0;
+ mutex_exit(&igb->link_lock);
+}
+/*
* igb_stall_check - check for transmit stall
*
* This function checks if the adapter is stalled (in transmit).
@@ -3302,6 +3349,50 @@ igb_stop_watchdog_timer(igb_t *igb)
}
/*
+ * igb_start_link_timer - Start the link setup timer
+ */
+static void
+igb_start_link_timer(struct igb *igb)
+{
+ struct e1000_hw *hw = &igb->hw;
+ clock_t link_timeout;
+
+ if (hw->mac.autoneg)
+ link_timeout = PHY_AUTO_NEG_LIMIT *
+ drv_usectohz(100000);
+ else
+ link_timeout = PHY_FORCE_LIMIT * drv_usectohz(100000);
+
+ mutex_enter(&igb->link_lock);
+ if (hw->phy.autoneg_wait_to_complete) {
+ igb->link_complete = B_TRUE;
+ } else {
+ igb->link_complete = B_FALSE;
+ igb->link_tid = timeout(igb_link_timer, (void *)igb,
+ link_timeout);
+ }
+ mutex_exit(&igb->link_lock);
+}
+
+/*
+ * igb_stop_link_timer - Stop the link setup timer
+ */
+static void
+igb_stop_link_timer(struct igb *igb)
+{
+ timeout_id_t tid;
+
+ mutex_enter(&igb->link_lock);
+ igb->link_complete = B_TRUE;
+ tid = igb->link_tid;
+ igb->link_tid = 0;
+ mutex_exit(&igb->link_lock);
+
+ if (tid != 0)
+ (void) untimeout(tid);
+}
+
+/*
* igb_disable_adapter_interrupts - Clear/disable all hardware interrupts
*/
static void
@@ -3829,6 +3920,12 @@ igb_intr_legacy(void *arg1, void *arg2)
link_changed = B_FALSE;
icr = E1000_READ_REG(&igb->hw, E1000_ICR);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (DDI_INTR_UNCLAIMED);
+ }
+
if (icr & E1000_ICR_INT_ASSERTED) {
/*
* E1000_ICR_INT_ASSERTED bit was set:
@@ -3872,7 +3969,7 @@ igb_intr_legacy(void *arg1, void *arg2)
if (icr & E1000_ICR_DRSTA) {
/* 82580 Full Device Reset needed */
- igb->igb_state |= IGB_STALL;
+ atomic_or_32(&igb->igb_state, IGB_STALL);
}
result = DDI_INTR_CLAIMED;
@@ -3917,6 +4014,12 @@ igb_intr_msi(void *arg1, void *arg2)
icr = E1000_READ_REG(&igb->hw, E1000_ICR);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (DDI_INTR_CLAIMED);
+ }
+
/* Make sure all interrupt causes cleared */
(void) E1000_READ_REG(&igb->hw, E1000_EICR);
@@ -3941,7 +4044,7 @@ igb_intr_msi(void *arg1, void *arg2)
if (icr & E1000_ICR_DRSTA) {
/* 82580 Full Device Reset needed */
- igb->igb_state |= IGB_STALL;
+ atomic_or_32(&igb->igb_state, IGB_STALL);
}
return (DDI_INTR_CLAIMED);
@@ -3999,6 +4102,12 @@ igb_intr_tx_other(void *arg1, void *arg2)
icr = E1000_READ_REG(&igb->hw, E1000_ICR);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (DDI_INTR_CLAIMED);
+ }
+
/*
* Look for tx reclaiming work first. Remember, in the
* case of only interrupt sharing, only one tx ring is
@@ -4027,7 +4136,7 @@ igb_intr_tx_other(void *arg1, void *arg2)
if (icr & E1000_ICR_DRSTA) {
/* 82580 Full Device Reset needed */
- igb->igb_state |= IGB_STALL;
+ atomic_or_32(&igb->igb_state, IGB_STALL);
}
return (DDI_INTR_CLAIMED);
diff --git a/usr/src/uts/common/io/igb/igb_ndd.c b/usr/src/uts/common/io/igb/igb_ndd.c
index 58ce0e77e5..3e00a82c89 100644
--- a/usr/src/uts/common/io/igb/igb_ndd.c
+++ b/usr/src/uts/common/io/igb/igb_ndd.c
@@ -33,7 +33,7 @@ static int igb_nd_get(queue_t *, mblk_t *, caddr_t, cred_t *);
static int igb_nd_set(queue_t *, mblk_t *, char *, caddr_t, cred_t *);
static int igb_nd_param_load(igb_t *);
static void igb_nd_get_param_val(nd_param_t *);
-static void igb_nd_set_param_val(nd_param_t *, uint32_t);
+static int igb_nd_set_param_val(nd_param_t *, uint32_t);
/*
* Notes:
@@ -146,7 +146,8 @@ igb_nd_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *credp)
if (new_value < nd->min || new_value > nd->max)
return (EINVAL);
- igb_nd_set_param_val(nd, new_value);
+ if (igb_nd_set_param_val(nd, new_value) != IGB_SUCCESS)
+ return (EIO);
return (0);
}
@@ -263,16 +264,17 @@ igb_nd_get_param_val(nd_param_t *nd)
/*
* igb_nd_set_param_val
*/
-static void
+static int
igb_nd_set_param_val(nd_param_t *nd, uint32_t value)
{
igb_t *igb = (igb_t *)nd->private;
+ int result = IGB_SUCCESS;
mutex_enter(&igb->gen_lock);
if (nd->val == value) {
mutex_exit(&igb->gen_lock);
- return;
+ return (IGB_SUCCESS);
}
switch (nd->info) {
@@ -284,16 +286,19 @@ igb_nd_set_param_val(nd_param_t *nd, uint32_t value)
case PARAM_ADV_10HDX_CAP:
nd->val = value;
(void) igb_setup_link(igb, B_TRUE);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ result = IGB_FAILURE;
+ }
break;
default:
break;
}
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_UNAFFECTED);
-
mutex_exit(&igb->gen_lock);
+
+ return (result);
}
/*
diff --git a/usr/src/uts/common/io/igb/igb_rx.c b/usr/src/uts/common/io/igb/igb_rx.c
index d1f6368a8d..13265e8a28 100644
--- a/usr/src/uts/common/io/igb/igb_rx.c
+++ b/usr/src/uts/common/io/igb/igb_rx.c
@@ -112,6 +112,8 @@ igb_rx_copy(igb_rx_ring_t *rx_ring, uint32_t index, uint32_t pkt_len)
if (igb_check_dma_handle(
current_rcb->rx_buf.dma_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (NULL);
}
/*
@@ -184,6 +186,9 @@ igb_rx_bind(igb_rx_ring_t *rx_ring, uint32_t index, uint32_t pkt_len)
if (igb_check_dma_handle(
current_rcb->rx_buf.dma_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ atomic_inc_32(&rx_ring->rcb_free);
+ return (NULL);
}
mp = current_rcb->mp;
@@ -253,8 +258,9 @@ igb_rx_ring_poll(void *arg, int bytes)
ASSERT(bytes >= 0);
- if (bytes == 0)
- return (mp);
+ if ((bytes == 0) || (rx_ring->igb->igb_state & IGB_SUSPENDED) ||
+ !(rx_ring->igb->igb_state & IGB_STARTED))
+ return (NULL);
mutex_enter(&rx_ring->rx_lock);
mp = igb_rx(rx_ring, bytes);
@@ -290,6 +296,9 @@ igb_rx(igb_rx_ring_t *rx_ring, int poll_bytes)
mblk_head = NULL;
mblk_tail = &mblk_head;
+ if (igb->igb_state & IGB_ERROR)
+ return (NULL);
+
/*
* Sync the receive descriptors before
* accepting the packets
@@ -299,6 +308,8 @@ igb_rx(igb_rx_ring_t *rx_ring, int poll_bytes)
if (igb_check_dma_handle(
rx_ring->rbd_area.dma_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (NULL);
}
/*
@@ -401,6 +412,7 @@ rx_discard:
if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
}
return (mblk_head);
diff --git a/usr/src/uts/common/io/igb/igb_stat.c b/usr/src/uts/common/io/igb/igb_stat.c
index a16d8bec3f..8edc4dbeed 100644
--- a/usr/src/uts/common/io/igb/igb_stat.c
+++ b/usr/src/uts/common/io/igb/igb_stat.c
@@ -136,8 +136,10 @@ igb_update_stats(kstat_t *ks, int rw)
mutex_exit(&igb->gen_lock);
- if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK)
- ddi_fm_service_impact(igb->dip, DDI_SERVICE_UNAFFECTED);
+ if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
+ ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ return (EIO);
+ }
return (0);
}
diff --git a/usr/src/uts/common/io/igb/igb_sw.h b/usr/src/uts/common/io/igb/igb_sw.h
index 5744f148f0..483f3342b2 100644
--- a/usr/src/uts/common/io/igb/igb_sw.h
+++ b/usr/src/uts/common/io/igb/igb_sw.h
@@ -82,6 +82,7 @@ extern "C" {
#define IGB_STARTED 0x02
#define IGB_SUSPENDED 0x04
#define IGB_STALL 0x08
+#define IGB_ERROR 0x80
#define IGB_INTR_NONE 0
#define IGB_INTR_MSIX 1
@@ -662,6 +663,8 @@ typedef struct igb {
uint32_t link_speed;
uint32_t link_duplex;
uint32_t link_down_timeout;
+ boolean_t link_complete;
+ timeout_id_t link_tid;
uint32_t reset_count;
uint32_t attach_progress;
@@ -715,6 +718,7 @@ typedef struct igb {
kmutex_t gen_lock; /* General lock for device access */
kmutex_t watchdog_lock;
+ kmutex_t link_lock;
boolean_t watchdog_enable;
boolean_t watchdog_start;
diff --git a/usr/src/uts/common/io/igb/igb_tx.c b/usr/src/uts/common/io/igb/igb_tx.c
index a24010cd30..54bde3d330 100644
--- a/usr/src/uts/common/io/igb/igb_tx.c
+++ b/usr/src/uts/common/io/igb/igb_tx.c
@@ -56,6 +56,13 @@ igb_tx_ring_send(void *arg, mblk_t *mp)
ASSERT(tx_ring != NULL);
+ if ((tx_ring->igb->igb_state & IGB_SUSPENDED) ||
+ (tx_ring->igb->igb_state & IGB_ERROR) ||
+ !(tx_ring->igb->igb_state & IGB_STARTED)) {
+ freemsg(mp);
+ return (NULL);
+ }
+
return ((igb_tx(tx_ring, mp)) ? NULL : mp);
}
@@ -1013,6 +1020,7 @@ igb_tx_fill_ring(igb_tx_ring_t *tx_ring, link_list_t *pending_list,
if (igb_check_acc_handle(igb->osdep.reg_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
}
return (desc_num);
@@ -1081,6 +1089,8 @@ igb_tx_recycle_legacy(igb_tx_ring_t *tx_ring)
if (igb_check_dma_handle(
tx_ring->tbd_area.dma_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (0);
}
LINK_LIST_INIT(&pending_list);
@@ -1227,6 +1237,8 @@ igb_tx_recycle_head_wb(igb_tx_ring_t *tx_ring)
if (igb_check_dma_handle(
tx_ring->tbd_area.dma_handle) != DDI_FM_OK) {
ddi_fm_service_impact(igb->dip, DDI_SERVICE_DEGRADED);
+ atomic_or_32(&igb->igb_state, IGB_ERROR);
+ return (0);
}
LINK_LIST_INIT(&pending_list);