summaryrefslogtreecommitdiffstats
path: root/sys/dev/ixl
diff options
context:
space:
mode:
authorerj <erj@FreeBSD.org>2016-05-12 18:21:34 +0000
committererj <erj@FreeBSD.org>2016-05-12 18:21:34 +0000
commite70f15d7421e2ab4b03d94dc569d755c262cafb2 (patch)
treedbb3ff49cdf6a72ef2688ace247a011b80189024 /sys/dev/ixl
parentb1978246c9e36ad26b0efba579c718c1cb0edf00 (diff)
downloadFreeBSD-src-e70f15d7421e2ab4b03d94dc569d755c262cafb2.zip
FreeBSD-src-e70f15d7421e2ab4b03d94dc569d755c262cafb2.tar.gz
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.pieper@intel.com MFC after: 2 weeks Sponsored by: Intel Corporation
Diffstat (limited to 'sys/dev/ixl')
-rw-r--r--sys/dev/ixl/i40e_common.c329
-rw-r--r--sys/dev/ixl/i40e_osdep.c19
-rw-r--r--sys/dev/ixl/i40e_osdep.h23
-rw-r--r--sys/dev/ixl/i40e_prototype.h13
-rw-r--r--sys/dev/ixl/i40e_type.h16
-rw-r--r--sys/dev/ixl/if_ixl.c543
-rw-r--r--sys/dev/ixl/ixl.h8
7 files changed, 780 insertions, 171 deletions
diff --git a/sys/dev/ixl/i40e_common.c b/sys/dev/ixl/i40e_common.c
index 4f6fbab..1b2d5fd 100644
--- a/sys/dev/ixl/i40e_common.c
+++ b/sys/dev/ixl/i40e_common.c
@@ -5601,6 +5601,335 @@ enum i40e_status_code i40e_aq_configure_partition_bw(struct i40e_hw *hw,
}
/**
+ * 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
diff --git a/sys/dev/ixl/i40e_osdep.c b/sys/dev/ixl/i40e_osdep.c
index 133f690..879d5fb 100644
--- a/sys/dev/ixl/i40e_osdep.c
+++ b/sys/dev/ixl/i40e_osdep.c
@@ -159,22 +159,19 @@ i40e_destroy_spinlock(struct i40e_spinlock *lock)
}
/*
-** 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
diff --git a/sys/dev/ixl/i40e_osdep.h b/sys/dev/ixl/i40e_osdep.h
index 67a4b18..f5ca7f4 100644
--- a/sys/dev/ixl/i40e_osdep.h
+++ b/sys/dev/ixl/i40e_osdep.h
@@ -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
diff --git a/sys/dev/ixl/i40e_prototype.h b/sys/dev/ixl/i40e_prototype.h
index 0f28573..b6ea458 100644
--- a/sys/dev/ixl/i40e_prototype.h
+++ b/sys/dev/ixl/i40e_prototype.h
@@ -84,6 +84,12 @@ const char *i40e_stat_str(struct i40e_hw *hw, enum i40e_status_code stat_err);
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_hw *hw, u8 cluster_id,
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_ */
diff --git a/sys/dev/ixl/i40e_type.h b/sys/dev/ixl/i40e_type.h
index c0151e1..76d55e7 100644
--- a/sys/dev/ixl/i40e_type.h
+++ b/sys/dev/ixl/i40e_type.h
@@ -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,
diff --git a/sys/dev/ixl/if_ixl.c b/sys/dev/ixl/if_ixl.c
index 5382ea9..53050ff 100644
--- a/sys/dev/ixl/if_ixl.c
+++ b/sys/dev/ixl/if_ixl.c
@@ -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_hw *, device_t);
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_vsi *);
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 i40e_hw *, u32, bool,
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)
I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK);
wr32(hw, I40E_PFINT_STAT_CTL0, 0);
+}
+
+/*
+ * Configure queue interrupt cause registers in hardware.
+ */
+static void
+ixl_configure_queue_intr_msix(struct ixl_pf *pf)
+{
+ struct i40e_hw *hw = &pf->hw;
+ struct ixl_vsi *vsi = &pf->vsi;
+ u32 reg;
+ u16 vector = 1;
- /* Next configure the queues */
for (int i = 0; i < vsi->num_queues; i++, vector++) {
wr32(hw, I40E_PFINT_DYN_CTLN(i), i);
wr32(hw, I40E_PFINT_LNKLSTN(i), i);
@@ -2570,21 +2698,49 @@ ixl_allocate_pci_resources(struct ixl_pf *pf)
return (0);
}
-static void
-ixl_free_interrupt_resources(struct ixl_pf *pf)
+/*
+ * Teardown and release the admin queue/misc vector
+ * interrupt.
+ */
+static int
+ixl_teardown_adminq_msix(struct ixl_pf *pf)
{
- struct ixl_vsi *vsi = &pf->vsi;
- struct ixl_queue *que = vsi->queues;
device_t dev = pf->dev;
- int rid;
+ int rid;
+
+ if (pf->admvec) /* we are doing MSIX */
+ rid = pf->admvec + 1;
+ else
+ (pf->msix != 0) ? (rid = 1):(rid = 0);
+
+ // TODO: Check for errors from bus_teardown_intr
+ // TODO: Check for errors from bus_release_resource
+ if (pf->tag != NULL) {
+ bus_teardown_intr(dev, pf->res, pf->tag);
+ pf->tag = NULL;
+ }
+ if (pf->res != NULL) {
+ bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
+ pf->res = NULL;
+ }
+
+ return (0);
+}
+
+static int
+ixl_teardown_queue_msix(struct ixl_vsi *vsi)
+{
+ struct ixl_queue *que = vsi->queues;
+ device_t dev = vsi->dev;
+ int rid;
/* We may get here before stations are setup */
if ((!ixl_enable_msix) || (que == NULL))
- goto early;
+ return (0);
- /*
- ** Release all msix VSI resources:
- */
+ /* Release all MSIX queue resources */
+ // TODO: Check for errors from bus_teardown_intr
+ // TODO: Check for errors from bus_release_resource
for (int i = 0; i < vsi->num_queues; i++, que++) {
rid = que->msix + 1;
if (que->tag != NULL) {
@@ -2597,21 +2753,7 @@ ixl_free_interrupt_resources(struct ixl_pf *pf)
}
}
-early:
- /* Clean the AdminQ interrupt last */
- if (pf->admvec) /* we are doing MSIX */
- rid = pf->admvec + 1;
- else
- (pf->msix != 0) ? (rid = 1):(rid = 0);
-
- if (pf->tag != NULL) {
- bus_teardown_intr(dev, pf->res, pf->tag);
- pf->tag = NULL;
- }
- if (pf->res != NULL) {
- bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res);
- pf->res = NULL;
- }
+ return (0);
}
static void
@@ -2620,7 +2762,8 @@ ixl_free_pci_resources(struct ixl_pf *pf)
device_t dev = pf->dev;
int memrid;
- ixl_free_interrupt_resources(pf);
+ ixl_teardown_queue_msix(&pf->vsi);
+ ixl_teardown_adminq_msix(pf);
if (pf->msix)
pci_release_msi(dev);
@@ -2837,7 +2980,6 @@ ixl_link_event(struct ixl_pf *pf, struct i40e_arq_event_info *e)
struct i40e_aqc_get_link_status *status =
(struct i40e_aqc_get_link_status *)&e->desc.params.raw;
-
/* Request link status from adapter */
hw->phy.get_link_info = TRUE;
i40e_get_link_status(hw, &pf->link_up);
@@ -4498,6 +4640,89 @@ ixl_update_stats_counters(struct ixl_pf *pf)
}
}
+static int
+ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf)
+{
+ struct i40e_hw *hw = &pf->hw;
+ struct ixl_vsi *vsi = &pf->vsi;
+ device_t dev = pf->dev;
+ bool is_up = false;
+ int error = 0;
+
+ is_up = !!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING);
+
+ /* Teardown */
+ if (is_up)
+ ixl_stop(pf);
+ error = i40e_shutdown_lan_hmc(hw);
+ if (error)
+ device_printf(dev,
+ "Shutdown LAN HMC failed with code %d\n", error);
+ ixl_disable_adminq(hw);
+ ixl_teardown_adminq_msix(pf);
+ error = i40e_shutdown_adminq(hw);
+ if (error)
+ device_printf(dev,
+ "Shutdown Admin queue failed with code %d\n", error);
+
+ /* Setup */
+ error = i40e_init_adminq(hw);
+ if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) {
+ device_printf(dev, "Unable to initialize Admin Queue, error %d\n",
+ error);
+ }
+ error = ixl_setup_adminq_msix(pf);
+ if (error) {
+ device_printf(dev, "ixl_setup_adminq_msix error: %d\n",
+ error);
+ }
+ ixl_configure_intr0_msix(pf);
+ ixl_enable_adminq(hw);
+ /* setup hmc */
+ error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
+ hw->func_caps.num_rx_qp, 0, 0);
+ if (error) {
+ device_printf(dev, "init_lan_hmc failed: %d\n", error);
+ }
+ error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
+ if (error) {
+ device_printf(dev, "configure_lan_hmc failed: %d\n", error);
+ }
+ if (is_up)
+ ixl_init(pf);
+
+ return (0);
+}
+
+static void
+ixl_handle_empr_reset(struct ixl_pf *pf)
+{
+ struct i40e_hw *hw = &pf->hw;
+ device_t dev = pf->dev;
+ int count = 0;
+ u32 reg;
+
+ /* Typically finishes within 3-4 seconds */
+ while (count++ < 100) {
+ reg = rd32(hw, I40E_GLGEN_RSTAT)
+ & I40E_GLGEN_RSTAT_DEVSTATE_MASK;
+ if (reg)
+ i40e_msec_delay(100);
+ else
+ break;
+ }
+#ifdef IXL_DEBUG
+ // Reset-related
+ device_printf(dev, "EMPR reset wait count: %d\n", count);
+#endif
+
+ device_printf(dev, "Rebuilding driver state...\n");
+ ixl_rebuild_hw_structs_after_reset(pf);
+ device_printf(dev, "Rebuilding driver state done.\n");
+
+ atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING);
+}
+
/*
** Tasklet handler for MSIX Adminq interrupts
** - do outside interrupt since it might sleep
@@ -4510,34 +4735,16 @@ ixl_do_adminq(void *context, int pending)
struct i40e_arq_event_info event;
i40e_status ret;
device_t dev = pf->dev;
- u32 reg, loop = 0;
+ u32 loop = 0;
u16 opcode, result;
- // XXX: Possibly inappropriate overload
if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
- int count = 0;
- // ERJ: Typically finishes within 3-4 seconds
- while (count++ < 100) {
- reg = rd32(hw, I40E_GLGEN_RSTAT);
- reg = reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK;
- if (reg) {
- i40e_msec_delay(100);
- } else {
- break;
- }
- }
- device_printf(dev, "EMPR reset wait count: %d\n", count);
-
- device_printf(dev, "Rebuilding HW structs...\n");
- // XXX: I feel like this could cause a kernel panic some time in the future
- ixl_stop(pf);
- ixl_init(pf);
-
- atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING);
+ /* Flag cleared at end of this function */
+ ixl_handle_empr_reset(pf);
return;
}
- // Actually do Admin Queue handling
+ /* Admin Queue handling */
event.buf_len = IXL_AQ_BUF_SZ;
event.msg_buf = malloc(event.buf_len,
M_DEVBUF, M_NOWAIT | M_ZERO);
@@ -4555,7 +4762,8 @@ ixl_do_adminq(void *context, int pending)
break;
opcode = LE16_TO_CPU(event.desc.opcode);
#ifdef IXL_DEBUG
- device_printf(dev, "%s: Admin Queue event: %#06x\n", __func__, opcode);
+ device_printf(dev, "%s: Admin Queue event: %#06x\n", __func__,
+ opcode);
#endif
switch (opcode) {
case i40e_aqc_opc_get_link_status:
@@ -4872,15 +5080,16 @@ ixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
struct ixl_pf *pf = (struct ixl_pf *)arg1;
struct i40e_hw *hw = &pf->hw;
device_t dev = pf->dev;
- int error = 0;
+ int requested_fc, error = 0;
enum i40e_status_code aq_error = 0;
u8 fc_aq_err = 0;
/* Get request */
- error = sysctl_handle_int(oidp, &pf->fc, 0, req);
+ requested_fc = pf->fc;
+ error = sysctl_handle_int(oidp, &requested_fc, 0, req);
if ((error) || (req->newptr == NULL))
return (error);
- if (pf->fc < 0 || pf->fc > 3) {
+ if (requested_fc < 0 || requested_fc > 3) {
device_printf(dev,
"Invalid fc mode; valid modes are 0 through 3\n");
return (EINVAL);
@@ -4898,7 +5107,7 @@ ixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
}
/* Set fc ability for port */
- hw->fc.requested_mode = pf->fc;
+ hw->fc.requested_mode = requested_fc;
aq_error = i40e_set_fc(hw, &fc_aq_err, TRUE);
if (aq_error) {
device_printf(dev,
@@ -4906,6 +5115,7 @@ ixl_set_flowcntl(SYSCTL_HANDLER_ARGS)
__func__, aq_error, fc_aq_err);
return (EIO);
}
+ pf->fc = requested_fc;
/* Get new link state */
i40e_msec_delay(250);
@@ -5192,6 +5402,39 @@ ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)
return 0;
}
+inline void
+ixl_print_nvm_cmd(device_t dev, struct i40e_nvm_access *nvma)
+{
+ if ((nvma->command == I40E_NVM_READ) &&
+ ((nvma->config & 0xFF) == 0xF) &&
+ (((nvma->config & 0xF00) >> 8) == 0xF) &&
+ (nvma->offset == 0) &&
+ (nvma->data_size == 1)) {
+ // device_printf(dev, "- Get Driver Status Command\n");
+ }
+ else if (nvma->command == I40E_NVM_READ) {
+
+ }
+ else {
+ switch (nvma->command) {
+ case 0xB:
+ device_printf(dev, "- command: I40E_NVM_READ\n");
+ break;
+ case 0xC:
+ device_printf(dev, "- command: I40E_NVM_WRITE\n");
+ break;
+ default:
+ device_printf(dev, "- command: unknown 0x%08x\n", nvma->command);
+ break;
+ }
+
+ device_printf(dev, "- config (ptr) : 0x%02x\n", nvma->config & 0xFF);
+ device_printf(dev, "- config (flags): 0x%01x\n", (nvma->config & 0xF00) >> 8);
+ device_printf(dev, "- offset : 0x%08x\n", nvma->offset);
+ device_printf(dev, "- data_s : 0x%08x\n", nvma->data_size);
+ }
+}
+
static int
ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd)
{
@@ -5203,17 +5446,24 @@ ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd)
DEBUGFUNC("ixl_handle_nvmupd_cmd");
+ /* Sanity checks */
if (ifd->ifd_len < sizeof(struct i40e_nvm_access) ||
ifd->ifd_data == NULL) {
- device_printf(dev, "%s: incorrect ifdrv length or data pointer\n", __func__);
- device_printf(dev, "%s: ifdrv length: %lu, sizeof(struct i40e_nvm_access): %lu\n", __func__,
- ifd->ifd_len, sizeof(struct i40e_nvm_access));
- device_printf(dev, "%s: data pointer: %p\n", __func__, ifd->ifd_data);
+ device_printf(dev, "%s: incorrect ifdrv length or data pointer\n",
+ __func__);
+ device_printf(dev, "%s: ifdrv length: %lu, sizeof(struct i40e_nvm_access): %lu\n",
+ __func__, ifd->ifd_len, sizeof(struct i40e_nvm_access));
+ device_printf(dev, "%s: data pointer: %p\n", __func__,
+ ifd->ifd_data);
return (EINVAL);
}
nvma = (struct i40e_nvm_access *)ifd->ifd_data;
+#ifdef IXL_DEBUG
+ ixl_print_nvm_cmd(dev, nvma);
+#endif
+
if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
int count = 0;
while (count++ < 100) {
@@ -5221,7 +5471,6 @@ ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd)
if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING))
break;
}
- // device_printf(dev, "ioctl EMPR reset wait count %d\n", count);
}
if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) {
@@ -7008,7 +7257,7 @@ ixl_iov_init(device_t dev, uint16_t num_vfs, const nvlist_t *params)
goto fail;
}
- ixl_configure_msix(pf);
+ // TODO: [Configure MSI-X here]
ixl_enable_adminq(hw);
pf->num_vfs = num_vfs;
diff --git a/sys/dev/ixl/ixl.h b/sys/dev/ixl/ixl.h
index 34ff880..d0bb84f 100644
--- a/sys/dev/ixl/ixl.h
+++ b/sys/dev/ixl/ixl.h
@@ -162,8 +162,10 @@
/*
* Ring Descriptors Valid Range: 32-4096 Default Value: 1024 This value is the
* number of tx/rx descriptors allocated by the driver. Increasing this
- * value allows the driver to queue more operations. Each descriptor is 16
- * or 32 bytes (configurable in FVL)
+ * value allows the driver to queue more operations.
+ *
+ * Tx descriptors are always 16 bytes, but Rx descriptors can be 32 bytes.
+ * The driver currently always uses 32 byte Rx descriptors.
*/
#define DEFAULT_RING 1024
#define PERFORM_RING 2048
@@ -215,7 +217,7 @@
#define IXL_TX_ITR 1
#define IXL_ITR_NONE 3
#define IXL_QUEUE_EOL 0x7FF
-#define IXL_MAX_FRAME 0x2600
+#define IXL_MAX_FRAME 9728
#define IXL_MAX_TX_SEGS 8
#define IXL_MAX_TSO_SEGS 66
#define IXL_SPARSE_CHAIN 6
OpenPOWER on IntegriCloud