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: