Author: erj
Date: Thu May 12 18:21:34 2016
New Revision: 299553
URL: https://svnweb.freebsd.org/changeset/base/299553

Log:
  ixl: Update to 1.4.20-k.
  
  Changes by author:
  
  Eric Joyner   ixl: Add more error messages/checks to ixl_vsi_assign_msix().
  Eric Joyner   ixl/ixlv: Clarify a comment about descriptors.
  Eric Joyner   ixl/ixlv: Improve i40e_debug() implementation.
  Eric Joyner   ixl/ixlv: Remove unused ASSERT() macro; move struct around.
  Eric Joyner   ixl: Set initial advertised speed value in init_locked().
  Eric Joyner   ixl: Fix flow control sysctl value being stored when new value 
is invalid.
  Eric Joyner   Edit comments and spacing.
  Carolyn Wyborny       i40e-shared: Add functions to blink led on Coppervale 
PHY
  Eric Joyner   ixl: Re-do interrupt setup.
  Eric Joyner   ixl: Remove VFLR task setup from legacy flow.
  Eric Joyner   ixl: Shutdown/setup HMC when handling an EMPR reset.
  
  Differential Revision:  https://reviews.freebsd.org/D6211
  Reviewed by:    sbruno, kmacy, jeffrey.e.pie...@intel.com
  MFC after:      2 weeks
  Sponsored by:   Intel Corporation

Modified:
  head/sys/dev/ixl/i40e_common.c
  head/sys/dev/ixl/i40e_osdep.c
  head/sys/dev/ixl/i40e_osdep.h
  head/sys/dev/ixl/i40e_prototype.h
  head/sys/dev/ixl/i40e_type.h
  head/sys/dev/ixl/if_ixl.c
  head/sys/dev/ixl/ixl.h

Modified: head/sys/dev/ixl/i40e_common.c
==============================================================================
--- head/sys/dev/ixl/i40e_common.c      Thu May 12 18:21:17 2016        
(r299552)
+++ head/sys/dev/ixl/i40e_common.c      Thu May 12 18:21:34 2016        
(r299553)
@@ -5601,6 +5601,335 @@ enum i40e_status_code i40e_aq_configure_
 }
 
 /**
+ * i40e_read_phy_register
+ * @hw: pointer to the HW structure
+ * @page: registers page number
+ * @reg: register address in the page
+ * @phy_adr: PHY address on MDIO interface
+ * @value: PHY register value
+ *
+ * Reads specified PHY register value
+ **/
+enum i40e_status_code i40e_read_phy_register(struct i40e_hw *hw,
+                                            u8 page, u16 reg, u8 phy_addr,
+                                            u16 *value)
+{
+       enum i40e_status_code status = I40E_ERR_TIMEOUT;
+       u32 command  = 0;
+       u16 retry = 1000;
+       u8 port_num = (u8)hw->func_caps.mdio_port_num;
+
+       command = (reg << I40E_GLGEN_MSCA_MDIADD_SHIFT) |
+                 (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+                 (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+                 (I40E_MDIO_OPCODE_ADDRESS) |
+                 (I40E_MDIO_STCODE) |
+                 (I40E_GLGEN_MSCA_MDICMD_MASK) |
+                 (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+       wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+       do {
+               command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+               if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+                       status = I40E_SUCCESS;
+                       break;
+               }
+               i40e_usec_delay(10);
+               retry--;
+       } while (retry);
+
+       if (status) {
+               i40e_debug(hw, I40E_DEBUG_PHY,
+                          "PHY: Can't write command to external PHY.\n");
+               goto phy_read_end;
+       }
+
+       command = (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+                 (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+                 (I40E_MDIO_OPCODE_READ) |
+                 (I40E_MDIO_STCODE) |
+                 (I40E_GLGEN_MSCA_MDICMD_MASK) |
+                 (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+       status = I40E_ERR_TIMEOUT;
+       retry = 1000;
+       wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+       do {
+               command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+               if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+                       status = I40E_SUCCESS;
+                       break;
+               }
+               i40e_usec_delay(10);
+               retry--;
+       } while (retry);
+
+       if (!status) {
+               command = rd32(hw, I40E_GLGEN_MSRWD(port_num));
+               *value = (command & I40E_GLGEN_MSRWD_MDIRDDATA_MASK) >>
+                        I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT;
+       } else {
+               i40e_debug(hw, I40E_DEBUG_PHY,
+                          "PHY: Can't read register value from external 
PHY.\n");
+       }
+
+phy_read_end:
+       return status;
+}
+
+/**
+ * i40e_write_phy_register
+ * @hw: pointer to the HW structure
+ * @page: registers page number
+ * @reg: register address in the page
+ * @phy_adr: PHY address on MDIO interface
+ * @value: PHY register value
+ *
+ * Writes value to specified PHY register
+ **/
+enum i40e_status_code i40e_write_phy_register(struct i40e_hw *hw,
+                                             u8 page, u16 reg, u8 phy_addr,
+                                             u16 value)
+{
+       enum i40e_status_code status = I40E_ERR_TIMEOUT;
+       u32 command  = 0;
+       u16 retry = 1000;
+       u8 port_num = (u8)hw->func_caps.mdio_port_num;
+
+       command = (reg << I40E_GLGEN_MSCA_MDIADD_SHIFT) |
+                 (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+                 (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+                 (I40E_MDIO_OPCODE_ADDRESS) |
+                 (I40E_MDIO_STCODE) |
+                 (I40E_GLGEN_MSCA_MDICMD_MASK) |
+                 (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+       wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+       do {
+               command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+               if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+                       status = I40E_SUCCESS;
+                       break;
+               }
+               i40e_usec_delay(10);
+               retry--;
+       } while (retry);
+       if (status) {
+               i40e_debug(hw, I40E_DEBUG_PHY,
+                          "PHY: Can't write command to external PHY.\n");
+               goto phy_write_end;
+       }
+
+       command = value << I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT;
+       wr32(hw, I40E_GLGEN_MSRWD(port_num), command);
+
+       command = (page << I40E_GLGEN_MSCA_DEVADD_SHIFT) |
+                 (phy_addr << I40E_GLGEN_MSCA_PHYADD_SHIFT) |
+                 (I40E_MDIO_OPCODE_WRITE) |
+                 (I40E_MDIO_STCODE) |
+                 (I40E_GLGEN_MSCA_MDICMD_MASK) |
+                 (I40E_GLGEN_MSCA_MDIINPROGEN_MASK);
+       status = I40E_ERR_TIMEOUT;
+       retry = 1000;
+       wr32(hw, I40E_GLGEN_MSCA(port_num), command);
+       do {
+               command = rd32(hw, I40E_GLGEN_MSCA(port_num));
+               if (!(command & I40E_GLGEN_MSCA_MDICMD_MASK)) {
+                       status = I40E_SUCCESS;
+                       break;
+               }
+               i40e_usec_delay(10);
+               retry--;
+       } while (retry);
+
+phy_write_end:
+       return status;
+}
+
+/**
+ * i40e_get_phy_address
+ * @hw: pointer to the HW structure
+ * @dev_num: PHY port num that address we want
+ * @phy_addr: Returned PHY address
+ *
+ * Gets PHY address for current port
+ **/
+u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num)
+{
+       u8 port_num = (u8)hw->func_caps.mdio_port_num;
+       u32 reg_val = rd32(hw, I40E_GLGEN_MDIO_I2C_SEL(port_num));
+
+       return (u8)(reg_val >> ((dev_num + 1) * 5)) & 0x1f;
+}
+
+/**
+ * i40e_blink_phy_led
+ * @hw: pointer to the HW structure
+ * @time: time how long led will blinks in secs
+ * @interval: gap between LED on and off in msecs
+ *
+ * Blinks PHY link LED
+ **/
+enum i40e_status_code i40e_blink_phy_link_led(struct i40e_hw *hw,
+                                             u32 time, u32 interval)
+{
+       enum i40e_status_code status = I40E_SUCCESS;
+       u32 i;
+       u16 led_ctl = 0;
+       u16 gpio_led_port;
+       u16 led_reg;
+       u16 led_addr = I40E_PHY_LED_PROV_REG_1;
+       u8 phy_addr = 0;
+       u8 port_num;
+
+       i = rd32(hw, I40E_PFGEN_PORTNUM);
+       port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK);
+       phy_addr = i40e_get_phy_address(hw, port_num);
+
+       for (gpio_led_port = 0; gpio_led_port < 3; gpio_led_port++,
+            led_addr++) {
+               status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+                                               led_addr, phy_addr, &led_reg);
+               if (status)
+                       goto phy_blinking_end;
+               led_ctl = led_reg;
+               if (led_reg & I40E_PHY_LED_LINK_MODE_MASK) {
+                       led_reg = 0;
+                       status = i40e_write_phy_register(hw,
+                                                        I40E_PHY_COM_REG_PAGE,
+                                                        led_addr, phy_addr,
+                                                        led_reg);
+                       if (status)
+                               goto phy_blinking_end;
+                       break;
+               }
+       }
+
+       if (time > 0 && interval > 0) {
+               for (i = 0; i < time * 1000; i += interval) {
+                       status = i40e_read_phy_register(hw,
+                                                       I40E_PHY_COM_REG_PAGE,
+                                                       led_addr, phy_addr,
+                                                       &led_reg);
+                       if (status)
+                               goto restore_config;
+                       if (led_reg & I40E_PHY_LED_MANUAL_ON)
+                               led_reg = 0;
+                       else
+                               led_reg = I40E_PHY_LED_MANUAL_ON;
+                       status = i40e_write_phy_register(hw,
+                                                        I40E_PHY_COM_REG_PAGE,
+                                                        led_addr, phy_addr,
+                                                        led_reg);
+                       if (status)
+                               goto restore_config;
+                       i40e_msec_delay(interval);
+               }
+       }
+
+restore_config:
+       status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr,
+                                        phy_addr, led_ctl);
+
+phy_blinking_end:
+       return status;
+}
+
+/**
+ * i40e_led_get_phy - return current on/off mode
+ * @hw: pointer to the hw struct
+ * @led_addr: address of led register to use
+ * @val: original value of register to use
+ *
+ **/
+enum i40e_status_code i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
+                                      u16 *val)
+{
+       enum i40e_status_code status = I40E_SUCCESS;
+       u16 gpio_led_port;
+       u8 phy_addr = 0;
+       u16 reg_val;
+       u16 temp_addr;
+       u8 port_num;
+       u32 i;
+
+       temp_addr = I40E_PHY_LED_PROV_REG_1;
+       i = rd32(hw, I40E_PFGEN_PORTNUM);
+       port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK);
+       phy_addr = i40e_get_phy_address(hw, port_num);
+
+       for (gpio_led_port = 0; gpio_led_port < 3; gpio_led_port++,
+            temp_addr++) {
+               status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+                                               temp_addr, phy_addr, &reg_val);
+               if (status)
+                       return status;
+               *val = reg_val;
+               if (reg_val & I40E_PHY_LED_LINK_MODE_MASK) {
+                       *led_addr = temp_addr;
+                       break;
+               }
+       }
+       return status;
+}
+
+/**
+ * i40e_led_set_phy
+ * @hw: pointer to the HW structure
+ * @on: TRUE or FALSE
+ * @mode: original val plus bit for set or ignore
+ * Set led's on or off when controlled by the PHY
+ *
+ **/
+enum i40e_status_code i40e_led_set_phy(struct i40e_hw *hw, bool on,
+                                      u16 led_addr, u32 mode)
+{
+       enum i40e_status_code status = I40E_SUCCESS;
+       u16 led_ctl = 0;
+       u16 led_reg = 0;
+       u8 phy_addr = 0;
+       u8 port_num;
+       u32 i;
+
+       i = rd32(hw, I40E_PFGEN_PORTNUM);
+       port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK);
+       phy_addr = i40e_get_phy_address(hw, port_num);
+
+       status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr,
+                                       phy_addr, &led_reg);
+       if (status)
+               return status;
+       led_ctl = led_reg;
+       if (led_reg & I40E_PHY_LED_LINK_MODE_MASK) {
+               led_reg = 0;
+               status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+                                                led_addr, phy_addr, led_reg);
+               if (status)
+                       return status;
+       }
+       status = i40e_read_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+                                       led_addr, phy_addr, &led_reg);
+       if (status)
+               goto restore_config;
+       if (on)
+               led_reg = I40E_PHY_LED_MANUAL_ON;
+       else
+               led_reg = 0;
+       status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE,
+                                        led_addr, phy_addr, led_reg);
+       if (status)
+               goto restore_config;
+       if (mode & I40E_PHY_LED_MODE_ORIG) {
+               led_ctl = (mode & I40E_PHY_LED_MODE_MASK);
+               status = i40e_write_phy_register(hw,
+                                                I40E_PHY_COM_REG_PAGE,
+                                                led_addr, phy_addr, led_ctl);
+       }
+       return status;
+restore_config:
+       status = i40e_write_phy_register(hw, I40E_PHY_COM_REG_PAGE, led_addr,
+                                        phy_addr, led_ctl);
+       return status;
+}
+
+/**
  * i40e_aq_send_msg_to_pf
  * @hw: pointer to the hardware structure
  * @v_opcode: opcodes for VF-PF communication

Modified: head/sys/dev/ixl/i40e_osdep.c
==============================================================================
--- head/sys/dev/ixl/i40e_osdep.c       Thu May 12 18:21:17 2016        
(r299552)
+++ head/sys/dev/ixl/i40e_osdep.c       Thu May 12 18:21:34 2016        
(r299553)
@@ -159,22 +159,19 @@ i40e_destroy_spinlock(struct i40e_spinlo
 }
 
 /*
-** i40e_debug_d - OS dependent version of shared code debug printing
-*/
-void i40e_debug_d(void *hw, u32 mask, char *fmt, ...)
+ * Helper function for debug statement printing
+ */
+void
+i40e_debug_d(struct i40e_hw *hw, enum i40e_debug_mask mask, char *fmt, ...)
 {
-        char buf[512];
-        va_list args;
+       va_list args;
 
-        if (!(mask & ((struct i40e_hw *)hw)->debug_mask))
-                return;
+       if (!(mask & ((struct i40e_hw *)hw)->debug_mask))
+               return;
 
        va_start(args, fmt);
-        vsnprintf(buf, sizeof(buf), fmt, args);
+       device_printf(((struct i40e_osdep *)hw->back)->dev, fmt, args);
        va_end(args);
-
-        /* the debug string is already formatted with a newline */
-        printf("%s", buf);
 }
 
 u16

Modified: head/sys/dev/ixl/i40e_osdep.h
==============================================================================
--- head/sys/dev/ixl/i40e_osdep.h       Thu May 12 18:21:17 2016        
(r299552)
+++ head/sys/dev/ixl/i40e_osdep.h       Thu May 12 18:21:34 2016        
(r299553)
@@ -54,8 +54,6 @@
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcireg.h>
 
-#define ASSERT(x) if(!(x)) panic("IXL: x")
-
 #define i40e_usec_delay(x) DELAY(x)
 #define i40e_msec_delay(x) DELAY(1000*(x))
 
@@ -169,21 +167,26 @@ struct i40e_dma_mem {
        int                     flags;
 };
 
+struct i40e_virt_mem {
+       void *va;
+       u32 size;
+};
+
 struct i40e_hw; /* forward decl */
 u16    i40e_read_pci_cfg(struct i40e_hw *, u32);
 void   i40e_write_pci_cfg(struct i40e_hw *, u32, u16);
 
+/*
+** i40e_debug - OS dependent version of shared code debug printing
+*/
+enum i40e_debug_mask;
 #define i40e_debug(h, m, s, ...)  i40e_debug_d(h, m, s, ##__VA_ARGS__)
-extern void i40e_debug_d(void *hw, u32 mask, char *fmt_str, ...);
-
-struct i40e_virt_mem {
-       void *va;
-       u32 size;
-};
+extern void i40e_debug_d(struct i40e_hw *hw, enum i40e_debug_mask mask,
+    char *fmt_str, ...);
 
 /*
-** This hardware supports either 16 or 32 byte rx descriptors
-** we default here to the larger size.
+** This hardware supports either 16 or 32 byte rx descriptors;
+** the driver only uses the 32 byte kind.
 */
 #define i40e_rx_desc i40e_32byte_rx_desc
 

Modified: head/sys/dev/ixl/i40e_prototype.h
==============================================================================
--- head/sys/dev/ixl/i40e_prototype.h   Thu May 12 18:21:17 2016        
(r299552)
+++ head/sys/dev/ixl/i40e_prototype.h   Thu May 12 18:21:34 2016        
(r299553)
@@ -84,6 +84,12 @@ const char *i40e_stat_str(struct i40e_hw
 
 u32 i40e_led_get(struct i40e_hw *hw);
 void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink);
+enum i40e_status_code i40e_led_set_phy(struct i40e_hw *hw, bool on,
+                                      u16 led_addr, u32 mode);
+enum i40e_status_code i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
+                                      u16 *val);
+enum i40e_status_code i40e_blink_phy_link_led(struct i40e_hw *hw,
+                                             u32 time, u32 interval);
 
 /* admin send queue commands */
 
@@ -483,4 +489,11 @@ enum i40e_status_code i40e_aq_debug_dump
                                struct i40e_asq_cmd_details *cmd_details);
 void i40e_add_filter_to_drop_tx_flow_control_frames(struct i40e_hw *hw,
                                                    u16 vsi_seid);
+enum i40e_status_code i40e_read_phy_register(struct i40e_hw *hw, u8 page,
+                                            u16 reg, u8 phy_addr, u16 *value);
+enum i40e_status_code i40e_write_phy_register(struct i40e_hw *hw, u8 page,
+                                             u16 reg, u8 phy_addr, u16 value);
+u8 i40e_get_phy_address(struct i40e_hw *hw, u8 dev_num);
+enum i40e_status_code i40e_blink_phy_link_led(struct i40e_hw *hw,
+                                             u32 time, u32 interval);
 #endif /* _I40E_PROTOTYPE_H_ */

Modified: head/sys/dev/ixl/i40e_type.h
==============================================================================
--- head/sys/dev/ixl/i40e_type.h        Thu May 12 18:21:17 2016        
(r299552)
+++ head/sys/dev/ixl/i40e_type.h        Thu May 12 18:21:34 2016        
(r299553)
@@ -147,6 +147,22 @@ enum i40e_debug_mask {
 #define I40E_PCI_LINK_SPEED_5000       0x2
 #define I40E_PCI_LINK_SPEED_8000       0x3
 
+#define I40E_MDIO_STCODE               0
+#define I40E_MDIO_OPCODE_ADDRESS       0
+#define I40E_MDIO_OPCODE_WRITE         I40E_MASK(1, \
+                                                 I40E_GLGEN_MSCA_OPCODE_SHIFT)
+#define I40E_MDIO_OPCODE_READ_INC_ADDR I40E_MASK(2, \
+                                                 I40E_GLGEN_MSCA_OPCODE_SHIFT)
+#define I40E_MDIO_OPCODE_READ          I40E_MASK(3, \
+                                                 I40E_GLGEN_MSCA_OPCODE_SHIFT)
+
+#define I40E_PHY_COM_REG_PAGE                  0x1E
+#define I40E_PHY_LED_LINK_MODE_MASK            0xF0
+#define I40E_PHY_LED_MANUAL_ON                 0x100
+#define I40E_PHY_LED_PROV_REG_1                        0xC430
+#define I40E_PHY_LED_MODE_MASK                 0xFFFF
+#define I40E_PHY_LED_MODE_ORIG                 0x80000000
+
 /* Memory types */
 enum i40e_memset_type {
        I40E_NONDMA_MEM = 0,

Modified: head/sys/dev/ixl/if_ixl.c
==============================================================================
--- head/sys/dev/ixl/if_ixl.c   Thu May 12 18:21:17 2016        (r299552)
+++ head/sys/dev/ixl/if_ixl.c   Thu May 12 18:21:34 2016        (r299553)
@@ -48,7 +48,7 @@
 /*********************************************************************
  *  Driver version
  *********************************************************************/
-char ixl_driver_version[] = "1.4.17-k";
+char ixl_driver_version[] = "1.4.20-k";
 
 /*********************************************************************
  *  PCI Device ID Table
@@ -105,15 +105,22 @@ static u16        ixl_get_bus_info(struct i40e_
 static int     ixl_setup_stations(struct ixl_pf *);
 static int     ixl_switch_config(struct ixl_pf *);
 static int     ixl_initialize_vsi(struct ixl_vsi *);
-static int     ixl_assign_vsi_msix(struct ixl_pf *);
+
+static int     ixl_setup_adminq_msix(struct ixl_pf *);
+static int     ixl_setup_adminq_tq(struct ixl_pf *);
+static int     ixl_setup_queue_msix(struct ixl_vsi *);
+static int     ixl_setup_queue_tqs(struct ixl_vsi *);
+static int     ixl_teardown_adminq_msix(struct ixl_pf *);
+static int     ixl_teardown_queue_msix(struct ixl_vsi *);
+static void    ixl_configure_intr0_msix(struct ixl_pf *);
+static void    ixl_configure_queue_intr_msix(struct ixl_pf *);
+static void    ixl_free_queue_tqs(struct ixl_vsi *);
+static void    ixl_free_adminq_tq(struct ixl_pf *);
+
 static int     ixl_assign_vsi_legacy(struct ixl_pf *);
 static int     ixl_init_msix(struct ixl_pf *);
-static void    ixl_configure_msix(struct ixl_pf *);
 static void    ixl_configure_itr(struct ixl_pf *);
 static void    ixl_configure_legacy(struct ixl_pf *);
-static void    ixl_init_taskqueues(struct ixl_pf *);
-static void    ixl_free_taskqueues(struct ixl_pf *);
-static void    ixl_free_interrupt_resources(struct ixl_pf *);
 static void    ixl_free_pci_resources(struct ixl_pf *);
 static void    ixl_local_timer(void *);
 static int     ixl_setup_interface(device_t, struct ixl_vsi *);
@@ -122,6 +129,7 @@ static void ixl_config_rss(struct ixl_vs
 static void    ixl_set_queue_rx_itr(struct ixl_queue *);
 static void    ixl_set_queue_tx_itr(struct ixl_queue *);
 static int     ixl_set_advertised_speeds(struct ixl_pf *, int);
+static void    ixl_get_initial_advertised_speeds(struct ixl_pf *);
 
 static int     ixl_enable_rings(struct ixl_vsi *);
 static int     ixl_disable_rings(struct ixl_vsi *);
@@ -200,6 +208,8 @@ static void ixl_stat_update32(struct i40
                    u64 *, u64 *);
 /* NVM update */
 static int     ixl_handle_nvmupd_cmd(struct ixl_pf *, struct ifdrv *);
+static void    ixl_handle_empr_reset(struct ixl_pf *);
+static int     ixl_rebuild_hw_structs_after_reset(struct ixl_pf *);
 
 
 #ifdef PCI_IOV
@@ -586,7 +596,8 @@ ixl_attach(device_t dev)
 
        error = ixl_switch_config(pf);
        if (error) {
-               device_printf(dev, "Initial ixl_switch_config() failed: %d\n", 
error);
+               device_printf(dev, "Initial ixl_switch_config() failed: %d\n",
+                    error);
                goto err_late;
        }
 
@@ -599,12 +610,31 @@ ixl_attach(device_t dev)
                goto err_late;
        }
 
-       /* Get the bus configuration and set the shared code */
+       /* Get the bus configuration and set the shared code's config */
        bus = ixl_get_bus_info(hw, dev);
        i40e_set_pci_config_data(hw, bus);
 
-       /* Initialize taskqueues */
-       ixl_init_taskqueues(pf);
+       /*
+        * In MSI-X mode, initialize the Admin Queue interrupt,
+        * so userland tools can communicate with the adapter regardless of
+        * the ifnet interface's status.
+        */
+       if (pf->msix > 1) {
+               error = ixl_setup_adminq_msix(pf);
+               if (error) {
+                       device_printf(dev, "ixl_setup_adminq_msix error: %d\n",
+                           error);
+                       goto err_late;
+               }
+               error = ixl_setup_adminq_tq(pf);
+               if (error) {
+                       device_printf(dev, "ixl_setup_adminq_tq error: %d\n",
+                           error);
+                       goto err_late;
+               }
+               ixl_configure_intr0_msix(pf);
+               ixl_enable_adminq(hw);
+       }
 
        /* Initialize statistics & add sysctls */
        ixl_add_device_sysctls(pf);
@@ -678,7 +708,7 @@ ixl_detach(device_t dev)
        struct ixl_pf           *pf = device_get_softc(dev);
        struct i40e_hw          *hw = &pf->hw;
        struct ixl_vsi          *vsi = &pf->vsi;
-       i40e_status             status;
+       enum i40e_status_code   status;
 #ifdef PCI_IOV
        int                     error;
 #endif
@@ -687,7 +717,7 @@ ixl_detach(device_t dev)
 
        /* Make sure VLANS are not using driver */
        if (vsi->ifp->if_vlantrunk != NULL) {
-               device_printf(dev,"Vlan in use, detach first\n");
+               device_printf(dev, "Vlan in use, detach first\n");
                return (EBUSY);
        }
 
@@ -703,7 +733,7 @@ ixl_detach(device_t dev)
        if (vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)
                ixl_stop(pf);
 
-       ixl_free_taskqueues(pf);
+       ixl_free_queue_tqs(vsi);
 
        /* Shutdown LAN HMC */
        status = i40e_shutdown_lan_hmc(hw);
@@ -712,6 +742,9 @@ ixl_detach(device_t dev)
                    "Shutdown LAN HMC failed with code %d\n", status);
 
        /* Shutdown admin queue */
+       ixl_disable_adminq(hw);
+       ixl_free_adminq_tq(pf);
+       ixl_teardown_adminq_msix(pf);
        status = i40e_shutdown_adminq(hw);
        if (status)
                device_printf(dev,
@@ -794,7 +827,7 @@ retry:
        pf->qbase = hw->func_caps.base_queue;
 
 #ifdef IXL_DEBUG
-       device_printf(dev,"pf_id=%d, num_vfs=%d, msix_pf=%d, "
+       device_printf(dev, "pf_id=%d, num_vfs=%d, msix_pf=%d, "
            "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n",
            hw->pf_id, hw->func_caps.num_vfs,
            hw->func_caps.num_msix_vectors,
@@ -1131,7 +1164,7 @@ ixl_init_locked(struct ixl_pf *pf)
 
        /* Set up MSI/X routing and the ITR settings */
        if (ixl_enable_msix) {
-               ixl_configure_msix(pf);
+               ixl_configure_queue_intr_msix(pf);
                ixl_configure_itr(pf);
        } else
                ixl_configure_legacy(pf);
@@ -1150,6 +1183,9 @@ ixl_init_locked(struct ixl_pf *pf)
        i40e_get_link_status(hw, &pf->link_up);
        ixl_update_link_status(pf);
 
+       /* Set initial advertised speed sysctl value */
+       ixl_get_initial_advertised_speeds(pf);
+
        /* Start the local timer */
        callout_reset(&pf->timer, hz, ixl_local_timer, pf);
 
@@ -1159,6 +1195,37 @@ ixl_init_locked(struct ixl_pf *pf)
        return;
 }
 
+/* For the set_advertise sysctl */
+static void
+ixl_get_initial_advertised_speeds(struct ixl_pf *pf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       device_t dev = pf->dev;
+       enum i40e_status_code status;
+       struct i40e_aq_get_phy_abilities_resp abilities;
+
+       /* Set initial sysctl values */
+       status = i40e_aq_get_phy_capabilities(hw, FALSE, false, &abilities,
+                                             NULL);
+       if (status) {
+               /* Non-fatal error */
+               device_printf(dev, "%s: i40e_aq_get_phy_capabilities() error 
%d\n",
+                    __func__, status);
+               return;
+       }
+
+       if (abilities.link_speed & I40E_LINK_SPEED_40GB)
+               pf->advertised_speed |= 0x10;
+       if (abilities.link_speed & I40E_LINK_SPEED_20GB)
+               pf->advertised_speed |= 0x8;
+       if (abilities.link_speed & I40E_LINK_SPEED_10GB)
+               pf->advertised_speed |= 0x4;
+       if (abilities.link_speed & I40E_LINK_SPEED_1GB)
+               pf->advertised_speed |= 0x2;
+       if (abilities.link_speed & I40E_LINK_SPEED_100MB)
+               pf->advertised_speed |= 0x1;
+}
+
 static int
 ixl_teardown_hw_structs(struct ixl_pf *pf)
 {
@@ -1277,7 +1344,8 @@ static void
 ixl_init(void *arg)
 {
        struct ixl_pf *pf = arg;
-       int ret = 0;
+       device_t dev = pf->dev;
+       int error = 0;
 
        /*
         * If the aq is dead here, it probably means something outside of the 
driver
@@ -1285,20 +1353,32 @@ ixl_init(void *arg)
         * So rebuild the driver's state here if that occurs.
         */
        if (!i40e_check_asq_alive(&pf->hw)) {
-               device_printf(pf->dev, "asq is not alive; rebuilding...\n");
+               device_printf(dev, "Admin Queue is down; resetting...\n");
                IXL_PF_LOCK(pf);
                ixl_teardown_hw_structs(pf);
                ixl_reset(pf);
                IXL_PF_UNLOCK(pf);
        }
 
-       /* Set up interrupt routing here */
-       if (pf->msix > 1)
-               ret = ixl_assign_vsi_msix(pf);
-       else
-               ret = ixl_assign_vsi_legacy(pf);
-       if (ret) {
-               device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", 
ret);
+       /*
+        * Set up LAN queue interrupts here.
+        * Kernel interrupt setup functions cannot be called while holding a 
lock,
+        * so this is done outside of init_locked().
+        */
+       if (pf->msix > 1) {
+               error = ixl_setup_queue_msix(&pf->vsi);
+               if (error)
+                       device_printf(dev, "ixl_setup_queue_msix() error: %d\n",
+                           error);
+               error = ixl_setup_queue_tqs(&pf->vsi);
+               if (error)
+                       device_printf(dev, "ixl_setup_queue_tqs() error: %d\n",
+                           error);
+       } else
+               // possibly broken
+               error = ixl_assign_vsi_legacy(pf);
+       if (error) {
+               device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", 
error);
                return;
        }
 
@@ -1309,9 +1389,7 @@ ixl_init(void *arg)
 }
 
 /*
-**
 ** MSIX Interrupt Handlers and Tasklets
-**
 */
 static void
 ixl_handle_que(void *context, int pending)
@@ -2050,7 +2128,7 @@ ixl_stop(struct ixl_pf *pf)
        ixl_stop_locked(pf);
        IXL_PF_UNLOCK(pf);
 
-       ixl_free_interrupt_resources(pf);
+       ixl_teardown_queue_msix(&pf->vsi);
 }
 
 /*********************************************************************
@@ -2073,14 +2151,11 @@ ixl_stop_locked(struct ixl_pf *pf)
        /* Stop the local timer */
        callout_stop(&pf->timer);
 
-       if (pf->num_vfs == 0)
-               ixl_disable_intr(vsi);
-       else
-               ixl_disable_rings_intr(vsi);
+       ixl_disable_rings_intr(vsi);
        ixl_disable_rings(vsi);
 
        /* Tell the stack that the interface is no longer active */
-       ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+       ifp->if_drv_flags &= ~(IFF_DRV_RUNNING);
 }
 
 
@@ -2125,10 +2200,6 @@ ixl_assign_vsi_legacy(struct ixl_pf *pf)
            device_get_nameunit(dev));
        TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
 
-#ifdef PCI_IOV
-       TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
-#endif
-
        pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
            taskqueue_thread_enqueue, &pf->tq);
        taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
@@ -2137,25 +2208,41 @@ ixl_assign_vsi_legacy(struct ixl_pf *pf)
        return (0);
 }
 
-static void
-ixl_init_taskqueues(struct ixl_pf *pf)
+static int
+ixl_setup_adminq_tq(struct ixl_pf *pf)
 {
-       struct ixl_vsi *vsi = &pf->vsi;
-       struct ixl_queue *que = vsi->queues;
        device_t dev = pf->dev;
+       int error = 0;
 
-       /* Tasklet for Admin Queue */
+       /* Tasklet for Admin Queue interrupts */
        TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf);
 #ifdef PCI_IOV
        /* VFLR Tasklet */
        TASK_INIT(&pf->vflr_task, 0, ixl_handle_vflr, pf);
 #endif
-
-       /* Create and start PF taskqueue */
-       pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT,
+       /* Create and start Admin Queue taskqueue */
+       pf->tq = taskqueue_create_fast("ixl_aq", M_NOWAIT,
            taskqueue_thread_enqueue, &pf->tq);
-       taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq",
+       if (!pf->tq) {
+               device_printf(dev, "taskqueue_create_fast (for AQ) returned 
NULL!\n");
+               return (ENOMEM);
+       }
+       error = taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s aq",
            device_get_nameunit(dev));
+       if (error) {
+               device_printf(dev, "taskqueue_start_threads (for AQ) error: 
%d\n",
+                   error);
+               taskqueue_free(pf->tq);
+               return (error);
+       }
+       return (0);
+}
+
+static int
+ixl_setup_queue_tqs(struct ixl_vsi *vsi)
+{
+       struct ixl_queue *que = vsi->queues;
+       device_t dev = vsi->dev;
 
        /* Create queue tasks and start queue taskqueues */
        for (int i = 0; i < vsi->num_queues; i++, que++) {
@@ -2174,71 +2261,90 @@ ixl_init_taskqueues(struct ixl_pf *pf)
 #endif
        }
 
+       return (0);
 }
 
 static void
-ixl_free_taskqueues(struct ixl_pf *pf)
+ixl_free_adminq_tq(struct ixl_pf *pf)
 {
-       struct ixl_vsi          *vsi = &pf->vsi;
-       struct ixl_queue        *que = vsi->queues;
-
        if (pf->tq)
                taskqueue_free(pf->tq);
+}
+
+static void
+ixl_free_queue_tqs(struct ixl_vsi *vsi)
+{
+       struct ixl_queue        *que = vsi->queues;
+
        for (int i = 0; i < vsi->num_queues; i++, que++) {
                if (que->tq)
                        taskqueue_free(que->tq);
        }
 }
 
-/*********************************************************************
- *
- *  Setup MSIX Interrupt resources and handlers for the VSI
- *
- **********************************************************************/
 static int
