Print this page
9095 ixgbe MAC_CAPAB_LED support
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Sebastian Wiedenroth <sebastian.wiedenroth@skylime.net>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Dan McDonald <danmcd@joyent.com>
NEX-2081 ixgbe triggers warning when receiving too many interrupt vectors from DDI
SUP-479 10 Gigabit CX4 Dual Port Server Adapter EXPX9502CX4 unresponsive to external pings after upgrade from 3.1.2 to 3.1.3.5
@@ -24,11 +24,11 @@
*/
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, Joyent, Inc.
- * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2013 Saso Kiselkov. All rights reserved.
* Copyright (c) 2013 OSN Online Service Nuernberg GmbH. All rights reserved.
* Copyright 2016 OmniTI Computer Consulting, Inc. All rights reserved.
*/
@@ -491,18 +491,10 @@
*/
ixgbe_init_properties(ixgbe);
ixgbe->attach_progress |= ATTACH_PROGRESS_PROPS;
/*
- * Register interrupt callback
- */
- if (ixgbe_intr_cb_register(ixgbe) != IXGBE_SUCCESS) {
- ixgbe_error(ixgbe, "Failed to register interrupt callback");
- goto attach_fail;
- }
-
- /*
* Allocate interrupts
*/
if (ixgbe_alloc_intrs(ixgbe) != IXGBE_SUCCESS) {
ixgbe_error(ixgbe, "Failed to allocate interrupts");
goto attach_fail;
@@ -648,10 +640,19 @@
ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
ixgbe_log(ixgbe, "%s", ixgbe_ident);
atomic_or_32(&ixgbe->ixgbe_state, IXGBE_INITIALIZED);
+ /*
+ * Register interrupt callback
+ */
+ if (ixgbe->intr_type == DDI_INTR_TYPE_MSIX)
+ if (ixgbe_intr_cb_register(ixgbe) != IXGBE_SUCCESS) {
+ ixgbe_error(ixgbe,
+ "Failed to register interrupt callback");
+ }
+
return (DDI_SUCCESS);
attach_fail:
ixgbe_unconfigure(devinfo, ixgbe);
return (DDI_FAILURE);
@@ -776,10 +777,16 @@
static void
ixgbe_unconfigure(dev_info_t *devinfo, ixgbe_t *ixgbe)
{
/*
+ * Unregister interrupt callback handler
+ */
+ if (ixgbe->cb_hdl != NULL)
+ (void) ddi_cb_unregister(ixgbe->cb_hdl);
+
+ /*
* Disable interrupt
*/
if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
(void) ixgbe_disable_intrs(ixgbe);
}
@@ -1239,10 +1246,46 @@
mutex_destroy(&ixgbe->gen_lock);
mutex_destroy(&ixgbe->watchdog_lock);
}
+/*
+ * We need to try and determine which LED index in hardware corresponds to the
+ * link/activity LED. This is the one that'll be overwritten when we perform
+ * GLDv3 LED activity.
+ */
+static void
+ixgbe_led_init(ixgbe_t *ixgbe)
+{
+ uint32_t reg, i;
+ struct ixgbe_hw *hw = &ixgbe->hw;
+
+ reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+ for (i = 0; i < 4; i++) {
+ if (((reg >> IXGBE_LED_MODE_SHIFT(i)) &
+ IXGBE_LED_MODE_MASK_BASE) == IXGBE_LED_LINK_ACTIVE) {
+ ixgbe->ixgbe_led_index = i;
+ return;
+ }
+ }
+
+ /*
+ * If we couldn't determine this, we use the default for various MACs
+ * based on information Intel has inserted into other drivers over the
+ * years. Note, when we have support for the X553 which should add the
+ * ixgbe_x550_em_a mac type, that should be at index 0.
+ */
+ switch (hw->mac.type) {
+ case ixgbe_mac_X550EM_x:
+ ixgbe->ixgbe_led_index = 1;
+ break;
+ default:
+ ixgbe->ixgbe_led_index = 2;
+ break;
+ }
+}
+
static int
ixgbe_resume(dev_info_t *devinfo)
{
ixgbe_t *ixgbe;
int i;
@@ -1393,12 +1436,29 @@
/*
* Setup default flow control thresholds - enable/disable
* & flow control type is controlled by ixgbe.conf
*/
- hw->fc.high_water[0] = DEFAULT_FCRTH;
- hw->fc.low_water[0] = DEFAULT_FCRTL;
+ {
+ uint32_t rxpb, frame, size, hitmp, lotmp;
+
+ frame = ixgbe->max_frame_size;
+
+ /* Calculate High and Low Water */
+ if (hw->mac.type == ixgbe_mac_X540) {
+ hitmp = IXGBE_DV_X540(frame, frame);
+ lotmp = IXGBE_LOW_DV_X540(frame);
+ } else {
+ hitmp = IXGBE_DV(frame, frame);
+ lotmp = IXGBE_LOW_DV(frame);
+ }
+ size = IXGBE_BT2KB(hitmp);
+ rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10;
+ hw->fc.high_water[0] = rxpb - size;
+ hw->fc.low_water[0] = IXGBE_BT2KB(lotmp);
+ }
+
hw->fc.pause_time = DEFAULT_FCPAUSE;
hw->fc.send_xon = B_TRUE;
/*
* Initialize flow control
@@ -1426,10 +1486,15 @@
if (*pbanum != '\0') {
(void) ddi_prop_update_string(DDI_DEV_T_NONE, ixgbe->dip,
"printed-board-assembly", (char *)pbanum);
}
+ /*
+ * Determine LED index.
+ */
+ ixgbe_led_init(ixgbe);
+
if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK) {
goto init_fail;
}
mutex_exit(&ixgbe->gen_lock);
@@ -1990,35 +2055,40 @@
*/
static int
ixgbe_intr_adjust(ixgbe_t *ixgbe, ddi_cb_action_t cbaction, int count)
{
int i, rc, actual;
+ uint32_t started;
- if (count == 0)
- return (DDI_SUCCESS);
-
- if ((cbaction == DDI_CB_INTR_ADD &&
- ixgbe->intr_cnt + count > ixgbe->intr_cnt_max) ||
- (cbaction == DDI_CB_INTR_REMOVE &&
- ixgbe->intr_cnt - count < ixgbe->intr_cnt_min))
+ if (!(ixgbe->ixgbe_state & IXGBE_INITIALIZED)) {
return (DDI_FAILURE);
+ }
- if (!(ixgbe->ixgbe_state & IXGBE_STARTED)) {
+ if (cbaction == DDI_CB_INTR_REMOVE &&
+ ixgbe->intr_cnt - count < ixgbe->intr_cnt_min)
return (DDI_FAILURE);
- }
+ if (cbaction == DDI_CB_INTR_ADD &&
+ ixgbe->intr_cnt + count > ixgbe->intr_cnt_max)
+ count = ixgbe->intr_cnt_max - ixgbe->intr_cnt;
+
+ if (count == 0)
+ return (DDI_SUCCESS);
+
for (i = 0; i < ixgbe->num_rx_rings; i++)
mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle, NULL);
for (i = 0; i < ixgbe->num_tx_rings; i++)
mac_ring_intr_set(ixgbe->tx_rings[i].ring_handle, NULL);
mutex_enter(&ixgbe->gen_lock);
+ started = ixgbe->ixgbe_state & IXGBE_STARTED;
ixgbe->ixgbe_state &= ~IXGBE_STARTED;
ixgbe->ixgbe_state |= IXGBE_INTR_ADJUST;
ixgbe->ixgbe_state |= IXGBE_SUSPENDED;
mac_link_update(ixgbe->mac_hdl, LINK_STATE_UNKNOWN);
+ if (started)
ixgbe_stop(ixgbe, B_FALSE);
/*
* Disable interrupts
*/
if (ixgbe->attach_progress & ATTACH_PROGRESS_ENABLE_INTR) {
@@ -2110,17 +2180,18 @@
if (ixgbe_enable_intrs(ixgbe) != IXGBE_SUCCESS) {
ixgbe_error(ixgbe, "IRM CB: Failed to enable DDI interrupts");
goto intr_adjust_fail;
}
ixgbe->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
+ if (started)
if (ixgbe_start(ixgbe, B_FALSE) != IXGBE_SUCCESS) {
ixgbe_error(ixgbe, "IRM CB: Failed to start");
goto intr_adjust_fail;
}
ixgbe->ixgbe_state &= ~IXGBE_INTR_ADJUST;
ixgbe->ixgbe_state &= ~IXGBE_SUSPENDED;
- ixgbe->ixgbe_state |= IXGBE_STARTED;
+ ixgbe->ixgbe_state |= started;
mutex_exit(&ixgbe->gen_lock);
for (i = 0; i < ixgbe->num_rx_rings; i++) {
mac_ring_intr_set(ixgbe->rx_rings[i].ring_handle,
ixgbe->htable[ixgbe->rx_rings[i].intr_vector]);
@@ -3675,17 +3746,18 @@
(void) ixgbe_check_link(hw, &speed, &link_up, B_FALSE);
if (link_up) {
ixgbe->link_check_complete = B_TRUE;
- /* Link is up, enable flow control settings */
- (void) ixgbe_fc_enable(hw);
-
/*
* The Link is up, check whether it was marked as down earlier
*/
if (ixgbe->link_state != LINK_STATE_UP) {
+
+ /* Link is up, enable flow control settings */
+ (void) ixgbe_fc_enable(hw);
+
switch (speed) {
case IXGBE_LINK_SPEED_10GB_FULL:
ixgbe->link_speed = SPEED_10GB;
break;
case IXGBE_LINK_SPEED_5GB_FULL: