Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 12 May 2016 18:20:36 +0000 (UTC)
From:      Eric Joyner <erj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r299549 - head/sys/dev/ixl
Message-ID:  <201605121820.u4CIKalr004710@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: erj
Date: Thu May 12 18:20:36 2016
New Revision: 299549
URL: https://svnweb.freebsd.org/changeset/base/299549

Log:
  ixl: Update to 1.4.12-k.
  
  Changes by author:
  
  Eric Joyner		ixl: Remove substitution of EACCES for EPERM when perrno is set on an nvmupdate command return.
  Eric Joyner		ixl: Print message when hardware sends GRST interrupt.
  Eric Joyner		ixl: Fix kernel panic when driver fails to initialize admin queue.
  Eric Joyner		ixl: Print out messages when a non-handled other interrupt occurs.
  Eric Joyner		ixl: Fix spaces in a couple messages.
  Eric Joyner		ixl: Add lock around nvmupd command entry point and reconvert EPERM errors to EACCES.
  Anjali Singhai Jain	i40e-shared: Make some changes in the nvm read code
  Shannon Nelson		i40e-shared: AQ Add Run PHY Activity struct
  Shannon Nelson		i40e-shared: AQ Add Geneve cloud tunnel type
  Shannon Nelson		i40e-shared: AQ Add external power class to get link status response struct
  Shannon Nelson		i40e-shared: AQ Add shared resource flags for macvlan filters
  Shannon Nelson		i40e-shared: AQ Add set_switch_config
  Shannon Nelson		i40e-shared: AQ Add VXLAN-GPE tunnel type for cloud filter and tunnel commands
  Shannon Nelson		i40e-shared: AQ thermal sensor control struct
  Shannon Nelson		i40e-shared: Bump AQ minor version to 1.5 for FVL5 features
  Shannon Nelson		i40e-shared: add a little more to an NVM update debug message
  Carolyn Wyborny		i40e-shared: Fix for PHY NVM interaction problem
  Eric Joyner		i40e-shared: Add prototypes for private NVM write functions
  Eric Joyner		ixl/ixlv: Remove unused define from ixl.h.
  Eric Joyner		ixl: Add handling of EMP reset for nvm update purposes.
  Eric Joyner		ixl: Move addition of device sysctls to separate function.
  Eric Joyner		ixl: Fix up a couple error messages in ixl_attach().
  Eric Joyner		ixl: Update the hardware resource allocation debug sysctl.
  
  Differential Revision:  https://reviews.freebsd.org/D6211
  Reviewed by:    sbruno, kmacy, jeffrey.e.pieper@intel.com
  MFC after:      2 weeks
  Sponsored by:   Intel Corporation

Modified:
  head/sys/dev/ixl/i40e_adminq_cmd.h
  head/sys/dev/ixl/i40e_common.c
  head/sys/dev/ixl/i40e_nvm.c
  head/sys/dev/ixl/i40e_prototype.h
  head/sys/dev/ixl/if_ixl.c
  head/sys/dev/ixl/ixl.h
  head/sys/dev/ixl/ixl_pf.h

Modified: head/sys/dev/ixl/i40e_adminq_cmd.h
==============================================================================
--- head/sys/dev/ixl/i40e_adminq_cmd.h	Thu May 12 18:20:18 2016	(r299548)
+++ head/sys/dev/ixl/i40e_adminq_cmd.h	Thu May 12 18:20:36 2016	(r299549)
@@ -42,7 +42,7 @@
  */
 
 #define I40E_FW_API_VERSION_MAJOR	0x0001
-#define I40E_FW_API_VERSION_MINOR	0x0004
+#define I40E_FW_API_VERSION_MINOR	0x0005
 
 struct i40e_aq_desc {
 	__le16 flags;
@@ -153,6 +153,7 @@ enum i40e_admin_queue_opc {
 	i40e_aqc_opc_remove_statistics		= 0x0202,
 	i40e_aqc_opc_set_port_parameters	= 0x0203,
 	i40e_aqc_opc_get_switch_resource_alloc	= 0x0204,
+	i40e_aqc_opc_set_switch_config		= 0x0205,
 
 	i40e_aqc_opc_add_vsi			= 0x0210,
 	i40e_aqc_opc_update_vsi_parameters	= 0x0211,
@@ -228,6 +229,7 @@ enum i40e_admin_queue_opc {
 	i40e_aqc_opc_get_phy_wol_caps		= 0x0621,
 	i40e_aqc_opc_set_phy_debug		= 0x0622,
 	i40e_aqc_opc_upload_ext_phy_fm		= 0x0625,
+	i40e_aqc_opc_run_phy_activity		= 0x0626,
 
 	/* NVM commands */
 	i40e_aqc_opc_nvm_read			= 0x0701,
@@ -236,6 +238,7 @@ enum i40e_admin_queue_opc {
 	i40e_aqc_opc_nvm_config_read		= 0x0704,
 	i40e_aqc_opc_nvm_config_write		= 0x0705,
 	i40e_aqc_opc_oem_post_update		= 0x0720,
+	i40e_aqc_opc_thermal_sensor		= 0x0721,
 
 	/* virtualization commands */
 	i40e_aqc_opc_send_msg_to_pf		= 0x0801,
@@ -686,6 +689,17 @@ struct i40e_aqc_switch_resource_alloc_el
 
 I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
 
+/* Set Switch Configuration (direct 0x0205) */
+struct i40e_aqc_set_switch_config {
+	__le16	flags;
+#define I40E_AQ_SET_SWITCH_CFG_PROMISC		0x0001
+#define I40E_AQ_SET_SWITCH_CFG_L2_FILTER	0x0002
+	__le16	valid_flags;
+	u8	reserved[12];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_switch_config);
+
 /* Add VSI (indirect 0x0210)
  *    this indirect command uses struct i40e_aqc_vsi_properties_data
  *    as the indirect buffer (128 bytes)
@@ -908,7 +922,8 @@ struct i40e_aqc_add_veb {
 					I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT)
 #define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT	0x2
 #define I40E_AQC_ADD_VEB_PORT_TYPE_DATA		0x4
-#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER	0x8
+#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER	0x8     /* deprecated */
+#define I40E_AQC_ADD_VEB_ENABLE_DISABLE_STATS	0x10
 	u8	enable_tcs;
 	u8	reserved[9];
 };
@@ -975,6 +990,7 @@ struct i40e_aqc_add_macvlan_element_data
 #define I40E_AQC_MACVLAN_ADD_HASH_MATCH		0x0002
 #define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN	0x0004
 #define I40E_AQC_MACVLAN_ADD_TO_QUEUE		0x0008
+#define I40E_AQC_MACVLAN_ADD_USE_SHARED_MAC	0x0010
 	__le16	queue_number;
 #define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT	0
 #define I40E_AQC_MACVLAN_CMD_QUEUE_MASK		(0x7FF << \
@@ -1259,10 +1275,16 @@ struct i40e_aqc_add_remove_cloud_filters
 
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT		9
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK		0x1E00
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_XVLAN		0
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN		0
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC		1
-#define I40E_AQC_ADD_CLOUD_TNL_TYPE_NGE			2
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE		2
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP			3
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_RESERVED		4
+#define I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN_GPE		5
+
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_MAC	0x2000
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_INNER_MAC	0x4000
+#define I40E_AQC_ADD_CLOUD_FLAGS_SHARED_OUTER_IP	0x8000
 
 	__le32	tenant_id;
 	u8	reserved[4];
@@ -1756,7 +1778,12 @@ struct i40e_aqc_get_link_status {
 	u8	config;
 #define I40E_AQ_CONFIG_CRC_ENA		0x04
 #define I40E_AQ_CONFIG_PACING_MASK	0x78
-	u8	reserved[5];
+	u8	external_power_ability;
+#define I40E_AQ_LINK_POWER_CLASS_1	0x00
+#define I40E_AQ_LINK_POWER_CLASS_2	0x01
+#define I40E_AQ_LINK_POWER_CLASS_3	0x02
+#define I40E_AQ_LINK_POWER_CLASS_4	0x03
+	u8	reserved[4];
 };
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status);
@@ -1824,6 +1851,18 @@ enum i40e_aq_phy_reg_type {
 	I40E_AQC_PHY_REG_EXERNAL_MODULE	= 0x3
 };
 
+/* Run PHY Activity (0x0626) */
+struct i40e_aqc_run_phy_activity {
+	__le16  activity_id;
+	u8      flags;
+	u8      reserved1;
+	__le32  control;
+	__le32  data;
+	u8      reserved2[4];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_run_phy_activity);
+
 /* NVM Read command (indirect 0x0701)
  * NVM Erase commands (direct 0x0702)
  * NVM Update commands (indirect 0x0703)
@@ -1912,6 +1951,22 @@ struct i40e_aqc_nvm_oem_post_update_buff
 
 I40E_CHECK_STRUCT_LEN(0x28, i40e_aqc_nvm_oem_post_update_buffer);
 
+/* Thermal Sensor (indirect 0x0721)
+ *     read or set thermal sensor configs and values
+ *     takes a sensor and command specific data buffer, not detailed here
+ */
+struct i40e_aqc_thermal_sensor {
+	u8 sensor_action;
+#define I40E_AQ_THERMAL_SENSOR_READ_CONFIG	0
+#define I40E_AQ_THERMAL_SENSOR_SET_CONFIG	1
+#define I40E_AQ_THERMAL_SENSOR_READ_TEMP	2
+	u8 reserved[7];
+	__le32	addr_high;
+	__le32	addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_thermal_sensor);
+
 /* Send to PF command (indirect 0x0801) id is only used by PF
  * Send to VF command (indirect 0x0802) id is only used by PF
  * Send to Peer PF command (indirect 0x0803)
@@ -2184,6 +2239,7 @@ struct i40e_aqc_add_udp_tunnel {
 #define I40E_AQC_TUNNEL_TYPE_VXLAN	0x00
 #define I40E_AQC_TUNNEL_TYPE_NGE	0x01
 #define I40E_AQC_TUNNEL_TYPE_TEREDO	0x10
+#define I40E_AQC_TUNNEL_TYPE_VXLAN_GPE	0x11
 	u8	reserved1[10];
 };
 

Modified: head/sys/dev/ixl/i40e_common.c
==============================================================================
--- head/sys/dev/ixl/i40e_common.c	Thu May 12 18:20:18 2016	(r299548)
+++ head/sys/dev/ixl/i40e_common.c	Thu May 12 18:20:36 2016	(r299549)
@@ -2393,14 +2393,15 @@ enum i40e_status_code i40e_update_link_i
 	if (status)
 		return status;
 
-	status = i40e_aq_get_phy_capabilities(hw, FALSE, false, &abilities,
-					      NULL);
-	if (status)
-		return status;
-
-	memcpy(hw->phy.link_info.module_type, &abilities.module_type,
-		sizeof(hw->phy.link_info.module_type));
+	if (hw->phy.link_info.link_info & I40E_AQ_MEDIA_AVAILABLE) {
+		status = i40e_aq_get_phy_capabilities(hw, FALSE, false,
+						      &abilities, NULL);
+		if (status)
+			return status;
 
+		memcpy(hw->phy.link_info.module_type, &abilities.module_type,
+			sizeof(hw->phy.link_info.module_type));
+	}
 	return status;
 }
 

Modified: head/sys/dev/ixl/i40e_nvm.c
==============================================================================
--- head/sys/dev/ixl/i40e_nvm.c	Thu May 12 18:20:18 2016	(r299548)
+++ head/sys/dev/ixl/i40e_nvm.c	Thu May 12 18:20:36 2016	(r299549)
@@ -208,7 +208,7 @@ static enum i40e_status_code i40e_poll_s
 }
 
 /**
- * i40e_read_nvm_word - Reads Shadow RAM
+ * i40e_read_nvm_word - Reads nvm word and acquire lock if necessary
  * @hw: pointer to the HW structure
  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
  * @data: word read from the Shadow RAM
@@ -225,6 +225,24 @@ enum i40e_status_code i40e_read_nvm_word
 }
 
 /**
+ * __i40e_read_nvm_word - Reads nvm word, assumes caller does the locking
+ * @hw: pointer to the HW structure
+ * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
+ * @data: word read from the Shadow RAM
+ *
+ * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
+ **/
+enum i40e_status_code __i40e_read_nvm_word(struct i40e_hw *hw,
+					   u16 offset,
+					   u16 *data)
+{
+	enum i40e_status_code ret_code = I40E_SUCCESS;
+
+	ret_code = i40e_read_nvm_word_srctl(hw, offset, data);
+	return ret_code;
+}
+
+/**
  * i40e_read_nvm_word_srctl - Reads Shadow RAM via SRCTL register
  * @hw: pointer to the HW structure
  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
@@ -296,7 +314,28 @@ enum i40e_status_code i40e_read_nvm_word
 }
 
 /**
- * i40e_read_nvm_buffer - Reads Shadow RAM buffer
+ * __i40e_read_nvm_buffer - Reads nvm buffer, caller must acquire lock
+ * @hw: pointer to the HW structure
+ * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
+ * @words: (in) number of words to read; (out) number of words actually read
+ * @data: words read from the Shadow RAM
+ *
+ * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
+ * method. The buffer read is preceded by the NVM ownership take
+ * and followed by the release.
+ **/
+enum i40e_status_code __i40e_read_nvm_buffer(struct i40e_hw *hw,
+					     u16 offset,
+					     u16 *words, u16 *data)
+{
+	enum i40e_status_code ret_code = I40E_SUCCESS;
+
+	ret_code = i40e_read_nvm_buffer_srctl(hw, offset, words, data);
+	return ret_code;
+}
+
+/**
+ * i40e_read_nvm_buffer - Reads Shadow RAM buffer and acuire lock if necessary
  * @hw: pointer to the HW structure
  * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
  * @words: (in) number of words to read; (out) number of words actually read
@@ -506,7 +545,7 @@ enum i40e_status_code i40e_write_nvm_aq(
 }
 
 /**
- * i40e_write_nvm_word - Writes Shadow RAM word
+ * __i40e_write_nvm_word - Writes Shadow RAM word
  * @hw: pointer to the HW structure
  * @offset: offset of the Shadow RAM word to write
  * @data: word to write to the Shadow RAM
@@ -516,8 +555,8 @@ enum i40e_status_code i40e_write_nvm_aq(
  * reception) by caller. To commit SR to NVM update checksum function
  * should be called.
  **/
-enum i40e_status_code i40e_write_nvm_word(struct i40e_hw *hw, u32 offset,
-					  void *data)
+enum i40e_status_code __i40e_write_nvm_word(struct i40e_hw *hw, u32 offset,
+					    void *data)
 {
 	DEBUGFUNC("i40e_write_nvm_word");
 
@@ -528,7 +567,7 @@ enum i40e_status_code i40e_write_nvm_wor
 }
 
 /**
- * i40e_write_nvm_buffer - Writes Shadow RAM buffer
+ * __i40e_write_nvm_buffer - Writes Shadow RAM buffer
  * @hw: pointer to the HW structure
  * @module_pointer: module pointer location in words from the NVM beginning
  * @offset: offset of the Shadow RAM buffer to write
@@ -540,9 +579,9 @@ enum i40e_status_code i40e_write_nvm_wor
  * on ARQ completion event reception by caller. To commit SR to NVM update
  * checksum function should be called.
  **/
-enum i40e_status_code i40e_write_nvm_buffer(struct i40e_hw *hw,
-					    u8 module_pointer, u32 offset,
-					    u16 words, void *data)
+enum i40e_status_code __i40e_write_nvm_buffer(struct i40e_hw *hw,
+					      u8 module_pointer, u32 offset,
+					      u16 words, void *data)
 {
 	__le16 *le_word_ptr = (__le16 *)data;
 	u16 *word_ptr = (u16 *)data;
@@ -589,15 +628,17 @@ enum i40e_status_code i40e_calc_nvm_chec
 	data = (u16 *)vmem.va;
 
 	/* read pointer to VPD area */
-	ret_code = i40e_read_nvm_word(hw, I40E_SR_VPD_PTR, &vpd_module);
+	ret_code = __i40e_read_nvm_word(hw, I40E_SR_VPD_PTR,
+					&vpd_module);
 	if (ret_code != I40E_SUCCESS) {
 		ret_code = I40E_ERR_NVM_CHECKSUM;
 		goto i40e_calc_nvm_checksum_exit;
 	}
 
 	/* read pointer to PCIe Alt Auto-load module */
-	ret_code = i40e_read_nvm_word(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
-				      &pcie_alt_module);
+	ret_code = __i40e_read_nvm_word(hw,
+					I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
+					&pcie_alt_module);
 	if (ret_code != I40E_SUCCESS) {
 		ret_code = I40E_ERR_NVM_CHECKSUM;
 		goto i40e_calc_nvm_checksum_exit;
@@ -611,7 +652,7 @@ enum i40e_status_code i40e_calc_nvm_chec
 		if ((i % I40E_SR_SECTOR_SIZE_IN_WORDS) == 0) {
 			u16 words = I40E_SR_SECTOR_SIZE_IN_WORDS;
 
-			ret_code = i40e_read_nvm_buffer(hw, i, &words, data);
+			ret_code = __i40e_read_nvm_buffer(hw, i, &words, data);
 			if (ret_code != I40E_SUCCESS) {
 				ret_code = I40E_ERR_NVM_CHECKSUM;
 				goto i40e_calc_nvm_checksum_exit;
@@ -686,13 +727,18 @@ enum i40e_status_code i40e_validate_nvm_
 
 	DEBUGFUNC("i40e_validate_nvm_checksum");
 
-	ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
-	if (ret_code != I40E_SUCCESS)
+	if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
+		ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+	if (!ret_code) {
+		ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
+		if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE)
+			i40e_release_nvm(hw);
+		if (ret_code != I40E_SUCCESS)
+			goto i40e_validate_nvm_checksum_exit;
+	} else {
 		goto i40e_validate_nvm_checksum_exit;
+	}
 
-	/* Do not use i40e_read_nvm_word() because we do not want to take
-	 * the synchronization semaphores twice here.
-	 */
 	i40e_read_nvm_word(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
 
 	/* Verify read checksum from EEPROM is the same as
@@ -788,10 +834,11 @@ enum i40e_status_code i40e_nvmupd_comman
 	/* early check for status command and debug msgs */
 	upd_cmd = i40e_nvmupd_validate_command(hw, cmd, perrno);
 
-	i40e_debug(hw, I40E_DEBUG_NVM, "%s state %d nvm_release_on_hold %d\n",
+	i40e_debug(hw, I40E_DEBUG_NVM, "%s state %d nvm_release_on_hold %d cmd 0x%08x config 0x%08x offset 0x%08x data_size 0x%08x\n",
 		   i40e_nvm_update_state_str[upd_cmd],
 		   hw->nvmupd_state,
-		   hw->aq.nvm_release_on_done);
+		   hw->aq.nvm_release_on_done,
+		   cmd->command, cmd->config, cmd->offset, cmd->data_size);
 
 	if (upd_cmd == I40E_NVMUPD_INVALID) {
 		*perrno = -EFAULT;
@@ -1059,6 +1106,7 @@ retry:
 		break;
 
 	case I40E_NVMUPD_CSUM_CON:
+		/* Assumes the caller has acquired the nvm */
 		status = i40e_update_nvm_checksum(hw);
 		if (status) {
 			*perrno = hw->aq.asq_last_status ?
@@ -1072,6 +1120,7 @@ retry:
 		break;
 
 	case I40E_NVMUPD_CSUM_LCB:
+		/* Assumes the caller has acquired the nvm */
 		status = i40e_update_nvm_checksum(hw);
 		if (status) {
 			*perrno = hw->aq.asq_last_status ?

Modified: head/sys/dev/ixl/i40e_prototype.h
==============================================================================
--- head/sys/dev/ixl/i40e_prototype.h	Thu May 12 18:20:18 2016	(r299548)
+++ head/sys/dev/ixl/i40e_prototype.h	Thu May 12 18:20:36 2016	(r299549)
@@ -413,9 +413,13 @@ enum i40e_status_code i40e_read_nvm_buff
 enum i40e_status_code i40e_write_nvm_aq(struct i40e_hw *hw, u8 module,
 					u32 offset, u16 words, void *data,
 					bool last_command);
-enum i40e_status_code i40e_write_nvm_word(struct i40e_hw *hw, u32 offset,
+enum i40e_status_code __i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
+					   u16 *data);
+enum i40e_status_code __i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
+					     u16 *words, u16 *data);
+enum i40e_status_code __i40e_write_nvm_word(struct i40e_hw *hw, u32 offset,
 					  void *data);
-enum i40e_status_code i40e_write_nvm_buffer(struct i40e_hw *hw, u8 module,
+enum i40e_status_code __i40e_write_nvm_buffer(struct i40e_hw *hw, u8 module,
 					    u32 offset, u16 words, void *data);
 enum i40e_status_code i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum);
 enum i40e_status_code i40e_update_nvm_checksum(struct i40e_hw *hw);

Modified: head/sys/dev/ixl/if_ixl.c
==============================================================================
--- head/sys/dev/ixl/if_ixl.c	Thu May 12 18:20:18 2016	(r299548)
+++ head/sys/dev/ixl/if_ixl.c	Thu May 12 18:20:36 2016	(r299549)
@@ -48,7 +48,7 @@
 /*********************************************************************
  *  Driver version
  *********************************************************************/
-char ixl_driver_version[] = "1.4.9-k";
+char ixl_driver_version[] = "1.4.12-k";
 
 /*********************************************************************
  *  PCI Device ID Table
@@ -154,11 +154,25 @@ static struct ixl_mac_filter *
 static void	ixl_add_mc_filter(struct ixl_vsi *, u8 *);
 static void	ixl_free_mac_filters(struct ixl_vsi *vsi);
 
+/* Sysctls*/
+static void	ixl_add_device_sysctls(struct ixl_pf *);
 
-/* Sysctl debug interface */
 static int	ixl_debug_info(SYSCTL_HANDLER_ARGS);
 static void	ixl_print_debug_info(struct ixl_pf *);
 
+static int	ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
+static int	ixl_set_advertise(SYSCTL_HANDLER_ARGS);
+static int	ixl_current_speed(SYSCTL_HANDLER_ARGS);
+static int	ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS);
+
+#ifdef IXL_DEBUG_SYSCTL
+static int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
+static int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
+static int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
+static int	ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS);
+static int	ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS);
+#endif
+
 /* The MSI/X Interrupt handlers */
 static void	ixl_intr(void *);
 static void	ixl_msix_que(void *);
@@ -168,12 +182,6 @@ static void	ixl_handle_mdd_event(struct 
 /* Deferred interrupt tasklets */
 static void	ixl_do_adminq(void *, int);
 
-/* Sysctl handlers */
-static int	ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
-static int	ixl_set_advertise(SYSCTL_HANDLER_ARGS);
-static int	ixl_current_speed(SYSCTL_HANDLER_ARGS);
-static int	ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS);
-
 /* Statistics */
 static void     ixl_add_hw_stats(struct ixl_pf *);
 static void	ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *,
@@ -193,14 +201,6 @@ static void	ixl_stat_update32(struct i40
 /* NVM update */
 static int	ixl_handle_nvmupd_cmd(struct ixl_pf *, struct ifdrv *);
 
-#ifdef IXL_DEBUG_SYSCTL
-static int 	ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
-static int	ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
-static int	ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
-static int	ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS);
-static int	ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS);
-#endif
-
 
 #ifdef PCI_IOV
 static int	ixl_adminq_err_to_errno(enum i40e_admin_queue_err err);
@@ -440,90 +440,6 @@ ixl_attach(device_t dev)
 	/* Set up the timer callout */
 	callout_init_mtx(&pf->timer, &pf->pf_mtx, 0);
 
-	/* Set up sysctls */
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
-	    pf, 0, ixl_set_flowcntl, "I", "Flow Control");
-
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
-	    pf, 0, ixl_set_advertise, "I", "Advertised Speed");
-
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
-	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
-
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD,
-	    pf, 0, ixl_sysctl_show_fw, "A", "Firmware version");
-
-	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "rx_itr", CTLFLAG_RW,
-	    &ixl_rx_itr, IXL_ITR_8K, "RX ITR");
-
-	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW,
-	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
-
-	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "tx_itr", CTLFLAG_RW,
-	    &ixl_tx_itr, IXL_ITR_4K, "TX ITR");
-
-	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW,
-	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
-
-#ifdef IXL_DEBUG_SYSCTL
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
-	    ixl_debug_info, "I", "Debug Information");
-
-	/* Debug shared-code message level */
-	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "debug_mask", CTLFLAG_RW,
-	    &pf->hw.debug_mask, 0, "Debug Message Level");
-
-	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl,
-	    0, "PF/VF Virtual Channel debug level");
-
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
-	    pf, 0, ixl_sysctl_link_status, "A", "Current Link Status");
-
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
-	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
-
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
-	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
-
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD,
-	    pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
-
-	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
-	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
-	    OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD,
-	    pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
-#endif
-
 	/* Save off the PCI information */
 	hw->vendor_id = pci_get_vendor(dev);
 	hw->device_id = pci_get_device(dev);
@@ -549,7 +465,7 @@ ixl_attach(device_t dev)
 	i40e_clear_hw(hw);
 	error = i40e_pf_reset(hw);
 	if (error) {
-		device_printf(dev, "PF reset failure %x\n", error);
+		device_printf(dev, "PF reset failure %d\n", error);
 		error = EIO;
 		goto err_out;
 	}
@@ -560,24 +476,35 @@ ixl_attach(device_t dev)
 	hw->aq.arq_buf_size = IXL_AQ_BUFSZ;
 	hw->aq.asq_buf_size = IXL_AQ_BUFSZ;
 
+	/* Initialize mac filter list for VSI */
+	SLIST_INIT(&vsi->ftl);
+
 	/* Initialize the shared code */
 	error = i40e_init_shared_code(hw);
 	if (error) {
-		device_printf(dev, "Unable to initialize the shared code\n");
+		device_printf(dev, "Unable to initialize shared code, error %d\n",
+		    error);
 		error = EIO;
 		goto err_out;
 	}
 
 	/* Set up the admin queue */
 	error = i40e_init_adminq(hw);
-	if (error) {
+	if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) {
+		device_printf(dev, "Unable to initialize Admin Queue, error %d\n",
+		    error);
+		error = EIO;
+		goto err_out;
+	}
+	device_printf(dev, "%s\n", ixl_fw_version_str(hw));
+	if (error == I40E_ERR_FIRMWARE_API_VERSION) {
 		device_printf(dev, "The driver for the device stopped "
 		    "because the NVM image is newer than expected.\n"
 		    "You must install the most recent version of "
-		    " the network driver.\n");
+		    "the network driver.\n");
+		error = EIO;
 		goto err_out;
 	}
-	device_printf(dev, "%s\n", ixl_fw_version_str(hw));
 
         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
 	    hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
@@ -633,9 +560,6 @@ ixl_attach(device_t dev)
 		goto err_mac_hmc;
 	}
 
-	/* Initialize mac filter list for VSI */
-	SLIST_INIT(&vsi->ftl);
-
 	if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
 	    (hw->aq.fw_maj_ver < 4)) {
 		i40e_msec_delay(75);
@@ -680,7 +604,9 @@ ixl_attach(device_t dev)
 	/* Initialize taskqueues */
 	ixl_init_taskqueues(pf);
 
-	/* Initialize statistics */
+	/* Initialize statistics & add sysctls */
+	ixl_add_device_sysctls(pf);
+
 	ixl_pf_reset_stats(pf);
 	ixl_update_stats_counters(pf);
 	ixl_add_hw_stats(pf);
@@ -1558,7 +1484,8 @@ ixl_msix_adminq(void *arg)
 {
 	struct ixl_pf	*pf = arg;
 	struct i40e_hw	*hw = &pf->hw;
-	u32		reg, mask;
+	u32		reg, mask, rstat_reg;
+	bool		do_task = FALSE;
 
 	++pf->admin_irq;
 
@@ -1566,12 +1493,52 @@ ixl_msix_adminq(void *arg)
 	mask = rd32(hw, I40E_PFINT_ICR0_ENA);
 
 	/* Check on the cause */
-	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK)
-		mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
+	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK) {
+		mask &= ~I40E_PFINT_ICR0_ADMINQ_MASK;
+		do_task = TRUE;
+	}
 
 	if (reg & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
 		ixl_handle_mdd_event(pf);
-		mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
+		mask &= ~I40E_PFINT_ICR0_MAL_DETECT_MASK;
+	}
+
+	if (reg & I40E_PFINT_ICR0_GRST_MASK) {
+		device_printf(pf->dev, "Reset Requested!\n");
+		rstat_reg = rd32(hw, I40E_GLGEN_RSTAT);
+		rstat_reg = (rstat_reg & I40E_GLGEN_RSTAT_RESET_TYPE_MASK)
+		    >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT;
+		device_printf(pf->dev, "Reset type: ");
+		switch (rstat_reg) {
+		/* These others might be handled similarly to an EMPR reset */
+		case I40E_RESET_CORER:
+			printf("CORER\n");
+			break;
+		case I40E_RESET_GLOBR:
+			printf("GLOBR\n");
+			break;
+		case I40E_RESET_EMPR:
+			printf("EMPR\n");
+			atomic_set_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING);
+			break;
+		default:
+			printf("?\n");
+			break;
+		}
+		// overload admin queue task to check reset progress?
+		do_task = TRUE;
+	}
+
+	if (reg & I40E_PFINT_ICR0_ECC_ERR_MASK) {
+		device_printf(pf->dev, "ECC Error detected!\n");
+	}
+
+	if (reg & I40E_PFINT_ICR0_HMC_ERR_MASK) {
+		device_printf(pf->dev, "HMC Error detected!\n");
+	}
+
+	if (reg & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) {
+		device_printf(pf->dev, "PCI Exception detected!\n");
 	}
 
 #ifdef PCI_IOV
@@ -1585,8 +1552,8 @@ ixl_msix_adminq(void *arg)
 	reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
 	wr32(hw, I40E_PFINT_DYN_CTL0, reg);
 
-	taskqueue_enqueue(pf->tq, &pf->adminq);
-	return;
+	if (do_task)
+		taskqueue_enqueue(pf->tq, &pf->adminq);
 }
 
 /*********************************************************************
@@ -2330,7 +2297,7 @@ ixl_init_msix(struct ixl_pf *pf)
        	if (!pf->msix_mem) {
 		/* May not be enabled */
 		device_printf(pf->dev,
-		    "Unable to map MSIX table \n");
+		    "Unable to map MSIX table\n");
 		goto msi;
 	}
 
@@ -2435,7 +2402,7 @@ ixl_configure_msix(struct ixl_pf *pf)
 
 	reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
 	    I40E_PFINT_ICR0_ENA_GRST_MASK |
-	    I40E_PFINT_ICR0_HMC_ERR_MASK |
+	    I40E_PFINT_ICR0_ENA_HMC_ERR_MASK |
 	    I40E_PFINT_ICR0_ENA_ADMINQ_MASK |
 	    I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
 	    I40E_PFINT_ICR0_ENA_VFLR_MASK |
@@ -2583,7 +2550,7 @@ ixl_allocate_pci_resources(struct ixl_pf
 	    &rid, RF_ACTIVE);
 
 	if (!(pf->pci_mem)) {
-		device_printf(dev,"Unable to allocate bus resource: memory\n");
+		device_printf(dev, "Unable to allocate bus resource: memory\n");
 		return (ENXIO);
 	}
 
@@ -3128,6 +3095,9 @@ ixl_free_vsi(struct ixl_vsi *vsi)
 	struct ixl_queue	*que = vsi->queues;
 
 	/* Free station queues */
+	if (!vsi->queues)
+		goto free_filters;
+
 	for (int i = 0; i < vsi->num_queues; i++, que++) {
 		struct tx_ring *txr = &que->txr;
 		struct rx_ring *rxr = &que->rxr;
@@ -3153,6 +3123,7 @@ ixl_free_vsi(struct ixl_vsi *vsi)
 	}
 	free(vsi->queues, M_DEVBUF);
 
+free_filters:
 	/* Free VSI filter list */
 	ixl_free_mac_filters(vsi);
 }
@@ -4538,9 +4509,34 @@ ixl_do_adminq(void *context, int pending
 	struct i40e_arq_event_info	event;
 	i40e_status			ret;
 	device_t			dev = pf->dev;
-	u32				loop = 0;
+	u32				reg, 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);
+		return;
+	}
+
+	// Actually do Admin Queue handling
 	event.buf_len = IXL_AQ_BUF_SZ;
 	event.msg_buf = malloc(event.buf_len,
 	    M_DEVBUF, M_NOWAIT | M_ZERO);
@@ -4830,6 +4826,96 @@ ixl_stat_update32(struct i40e_hw *hw, u3
 		*stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
 }
 
+static void
+ixl_add_device_sysctls(struct ixl_pf *pf)
+{
+	device_t dev = pf->dev;
+
+	/* Set up sysctls */
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW,
+	    pf, 0, ixl_set_flowcntl, "I", "Flow Control");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW,
+	    pf, 0, ixl_set_advertise, "I", "Advertised Speed");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
+	    pf, 0, ixl_current_speed, "A", "Current Port Speed");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD,
+	    pf, 0, ixl_sysctl_show_fw, "A", "Firmware version");
+
+	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "rx_itr", CTLFLAG_RW,
+	    &ixl_rx_itr, IXL_ITR_8K, "RX ITR");
+
+	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW,
+	    &ixl_dynamic_rx_itr, 0, "Dynamic RX ITR");
+
+	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "tx_itr", CTLFLAG_RW,
+	    &ixl_tx_itr, IXL_ITR_4K, "TX ITR");
+
+	SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW,
+	    &ixl_dynamic_tx_itr, 0, "Dynamic TX ITR");
+
+#ifdef IXL_DEBUG_SYSCTL
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "debug", CTLTYPE_INT|CTLFLAG_RW, pf, 0,
+	    ixl_debug_info, "I", "Debug Information");
+
+	/* Debug shared-code message level */
+	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "debug_mask", CTLFLAG_RW,
+	    &pf->hw.debug_mask, 0, "Debug Message Level");
+
+	SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl,
+	    0, "PF/VF Virtual Channel debug level");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "link_status", CTLTYPE_STRING | CTLFLAG_RD,
+	    pf, 0, ixl_sysctl_link_status, "A", "Current Link Status");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "phy_abilities", CTLTYPE_STRING | CTLFLAG_RD,
+	    pf, 0, ixl_sysctl_phy_abilities, "A", "PHY Abilities");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "filter_list", CTLTYPE_STRING | CTLFLAG_RD,
+	    pf, 0, ixl_sysctl_sw_filter_list, "A", "SW Filter List");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD,
+	    pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
+
+	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
+	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
+	    OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD,
+	    pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
+#endif
+}
+
 /*
 ** Set flow control using sysctl:
 ** 	0 - off
@@ -5185,12 +5271,32 @@ ixl_handle_nvmupd_cmd(struct ixl_pf *pf,
 
 	nvma = (struct i40e_nvm_access *)ifd->ifd_data;
 
-	status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno);
+	if (pf->state & IXL_PF_STATE_EMPR_RESETTING) {
+		int count = 0;
+		while (count++ < 100) {
+			i40e_msec_delay(100);
+			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)) {
+		IXL_PF_LOCK(pf);
+		status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno);
+		IXL_PF_UNLOCK(pf);
+	} else {
+		perrno = -EBUSY;
+	}
+
 	if (status)
 		device_printf(dev, "i40e_nvmupd_command status %d, perrno %d\n",
 		    status, perrno);
 
-	/* Convert EPERM error code for tools */
+	/*
+	 * -EPERM is actually ERESTART, which the kernel interprets as it needing
+	 * to run this ioctl again. So use -EACCES for -EPERM instead.
+	 */
 	if (perrno == -EPERM)
 		return (-EACCES);
 	else
