diff options
author | erj <erj@FreeBSD.org> | 2016-05-12 18:21:34 +0000 |
---|---|---|
committer | erj <erj@FreeBSD.org> | 2016-05-12 18:21:34 +0000 |
commit | e70f15d7421e2ab4b03d94dc569d755c262cafb2 (patch) | |
tree | dbb3ff49cdf6a72ef2688ace247a011b80189024 /sys/dev/ixl | |
parent | b1978246c9e36ad26b0efba579c718c1cb0edf00 (diff) | |
download | FreeBSD-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.c | 329 | ||||
-rw-r--r-- | sys/dev/ixl/i40e_osdep.c | 19 | ||||
-rw-r--r-- | sys/dev/ixl/i40e_osdep.h | 23 | ||||
-rw-r--r-- | sys/dev/ixl/i40e_prototype.h | 13 | ||||
-rw-r--r-- | sys/dev/ixl/i40e_type.h | 16 | ||||
-rw-r--r-- | sys/dev/ixl/if_ixl.c | 543 | ||||
-rw-r--r-- | sys/dev/ixl/ixl.h | 8 |
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, ®_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 |