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
This commit is contained in:
parent
1d767a8eae
commit
6c42605965
@ -5600,6 +5600,335 @@ enum i40e_status_code i40e_aq_configure_partition_bw(struct i40e_hw *hw,
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -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
|
||||
|
@ -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_hw; /* forward decl */
|
||||
u16 i40e_read_pci_cfg(struct i40e_hw *, u32);
|
||||
void i40e_write_pci_cfg(struct i40e_hw *, u32, u16);
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
struct i40e_hw; /* forward decl */
|
||||
u16 i40e_read_pci_cfg(struct i40e_hw *, u32);
|
||||
void i40e_write_pci_cfg(struct i40e_hw *, u32, u16);
|
||||
|
||||
/*
|
||||
** This hardware supports either 16 or 32 byte rx descriptors
|
||||
** we default here to the larger size.
|
||||
** 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(struct i40e_hw *hw, enum i40e_debug_mask mask,
|
||||
char *fmt_str, ...);
|
||||
|
||||
/*
|
||||
** 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
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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,
|
||||
|
@ -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 @@ ixl_get_hw_capabilities(struct ixl_pf *pf)
|
||||
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);
|
||||
}
|
||||
bus_describe_intr(dev, pf->res, pf->tag, "aq");
|
||||
pf->admvec = vector;
|
||||
++vector;
|
||||
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);
|
||||
}
|
||||
pf->admvec = 0;
|
||||
|
||||
/* Now set up the stations */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 @@ ixl_init_msix(struct ixl_pf *pf)
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user