-ixl_assign_vsi_msix(struct ixl_pf *pf)
+ixl_setup_adminq_msix(struct ixl_pf *pf)
 {
-       device_t        dev = pf->dev;
-       struct          ixl_vsi *vsi = &pf->vsi;
-       struct          ixl_queue *que = vsi->queues;
-       struct          tx_ring  *txr;
-       int             error, rid, vector = 0;
-#ifdef RSS
-       cpuset_t cpu_mask;
-#endif
+       device_t dev = pf->dev;
+       int rid, error = 0;
 
-       /* Admin Queue interrupt vector is 0 */
-       rid = vector + 1;
+       /* Admin IRQ rid is 1, vector is 0 */
+       rid = 1;
+       /* Get interrupt resource from bus */
        pf->res = bus_alloc_resource_any(dev,
            SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
        if (!pf->res) {
-               device_printf(dev, "Unable to allocate"
-                   " bus resource: Adminq interrupt [rid=%d]\n", rid);
+               device_printf(dev, "bus_alloc_resource_any() for Admin Queue"
+                   " interrupt failed [rid=%d]\n", rid);
                return (ENXIO);
        }
-       /* Set the adminq vector and handler */
+       /* Then associate interrupt with handler */
        error = bus_setup_intr(dev, pf->res,
            INTR_TYPE_NET | INTR_MPSAFE, NULL,
            ixl_msix_adminq, pf, &pf->tag);
        if (error) {
                pf->res = NULL;
-               device_printf(dev, "Failed to register Admin que handler");
-               return (error);
+               device_printf(dev, "bus_setup_intr() for Admin Queue"
+                   " interrupt handler failed, error %d\n", error);
+               return (ENXIO);
+       }
+       error = bus_describe_intr(dev, pf->res, pf->tag, "aq");
+       if (error) {
+               /* Probably non-fatal? */
+               device_printf(dev, "bus_describe_intr() for Admin Queue"
+                   " interrupt name failed, error %d\n", error);
        }
-       bus_describe_intr(dev, pf->res, pf->tag, "aq");
-       pf->admvec = vector;
-       ++vector;
+       pf->admvec = 0;
+
+       return (0);
+}
 
-       /* Now set up the stations */
+/*
+ * Allocate interrupt resources from bus and associate an interrupt handler
+ * to those for the VSI's queues.
+ */
+static int
+ixl_setup_queue_msix(struct ixl_vsi *vsi)
+{
+       device_t        dev = vsi->dev;
+       struct          ixl_queue *que = vsi->queues;
+       struct          tx_ring  *txr;
+       int             error, rid, vector = 1;
+#ifdef RSS
+       cpuset_t cpu_mask;
+#endif
+
+       /* Queue interrupt vector numbers start at 1 (adminq intr is 0) */
        for (int i = 0; i < vsi->num_queues; i++, vector++, que++) {
                int cpu_id = i;
                rid = vector + 1;
                txr = &que->txr;
                que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
                    RF_SHAREABLE | RF_ACTIVE);
-               if (que->res == NULL) {
-                       device_printf(dev, "Unable to allocate"
-                           " bus resource: que interrupt [rid=%d]\n", rid);
+               if (!que->res) {
+                       device_printf(dev, "bus_alloc_resource_any() for"
+                           " Queue %d interrupt failed [rid=%d]\n",
+                           que->me, rid);
                        return (ENXIO);
                }
                /* Set the handler function */
@@ -2246,16 +2352,29 @@ ixl_assign_vsi_msix(struct ixl_pf *pf)
                    INTR_TYPE_NET | INTR_MPSAFE, NULL,
                    ixl_msix_que, que, &que->tag);
                if (error) {
-                       que->res = NULL;
-                       device_printf(dev, "Failed to register que handler");
+                       device_printf(dev, "bus_setup_intr() for Queue %d"
+                           " interrupt handler failed, error %d\n",
+                           que->me, error);
+                       // TODO: Check for error from this?
+                       bus_release_resource(dev, SYS_RES_IRQ, rid, que->res);
                        return (error);
                }
-               bus_describe_intr(dev, que->res, que->tag, "que%d", i);
+               error = bus_describe_intr(dev, que->res, que->tag, "que%d", i);
+               if (error) {
+                       device_printf(dev, "bus_describe_intr() for Queue %d"
+                           " interrupt name failed, error %d\n",
+                           que->me, error);
+               }
                /* Bind the vector to a CPU */
 #ifdef RSS
                cpu_id = rss_getcpu(i % rss_getnumbuckets());
 #endif
-               bus_bind_intr(dev, que->res, cpu_id);
+               error = bus_bind_intr(dev, que->res, cpu_id);
+               if (error) {
+                       device_printf(dev, "bus_bind_intr() for Queue %d"
+                           " to CPU %d failed, error %d\n",
+                           que->me, cpu_id, error);
+               }
                que->msix = vector;
        }
 
@@ -2391,15 +2510,13 @@ no_msix:
 }
 
 /*
- * Plumb MSIX vectors
+ * Configure admin queue/misc interrupt cause registers in hardware.
  */
 static void
-ixl_configure_msix(struct ixl_pf *pf)
+ixl_configure_intr0_msix(struct ixl_pf *pf)
 {
-       struct i40e_hw  *hw = &pf->hw;
-       struct ixl_vsi *vsi = &pf->vsi;
-       u32             reg;
-       u16             vector = 1;
+       struct i40e_hw *hw = &pf->hw;
+       u32 reg;
 
        /* First set up the adminq - vector 0 */
        wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
@@ -2428,8 +2545,19 @@ ixl_configure_msix(struct ixl_pf *pf)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to