@@ -5315,6 +5421,41 @@ ixl_res_alloc_cmp(const void *a, const v
 	return ((int)one->resource_type - (int)two->resource_type);
 }
 
+/*
+ * Longest string length: 25 
+ */
+static char *
+ixl_switch_res_type_string(u8 type)
+{
+	static char * ixl_switch_res_type_strings[0x14] = {
+		"VEB",
+		"VSI",
+		"Perfect Match MAC address",
+		"S-tag",
+		"(Reserved)",
+		"Multicast hash entry",
+		"Unicast hash entry",
+		"VLAN",
+		"VSI List entry",
+		"(Reserved)",
+		"VLAN Statistic Pool",
+		"Mirror Rule",
+		"Queue Set",
+		"Inner VLAN Forward filter",
+		"(Reserved)",
+		"Inner MAC",
+		"IP",
+		"GRE/VN1 Key",
+		"VN2 Key",
+		"Tunneling Port"
+	};
+
+	if (type < 0x14)
+		return ixl_switch_res_type_strings[type];
+	else
+		return "(Reserved)";
+}
+
 static int
 ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)
 {
@@ -5354,12 +5495,20 @@ ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_A
 	sbuf_cat(buf, "\n");
 	sbuf_printf(buf, "# of entries: %d\n", num_entries);
 	sbuf_printf(buf,
+#if 0
 	    "Type | Guaranteed | Total | Used   | Un-allocated\n"
 	    "     | (this)     | (all) | (this) | (all)       \n");
+#endif
+	    "                     Type | Guaranteed | Total | Used   | Un-allocated\n"
+	    "                          | (this)     | (all) | (this) | (all)       \n");
 	for (int i = 0; i < num_entries; i++) {
 		sbuf_printf(buf,
+#if 0
 		    "%#4x | %10d   %5d   %6d   %12d",
 		    resp[i].resource_type,
+#endif
+		    "%25s | %10d   %5d   %6d   %12d",
+		    ixl_switch_res_type_string(resp[i].resource_type),
 		    resp[i].guaranteed,
 		    resp[i].total,
 		    resp[i].used,
@@ -5379,36 +5528,48 @@ ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_A
 /*
 ** Caller must init and delete sbuf; this function will clear and
 ** finish it for caller.
+**
+** XXX: Cannot use the SEID for this, since there is no longer a 
+** fixed mapping between SEID and element type.
 */
 static char *
-ixl_switch_element_string(struct sbuf *s, u16 seid, bool uplink)
+ixl_switch_element_string(struct sbuf *s,
+    struct i40e_aqc_switch_config_element_resp *element)
 {
 	sbuf_clear(s);
 
-	if (seid == 0 && uplink)
-		sbuf_cat(s, "Network");
-	else if (seid == 0)
-		sbuf_cat(s, "Host");
-	else if (seid == 1)
+	switch (element->element_type) {
+	case I40E_AQ_SW_ELEM_TYPE_MAC:
+		sbuf_printf(s, "MAC %3d", element->element_info);
+		break;
+	case I40E_AQ_SW_ELEM_TYPE_PF:
+		sbuf_printf(s, "PF  %3d", element->element_info);
+		break;
+	case I40E_AQ_SW_ELEM_TYPE_VF:
+		sbuf_printf(s, "VF  %3d", element->element_info);
+		break;
+	case I40E_AQ_SW_ELEM_TYPE_EMP:

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201605121820.u4CIKalr004710>