All of lore.kernel.org
 help / color / mirror / Atom feed
* [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior
@ 2017-08-04 13:52 Alice Michael
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 02/12] i40e: Fix reporting of supported link modes Alice Michael
                   ` (12 more replies)
  0 siblings, 13 replies; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Mariusz Stachura <mariusz.stachura@intel.com>

Instead of accessing register directly, use newly added AQC in
order to blink LEDs. Introduce and utilize a new flag to prevent
excessive API version checking.

Signed-off-by: Mariusz Stachura <mariusz.stachura@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e_adminq.c |   6 ++
 drivers/net/ethernet/intel/i40e/i40e_common.c | 148 ++++++++++++++++++++------
 drivers/net/ethernet/intel/i40e/i40e_type.h   |   1 +
 drivers/net/ethernet/intel/i40evf/i40e_type.h |   2 +
 4 files changed, 122 insertions(+), 35 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
index ba04988..340e5a2 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
@@ -607,6 +607,12 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw)
 			   &oem_lo);
 	hw->nvm.oem_ver = ((u32)oem_hi << 16) | oem_lo;
 
+	if (hw->mac.type ==  I40E_MAC_XL710 &&
+	    hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
+	    hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) {
+		hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE;
+	}
+
 	if (hw->aq.api_maj_ver > I40E_FW_API_VERSION_MAJOR) {
 		ret_code = I40E_ERR_FIRMWARE_API_VERSION;
 		goto init_adminq_free_arq;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index e4e86e0..e9f30b8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -4849,24 +4849,38 @@ i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
 	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_clause45(hw,
+	u32 reg_val_aq;
+
+	if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
+		status =
+		      i40e_aq_get_phy_register(hw,
+					       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
+					       I40E_PHY_COM_REG_PAGE,
+					       I40E_PHY_LED_PROV_REG_1,
+					       &reg_val_aq, NULL);
+		if (status)
+			return status;
+		*val = (u16)reg_val_aq;
+	} else {
+		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_clause45(hw,
 							 I40E_PHY_COM_REG_PAGE,
 							 temp_addr, phy_addr,
 							 &reg_val);
-		if (status)
-			return status;
-		*val = reg_val;
-		if (reg_val & I40E_PHY_LED_LINK_MODE_MASK) {
-			*led_addr = temp_addr;
-			break;
+			if (status)
+				return status;
+			*val = reg_val;
+			if (reg_val & I40E_PHY_LED_LINK_MODE_MASK) {
+				*led_addr = temp_addr;
+				break;
+			}
 		}
 	}
 	return status;
@@ -4884,51 +4898,115 @@ i40e_status i40e_led_set_phy(struct i40e_hw *hw, bool on,
 			     u16 led_addr, u32 mode)
 {
 	i40e_status status = 0;
-	u16 led_ctl = 0;
-	u16 led_reg = 0;
+	u32 led_ctl = 0;
+	u32 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_clause45(hw, I40E_PHY_COM_REG_PAGE,
-						 led_addr, phy_addr, &led_reg);
+	if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
+		status =
+		      i40e_aq_get_phy_register(hw,
+					       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
+					       I40E_PHY_COM_REG_PAGE,
+					       I40E_PHY_LED_PROV_REG_1,
+					       &led_reg, NULL);
+	} else {
+		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_clause45(hw,
+							 I40E_PHY_COM_REG_PAGE,
+							 led_addr, phy_addr,
+							 (u16 *)&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_clause45(hw,
-							  I40E_PHY_COM_REG_PAGE,
-							  led_addr, phy_addr,
-							  led_reg);
+		if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
+		    hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) {
+			status = i40e_aq_set_phy_register(hw,
+					I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
+					I40E_PHY_COM_REG_PAGE,
+					I40E_PHY_LED_PROV_REG_1,
+					led_reg, NULL);
+		} else {
+			status = i40e_write_phy_register_clause45(hw,
+							I40E_PHY_COM_REG_PAGE,
+							led_addr, phy_addr,
+							(u16)led_reg);
+		}
 		if (status)
 			return status;
 	}
-	status = i40e_read_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE,
-						 led_addr, phy_addr, &led_reg);
+	if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
+		status =
+		      i40e_aq_get_phy_register(hw,
+					       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
+					       I40E_PHY_COM_REG_PAGE,
+					       I40E_PHY_LED_PROV_REG_1,
+					       &led_reg, NULL);
+	} else {
+		status = i40e_read_phy_register_clause45(hw,
+							 I40E_PHY_COM_REG_PAGE,
+							 led_addr, phy_addr,
+							 (u16 *)&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_clause45(hw, I40E_PHY_COM_REG_PAGE,
-						  led_addr, phy_addr, led_reg);
+
+	if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
+		status =
+		      i40e_aq_set_phy_register(hw,
+					       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
+					       I40E_PHY_COM_REG_PAGE,
+					       I40E_PHY_LED_PROV_REG_1,
+					       led_reg, NULL);
+	} else {
+		status =
+		    i40e_write_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE,
+						     led_addr, phy_addr,
+						     (u16)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_clause45(hw,
-						 I40E_PHY_COM_REG_PAGE,
-						 led_addr, phy_addr, led_ctl);
+		if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
+			status = i40e_aq_set_phy_register(hw,
+					I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
+					I40E_PHY_COM_REG_PAGE,
+					I40E_PHY_LED_PROV_REG_1,
+					led_ctl, NULL);
+		} else {
+			status = i40e_write_phy_register_clause45(hw,
+							 I40E_PHY_COM_REG_PAGE,
+							 led_addr, phy_addr,
+							 (u16)led_ctl);
+		}
 	}
 	return status;
 restore_config:
-	status = i40e_write_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE,
-						  led_addr, phy_addr, led_ctl);
+	if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
+		status =
+		      i40e_aq_set_phy_register(hw,
+					       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
+					       I40E_PHY_COM_REG_PAGE,
+					       I40E_PHY_LED_PROV_REG_1,
+					       led_ctl, NULL);
+	} else {
+		status =
+			i40e_write_phy_register_clause45(hw,
+							 I40E_PHY_COM_REG_PAGE,
+							 led_addr, phy_addr,
+							 (u16)led_ctl);
+	}
 	return status;
 }
 
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index fd4bbdd..78fda11 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -598,6 +598,7 @@ struct i40e_hw {
 	struct i40e_dcbx_config desired_dcbx_config; /* CEE Desired Cfg */
 
 #define I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE BIT_ULL(0)
+#define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE  BIT_ULL(2)
 	u64 flags;
 
 	/* debug mask */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h
index 2ea919d..412a32c 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h
@@ -556,6 +556,8 @@ struct i40e_hw {
 	/* LLDP/DCBX Status */
 	u16 dcbx_status;
 
+#define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE  BIT_ULL(2)
+
 	/* DCBX info */
 	struct i40e_dcbx_config local_dcbx_config; /* Oper/Local Cfg */
 	struct i40e_dcbx_config remote_dcbx_config; /* Peer Cfg */
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 02/12] i40e: Fix reporting of supported link modes
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
@ 2017-08-04 13:52 ` Alice Michael
  2017-08-07 17:18   ` Shannon Nelson
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 03/12] i40e: Add support for 'ethtool -m' Alice Michael
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Filip Sadowski <filip.sadowski@intel.com>

This patch fixes incorrect reporting of supported link modes on some NICs.

Signed-off-by: Filip Sadowski <filip.sadowski@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h   | 20 ++++++++++++++++++--
 drivers/net/ethernet/intel/i40e/i40e_common.c       |  8 +++++++-
 drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 20 ++++++++++++++++++--
 3 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
index e2a9ec8..5d0291c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
@@ -1734,6 +1734,8 @@ enum i40e_aq_phy_type {
 	I40E_PHY_TYPE_10GBASE_CR1_CU		= 0xB,
 	I40E_PHY_TYPE_10GBASE_AOC		= 0xC,
 	I40E_PHY_TYPE_40GBASE_AOC		= 0xD,
+	I40E_PHY_TYPE_UNRECOGNIZED		= 0xE,
+	I40E_PHY_TYPE_UNSUPPORTED		= 0xF,
 	I40E_PHY_TYPE_100BASE_TX		= 0x11,
 	I40E_PHY_TYPE_1000BASE_T		= 0x12,
 	I40E_PHY_TYPE_10GBASE_T			= 0x13,
@@ -1752,6 +1754,8 @@ enum i40e_aq_phy_type {
 	I40E_PHY_TYPE_25GBASE_CR		= 0x20,
 	I40E_PHY_TYPE_25GBASE_SR		= 0x21,
 	I40E_PHY_TYPE_25GBASE_LR		= 0x22,
+	I40E_PHY_TYPE_EMPTY			= 0xFE,
+	I40E_PHY_TYPE_DEFAULT			= 0xFF,
 	I40E_PHY_TYPE_MAX
 };
 
@@ -1942,19 +1946,31 @@ struct i40e_aqc_get_link_status {
 #define I40E_AQ_25G_SERDES_UCODE_ERR	0X04
 #define I40E_AQ_25G_NIMB_UCODE_ERR	0X05
 	u8	loopback; /* use defines from i40e_aqc_set_lb_mode */
+/* Since firmware API 1.7 loopback field keeps power class info as well */
+#define I40E_AQ_LOOPBACK_MASK		0x07
+#define I40E_AQ_PWR_CLASS_SHIFT_LB	6
+#define I40E_AQ_PWR_CLASS_MASK_LB	(0x03 << I40E_AQ_PWR_CLASS_SHIFT_LB)
 	__le16	max_frame_size;
 	u8	config;
 #define I40E_AQ_CONFIG_FEC_KR_ENA	0x01
 #define I40E_AQ_CONFIG_FEC_RS_ENA	0x02
 #define I40E_AQ_CONFIG_CRC_ENA		0x04
 #define I40E_AQ_CONFIG_PACING_MASK	0x78
-	u8	power_desc;
+	union {
+		struct {
+			u8	power_desc;
 #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
 #define I40E_AQ_PWR_CLASS_MASK		0x03
-	u8	reserved[4];
+			u8	reserved[4];
+		};
+		struct {
+			u8	link_type[4];
+			u8	link_type_ext;
+		};
+	};
 };
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index e9f30b8..c0aeda7 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -1826,7 +1826,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
 	hw_link_info->fec_info = resp->config & (I40E_AQ_CONFIG_FEC_KR_ENA |
 						 I40E_AQ_CONFIG_FEC_RS_ENA);
 	hw_link_info->ext_info = resp->ext_info;
-	hw_link_info->loopback = resp->loopback;
+	hw_link_info->loopback = resp->loopback & I40E_AQ_LOOPBACK_MASK;
 	hw_link_info->max_frame_size = le16_to_cpu(resp->max_frame_size);
 	hw_link_info->pacing = resp->config & I40E_AQ_CONFIG_PACING_MASK;
 
@@ -1857,6 +1857,12 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
 	     hw->aq.fw_min_ver < 40)) && hw_link_info->phy_type == 0xE)
 		hw_link_info->phy_type = I40E_PHY_TYPE_10GBASE_SFPP_CU;
 
+	if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
+	    hw->aq.api_min_ver >= 7) {
+		hw->phy.phy_types = le32_to_cpu(*(__le32 *)resp->link_type);
+		hw->phy.phy_types |= ((u64)resp->link_type_ext << 32);
+	}
+
 	/* save link status information */
 	if (link)
 		*link = *hw_link_info;
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
index f9f48d1..709d114 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
@@ -1730,6 +1730,8 @@ enum i40e_aq_phy_type {
 	I40E_PHY_TYPE_10GBASE_CR1_CU		= 0xB,
 	I40E_PHY_TYPE_10GBASE_AOC		= 0xC,
 	I40E_PHY_TYPE_40GBASE_AOC		= 0xD,
+	I40E_PHY_TYPE_UNRECOGNIZED		= 0xE,
+	I40E_PHY_TYPE_UNSUPPORTED		= 0xF,
 	I40E_PHY_TYPE_100BASE_TX		= 0x11,
 	I40E_PHY_TYPE_1000BASE_T		= 0x12,
 	I40E_PHY_TYPE_10GBASE_T			= 0x13,
@@ -1748,6 +1750,8 @@ enum i40e_aq_phy_type {
 	I40E_PHY_TYPE_25GBASE_CR		= 0x20,
 	I40E_PHY_TYPE_25GBASE_SR		= 0x21,
 	I40E_PHY_TYPE_25GBASE_LR		= 0x22,
+	I40E_PHY_TYPE_EMPTY			= 0xFE,
+	I40E_PHY_TYPE_DEFAULT			= 0xFF,
 	I40E_PHY_TYPE_MAX
 };
 
@@ -1938,19 +1942,31 @@ struct i40e_aqc_get_link_status {
 #define I40E_AQ_25G_SERDES_UCODE_ERR	0X04
 #define I40E_AQ_25G_NIMB_UCODE_ERR	0X05
 	u8	loopback; /* use defines from i40e_aqc_set_lb_mode */
+/* Since firmware API 1.7 loopback field keeps power class info as well */
+#define I40E_AQ_LOOPBACK_MASK		0x07
+#define I40E_AQ_PWR_CLASS_SHIFT_LB	6
+#define I40E_AQ_PWR_CLASS_MASK_LB	(0x03 << I40E_AQ_PWR_CLASS_SHIFT_LB)
 	__le16	max_frame_size;
 	u8	config;
 #define I40E_AQ_CONFIG_FEC_KR_ENA	0x01
 #define I40E_AQ_CONFIG_FEC_RS_ENA	0x02
 #define I40E_AQ_CONFIG_CRC_ENA		0x04
 #define I40E_AQ_CONFIG_PACING_MASK	0x78
-	u8	power_desc;
+	union {
+		struct {
+			u8	power_desc;
 #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
 #define I40E_AQ_PWR_CLASS_MASK		0x03
-	u8	reserved[4];
+			u8	reserved[4];
+		};
+		struct {
+			u8	link_type[4];
+			u8	link_type_ext;
+		};
+	};
 };
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status);
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 03/12] i40e: Add support for 'ethtool -m'
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 02/12] i40e: Fix reporting of supported link modes Alice Michael
@ 2017-08-04 13:52 ` Alice Michael
  2017-08-07 17:19   ` Shannon Nelson
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 04/12] i40e: don't hold spinlock while resetting VF Alice Michael
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Filip Sadowski <filip.sadowski@intel.com>

This patch adds support for 'ethtool -m' command which displays
information about (Q)SFP+ module plugged into NIC's cage.

Signed-off-by: Filip Sadowski <filip.sadowski@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |  18 +++
 drivers/net/ethernet/intel/i40e/i40e_common.c      |  69 +++++++++
 drivers/net/ethernet/intel/i40e/i40e_ethtool.c     | 154 +++++++++++++++++++++
 drivers/net/ethernet/intel/i40e/i40e_prototype.h   |   9 ++
 drivers/net/ethernet/intel/i40e/i40e_type.h        |  12 ++
 .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |  18 +++
 drivers/net/ethernet/intel/i40evf/i40e_common.c    |  69 +++++++++
 drivers/net/ethernet/intel/i40evf/i40e_prototype.h |   9 ++
 drivers/net/ethernet/intel/i40evf/i40e_type.h      |  12 ++
 9 files changed, 370 insertions(+)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
index 5d0291c..8fcbbd8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
@@ -244,6 +244,8 @@ enum i40e_admin_queue_opc {
 	i40e_aqc_opc_set_phy_debug		= 0x0622,
 	i40e_aqc_opc_upload_ext_phy_fm		= 0x0625,
 	i40e_aqc_opc_run_phy_activity		= 0x0626,
+	i40e_aqc_opc_set_phy_register		= 0x0628,
+	i40e_aqc_opc_get_phy_register		= 0x0629,
 
 	/* NVM commands */
 	i40e_aqc_opc_nvm_read			= 0x0701,
@@ -2053,6 +2055,22 @@ struct i40e_aqc_run_phy_activity {
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_run_phy_activity);
 
+/* Set PHY Register command (0x0628) */
+/* Get PHY Register command (0x0629) */
+struct i40e_aqc_phy_register_access {
+	u8	phy_interface;
+#define I40E_AQ_PHY_REG_ACCESS_INTERNAL	0
+#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL	1
+#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE	2
+	u8	dev_address;
+	u8	reserved1[2];
+	u32	reg_address;
+	u32	reg_value;
+	u8	reserved2[4];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_phy_register_access);
+
 /* NVM Read command (indirect 0x0701)
  * NVM Erase commands (direct 0x0702)
  * NVM Update commands (indirect 0x0703)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index c0aeda7..6b7712c 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -5143,6 +5143,75 @@ void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
 }
 
 /**
+ * i40e_aq_set_phy_register
+ * @hw: pointer to the hw struct
+ * @phy_select: select which phy should be accessed
+ * @dev_addr: PHY device address
+ * @reg_addr: PHY register address
+ * @reg_val: new register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Write the external PHY register.
+ **/
+i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
+				     u8 phy_select, u8 dev_addr,
+				     u32 reg_addr, u32 reg_val,
+				     struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_phy_register_access *cmd =
+		(struct i40e_aqc_phy_register_access *)&desc.params.raw;
+	i40e_status status;
+
+	i40e_fill_default_direct_cmd_desc(&desc,
+					  i40e_aqc_opc_set_phy_register);
+
+	cmd->phy_interface = phy_select;
+	cmd->dev_address = dev_addr;
+	cmd->reg_address = reg_addr;
+	cmd->reg_value = reg_val;
+
+	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+	return status;
+}
+
+/**
+ * i40e_aq_get_phy_register
+ * @hw: pointer to the hw struct
+ * @phy_select: select which phy should be accessed
+ * @dev_addr: PHY device address
+ * @reg_addr: PHY register address
+ * @reg_val: read register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Read the external PHY register.
+ **/
+i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw,
+				     u8 phy_select, u8 dev_addr,
+				     u32 reg_addr, u32 *reg_val,
+				     struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_phy_register_access *cmd =
+		(struct i40e_aqc_phy_register_access *)&desc.params.raw;
+	i40e_status status;
+
+	i40e_fill_default_direct_cmd_desc(&desc,
+					  i40e_aqc_opc_get_phy_register);
+
+	cmd->phy_interface = phy_select;
+	cmd->dev_address = dev_addr;
+	cmd->reg_address = reg_addr;
+
+	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+	if (!status)
+		*reg_val = cmd->reg_value;
+
+	return status;
+}
+
+/**
  * i40e_aq_write_ppp - Write pipeline personalization profile (ppp)
  * @hw: pointer to the hw struct
  * @buff: command buffer (size in bytes = buff_size)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index 326fc18..72910c5 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -4202,6 +4202,158 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
 	return 0;
 }
 
+/**
+ * i40e_get_module_info - get (Q)SFP+ module type info
+ * @netdev: network interface device structure
+ * @modinfo: module EEPROM size and layout information structure
+ **/
+static int i40e_get_module_info(struct net_device *netdev,
+				struct ethtool_modinfo *modinfo)
+{
+	i40e_status status;
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+	struct i40e_hw *hw = &pf->hw;
+	u32 sff8472_comp = 0;
+	u32 sff8472_swap = 0;
+	u32 sff8636_rev = 0;
+	u32 type = 0;
+
+	/* Check if firmware supports reading module EEPROM. */
+	if (!(hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE)) {
+		netdev_err(vsi->netdev, "Module EEPROM memory read not supported. Please update the NVM image.\n");
+		return -EINVAL;
+	}
+
+	status = i40e_update_link_info(hw);
+	if (status)
+		return -EIO;
+
+	if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_EMPTY) {
+		netdev_err(vsi->netdev, "Cannot read module EEPROM memory. No module connected.\n");
+		return -EINVAL;
+	}
+
+	type = hw->phy.link_info.module_type[0];
+
+	switch (type) {
+	case I40E_MODULE_TYPE_SFP:
+		status = i40e_aq_get_phy_register(hw,
+				I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
+				I40E_I2C_EEPROM_DEV_ADDR,
+				I40E_MODULE_SFF_8472_COMP,
+				&sff8472_comp, NULL);
+		if (status)
+			return -EIO;
+
+		status = i40e_aq_get_phy_register(hw,
+				I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
+				I40E_I2C_EEPROM_DEV_ADDR,
+				I40E_MODULE_SFF_8472_SWAP,
+				&sff8472_swap, NULL);
+		if (status)
+			return -EIO;
+
+		/* Check if the module requires address swap to access
+		 * the other EEPROM memory page.
+		 */
+		if (sff8472_swap & I40E_MODULE_SFF_ADDR_MODE) {
+			netdev_warn(vsi->netdev, "Module address swap to access page 0xA2 is not supported.\n");
+			modinfo->type = ETH_MODULE_SFF_8079;
+			modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
+		} else if (sff8472_comp == 0x00) {
+			/* Module is not SFF-8472 compliant */
+			modinfo->type = ETH_MODULE_SFF_8079;
+			modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
+		} else {
+			modinfo->type = ETH_MODULE_SFF_8472;
+			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
+		}
+		break;
+	case I40E_MODULE_TYPE_QSFP_PLUS:
+		/* Read from memory page 0. */
+		status = i40e_aq_get_phy_register(hw,
+				I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
+				0,
+				I40E_MODULE_REVISION_ADDR,
+				&sff8636_rev, NULL);
+		if (status)
+			return -EIO;
+		/* Determine revision compliance byte */
+		if (sff8636_rev > 0x02) {
+			/* Module is SFF-8636 compliant */
+			modinfo->type = ETH_MODULE_SFF_8636;
+			modinfo->eeprom_len = I40E_MODULE_QSFP_MAX_LEN;
+		} else {
+			modinfo->type = ETH_MODULE_SFF_8436;
+			modinfo->eeprom_len = I40E_MODULE_QSFP_MAX_LEN;
+		}
+		break;
+	case I40E_MODULE_TYPE_QSFP28:
+		modinfo->type = ETH_MODULE_SFF_8636;
+		modinfo->eeprom_len = I40E_MODULE_QSFP_MAX_LEN;
+		break;
+	default:
+		netdev_err(vsi->netdev, "Module type unrecognized\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * i40e_get_module_eeprom - fills buffer with (Q)SFP+ module memory contents
+ * @netdev: network interface device structure
+ * @ee: EEPROM dump request structure
+ * @data: buffer to be filled with EEPROM contents
+ **/
+static int i40e_get_module_eeprom(struct net_device *netdev,
+				  struct ethtool_eeprom *ee,
+				  u8 *data)
+{
+	i40e_status status;
+	struct i40e_netdev_priv *np = netdev_priv(netdev);
+	struct i40e_vsi *vsi = np->vsi;
+	struct i40e_pf *pf = vsi->back;
+	struct i40e_hw *hw = &pf->hw;
+	bool is_sfp = false;
+	u32 value = 0;
+	int i;
+
+	if (!ee || !ee->len || !data)
+		return -EINVAL;
+
+	if (hw->phy.link_info.module_type[0] == I40E_MODULE_TYPE_SFP)
+		is_sfp = true;
+
+	for (i = 0; i < ee->len; i++) {
+		u32 offset = i + ee->offset;
+		u32 addr = is_sfp ? I40E_I2C_EEPROM_DEV_ADDR : 0;
+
+		/* Check if we need to access the other memory page */
+		if (is_sfp) {
+			if (offset >= ETH_MODULE_SFF_8079_LEN) {
+				offset -= ETH_MODULE_SFF_8079_LEN;
+				addr = I40E_I2C_EEPROM_DEV_ADDR2;
+			}
+		} else {
+			while (offset >= ETH_MODULE_SFF_8436_LEN) {
+				/* Compute memory page number and offset. */
+				offset -= ETH_MODULE_SFF_8436_LEN / 2;
+				addr++;
+			}
+		}
+
+		status = i40e_aq_get_phy_register(hw,
+				I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
+				addr, offset, &value, NULL);
+		if (status)
+			return -EIO;
+		data[i] = value;
+	}
+	return 0;
+}
+
 static const struct ethtool_ops i40e_ethtool_ops = {
 	.get_drvinfo		= i40e_get_drvinfo,
 	.get_regs_len		= i40e_get_regs_len,
@@ -4234,6 +4386,8 @@ static const struct ethtool_ops i40e_ethtool_ops = {
 	.set_rxfh		= i40e_set_rxfh,
 	.get_channels		= i40e_get_channels,
 	.set_channels		= i40e_set_channels,
+	.get_module_info	= i40e_get_module_info,
+	.get_module_eeprom	= i40e_get_module_eeprom,
 	.get_ts_info		= i40e_get_ts_info,
 	.get_priv_flags		= i40e_get_priv_flags,
 	.set_priv_flags		= i40e_set_priv_flags,
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
index df613ea..6254ad5 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -362,6 +362,15 @@ i40e_status i40e_aq_rx_ctl_write_register(struct i40e_hw *hw,
 				u32 reg_addr, u32 reg_val,
 				struct i40e_asq_cmd_details *cmd_details);
 void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val);
+i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
+				     u8 phy_select, u8 dev_addr,
+				     u32 reg_addr, u32 reg_val,
+				     struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw,
+				     u8 phy_select, u8 dev_addr,
+				     u32 reg_addr, u32 *reg_val,
+				     struct i40e_asq_cmd_details *cmd_details);
+
 i40e_status i40e_read_phy_register_clause22(struct i40e_hw *hw,
 					    u16 reg, u8 phy_addr, u16 *value);
 i40e_status i40e_write_phy_register_clause22(struct i40e_hw *hw,
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index 78fda11..8b0b9f8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -428,6 +428,18 @@ struct i40e_nvm_access {
 	u8 data[1];
 };
 
+/* (Q)SFP module access definitions */
+#define I40E_I2C_EEPROM_DEV_ADDR	0xA0
+#define I40E_I2C_EEPROM_DEV_ADDR2	0xA2
+#define I40E_MODULE_TYPE_ADDR		0x00
+#define I40E_MODULE_REVISION_ADDR	0x01
+#define I40E_MODULE_SFF_8472_COMP	0x5E
+#define I40E_MODULE_SFF_8472_SWAP	0x5C
+#define I40E_MODULE_SFF_ADDR_MODE	0x04
+#define I40E_MODULE_TYPE_QSFP_PLUS	0x0D
+#define I40E_MODULE_TYPE_QSFP28		0x11
+#define I40E_MODULE_QSFP_MAX_LEN	640
+
 /* PCI bus types */
 enum i40e_bus_type {
 	i40e_bus_type_unknown = 0,
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
index 709d114..b7715d4 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
@@ -244,6 +244,8 @@ enum i40e_admin_queue_opc {
 	i40e_aqc_opc_set_phy_debug		= 0x0622,
 	i40e_aqc_opc_upload_ext_phy_fm		= 0x0625,
 	i40e_aqc_opc_run_phy_activity		= 0x0626,
+	i40e_aqc_opc_set_phy_register		= 0x0628,
+	i40e_aqc_opc_get_phy_register		= 0x0629,
 
 	/* NVM commands */
 	i40e_aqc_opc_nvm_read			= 0x0701,
@@ -2046,6 +2048,22 @@ struct i40e_aqc_run_phy_activity {
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_run_phy_activity);
 
+/* Set PHY Register command (0x0628) */
+/* Get PHY Register command (0x0629) */
+struct i40e_aqc_phy_register_access {
+	u8	phy_interface;
+#define I40E_AQ_PHY_REG_ACCESS_INTERNAL	0
+#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL	1
+#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE	2
+	u8	dev_address;
+	u8	reserved1[2];
+	u32	reg_address;
+	u32	reg_value;
+	u8	reserved2[4];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_phy_register_access);
+
 /* NVM Read command (indirect 0x0701)
  * NVM Erase commands (direct 0x0702)
  * NVM Update commands (indirect 0x0703)
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c
index 8d3a2bf..7df4610 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c
@@ -1042,6 +1042,75 @@ void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
 }
 
 /**
+ * i40evf_aq_set_phy_register
+ * @hw: pointer to the hw struct
+ * @phy_select: select which phy should be accessed
+ * @dev_addr: PHY device address
+ * @reg_addr: PHY register address
+ * @reg_val: new register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Reset the external PHY.
+ **/
+i40e_status i40evf_aq_set_phy_register(struct i40e_hw *hw,
+				       u8 phy_select, u8 dev_addr,
+				       u32 reg_addr, u32 reg_val,
+				       struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_phy_register_access *cmd =
+		(struct i40e_aqc_phy_register_access *)&desc.params.raw;
+	i40e_status status;
+
+	i40evf_fill_default_direct_cmd_desc(&desc,
+					    i40e_aqc_opc_set_phy_register);
+
+	cmd->phy_interface = phy_select;
+	cmd->dev_address = dev_addr;
+	cmd->reg_address = reg_addr;
+	cmd->reg_value = reg_val;
+
+	status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+	return status;
+}
+
+/**
+ * i40evf_aq_get_phy_register
+ * @hw: pointer to the hw struct
+ * @phy_select: select which phy should be accessed
+ * @dev_addr: PHY device address
+ * @reg_addr: PHY register address
+ * @reg_val: read register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Reset the external PHY.
+ **/
+i40e_status i40evf_aq_get_phy_register(struct i40e_hw *hw,
+				       u8 phy_select, u8 dev_addr,
+				       u32 reg_addr, u32 *reg_val,
+				       struct i40e_asq_cmd_details *cmd_details)
+{
+	struct i40e_aq_desc desc;
+	struct i40e_aqc_phy_register_access *cmd =
+		(struct i40e_aqc_phy_register_access *)&desc.params.raw;
+	i40e_status status;
+
+	i40evf_fill_default_direct_cmd_desc(&desc,
+					    i40e_aqc_opc_get_phy_register);
+
+	cmd->phy_interface = phy_select;
+	cmd->dev_address = dev_addr;
+	cmd->reg_address = reg_addr;
+
+	status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+	if (!status)
+		*reg_val = cmd->reg_value;
+
+	return status;
+}
+
+/**
  * i40e_aq_send_msg_to_pf
  * @hw: pointer to the hardware structure
  * @v_opcode: opcodes for VF-PF communication
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
index c9836bb..b624b59 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
@@ -111,6 +111,15 @@ i40e_status i40evf_aq_rx_ctl_write_register(struct i40e_hw *hw,
 				u32 reg_addr, u32 reg_val,
 				struct i40e_asq_cmd_details *cmd_details);
 void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val);
+i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
+				     u8 phy_select, u8 dev_addr,
+				     u32 reg_addr, u32 reg_val,
+				     struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw,
+				     u8 phy_select, u8 dev_addr,
+				     u32 reg_addr, u32 *reg_val,
+				     struct i40e_asq_cmd_details *cmd_details);
+
 i40e_status i40e_read_phy_register(struct i40e_hw *hw, u8 page,
 				   u16 reg, u8 phy_addr, u16 *value);
 i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page,
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h
index 412a32c..48eacf5 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h
@@ -401,6 +401,18 @@ struct i40e_nvm_access {
 	u8 data[1];
 };
 
+/* (Q)SFP module access definitions */
+#define I40E_I2C_EEPROM_DEV_ADDR	0xA0
+#define I40E_I2C_EEPROM_DEV_ADDR2	0xA2
+#define I40E_MODULE_TYPE_ADDR		0x00
+#define I40E_MODULE_REVISION_ADDR	0x01
+#define I40E_MODULE_SFF_8472_COMP	0x5E
+#define I40E_MODULE_SFF_8472_SWAP	0x5C
+#define I40E_MODULE_SFF_ADDR_MODE	0x04
+#define I40E_MODULE_TYPE_QSFP_PLUS	0x0D
+#define I40E_MODULE_TYPE_QSFP28		0x11
+#define I40E_MODULE_QSFP_MAX_LEN	640
+
 /* PCI bus types */
 enum i40e_bus_type {
 	i40e_bus_type_unknown = 0,
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 04/12] i40e: don't hold spinlock while resetting VF
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 02/12] i40e: Fix reporting of supported link modes Alice Michael
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 03/12] i40e: Add support for 'ethtool -m' Alice Michael
@ 2017-08-04 13:52 ` Alice Michael
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 05/12] i40e: drop i40e_pf *pf from i40e_vc_disable_vf() Alice Michael
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Jacob Keller <jacob.e.keller@intel.com>

When we refactored handling of the PVID in commit 9af52f60b2d9
("i40e: use (add|rm)_vlan_all_mac helper functions when changing PVID")
we introduced a scheduling while atomic regression.

This occurred because we now held the spinlock across a call to
i40e_reset_vf(), which results in a usleep_range() call that triggers
a scheduling while atomic bug. This was rare as it only occurred if the
user configured a VLAN on a VF and also attempted to reconfigure the VF
from the host system with a port VLAN.

We do need to hold the lock while calling i40e_is_vsi_in_vlan(), but we
should not be holding it while we reset the VF.

We'll fix this by introducing a separate helper function
i40e_vsi_has_vlans which checks whether we have a PVID and whether the
VSI has configured VLANs. This helper function will manage its own need
for the mac_filter_hash_lock.

Then, we can move the acquiring of the spinlock until after we reset the
VF, which ensures that we do not sleep while holding the lock.

Using a separate function like this makes the code more clear and is
easier to read than attempting to release and re-acquire the spinlock
when we reset the VF.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 36 +++++++++++++++++++---
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index f78aa7e..fd85dd8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -2922,6 +2922,34 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
 }
 
 /**
+ * i40e_vsi_has_vlans - True if VSI has configured VLANs
+ * @vsi: pointer to the vsi
+ *
+ * Check if a VSI has configured any VLANs. False if we have a port VLAN or if
+ * we have no configured VLANs. Do not call while holding the
+ * mac_filter_hash_lock.
+ */
+static bool i40e_vsi_has_vlans(struct i40e_vsi *vsi)
+{
+	bool have_vlans;
+
+	/* If we have a port VLAN, then the VSI cannot have any VLANs
+	 * configured, as all MAC/VLAN filters will be assigned to the PVID.
+	 */
+	if (vsi->info.pvid)
+		return false;
+
+	/* Since we don't have a PVID, we know that if the device is in VLAN
+	 * mode it must be because of a VLAN filter configured on this VSI.
+	 */
+	spin_lock_bh(&vsi->mac_filter_hash_lock);
+	have_vlans = i40e_is_vsi_in_vlan(vsi);
+	spin_unlock_bh(&vsi->mac_filter_hash_lock);
+
+	return have_vlans;
+}
+
+/**
  * i40e_ndo_set_vf_port_vlan
  * @netdev: network interface device structure
  * @vf_id: VF identifier
@@ -2973,10 +3001,7 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
 		/* duplicate request, so just return success */
 		goto error_pvid;
 
-	/* Locked once because multiple functions below iterate list */
-	spin_lock_bh(&vsi->mac_filter_hash_lock);
-
-	if (le16_to_cpu(vsi->info.pvid) == 0 && i40e_is_vsi_in_vlan(vsi)) {
+	if (i40e_vsi_has_vlans(vsi)) {
 		dev_err(&pf->pdev->dev,
 			"VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n",
 			vf_id);
@@ -2989,6 +3014,9 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
 		vsi = pf->vsi[vf->lan_vsi_idx];
 	}
 
+	/* Locked once because multiple functions below iterate list */
+	spin_lock_bh(&vsi->mac_filter_hash_lock);
+
 	/* Check for condition where there was already a port VLAN ID
 	 * filter set and now it is being deleted by setting it to zero.
 	 * Additionally check for the condition where there was a port
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 05/12] i40e: drop i40e_pf *pf from i40e_vc_disable_vf()
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
                   ` (2 preceding siblings ...)
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 04/12] i40e: don't hold spinlock while resetting VF Alice Michael
@ 2017-08-04 13:52 ` Alice Michael
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 06/12] i40e: make use of i40e_vc_disable_vf Alice Michael
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Jacob Keller <jacob.e.keller@intel.com>

It's never used, and the vf structure could get back to the PF if
necessary. Lets just drop the extra unneeded parameter.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index fd85dd8..2adcc7f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -154,12 +154,11 @@ void i40e_vc_notify_vf_reset(struct i40e_vf *vf)
 
 /**
  * i40e_vc_disable_vf
- * @pf: pointer to the PF info
  * @vf: pointer to the VF info
  *
  * Disable the VF through a SW reset
  **/
-static inline void i40e_vc_disable_vf(struct i40e_pf *pf, struct i40e_vf *vf)
+static inline void i40e_vc_disable_vf(struct i40e_vf *vf)
 {
 	i40e_vc_notify_vf_reset(vf);
 	i40e_reset_vf(vf, false);
@@ -2914,7 +2913,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
 	}
 
 	/* Force the VF driver stop so it has to reload with new MAC address */
-	i40e_vc_disable_vf(pf, vf);
+	i40e_vc_disable_vf(vf);
 	dev_info(&pf->pdev->dev, "Reload the VF driver to make this change effective.\n");
 
 error_param:
@@ -3009,7 +3008,7 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
 		 * the right thing by reconfiguring his network correctly
 		 * and then reloading the VF driver.
 		 */
-		i40e_vc_disable_vf(pf, vf);
+		i40e_vc_disable_vf(vf);
 		/* During reset the VF got a new VSI, so refresh the pointer. */
 		vsi = pf->vsi[vf->lan_vsi_idx];
 	}
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 06/12] i40e: make use of i40e_vc_disable_vf
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
                   ` (3 preceding siblings ...)
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 05/12] i40e: drop i40e_pf *pf from i40e_vc_disable_vf() Alice Michael
@ 2017-08-04 13:52 ` Alice Michael
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 07/12] i40e: ensure reset occurs when disabling VF Alice Michael
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Jacob Keller <jacob.e.keller@intel.com>

Replace i40e_vc_notify_vf_reset and i40e_reset_vf with a call to
i40e_vc_disable_vf which does this exact thing. This matches similar
code patterns throughout the driver.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index 2adcc7f..c9898cb 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -3345,8 +3345,7 @@ int i40e_ndo_set_vf_trust(struct net_device *netdev, int vf_id, bool setting)
 		goto out;
 
 	vf->trusted = setting;
-	i40e_vc_notify_vf_reset(vf);
-	i40e_reset_vf(vf, false);
+	i40e_vc_disable_vf(vf);
 	dev_info(&pf->pdev->dev, "VF %u is now %strusted\n",
 		 vf_id, setting ? "" : "un");
 out:
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 07/12] i40e: ensure reset occurs when disabling VF
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
                   ` (4 preceding siblings ...)
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 06/12] i40e: make use of i40e_vc_disable_vf Alice Michael
@ 2017-08-04 13:52 ` Alice Michael
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 08/12] i40evf: Enable VF to request an alternate queue allocation Alice Michael
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Jacob Keller <jacob.e.keller@intel.com>

It is possible although rare that we may not reset when
i40e_vc_disable_vf() is called. This can lead to some weird
circumstances with some values not being properly set. Modify
i40e_reset_vf() to return a code indicating whether it reset or not.

Now, i40e_vc_disable_vf() can wait until a reset actually occurs. If it
fails to free up within a reasonable timeframe we'll display a warning
message.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 42 +++++++++++++++++-----
 drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h |  4 +--
 2 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index c9898cb..c7f1819 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -156,12 +156,28 @@ void i40e_vc_notify_vf_reset(struct i40e_vf *vf)
  * i40e_vc_disable_vf
  * @vf: pointer to the VF info
  *
- * Disable the VF through a SW reset
+ * Disable the VF through a SW reset.
  **/
 static inline void i40e_vc_disable_vf(struct i40e_vf *vf)
 {
+	int i;
+
 	i40e_vc_notify_vf_reset(vf);
-	i40e_reset_vf(vf, false);
+
+	/* We want to ensure that an actual reset occurs initiated after this
+	 * function was called. However, we do not want to wait forever, so
+	 * we'll give a reasonable time and print a message if we failed to
+	 * ensure a reset.
+	 */
+	for (i = 0; i < 20; i++) {
+		if (i40e_reset_vf(vf, false))
+			return;
+		usleep_range(10000, 20000);
+	}
+
+	dev_warn(&vf->pf->pdev->dev,
+		 "Failed to initiate reset for VF %d after 200 milliseconds\n",
+		 vf->vf_id);
 }
 
 /**
@@ -1048,9 +1064,9 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf)
  * @vf: pointer to the VF structure
  * @flr: VFLR was issued or not
  *
- * reset the VF
+ * Returns true if the VF is reset, false otherwise.
  **/
-void i40e_reset_vf(struct i40e_vf *vf, bool flr)
+bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
 {
 	struct i40e_pf *pf = vf->pf;
 	struct i40e_hw *hw = &pf->hw;
@@ -1058,9 +1074,11 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
 	u32 reg;
 	int i;
 
-	/* If VFs have been disabled, there is no need to reset */
+	/* If the VFs have been disabled, this means something else is
+	 * resetting the VF, so we shouldn't continue.
+	 */
 	if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
-		return;
+		return false;
 
 	i40e_trigger_vf_reset(vf, flr);
 
@@ -1097,6 +1115,8 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
 
 	i40e_flush(hw);
 	clear_bit(__I40E_VF_DISABLE, pf->state);
+
+	return true;
 }
 
 /**
@@ -1108,8 +1128,10 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
  * VF, then do all the waiting in one chunk, and finally finish restoring each
  * VF after the wait. This is useful during PF routines which need to reset
  * all VFs, as otherwise it must perform these resets in a serialized fashion.
+ *
+ * Returns true if any VFs were reset, and false otherwise.
  **/
-void i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
+bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
 {
 	struct i40e_hw *hw = &pf->hw;
 	struct i40e_vf *vf;
@@ -1118,11 +1140,11 @@ void i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
 
 	/* If we don't have any VFs, then there is nothing to reset */
 	if (!pf->num_alloc_vfs)
-		return;
+		return false;
 
 	/* If VFs have been disabled, there is no need to reset */
 	if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
-		return;
+		return false;
 
 	/* Begin reset on all VFs at once */
 	for (v = 0; v < pf->num_alloc_vfs; v++)
@@ -1197,6 +1219,8 @@ void i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
 
 	i40e_flush(hw);
 	clear_bit(__I40E_VF_DISABLE, pf->state);
+
+	return true;
 }
 
 /**
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
index 5111d05..5ea42ad 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
@@ -122,8 +122,8 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs);
 int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
 			   u32 v_retval, u8 *msg, u16 msglen);
 int i40e_vc_process_vflr_event(struct i40e_pf *pf);
-void i40e_reset_vf(struct i40e_vf *vf, bool flr);
-void i40e_reset_all_vfs(struct i40e_pf *pf, bool flr);
+bool i40e_reset_vf(struct i40e_vf *vf, bool flr);
+bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr);
 void i40e_vc_notify_vf_reset(struct i40e_vf *vf);
 
 /* VF configuration related iplink handlers */
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 08/12] i40evf: Enable VF to request an alternate queue allocation
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
                   ` (5 preceding siblings ...)
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 07/12] i40e: ensure reset occurs when disabling VF Alice Michael
@ 2017-08-04 13:52 ` Alice Michael
  2017-08-07 17:19   ` Shannon Nelson
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 09/12] i40e: make i40evf_map_rings_to_vectors void Alice Michael
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Alan Brady <alan.brady@intel.com>

Currently the VF gets a default number of allocated queues from HW on
init and it could choose to enable or disable those allocated queues.
This makes it such that the VF can request more or less underlying
allocated queues from the PF.

First the VF negotiates the number of queues it wants that can be
supported by the PF and if successful asks for a reset.  During reset
the PF will reallocate the HW queues for the VF and will then remap the
new queues.

Signed-off-by: Alan Brady <alan.brady@intel.com>
---
 drivers/net/ethernet/intel/i40evf/i40evf.h         |  4 +
 drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | 38 ++++++++-
 drivers/net/ethernet/intel/i40evf/i40evf_main.c    | 94 ++++++++++++++++++++--
 .../net/ethernet/intel/i40evf/i40evf_virtchnl.c    | 44 +++++++++-
 4 files changed, 173 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h
index a1af9b1..de0af52 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf.h
+++ b/drivers/net/ethernet/intel/i40evf/i40evf.h
@@ -102,6 +102,7 @@ struct i40e_vsi {
 #define I40E_TX_CTXTDESC(R, i) \
 	(&(((struct i40e_tx_context_desc *)((R)->desc))[i]))
 #define MAX_QUEUES 16
+#define I40EVF_MAX_REQ_QUEUES 4
 
 #define I40EVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4)
 #define I40EVF_HLUT_ARRAY_SIZE ((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4)
@@ -200,6 +201,7 @@ struct i40evf_adapter {
 	struct list_head vlan_filter_list;
 	char misc_vector_name[IFNAMSIZ + 9];
 	int num_active_queues;
+	int num_req_queues;
 
 	/* TX */
 	struct i40e_ring *tx_rings;
@@ -235,6 +237,7 @@ struct i40evf_adapter {
 #define I40EVF_FLAG_PROMISC_ON			BIT(13)
 #define I40EVF_FLAG_ALLMULTI_ON			BIT(14)
 #define I40EVF_FLAG_LEGACY_RX			BIT(15)
+#define I40EVF_FLAG_REINIT_ITR_NEEDED		BIT(16)
 /* duplicates for common code */
 #define I40E_FLAG_DCB_ENABLED			0
 #define I40E_FLAG_RX_CSUM_ENABLED		I40EVF_FLAG_RX_CSUM_ENABLED
@@ -349,6 +352,7 @@ void i40evf_deconfigure_queues(struct i40evf_adapter *adapter);
 void i40evf_enable_queues(struct i40evf_adapter *adapter);
 void i40evf_disable_queues(struct i40evf_adapter *adapter);
 void i40evf_map_queues(struct i40evf_adapter *adapter);
+int i40evf_request_queues(struct i40evf_adapter *adapter, int num);
 void i40evf_add_ether_addrs(struct i40evf_adapter *adapter);
 void i40evf_del_ether_addrs(struct i40evf_adapter *adapter);
 void i40evf_add_vlans(struct i40evf_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
index 65874d6..da006fa 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
@@ -669,7 +669,7 @@ static void i40evf_get_channels(struct net_device *netdev,
 	struct i40evf_adapter *adapter = netdev_priv(netdev);
 
 	/* Report maximum channels */
-	ch->max_combined = adapter->num_active_queues;
+	ch->max_combined = I40EVF_MAX_REQ_QUEUES;
 
 	ch->max_other = NONQ_VECS;
 	ch->other_count = NONQ_VECS;
@@ -678,6 +678,41 @@ static void i40evf_get_channels(struct net_device *netdev,
 }
 
 /**
+ * i40evf_set_channels: set the new channel count
+ * @netdev: network interface device structure
+ * @ch: channel information structure
+ *
+ * Negotiate a new number of channels with the PF then do a reset.  During
+ * reset we'll realloc queues and fix the RSS table.  Returns 0 on success,
+ * negative on failure.
+ **/
+static int i40evf_set_channels(struct net_device *netdev,
+			       struct ethtool_channels *ch)
+{
+	struct i40evf_adapter *adapter = netdev_priv(netdev);
+	int num_req = ch->combined_count;
+
+	if (num_req != adapter->num_active_queues &&
+	    !(adapter->vf_res->vf_cap_flags &
+	      VIRTCHNL_VF_OFFLOAD_REQ_QUEUES)) {
+		dev_info(&adapter->pdev->dev, "PF is not capable of queue negotiation.\n");
+		return -EINVAL;
+	}
+
+	/* All of these should have already been checked by ethtool before this
+	 * even gets to us, but just to be sure.
+	 */
+	if (num_req <= 0 || num_req > I40EVF_MAX_REQ_QUEUES)
+		return -EINVAL;
+
+	if (ch->rx_count || ch->tx_count || ch->other_count != NONQ_VECS)
+		return -EINVAL;
+
+	adapter->num_req_queues = num_req;
+	return i40evf_request_queues(adapter, num_req);
+}
+
+/**
  * i40evf_get_rxfh_key_size - get the RSS hash key size
  * @netdev: network interface device structure
  *
@@ -785,6 +820,7 @@ static const struct ethtool_ops i40evf_ethtool_ops = {
 	.get_rxfh		= i40evf_get_rxfh,
 	.set_rxfh		= i40evf_set_rxfh,
 	.get_channels		= i40evf_get_channels,
+	.set_channels		= i40evf_set_channels,
 	.get_rxfh_key_size	= i40evf_get_rxfh_key_size,
 	.get_link_ksettings	= i40evf_get_link_ksettings,
 };
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index a216fd2..a803c6b 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -1189,9 +1189,18 @@ static int i40evf_alloc_queues(struct i40evf_adapter *adapter)
 {
 	int i, num_active_queues;
 
-	num_active_queues = min_t(int,
-				  adapter->vsi_res->num_queue_pairs,
-				  (int)(num_online_cpus()));
+	/* If we're in reset reallocating queues we don't actually know yet for
+	 * certain the PF gave us the number of queues we asked for but we'll
+	 * assume it did.  Once basic reset is finished we'll confirm once we
+	 * start negotiating config with PF.
+	 */
+	if (adapter->num_req_queues)
+		num_active_queues = adapter->num_req_queues;
+	else
+		num_active_queues = min_t(int,
+					  adapter->vsi_res->num_queue_pairs,
+					  (int)(num_online_cpus()));
+
 
 	adapter->tx_rings = kcalloc(num_active_queues,
 				    sizeof(struct i40e_ring), GFP_KERNEL);
@@ -1540,6 +1549,48 @@ static void i40evf_free_rss(struct i40evf_adapter *adapter)
 }
 
 /**
+ * i40evf_reinit_interrupt_scheme - Reallocate queues and vectors
+ * @adapter: board private structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40evf_reinit_interrupt_scheme(struct i40evf_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int err;
+
+	if (netif_running(netdev))
+		i40evf_free_traffic_irqs(adapter);
+	i40evf_free_misc_irq(adapter);
+	i40evf_reset_interrupt_capability(adapter);
+	i40evf_free_q_vectors(adapter);
+	i40evf_free_queues(adapter);
+
+	err =  i40evf_init_interrupt_scheme(adapter);
+	if (err)
+		goto err;
+
+	netif_tx_stop_all_queues(netdev);
+
+	err = i40evf_request_misc_irq(adapter);
+	if (err)
+		goto err;
+
+	set_bit(__I40E_VSI_DOWN, adapter->vsi.state);
+
+	err = i40evf_map_rings_to_vectors(adapter);
+	if (err)
+		goto err;
+
+	if (RSS_AQ(adapter))
+		adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_RSS;
+	else
+		err = i40evf_init_rss(adapter);
+err:
+	return err;
+}
+
+/**
  * i40evf_watchdog_timer - Periodic call-back timer
  * @data: pointer to adapter disguised as unsigned long
  **/
@@ -1885,8 +1936,15 @@ static void i40evf_reset_task(struct work_struct *work)
 	if (err)
 		dev_info(&adapter->pdev->dev, "Failed to init adminq: %d\n",
 			 err);
+	adapter->aq_required = 0;
 
-	adapter->aq_required = I40EVF_FLAG_AQ_GET_CONFIG;
+	if (adapter->flags & I40EVF_FLAG_REINIT_ITR_NEEDED) {
+		err = i40evf_reinit_interrupt_scheme(adapter);
+		if (err)
+			goto reset_err;
+	}
+
+	adapter->aq_required |= I40EVF_FLAG_AQ_GET_CONFIG;
 	adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS;
 
 	/* re-add all MAC filters */
@@ -1916,6 +1974,15 @@ static void i40evf_reset_task(struct work_struct *work)
 		if (err)
 			goto reset_err;
 
+		if (adapter->flags & I40EVF_FLAG_REINIT_ITR_NEEDED) {
+			err = i40evf_request_traffic_irqs(adapter,
+							  netdev->name);
+			if (err)
+				goto reset_err;
+
+			adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
+		}
+
 		i40evf_configure(adapter);
 
 		i40evf_up_complete(adapter);
@@ -2432,9 +2499,9 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw)
 int i40evf_process_config(struct i40evf_adapter *adapter)
 {
 	struct virtchnl_vf_resource *vfres = adapter->vf_res;
+	int i, num_req_queues = adapter->num_req_queues;
 	struct net_device *netdev = adapter->netdev;
 	struct i40e_vsi *vsi = &adapter->vsi;
-	int i;
 	netdev_features_t hw_enc_features;
 	netdev_features_t hw_features;
 
@@ -2448,6 +2515,23 @@ int i40evf_process_config(struct i40evf_adapter *adapter)
 		return -ENODEV;
 	}
 
+	if (num_req_queues &&
+	    num_req_queues != adapter->vsi_res->num_queue_pairs) {
+		/* Problem.  The PF gave us fewer queues than what we had
+		 * negotiated in our request.  Need a reset to see if we can't
+		 * get back to a working state.
+		 */
+		dev_err(&adapter->pdev->dev,
+			"Requested %d queues, but PF only gave us %d.\n",
+			num_req_queues,
+			adapter->vsi_res->num_queue_pairs);
+		adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
+		adapter->num_req_queues = adapter->vsi_res->num_queue_pairs;
+		i40evf_schedule_reset(adapter);
+		return -ENODEV;
+	}
+	adapter->num_req_queues = 0;
+
 	hw_enc_features = NETIF_F_SG			|
 			  NETIF_F_IP_CSUM		|
 			  NETIF_F_IPV6_CSUM		|
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
index 2bb0fe0..2bb81c3 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
@@ -160,7 +160,8 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter)
 	       VIRTCHNL_VF_OFFLOAD_WB_ON_ITR |
 	       VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 |
 	       VIRTCHNL_VF_OFFLOAD_ENCAP |
-	       VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM;
+	       VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM |
+	       VIRTCHNL_VF_OFFLOAD_REQ_QUEUES;
 
 	adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES;
 	adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG;
@@ -385,6 +386,32 @@ void i40evf_map_queues(struct i40evf_adapter *adapter)
 }
 
 /**
+ * i40evf_request_queues
+ * @adapter: adapter structure
+ * @num: number of requested queues
+ *
+ * We get a default number of queues from the PF.  This enables us to request a
+ * different number.  Returns 0 on success, negative on failure
+ **/
+int i40evf_request_queues(struct i40evf_adapter *adapter, int num)
+{
+	struct virtchnl_vf_res_request vfres;
+
+	if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
+		/* bail because we already have a command pending */
+		dev_err(&adapter->pdev->dev, "Cannot request queues, command %d pending\n",
+			adapter->current_op);
+		return -EBUSY;
+	}
+
+	vfres.num_queue_pairs = num;
+
+	adapter->current_op = VIRTCHNL_OP_REQUEST_QUEUES;
+	return i40evf_send_pf_msg(adapter, VIRTCHNL_OP_REQUEST_QUEUES,
+				  (u8 *)&vfres, sizeof(vfres));
+}
+
+/**
  * i40evf_add_ether_addrs
  * @adapter: adapter structure
  * @addrs: the MAC address filters to add (contiguous)
@@ -1068,6 +1095,21 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
 				 "Invalid message %d from PF\n", v_opcode);
 		}
 		break;
+	case VIRTCHNL_OP_REQUEST_QUEUES: {
+		struct virtchnl_vf_res_request *vfres =
+			(struct virtchnl_vf_res_request *)msg;
+		if (vfres->num_queue_pairs == adapter->num_req_queues) {
+			adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
+			i40evf_schedule_reset(adapter);
+		} else {
+			dev_info(&adapter->pdev->dev,
+				 "Requested %d queues, PF can support %d\n",
+				 adapter->num_req_queues,
+				 vfres->num_queue_pairs);
+			adapter->num_req_queues = 0;
+		}
+		}
+		break;
 	default:
 		if (adapter->current_op && (v_opcode != adapter->current_op))
 			dev_warn(&adapter->pdev->dev, "Expected response %d from PF, received %d\n",
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 09/12] i40e: make i40evf_map_rings_to_vectors void
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
                   ` (6 preceding siblings ...)
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 08/12] i40evf: Enable VF to request an alternate queue allocation Alice Michael
@ 2017-08-04 13:52 ` Alice Michael
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 10/12] i40e: fix handling of vf_states variable Alice Michael
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Mitch Williams <mitch.a.williams@intel.com>

This function cannot fail, so why is it returning a value? And why are
we checking it? Why shouldn't we just make it void? Why is this commit
message made up of only questions?

Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
---
 drivers/net/ethernet/intel/i40evf/i40evf_main.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index a803c6b..85e66db 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -430,12 +430,11 @@ i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx)
  * group the rings as "efficiently" as possible.  You would add new
  * mapping configurations in here.
  **/
-static int i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter)
+static void i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter)
 {
 	int rings_remaining = adapter->num_active_queues;
 	int ridx = 0, vidx = 0;
 	int q_vectors;
-	int err = 0;
 
 	q_vectors = adapter->num_msix_vectors - NONQ_VECS;
 
@@ -451,8 +450,6 @@ static int i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter)
 	}
 
 	adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS;
-
-	return err;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1578,9 +1575,7 @@ static int i40evf_reinit_interrupt_scheme(struct i40evf_adapter *adapter)
 
 	set_bit(__I40E_VSI_DOWN, adapter->vsi.state);
 
-	err = i40evf_map_rings_to_vectors(adapter);
-	if (err)
-		goto err;
+	i40evf_map_rings_to_vectors(adapter);
 
 	if (RSS_AQ(adapter))
 		adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_RSS;
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 10/12] i40e: fix handling of vf_states variable
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
                   ` (7 preceding siblings ...)
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 09/12] i40e: make i40evf_map_rings_to_vectors void Alice Michael
@ 2017-08-04 13:52 ` Alice Michael
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 11/12] i40e: fix client notify of VF reset Alice Michael
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Alan Brady <alan.brady@intel.com>

Currently we inappropriately clear the vf_states variable with a null
assignment.  This is problematic because we should be using atomic
bitops on this variable and we don't actually want to clear all the
flags.  We should just clear the ones we know we want to clear.
Additionally remove the I40E_VF_STATE_FCOEENA bit because it is no
longer being used.

Signed-off-by: Alan Brady <alan.brady@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 5 ++++-
 drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 1 -
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index c7f1819..e65ecaf 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -876,7 +876,8 @@ static void i40e_free_vf_res(struct i40e_vf *vf)
 	}
 	/* reset some of the state variables keeping track of the resources */
 	vf->num_queue_pairs = 0;
-	vf->vf_states = 0;
+	clear_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states);
+	clear_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states);
 }
 
 /**
@@ -1582,6 +1583,8 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
 	    (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_IWARP)) {
 		vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_IWARP;
 		set_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states);
+	} else {
+		clear_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states);
 	}
 
 	if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
index 5ea42ad..5efc4f9 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
@@ -56,7 +56,6 @@ enum i40e_vf_states {
 	I40E_VF_STATE_INIT = 0,
 	I40E_VF_STATE_ACTIVE,
 	I40E_VF_STATE_IWARPENA,
-	I40E_VF_STATE_FCOEENA,
 	I40E_VF_STATE_DISABLED,
 	I40E_VF_STATE_MC_PROMISC,
 	I40E_VF_STATE_UC_PROMISC,
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 11/12] i40e: fix client notify of VF reset
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
                   ` (8 preceding siblings ...)
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 10/12] i40e: fix handling of vf_states variable Alice Michael
@ 2017-08-04 13:52 ` Alice Michael
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 12/12] i40e: Stop dropping 802.1ad tags (eth proto 0x88a8) Alice Michael
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Alan Brady <alan.brady@intel.com>

Currently there is a bug in which the PF driver fails to inform clients
of a VF reset which then causes clients to leak resources.  The bug
exists because we were incorrectly checking the I40E_VF_STATE_PRE_ENABLE
bit.

When a VF is first init we go through a reset to initialize variables
and allocate resources but we don't want to inform clients of this first
reset since the client isn't fully enabled yet so we set a state bit
signifying we're in a "pre-enabled" client state.  During the first
reset we should be clearing the bit, allowing all following resets to
notify the client of the reset when the bit is not set.  This patch
fixes the issue by negating the 'test_and_clear_bit' check to accurately
reflect the behavior we want.

Signed-off-by: Alan Brady <alan.brady@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index e65ecaf..137254e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -1047,8 +1047,8 @@ static void i40e_cleanup_reset_vf(struct i40e_vf *vf)
 		set_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
 		clear_bit(I40E_VF_STATE_DISABLED, &vf->vf_states);
 		/* Do not notify the client during VF init */
-		if (test_and_clear_bit(I40E_VF_STATE_PRE_ENABLE,
-				       &vf->vf_states))
+		if (!test_and_clear_bit(I40E_VF_STATE_PRE_ENABLE,
+					&vf->vf_states))
 			i40e_notify_client_of_vf_reset(pf, abs_vf_id);
 		vf->num_vlan = 0;
 	}
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 12/12] i40e: Stop dropping 802.1ad tags (eth proto 0x88a8)
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
                   ` (9 preceding siblings ...)
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 11/12] i40e: fix client notify of VF reset Alice Michael
@ 2017-08-04 13:52 ` Alice Michael
  2017-08-06  7:02 ` [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior kbuild test robot
  2017-08-07 17:18 ` Shannon Nelson
  12 siblings, 0 replies; 19+ messages in thread
From: Alice Michael @ 2017-08-04 13:52 UTC (permalink / raw)
  To: intel-wired-lan

From: Scott Peterson <scott.d.peterson@intel.com>

Enable i40e to pass traffic with VLAN tags using the 802.1ad ethernet
protocol ID (0x88a8).

This requires NIC firmware providing version 1.7 of the API. With
older NIC firmware 802.1ad tagged packets will continue to be dropped.

No VLAN offloads nor RSS are supported for 802.1ad VLANs.

Signed-off-by: Scott Peterson <scott.d.peterson@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e_adminq.c       |  6 ++++++
 drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h   | 17 ++++++++++++++++-
 drivers/net/ethernet/intel/i40e/i40e_common.c       |  6 +++++-
 drivers/net/ethernet/intel/i40e/i40e_main.c         |  7 +++++++
 drivers/net/ethernet/intel/i40e/i40e_type.h         |  6 ++++++
 drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 17 ++++++++++++++++-
 drivers/net/ethernet/intel/i40evf/i40e_type.h       |  6 ++++++
 7 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
index 340e5a2..8553f2b 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
@@ -613,6 +613,12 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw)
 		hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE;
 	}
 
+	/* The ability to RX (not drop) 802.1ad frames was added in API 1.7 */
+	if ((hw->aq.api_maj_ver > 1) ||
+	    ((hw->aq.api_maj_ver == 1) &&
+	     (hw->aq.api_min_ver >= 7)))
+		hw->flags |= I40E_HW_FLAG_802_1AD_CAPABLE;
+
 	if (hw->aq.api_maj_ver > I40E_FW_API_VERSION_MAJOR) {
 		ret_code = I40E_ERR_FIRMWARE_API_VERSION;
 		goto init_adminq_free_arq;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
index 8fcbbd8..b59e8a7 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
@@ -775,7 +775,22 @@ struct i40e_aqc_set_switch_config {
 #define I40E_AQ_SET_SWITCH_CFG_PROMISC		0x0001
 #define I40E_AQ_SET_SWITCH_CFG_L2_FILTER	0x0002
 	__le16	valid_flags;
-	u8	reserved[12];
+	/* The ethertype in switch_tag is dropped on ingress and used
+	 * internally by the switch. Set this to zero for the default
+	 * of 0x88a8 (802.1ad). Should be zero for firmware API
+	 * versions lower than 1.7.
+	 */
+	__le16	switch_tag;
+	/* The ethertypes in first_tag and second_tag are used to
+	 * match the outer and inner VLAN tags (respectively) when HW
+	 * double VLAN tagging is enabled via the set port parameters
+	 * AQ command. Otherwise these are both ignored. Set them to
+	 * zero for their defaults of 0x8100 (802.1Q). Should be zero
+	 * for firmware API versions lower than 1.7.
+	 */
+	__le16	first_tag;
+	__le16	second_tag;
+	u8	reserved[6];
 };
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_set_switch_config);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index 6b7712c..46db282 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -2404,7 +2404,11 @@ enum i40e_status_code i40e_aq_set_switch_config(struct i40e_hw *hw,
 					  i40e_aqc_opc_set_switch_config);
 	scfg->flags = cpu_to_le16(flags);
 	scfg->valid_flags = cpu_to_le16(valid_flags);
-
+	if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
+		scfg->switch_tag = cpu_to_le16(hw->switch_tag);
+		scfg->first_tag = cpu_to_le16(hw->first_tag);
+		scfg->second_tag = cpu_to_le16(hw->second_tag);
+	}
 	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
 
 	return status;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 370ce9f..17dc8e2 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -12451,6 +12451,13 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	hw->bus.bus_id = pdev->bus->number;
 	pf->instance = pfs_found;
 
+	/* Select something other than the 802.1ad ethertype for the
+	 * switch to use internally and drop on ingress.
+	 */
+	hw->switch_tag = 0xffff;
+	hw->first_tag = ETH_P_8021AD;
+	hw->second_tag = ETH_P_8021Q;
+
 	INIT_LIST_HEAD(&pf->l3_flex_pit_list);
 	INIT_LIST_HEAD(&pf->l4_flex_pit_list);
 
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index 8b0b9f8..4b32b1d 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -610,9 +610,15 @@ struct i40e_hw {
 	struct i40e_dcbx_config desired_dcbx_config; /* CEE Desired Cfg */
 
 #define I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE BIT_ULL(0)
+#define I40E_HW_FLAG_802_1AD_CAPABLE        BIT_ULL(1)
 #define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE  BIT_ULL(2)
 	u64 flags;
 
+	/* Used in set switch config AQ command */
+	u16 switch_tag;
+	u16 first_tag;
+	u16 second_tag;
+
 	/* debug mask */
 	u32 debug_mask;
 	char err_str[16];
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
index b7715d4..3a498d5 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
@@ -771,7 +771,22 @@ struct i40e_aqc_set_switch_config {
 #define I40E_AQ_SET_SWITCH_CFG_PROMISC		0x0001
 #define I40E_AQ_SET_SWITCH_CFG_L2_FILTER	0x0002
 	__le16	valid_flags;
-	u8	reserved[12];
+	/* The ethertype in switch_tag is dropped on ingress and used
+	 * internally by the switch. Set this to zero for the default
+	 * of 0x88a8 (802.1ad). Should be zero for firmware API
+	 * versions lower than 1.7.
+	 */
+	__le16	switch_tag;
+	/* The ethertypes in first_tag and second_tag are used to
+	 * match the outer and inner VLAN tags (respectively) when HW
+	 * double VLAN tagging is enabled via the set port parameters
+	 * AQ command. Otherwise these are both ignored. Set them to
+	 * zero for their defaults of 0x8100 (802.1Q). Should be zero
+	 * for firmware API versions lower than 1.7.
+	 */
+	__le16	first_tag;
+	__le16	second_tag;
+	u8	reserved[6];
 };
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_set_switch_config);
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h
index 48eacf5..9364b67 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h
@@ -568,6 +568,7 @@ struct i40e_hw {
 	/* LLDP/DCBX Status */
 	u16 dcbx_status;
 
+#define I40E_HW_FLAG_802_1AD_CAPABLE        BIT_ULL(1)
 #define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE  BIT_ULL(2)
 
 	/* DCBX info */
@@ -575,6 +576,11 @@ struct i40e_hw {
 	struct i40e_dcbx_config remote_dcbx_config; /* Peer Cfg */
 	struct i40e_dcbx_config desired_dcbx_config; /* CEE Desired Cfg */
 
+	/* Used in set switch config AQ command */
+	u16 switch_tag;
+	u16 first_tag;
+	u16 second_tag;
+
 	/* debug mask */
 	u32 debug_mask;
 	char err_str[16];
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
                   ` (10 preceding siblings ...)
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 12/12] i40e: Stop dropping 802.1ad tags (eth proto 0x88a8) Alice Michael
@ 2017-08-06  7:02 ` kbuild test robot
  2017-08-07 17:18 ` Shannon Nelson
  12 siblings, 0 replies; 19+ messages in thread
From: kbuild test robot @ 2017-08-06  7:02 UTC (permalink / raw)
  To: intel-wired-lan

Hi Mariusz,

[auto build test ERROR on jkirsher-next-queue/dev-queue]
[also build test ERROR on v4.13-rc3 next-20170804]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Alice-Michael/i40e-use-admin-queue-for-setting-LEDs-behavior/20170806-044014
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue.git dev-queue
config: x86_64-rhel (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

Note: the linux-review/Alice-Michael/i40e-use-admin-queue-for-setting-LEDs-behavior/20170806-044014 HEAD e6b14a85521c0cd2de206efff3ed84a86f94b5e2 builds fine.
      It only hurts bisectibility.

All errors (new ones prefixed by >>):

   drivers/net/ethernet/intel/i40e/i40e_common.c: In function 'i40e_led_get_phy':
>> drivers/net/ethernet/intel/i40e/i40e_common.c:4856:9: error: implicit declaration of function 'i40e_aq_get_phy_register' [-Werror=implicit-function-declaration]
            i40e_aq_get_phy_register(hw,
            ^~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/net/ethernet/intel/i40e/i40e_common.c:4857:13: error: 'I40E_AQ_PHY_REG_ACCESS_EXTERNAL' undeclared (first use in this function)
                I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/net/ethernet/intel/i40e/i40e_common.c:4857:13: note: each undeclared identifier is reported only once for each function it appears in
   drivers/net/ethernet/intel/i40e/i40e_common.c: In function 'i40e_led_set_phy':
   drivers/net/ethernet/intel/i40e/i40e_common.c:4910:13: error: 'I40E_AQ_PHY_REG_ACCESS_EXTERNAL' undeclared (first use in this function)
                I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/net/ethernet/intel/i40e/i40e_common.c:4930:13: error: implicit declaration of function 'i40e_aq_set_phy_register' [-Werror=implicit-function-declaration]
       status = i40e_aq_set_phy_register(hw,
                ^~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/i40e_aq_get_phy_register +4856 drivers/net/ethernet/intel/i40e/i40e_common.c

  4834	
  4835	/**
  4836	 * i40e_led_get_phy - return current on/off mode
  4837	 * @hw: pointer to the hw struct
  4838	 * @led_addr: address of led register to use
  4839	 * @val: original value of register to use
  4840	 *
  4841	 **/
  4842	i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
  4843				     u16 *val)
  4844	{
  4845		i40e_status status = 0;
  4846		u16 gpio_led_port;
  4847		u8 phy_addr = 0;
  4848		u16 reg_val;
  4849		u16 temp_addr;
  4850		u8 port_num;
  4851		u32 i;
  4852		u32 reg_val_aq;
  4853	
  4854		if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
  4855			status =
> 4856			      i40e_aq_get_phy_register(hw,
> 4857						       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
  4858						       I40E_PHY_COM_REG_PAGE,
  4859						       I40E_PHY_LED_PROV_REG_1,
  4860						       &reg_val_aq, NULL);
  4861			if (status)
  4862				return status;
  4863			*val = (u16)reg_val_aq;
  4864		} else {
  4865			temp_addr = I40E_PHY_LED_PROV_REG_1;
  4866			i = rd32(hw, I40E_PFGEN_PORTNUM);
  4867			port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK);
  4868			phy_addr = i40e_get_phy_address(hw, port_num);
  4869	
  4870			for (gpio_led_port = 0; gpio_led_port < 3; gpio_led_port++,
  4871			     temp_addr++) {
  4872				status =
  4873				 i40e_read_phy_register_clause45(hw,
  4874								 I40E_PHY_COM_REG_PAGE,
  4875								 temp_addr, phy_addr,
  4876								 &reg_val);
  4877				if (status)
  4878					return status;
  4879				*val = reg_val;
  4880				if (reg_val & I40E_PHY_LED_LINK_MODE_MASK) {
  4881					*led_addr = temp_addr;
  4882					break;
  4883				}
  4884			}
  4885		}
  4886		return status;
  4887	}
  4888	
  4889	/**
  4890	 * i40e_led_set_phy
  4891	 * @hw: pointer to the HW structure
  4892	 * @on: true or false
  4893	 * @mode: original val plus bit for set or ignore
  4894	 * Set led's on or off when controlled by the PHY
  4895	 *
  4896	 **/
  4897	i40e_status i40e_led_set_phy(struct i40e_hw *hw, bool on,
  4898				     u16 led_addr, u32 mode)
  4899	{
  4900		i40e_status status = 0;
  4901		u32 led_ctl = 0;
  4902		u32 led_reg = 0;
  4903		u8 phy_addr = 0;
  4904		u8 port_num;
  4905		u32 i;
  4906	
  4907		if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
  4908			status =
  4909			      i40e_aq_get_phy_register(hw,
  4910						       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
  4911						       I40E_PHY_COM_REG_PAGE,
  4912						       I40E_PHY_LED_PROV_REG_1,
  4913						       &led_reg, NULL);
  4914		} else {
  4915			i = rd32(hw, I40E_PFGEN_PORTNUM);
  4916			port_num = (u8)(i & I40E_PFGEN_PORTNUM_PORT_NUM_MASK);
  4917			phy_addr = i40e_get_phy_address(hw, port_num);
  4918			status = i40e_read_phy_register_clause45(hw,
  4919								 I40E_PHY_COM_REG_PAGE,
  4920								 led_addr, phy_addr,
  4921								 (u16 *)&led_reg);
  4922		}
  4923		if (status)
  4924			return status;
  4925		led_ctl = led_reg;
  4926		if (led_reg & I40E_PHY_LED_LINK_MODE_MASK) {
  4927			led_reg = 0;
  4928			if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
  4929			    hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) {
> 4930				status = i40e_aq_set_phy_register(hw,
  4931						I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
  4932						I40E_PHY_COM_REG_PAGE,
  4933						I40E_PHY_LED_PROV_REG_1,
  4934						led_reg, NULL);
  4935			} else {
  4936				status = i40e_write_phy_register_clause45(hw,
  4937								I40E_PHY_COM_REG_PAGE,
  4938								led_addr, phy_addr,
  4939								(u16)led_reg);
  4940			}
  4941			if (status)
  4942				return status;
  4943		}
  4944		if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
  4945			status =
  4946			      i40e_aq_get_phy_register(hw,
  4947						       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
  4948						       I40E_PHY_COM_REG_PAGE,
  4949						       I40E_PHY_LED_PROV_REG_1,
  4950						       &led_reg, NULL);
  4951		} else {
  4952			status = i40e_read_phy_register_clause45(hw,
  4953								 I40E_PHY_COM_REG_PAGE,
  4954								 led_addr, phy_addr,
  4955								 (u16 *)&led_reg);
  4956		}
  4957		if (status)
  4958			goto restore_config;
  4959		if (on)
  4960			led_reg = I40E_PHY_LED_MANUAL_ON;
  4961		else
  4962			led_reg = 0;
  4963	
  4964		if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
  4965			status =
  4966			      i40e_aq_set_phy_register(hw,
  4967						       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
  4968						       I40E_PHY_COM_REG_PAGE,
  4969						       I40E_PHY_LED_PROV_REG_1,
  4970						       led_reg, NULL);
  4971		} else {
  4972			status =
  4973			    i40e_write_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE,
  4974							     led_addr, phy_addr,
  4975							     (u16)led_reg);
  4976		}
  4977		if (status)
  4978			goto restore_config;
  4979		if (mode & I40E_PHY_LED_MODE_ORIG) {
  4980			led_ctl = (mode & I40E_PHY_LED_MODE_MASK);
  4981			if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
  4982				status = i40e_aq_set_phy_register(hw,
  4983						I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
  4984						I40E_PHY_COM_REG_PAGE,
  4985						I40E_PHY_LED_PROV_REG_1,
  4986						led_ctl, NULL);
  4987			} else {
  4988				status = i40e_write_phy_register_clause45(hw,
  4989								 I40E_PHY_COM_REG_PAGE,
  4990								 led_addr, phy_addr,
  4991								 (u16)led_ctl);
  4992			}
  4993		}
  4994		return status;
  4995	restore_config:
  4996		if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
  4997			status =
  4998			      i40e_aq_set_phy_register(hw,
  4999						       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
  5000						       I40E_PHY_COM_REG_PAGE,
  5001						       I40E_PHY_LED_PROV_REG_1,
  5002						       led_ctl, NULL);
  5003		} else {
  5004			status =
  5005				i40e_write_phy_register_clause45(hw,
  5006								 I40E_PHY_COM_REG_PAGE,
  5007								 led_addr, phy_addr,
  5008								 (u16)led_ctl);
  5009		}
  5010		return status;
  5011	}
  5012	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/gzip
Size: 39611 bytes
Desc: not available
URL: <http://lists.osuosl.org/pipermail/intel-wired-lan/attachments/20170806/8d56bd6a/attachment-0001.bin>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior
  2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
                   ` (11 preceding siblings ...)
  2017-08-06  7:02 ` [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior kbuild test robot
@ 2017-08-07 17:18 ` Shannon Nelson
  12 siblings, 0 replies; 19+ messages in thread
From: Shannon Nelson @ 2017-08-07 17:18 UTC (permalink / raw)
  To: intel-wired-lan

On 8/4/2017 6:52 AM, Alice Michael wrote:
> From: Mariusz Stachura <mariusz.stachura@intel.com>
> 
> Instead of accessing register directly, use newly added AQC in
> order to blink LEDs. Introduce and utilize a new flag to prevent
> excessive API version checking.
> 
> Signed-off-by: Mariusz Stachura <mariusz.stachura@intel.com>
> ---
>   drivers/net/ethernet/intel/i40e/i40e_adminq.c |   6 ++
>   drivers/net/ethernet/intel/i40e/i40e_common.c | 148 ++++++++++++++++++++------
>   drivers/net/ethernet/intel/i40e/i40e_type.h   |   1 +
>   drivers/net/ethernet/intel/i40evf/i40e_type.h |   2 +
>   4 files changed, 122 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
> index ba04988..340e5a2 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
> @@ -607,6 +607,12 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw)
>   			   &oem_lo);
>   	hw->nvm.oem_ver = ((u32)oem_hi << 16) | oem_lo;
>   
> +	if (hw->mac.type ==  I40E_MAC_XL710 &&

Extra space after ==

> +	    hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
> +	    hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) {
> +		hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE;
> +	}
> +
>   	if (hw->aq.api_maj_ver > I40E_FW_API_VERSION_MAJOR) {
>   		ret_code = I40E_ERR_FIRMWARE_API_VERSION;
>   		goto init_adminq_free_arq;
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
> index e4e86e0..e9f30b8 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_common.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
> @@ -4849,24 +4849,38 @@ i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
>   	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_clause45(hw,
> +	u32 reg_val_aq;
> +
> +	if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
> +		status =
> +		      i40e_aq_get_phy_register(hw,
> +					       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
> +					       I40E_PHY_COM_REG_PAGE,
> +					       I40E_PHY_LED_PROV_REG_1,
> +					       &reg_val_aq, NULL);

Since this call doesn't exist yet, please re-order this patchset so that 
"i40e: Add support for 'ethtool -m'" comes first.

> +		if (status)
> +			return status;
> +		*val = (u16)reg_val_aq;

The diffs below would be greatly simplified by doing the return here and 
not shifting the rest into an else block.  Something like this and the 
rest can be left alone:

		if (!status)
			*val = (u16)reg_val_aq;
		return status;
	}


> +	} else {
> +		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_clause45(hw,
>   							 I40E_PHY_COM_REG_PAGE,
>   							 temp_addr, phy_addr,
>   							 &reg_val);
> -		if (status)
> -			return status;
> -		*val = reg_val;
> -		if (reg_val & I40E_PHY_LED_LINK_MODE_MASK) {
> -			*led_addr = temp_addr;
> -			break;
> +			if (status)
> +				return status;
> +			*val = reg_val;
> +			if (reg_val & I40E_PHY_LED_LINK_MODE_MASK) {
> +				*led_addr = temp_addr;
> +				break;
> +			}
>   		}
>   	}
>   	return status;
> @@ -4884,51 +4898,115 @@ i40e_status i40e_led_set_phy(struct i40e_hw *hw, bool on,
>   			     u16 led_addr, u32 mode)
>   {
>   	i40e_status status = 0;
> -	u16 led_ctl = 0;
> -	u16 led_reg = 0;
> +	u32 led_ctl = 0;
> +	u32 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_clause45(hw, I40E_PHY_COM_REG_PAGE,
> -						 led_addr, phy_addr, &led_reg);
> +	if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
> +		status =
> +		      i40e_aq_get_phy_register(hw,
> +					       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
> +					       I40E_PHY_COM_REG_PAGE,
> +					       I40E_PHY_LED_PROV_REG_1,
> +					       &led_reg, NULL);
> +	} else {
> +		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_clause45(hw,
> +							 I40E_PHY_COM_REG_PAGE,
> +							 led_addr, phy_addr,
> +							 (u16 *)&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_clause45(hw,
> -							  I40E_PHY_COM_REG_PAGE,
> -							  led_addr, phy_addr,
> -							  led_reg);
> +		if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
> +		    hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) {

Why are you not using the I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE here?

> +			status = i40e_aq_set_phy_register(hw,
> +					I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
> +					I40E_PHY_COM_REG_PAGE,
> +					I40E_PHY_LED_PROV_REG_1,
> +					led_reg, NULL);
> +		} else {
> +			status = i40e_write_phy_register_clause45(hw,
> +							I40E_PHY_COM_REG_PAGE,
> +							led_addr, phy_addr,
> +							(u16)led_reg);
> +		}
>   		if (status)
>   			return status;
>   	}
> -	status = i40e_read_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE,
> -						 led_addr, phy_addr, &led_reg);
> +	if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
> +		status =
> +		      i40e_aq_get_phy_register(hw,
> +					       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
> +					       I40E_PHY_COM_REG_PAGE,
> +					       I40E_PHY_LED_PROV_REG_1,
> +					       &led_reg, NULL);
> +	} else {
> +		status = i40e_read_phy_register_clause45(hw,
> +							 I40E_PHY_COM_REG_PAGE,
> +							 led_addr, phy_addr,
> +							 (u16 *)&led_reg);
> +	}

Please abstract these read/write structures into helper functions 
instead of repeating this if/else so many times.

>   	if (status)
>   		goto restore_config;
>   	if (on)
>   		led_reg = I40E_PHY_LED_MANUAL_ON;
>   	else
>   		led_reg = 0;
> -	status = i40e_write_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE,
> -						  led_addr, phy_addr, led_reg);
> +
> +	if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
> +		status =
> +		      i40e_aq_set_phy_register(hw,
> +					       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
> +					       I40E_PHY_COM_REG_PAGE,
> +					       I40E_PHY_LED_PROV_REG_1,
> +					       led_reg, NULL);
> +	} else {
> +		status =
> +		    i40e_write_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE,
> +						     led_addr, phy_addr,
> +						     (u16)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_clause45(hw,
> -						 I40E_PHY_COM_REG_PAGE,
> -						 led_addr, phy_addr, led_ctl);
> +		if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
> +			status = i40e_aq_set_phy_register(hw,
> +					I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
> +					I40E_PHY_COM_REG_PAGE,
> +					I40E_PHY_LED_PROV_REG_1,
> +					led_ctl, NULL);
> +		} else {
> +			status = i40e_write_phy_register_clause45(hw,
> +							 I40E_PHY_COM_REG_PAGE,
> +							 led_addr, phy_addr,
> +							 (u16)led_ctl);
> +		}
>   	}
>   	return status;
>   restore_config:
> -	status = i40e_write_phy_register_clause45(hw, I40E_PHY_COM_REG_PAGE,
> -						  led_addr, phy_addr, led_ctl);
> +	if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
> +		status =
> +		      i40e_aq_set_phy_register(hw,
> +					       I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
> +					       I40E_PHY_COM_REG_PAGE,
> +					       I40E_PHY_LED_PROV_REG_1,
> +					       led_ctl, NULL);
> +	} else {
> +		status =
> +			i40e_write_phy_register_clause45(hw,
> +							 I40E_PHY_COM_REG_PAGE,
> +							 led_addr, phy_addr,
> +							 (u16)led_ctl);
> +	}
>   	return status;
>   }
>   
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
> index fd4bbdd..78fda11 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_type.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
> @@ -598,6 +598,7 @@ struct i40e_hw {
>   	struct i40e_dcbx_config desired_dcbx_config; /* CEE Desired Cfg */
>   
>   #define I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE BIT_ULL(0)
> +#define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE  BIT_ULL(2)
>   	u64 flags;
>   
>   	/* debug mask */
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h
> index 2ea919d..412a32c 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h
> @@ -556,6 +556,8 @@ struct i40e_hw {
>   	/* LLDP/DCBX Status */
>   	u16 dcbx_status;
>   
> +#define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE  BIT_ULL(2)
> +
>   	/* DCBX info */
>   	struct i40e_dcbx_config local_dcbx_config; /* Oper/Local Cfg */
>   	struct i40e_dcbx_config remote_dcbx_config; /* Peer Cfg */
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 02/12] i40e: Fix reporting of supported link modes
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 02/12] i40e: Fix reporting of supported link modes Alice Michael
@ 2017-08-07 17:18   ` Shannon Nelson
  0 siblings, 0 replies; 19+ messages in thread
From: Shannon Nelson @ 2017-08-07 17:18 UTC (permalink / raw)
  To: intel-wired-lan

On 8/4/2017 6:52 AM, Alice Michael wrote:
> From: Filip Sadowski <filip.sadowski@intel.com>
> 
> This patch fixes incorrect reporting of supported link modes on some NICs.
> 
> Signed-off-by: Filip Sadowski <filip.sadowski@intel.com>
> ---
>   drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h   | 20 ++++++++++++++++++--
>   drivers/net/ethernet/intel/i40e/i40e_common.c       |  8 +++++++-
>   drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 20 ++++++++++++++++++--
>   3 files changed, 43 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> index e2a9ec8..5d0291c 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> @@ -1734,6 +1734,8 @@ enum i40e_aq_phy_type {
>   	I40E_PHY_TYPE_10GBASE_CR1_CU		= 0xB,
>   	I40E_PHY_TYPE_10GBASE_AOC		= 0xC,
>   	I40E_PHY_TYPE_40GBASE_AOC		= 0xD,
> +	I40E_PHY_TYPE_UNRECOGNIZED		= 0xE,
> +	I40E_PHY_TYPE_UNSUPPORTED		= 0xF,
>   	I40E_PHY_TYPE_100BASE_TX		= 0x11,
>   	I40E_PHY_TYPE_1000BASE_T		= 0x12,
>   	I40E_PHY_TYPE_10GBASE_T			= 0x13,
> @@ -1752,6 +1754,8 @@ enum i40e_aq_phy_type {
>   	I40E_PHY_TYPE_25GBASE_CR		= 0x20,
>   	I40E_PHY_TYPE_25GBASE_SR		= 0x21,
>   	I40E_PHY_TYPE_25GBASE_LR		= 0x22,
> +	I40E_PHY_TYPE_EMPTY			= 0xFE,
> +	I40E_PHY_TYPE_DEFAULT			= 0xFF,
>   	I40E_PHY_TYPE_MAX
>   };
>   
> @@ -1942,19 +1946,31 @@ struct i40e_aqc_get_link_status {
>   #define I40E_AQ_25G_SERDES_UCODE_ERR	0X04
>   #define I40E_AQ_25G_NIMB_UCODE_ERR	0X05
>   	u8	loopback; /* use defines from i40e_aqc_set_lb_mode */
> +/* Since firmware API 1.7 loopback field keeps power class info as well */
> +#define I40E_AQ_LOOPBACK_MASK		0x07
> +#define I40E_AQ_PWR_CLASS_SHIFT_LB	6
> +#define I40E_AQ_PWR_CLASS_MASK_LB	(0x03 << I40E_AQ_PWR_CLASS_SHIFT_LB)
>   	__le16	max_frame_size;
>   	u8	config;
>   #define I40E_AQ_CONFIG_FEC_KR_ENA	0x01
>   #define I40E_AQ_CONFIG_FEC_RS_ENA	0x02
>   #define I40E_AQ_CONFIG_CRC_ENA		0x04
>   #define I40E_AQ_CONFIG_PACING_MASK	0x78
> -	u8	power_desc;
> +	union {
> +		struct {
> +			u8	power_desc;
>   #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
>   #define I40E_AQ_PWR_CLASS_MASK		0x03
> -	u8	reserved[4];
> +			u8	reserved[4];
> +		};
> +		struct {
> +			u8	link_type[4];

Wait, is this a 32-bit value on an odd-byte alignment?  No, no, no... we 
worked hard early on to not let the HW folks do this.

> +			u8	link_type_ext;
> +		};
> +	};
>   };
>   
>   I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status);
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
> index e9f30b8..c0aeda7 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_common.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
> @@ -1826,7 +1826,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
>   	hw_link_info->fec_info = resp->config & (I40E_AQ_CONFIG_FEC_KR_ENA |
>   						 I40E_AQ_CONFIG_FEC_RS_ENA);
>   	hw_link_info->ext_info = resp->ext_info;
> -	hw_link_info->loopback = resp->loopback;
> +	hw_link_info->loopback = resp->loopback & I40E_AQ_LOOPBACK_MASK;
>   	hw_link_info->max_frame_size = le16_to_cpu(resp->max_frame_size);
>   	hw_link_info->pacing = resp->config & I40E_AQ_CONFIG_PACING_MASK;
>   
> @@ -1857,6 +1857,12 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
>   	     hw->aq.fw_min_ver < 40)) && hw_link_info->phy_type == 0xE)
>   		hw_link_info->phy_type = I40E_PHY_TYPE_10GBASE_SFPP_CU;
>   
> +	if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
> +	    hw->aq.api_min_ver >= 7) {
> +		hw->phy.phy_types = le32_to_cpu(*(__le32 *)resp->link_type);

Reading a 32-bit word from an odd byte boundary will cause a non-x86 
machine (e.g. SPARC) a bit of heartburn, kernel log messages, and 
possibly a few customer complaints.  You're going to need a memcpy() to 
get it out of the funky memory address, then you can add in the byteswap.

		u32 tmp;
		memcpy(&tmp, &resp->link_type, sizeof(tmp));
		hw->phy.phy_types = le32_to_cpu(tmp);


> +		hw->phy.phy_types |= ((u64)resp->link_type_ext << 32);
> +	}
> +
>   	/* save link status information */
>   	if (link)
>   		*link = *hw_link_info;
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> index f9f48d1..709d114 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> @@ -1730,6 +1730,8 @@ enum i40e_aq_phy_type {
>   	I40E_PHY_TYPE_10GBASE_CR1_CU		= 0xB,
>   	I40E_PHY_TYPE_10GBASE_AOC		= 0xC,
>   	I40E_PHY_TYPE_40GBASE_AOC		= 0xD,
> +	I40E_PHY_TYPE_UNRECOGNIZED		= 0xE,
> +	I40E_PHY_TYPE_UNSUPPORTED		= 0xF,
>   	I40E_PHY_TYPE_100BASE_TX		= 0x11,
>   	I40E_PHY_TYPE_1000BASE_T		= 0x12,
>   	I40E_PHY_TYPE_10GBASE_T			= 0x13,
> @@ -1748,6 +1750,8 @@ enum i40e_aq_phy_type {
>   	I40E_PHY_TYPE_25GBASE_CR		= 0x20,
>   	I40E_PHY_TYPE_25GBASE_SR		= 0x21,
>   	I40E_PHY_TYPE_25GBASE_LR		= 0x22,
> +	I40E_PHY_TYPE_EMPTY			= 0xFE,
> +	I40E_PHY_TYPE_DEFAULT			= 0xFF,
>   	I40E_PHY_TYPE_MAX
>   };
>   
> @@ -1938,19 +1942,31 @@ struct i40e_aqc_get_link_status {
>   #define I40E_AQ_25G_SERDES_UCODE_ERR	0X04
>   #define I40E_AQ_25G_NIMB_UCODE_ERR	0X05
>   	u8	loopback; /* use defines from i40e_aqc_set_lb_mode */
> +/* Since firmware API 1.7 loopback field keeps power class info as well */
> +#define I40E_AQ_LOOPBACK_MASK		0x07
> +#define I40E_AQ_PWR_CLASS_SHIFT_LB	6
> +#define I40E_AQ_PWR_CLASS_MASK_LB	(0x03 << I40E_AQ_PWR_CLASS_SHIFT_LB)
>   	__le16	max_frame_size;
>   	u8	config;
>   #define I40E_AQ_CONFIG_FEC_KR_ENA	0x01
>   #define I40E_AQ_CONFIG_FEC_RS_ENA	0x02
>   #define I40E_AQ_CONFIG_CRC_ENA		0x04
>   #define I40E_AQ_CONFIG_PACING_MASK	0x78
> -	u8	power_desc;
> +	union {
> +		struct {
> +			u8	power_desc;
>   #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
>   #define I40E_AQ_PWR_CLASS_MASK		0x03
> -	u8	reserved[4];
> +			u8	reserved[4];
> +		};
> +		struct {
> +			u8	link_type[4];
> +			u8	link_type_ext;
> +		};
> +	};
>   };
>   
>   I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status);
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 03/12] i40e: Add support for 'ethtool -m'
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 03/12] i40e: Add support for 'ethtool -m' Alice Michael
@ 2017-08-07 17:19   ` Shannon Nelson
  0 siblings, 0 replies; 19+ messages in thread
From: Shannon Nelson @ 2017-08-07 17:19 UTC (permalink / raw)
  To: intel-wired-lan

On 8/4/2017 6:52 AM, Alice Michael wrote:
> From: Filip Sadowski <filip.sadowski@intel.com>
> 
> This patch adds support for 'ethtool -m' command which displays
> information about (Q)SFP+ module plugged into NIC's cage.
> 
> Signed-off-by: Filip Sadowski <filip.sadowski@intel.com>
> ---
>   drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |  18 +++
>   drivers/net/ethernet/intel/i40e/i40e_common.c      |  69 +++++++++
>   drivers/net/ethernet/intel/i40e/i40e_ethtool.c     | 154 +++++++++++++++++++++
>   drivers/net/ethernet/intel/i40e/i40e_prototype.h   |   9 ++
>   drivers/net/ethernet/intel/i40e/i40e_type.h        |  12 ++
>   .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |  18 +++
>   drivers/net/ethernet/intel/i40evf/i40e_common.c    |  69 +++++++++
>   drivers/net/ethernet/intel/i40evf/i40e_prototype.h |   9 ++
>   drivers/net/ethernet/intel/i40evf/i40e_type.h      |  12 ++
>   9 files changed, 370 insertions(+)
> 
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> index 5d0291c..8fcbbd8 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
> @@ -244,6 +244,8 @@ enum i40e_admin_queue_opc {
>   	i40e_aqc_opc_set_phy_debug		= 0x0622,
>   	i40e_aqc_opc_upload_ext_phy_fm		= 0x0625,
>   	i40e_aqc_opc_run_phy_activity		= 0x0626,
> +	i40e_aqc_opc_set_phy_register		= 0x0628,
> +	i40e_aqc_opc_get_phy_register		= 0x0629,
>   
>   	/* NVM commands */
>   	i40e_aqc_opc_nvm_read			= 0x0701,
> @@ -2053,6 +2055,22 @@ struct i40e_aqc_run_phy_activity {
>   
>   I40E_CHECK_CMD_LENGTH(i40e_aqc_run_phy_activity);
>   
> +/* Set PHY Register command (0x0628) */
> +/* Get PHY Register command (0x0629) */
> +struct i40e_aqc_phy_register_access {
> +	u8	phy_interface;
> +#define I40E_AQ_PHY_REG_ACCESS_INTERNAL	0
> +#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL	1
> +#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE	2
> +	u8	dev_address;
> +	u8	reserved1[2];
> +	u32	reg_address;
> +	u32	reg_value;
> +	u8	reserved2[4];
> +};
> +
> +I40E_CHECK_CMD_LENGTH(i40e_aqc_phy_register_access);
> +
>   /* NVM Read command (indirect 0x0701)
>    * NVM Erase commands (direct 0x0702)
>    * NVM Update commands (indirect 0x0703)
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
> index c0aeda7..6b7712c 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_common.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
> @@ -5143,6 +5143,75 @@ void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
>   }
>   
>   /**
> + * i40e_aq_set_phy_register
> + * @hw: pointer to the hw struct
> + * @phy_select: select which phy should be accessed
> + * @dev_addr: PHY device address
> + * @reg_addr: PHY register address
> + * @reg_val: new register value
> + * @cmd_details: pointer to command details structure or NULL
> + *
> + * Write the external PHY register.
> + **/
> +i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
> +				     u8 phy_select, u8 dev_addr,
> +				     u32 reg_addr, u32 reg_val,
> +				     struct i40e_asq_cmd_details *cmd_details)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_phy_register_access *cmd =
> +		(struct i40e_aqc_phy_register_access *)&desc.params.raw;
> +	i40e_status status;
> +
> +	i40e_fill_default_direct_cmd_desc(&desc,
> +					  i40e_aqc_opc_set_phy_register);
> +
> +	cmd->phy_interface = phy_select;
> +	cmd->dev_address = dev_addr;
> +	cmd->reg_address = reg_addr;
> +	cmd->reg_value = reg_val;

Byteswapping?

> +
> +	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
> +
> +	return status;
> +}
> +
> +/**
> + * i40e_aq_get_phy_register
> + * @hw: pointer to the hw struct
> + * @phy_select: select which phy should be accessed
> + * @dev_addr: PHY device address
> + * @reg_addr: PHY register address
> + * @reg_val: read register value
> + * @cmd_details: pointer to command details structure or NULL
> + *
> + * Read the external PHY register.
> + **/
> +i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw,
> +				     u8 phy_select, u8 dev_addr,
> +				     u32 reg_addr, u32 *reg_val,
> +				     struct i40e_asq_cmd_details *cmd_details)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_phy_register_access *cmd =
> +		(struct i40e_aqc_phy_register_access *)&desc.params.raw;
> +	i40e_status status;
> +
> +	i40e_fill_default_direct_cmd_desc(&desc,
> +					  i40e_aqc_opc_get_phy_register);
> +
> +	cmd->phy_interface = phy_select;
> +	cmd->dev_address = dev_addr;
> +	cmd->reg_address = reg_addr;

Byteswapping?

> +
> +	status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
> +	if (!status)
> +		*reg_val = cmd->reg_value;

Byteswapping?

> +
> +	return status;
> +}
> +
> +/**
>    * i40e_aq_write_ppp - Write pipeline personalization profile (ppp)
>    * @hw: pointer to the hw struct
>    * @buff: command buffer (size in bytes = buff_size)
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
> index 326fc18..72910c5 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
> +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
> @@ -4202,6 +4202,158 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags)
>   	return 0;
>   }
>   
> +/**
> + * i40e_get_module_info - get (Q)SFP+ module type info
> + * @netdev: network interface device structure
> + * @modinfo: module EEPROM size and layout information structure
> + **/
> +static int i40e_get_module_info(struct net_device *netdev,
> +				struct ethtool_modinfo *modinfo)
> +{
> +	i40e_status status;
> +	struct i40e_netdev_priv *np = netdev_priv(netdev);
> +	struct i40e_vsi *vsi = np->vsi;
> +	struct i40e_pf *pf = vsi->back;
> +	struct i40e_hw *hw = &pf->hw;
> +	u32 sff8472_comp = 0;
> +	u32 sff8472_swap = 0;
> +	u32 sff8636_rev = 0;
> +	u32 type = 0;
> +
> +	/* Check if firmware supports reading module EEPROM. */
> +	if (!(hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE)) {
> +		netdev_err(vsi->netdev, "Module EEPROM memory read not supported. Please update the NVM image.\n");
> +		return -EINVAL;
> +	}
> +
> +	status = i40e_update_link_info(hw);
> +	if (status)
> +		return -EIO;
> +
> +	if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_EMPTY) {
> +		netdev_err(vsi->netdev, "Cannot read module EEPROM memory. No module connected.\n");
> +		return -EINVAL;
> +	}
> +
> +	type = hw->phy.link_info.module_type[0];
> +
> +	switch (type) {
> +	case I40E_MODULE_TYPE_SFP:
> +		status = i40e_aq_get_phy_register(hw,
> +				I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
> +				I40E_I2C_EEPROM_DEV_ADDR,
> +				I40E_MODULE_SFF_8472_COMP,
> +				&sff8472_comp, NULL);
> +		if (status)
> +			return -EIO;
> +
> +		status = i40e_aq_get_phy_register(hw,
> +				I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
> +				I40E_I2C_EEPROM_DEV_ADDR,
> +				I40E_MODULE_SFF_8472_SWAP,
> +				&sff8472_swap, NULL);
> +		if (status)
> +			return -EIO;
> +
> +		/* Check if the module requires address swap to access
> +		 * the other EEPROM memory page.
> +		 */
> +		if (sff8472_swap & I40E_MODULE_SFF_ADDR_MODE) {
> +			netdev_warn(vsi->netdev, "Module address swap to access page 0xA2 is not supported.\n");
> +			modinfo->type = ETH_MODULE_SFF_8079;
> +			modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
> +		} else if (sff8472_comp == 0x00) {
> +			/* Module is not SFF-8472 compliant */
> +			modinfo->type = ETH_MODULE_SFF_8079;
> +			modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
> +		} else {
> +			modinfo->type = ETH_MODULE_SFF_8472;
> +			modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
> +		}
> +		break;
> +	case I40E_MODULE_TYPE_QSFP_PLUS:
> +		/* Read from memory page 0. */
> +		status = i40e_aq_get_phy_register(hw,
> +				I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
> +				0,
> +				I40E_MODULE_REVISION_ADDR,
> +				&sff8636_rev, NULL);
> +		if (status)
> +			return -EIO;
> +		/* Determine revision compliance byte */
> +		if (sff8636_rev > 0x02) {
> +			/* Module is SFF-8636 compliant */
> +			modinfo->type = ETH_MODULE_SFF_8636;
> +			modinfo->eeprom_len = I40E_MODULE_QSFP_MAX_LEN;
> +		} else {
> +			modinfo->type = ETH_MODULE_SFF_8436;
> +			modinfo->eeprom_len = I40E_MODULE_QSFP_MAX_LEN;
> +		}
> +		break;
> +	case I40E_MODULE_TYPE_QSFP28:
> +		modinfo->type = ETH_MODULE_SFF_8636;
> +		modinfo->eeprom_len = I40E_MODULE_QSFP_MAX_LEN;
> +		break;
> +	default:
> +		netdev_err(vsi->netdev, "Module type unrecognized\n");
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +/**
> + * i40e_get_module_eeprom - fills buffer with (Q)SFP+ module memory contents
> + * @netdev: network interface device structure
> + * @ee: EEPROM dump request structure
> + * @data: buffer to be filled with EEPROM contents
> + **/
> +static int i40e_get_module_eeprom(struct net_device *netdev,
> +				  struct ethtool_eeprom *ee,
> +				  u8 *data)
> +{
> +	i40e_status status;
> +	struct i40e_netdev_priv *np = netdev_priv(netdev);
> +	struct i40e_vsi *vsi = np->vsi;
> +	struct i40e_pf *pf = vsi->back;
> +	struct i40e_hw *hw = &pf->hw;
> +	bool is_sfp = false;
> +	u32 value = 0;
> +	int i;
> +
> +	if (!ee || !ee->len || !data)
> +		return -EINVAL;
> +
> +	if (hw->phy.link_info.module_type[0] == I40E_MODULE_TYPE_SFP)
> +		is_sfp = true;
> +
> +	for (i = 0; i < ee->len; i++) {
> +		u32 offset = i + ee->offset;
> +		u32 addr = is_sfp ? I40E_I2C_EEPROM_DEV_ADDR : 0;
> +
> +		/* Check if we need to access the other memory page */
> +		if (is_sfp) {
> +			if (offset >= ETH_MODULE_SFF_8079_LEN) {
> +				offset -= ETH_MODULE_SFF_8079_LEN;
> +				addr = I40E_I2C_EEPROM_DEV_ADDR2;
> +			}
> +		} else {
> +			while (offset >= ETH_MODULE_SFF_8436_LEN) {
> +				/* Compute memory page number and offset. */
> +				offset -= ETH_MODULE_SFF_8436_LEN / 2;
> +				addr++;
> +			}
> +		}
> +
> +		status = i40e_aq_get_phy_register(hw,
> +				I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
> +				addr, offset, &value, NULL);
> +		if (status)
> +			return -EIO;
> +		data[i] = value;
> +	}
> +	return 0;
> +}
> +
>   static const struct ethtool_ops i40e_ethtool_ops = {
>   	.get_drvinfo		= i40e_get_drvinfo,
>   	.get_regs_len		= i40e_get_regs_len,
> @@ -4234,6 +4386,8 @@ static const struct ethtool_ops i40e_ethtool_ops = {
>   	.set_rxfh		= i40e_set_rxfh,
>   	.get_channels		= i40e_get_channels,
>   	.set_channels		= i40e_set_channels,
> +	.get_module_info	= i40e_get_module_info,
> +	.get_module_eeprom	= i40e_get_module_eeprom,
>   	.get_ts_info		= i40e_get_ts_info,
>   	.get_priv_flags		= i40e_get_priv_flags,
>   	.set_priv_flags		= i40e_set_priv_flags,
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> index df613ea..6254ad5 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
> @@ -362,6 +362,15 @@ i40e_status i40e_aq_rx_ctl_write_register(struct i40e_hw *hw,
>   				u32 reg_addr, u32 reg_val,
>   				struct i40e_asq_cmd_details *cmd_details);
>   void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val);
> +i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
> +				     u8 phy_select, u8 dev_addr,
> +				     u32 reg_addr, u32 reg_val,
> +				     struct i40e_asq_cmd_details *cmd_details);
> +i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw,
> +				     u8 phy_select, u8 dev_addr,
> +				     u32 reg_addr, u32 *reg_val,
> +				     struct i40e_asq_cmd_details *cmd_details);
> +
>   i40e_status i40e_read_phy_register_clause22(struct i40e_hw *hw,
>   					    u16 reg, u8 phy_addr, u16 *value);
>   i40e_status i40e_write_phy_register_clause22(struct i40e_hw *hw,
> diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
> index 78fda11..8b0b9f8 100644
> --- a/drivers/net/ethernet/intel/i40e/i40e_type.h
> +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
> @@ -428,6 +428,18 @@ struct i40e_nvm_access {
>   	u8 data[1];
>   };
>   
> +/* (Q)SFP module access definitions */
> +#define I40E_I2C_EEPROM_DEV_ADDR	0xA0
> +#define I40E_I2C_EEPROM_DEV_ADDR2	0xA2
> +#define I40E_MODULE_TYPE_ADDR		0x00
> +#define I40E_MODULE_REVISION_ADDR	0x01
> +#define I40E_MODULE_SFF_8472_COMP	0x5E
> +#define I40E_MODULE_SFF_8472_SWAP	0x5C
> +#define I40E_MODULE_SFF_ADDR_MODE	0x04
> +#define I40E_MODULE_TYPE_QSFP_PLUS	0x0D
> +#define I40E_MODULE_TYPE_QSFP28		0x11
> +#define I40E_MODULE_QSFP_MAX_LEN	640
> +
>   /* PCI bus types */
>   enum i40e_bus_type {
>   	i40e_bus_type_unknown = 0,
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> index 709d114..b7715d4 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
> @@ -244,6 +244,8 @@ enum i40e_admin_queue_opc {
>   	i40e_aqc_opc_set_phy_debug		= 0x0622,
>   	i40e_aqc_opc_upload_ext_phy_fm		= 0x0625,
>   	i40e_aqc_opc_run_phy_activity		= 0x0626,
> +	i40e_aqc_opc_set_phy_register		= 0x0628,
> +	i40e_aqc_opc_get_phy_register		= 0x0629,
>   
>   	/* NVM commands */
>   	i40e_aqc_opc_nvm_read			= 0x0701,
> @@ -2046,6 +2048,22 @@ struct i40e_aqc_run_phy_activity {
>   
>   I40E_CHECK_CMD_LENGTH(i40e_aqc_run_phy_activity);
>   
> +/* Set PHY Register command (0x0628) */
> +/* Get PHY Register command (0x0629) */
> +struct i40e_aqc_phy_register_access {
> +	u8	phy_interface;
> +#define I40E_AQ_PHY_REG_ACCESS_INTERNAL	0
> +#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL	1
> +#define I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE	2
> +	u8	dev_address;
> +	u8	reserved1[2];
> +	u32	reg_address;
> +	u32	reg_value;
> +	u8	reserved2[4];
> +};
> +
> +I40E_CHECK_CMD_LENGTH(i40e_aqc_phy_register_access);
> +
>   /* NVM Read command (indirect 0x0701)
>    * NVM Erase commands (direct 0x0702)
>    * NVM Update commands (indirect 0x0703)
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c
> index 8d3a2bf..7df4610 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c
> @@ -1042,6 +1042,75 @@ void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val)
>   }
>   
>   /**
> + * i40evf_aq_set_phy_register
> + * @hw: pointer to the hw struct
> + * @phy_select: select which phy should be accessed
> + * @dev_addr: PHY device address
> + * @reg_addr: PHY register address
> + * @reg_val: new register value
> + * @cmd_details: pointer to command details structure or NULL
> + *
> + * Reset the external PHY.
> + **/
> +i40e_status i40evf_aq_set_phy_register(struct i40e_hw *hw,
> +				       u8 phy_select, u8 dev_addr,
> +				       u32 reg_addr, u32 reg_val,
> +				       struct i40e_asq_cmd_details *cmd_details)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_phy_register_access *cmd =
> +		(struct i40e_aqc_phy_register_access *)&desc.params.raw;
> +	i40e_status status;
> +
> +	i40evf_fill_default_direct_cmd_desc(&desc,
> +					    i40e_aqc_opc_set_phy_register);
> +
> +	cmd->phy_interface = phy_select;
> +	cmd->dev_address = dev_addr;
> +	cmd->reg_address = reg_addr;
> +	cmd->reg_value = reg_val;

Same byteswapping comments...


> +
> +	status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details);
> +
> +	return status;
> +}
> +
> +/**
> + * i40evf_aq_get_phy_register
> + * @hw: pointer to the hw struct
> + * @phy_select: select which phy should be accessed
> + * @dev_addr: PHY device address
> + * @reg_addr: PHY register address
> + * @reg_val: read register value
> + * @cmd_details: pointer to command details structure or NULL
> + *
> + * Reset the external PHY.
> + **/
> +i40e_status i40evf_aq_get_phy_register(struct i40e_hw *hw,
> +				       u8 phy_select, u8 dev_addr,
> +				       u32 reg_addr, u32 *reg_val,
> +				       struct i40e_asq_cmd_details *cmd_details)
> +{
> +	struct i40e_aq_desc desc;
> +	struct i40e_aqc_phy_register_access *cmd =
> +		(struct i40e_aqc_phy_register_access *)&desc.params.raw;
> +	i40e_status status;
> +
> +	i40evf_fill_default_direct_cmd_desc(&desc,
> +					    i40e_aqc_opc_get_phy_register);
> +
> +	cmd->phy_interface = phy_select;
> +	cmd->dev_address = dev_addr;
> +	cmd->reg_address = reg_addr;
> +
> +	status = i40evf_asq_send_command(hw, &desc, NULL, 0, cmd_details);
> +	if (!status)
> +		*reg_val = cmd->reg_value;
> +
> +	return status;
> +}
> +
> +/**
>    * i40e_aq_send_msg_to_pf
>    * @hw: pointer to the hardware structure
>    * @v_opcode: opcodes for VF-PF communication
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
> index c9836bb..b624b59 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h
> @@ -111,6 +111,15 @@ i40e_status i40evf_aq_rx_ctl_write_register(struct i40e_hw *hw,
>   				u32 reg_addr, u32 reg_val,
>   				struct i40e_asq_cmd_details *cmd_details);
>   void i40evf_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val);
> +i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
> +				     u8 phy_select, u8 dev_addr,
> +				     u32 reg_addr, u32 reg_val,
> +				     struct i40e_asq_cmd_details *cmd_details);
> +i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw,
> +				     u8 phy_select, u8 dev_addr,
> +				     u32 reg_addr, u32 *reg_val,
> +				     struct i40e_asq_cmd_details *cmd_details);
> +
>   i40e_status i40e_read_phy_register(struct i40e_hw *hw, u8 page,
>   				   u16 reg, u8 phy_addr, u16 *value);
>   i40e_status i40e_write_phy_register(struct i40e_hw *hw, u8 page,
> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h
> index 412a32c..48eacf5 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h
> +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h
> @@ -401,6 +401,18 @@ struct i40e_nvm_access {
>   	u8 data[1];
>   };
>   
> +/* (Q)SFP module access definitions */
> +#define I40E_I2C_EEPROM_DEV_ADDR	0xA0
> +#define I40E_I2C_EEPROM_DEV_ADDR2	0xA2
> +#define I40E_MODULE_TYPE_ADDR		0x00
> +#define I40E_MODULE_REVISION_ADDR	0x01
> +#define I40E_MODULE_SFF_8472_COMP	0x5E
> +#define I40E_MODULE_SFF_8472_SWAP	0x5C
> +#define I40E_MODULE_SFF_ADDR_MODE	0x04
> +#define I40E_MODULE_TYPE_QSFP_PLUS	0x0D
> +#define I40E_MODULE_TYPE_QSFP28		0x11
> +#define I40E_MODULE_QSFP_MAX_LEN	640
> +
>   /* PCI bus types */
>   enum i40e_bus_type {
>   	i40e_bus_type_unknown = 0,
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 08/12] i40evf: Enable VF to request an alternate queue allocation
  2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 08/12] i40evf: Enable VF to request an alternate queue allocation Alice Michael
@ 2017-08-07 17:19   ` Shannon Nelson
  2017-08-07 17:31     ` Brady, Alan
  0 siblings, 1 reply; 19+ messages in thread
From: Shannon Nelson @ 2017-08-07 17:19 UTC (permalink / raw)
  To: intel-wired-lan

On 8/4/2017 6:52 AM, Alice Michael wrote:
> From: Alan Brady <alan.brady@intel.com>
> 
> Currently the VF gets a default number of allocated queues from HW on
> init and it could choose to enable or disable those allocated queues.
> This makes it such that the VF can request more or less underlying
> allocated queues from the PF.
> 
> First the VF negotiates the number of queues it wants that can be
> supported by the PF and if successful asks for a reset.  During reset
> the PF will reallocate the HW queues for the VF and will then remap the
> new queues.
> 
> Signed-off-by: Alan Brady <alan.brady@intel.com>
> ---
>   drivers/net/ethernet/intel/i40evf/i40evf.h         |  4 +
>   drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | 38 ++++++++-
>   drivers/net/ethernet/intel/i40evf/i40evf_main.c    | 94 ++++++++++++++++++++--
>   .../net/ethernet/intel/i40evf/i40evf_virtchnl.c    | 44 +++++++++-
>   4 files changed, 173 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h
> index a1af9b1..de0af52 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40evf.h
> +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h
> @@ -102,6 +102,7 @@ struct i40e_vsi {
>   #define I40E_TX_CTXTDESC(R, i) \
>   	(&(((struct i40e_tx_context_desc *)((R)->desc))[i]))
>   #define MAX_QUEUES 16
> +#define I40EVF_MAX_REQ_QUEUES 4

Why can you only request 4 queues if a VF can have up to 16 queues?

>   
>   #define I40EVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4)
>   #define I40EVF_HLUT_ARRAY_SIZE ((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4)
> @@ -200,6 +201,7 @@ struct i40evf_adapter {
>   	struct list_head vlan_filter_list;
>   	char misc_vector_name[IFNAMSIZ + 9];
>   	int num_active_queues;
> +	int num_req_queues;
>   
>   	/* TX */
>   	struct i40e_ring *tx_rings;
> @@ -235,6 +237,7 @@ struct i40evf_adapter {
>   #define I40EVF_FLAG_PROMISC_ON			BIT(13)
>   #define I40EVF_FLAG_ALLMULTI_ON			BIT(14)
>   #define I40EVF_FLAG_LEGACY_RX			BIT(15)
> +#define I40EVF_FLAG_REINIT_ITR_NEEDED		BIT(16)
>   /* duplicates for common code */
>   #define I40E_FLAG_DCB_ENABLED			0
>   #define I40E_FLAG_RX_CSUM_ENABLED		I40EVF_FLAG_RX_CSUM_ENABLED
> @@ -349,6 +352,7 @@ void i40evf_deconfigure_queues(struct i40evf_adapter *adapter);
>   void i40evf_enable_queues(struct i40evf_adapter *adapter);
>   void i40evf_disable_queues(struct i40evf_adapter *adapter);
>   void i40evf_map_queues(struct i40evf_adapter *adapter);
> +int i40evf_request_queues(struct i40evf_adapter *adapter, int num);
>   void i40evf_add_ether_addrs(struct i40evf_adapter *adapter);
>   void i40evf_del_ether_addrs(struct i40evf_adapter *adapter);
>   void i40evf_add_vlans(struct i40evf_adapter *adapter);
> diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
> index 65874d6..da006fa 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
> +++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c
> @@ -669,7 +669,7 @@ static void i40evf_get_channels(struct net_device *netdev,
>   	struct i40evf_adapter *adapter = netdev_priv(netdev);
>   
>   	/* Report maximum channels */
> -	ch->max_combined = adapter->num_active_queues;
> +	ch->max_combined = I40EVF_MAX_REQ_QUEUES;
>   
>   	ch->max_other = NONQ_VECS;
>   	ch->other_count = NONQ_VECS;
> @@ -678,6 +678,41 @@ static void i40evf_get_channels(struct net_device *netdev,
>   }
>   
>   /**
> + * i40evf_set_channels: set the new channel count
> + * @netdev: network interface device structure
> + * @ch: channel information structure
> + *
> + * Negotiate a new number of channels with the PF then do a reset.  During
> + * reset we'll realloc queues and fix the RSS table.  Returns 0 on success,
> + * negative on failure.
> + **/
> +static int i40evf_set_channels(struct net_device *netdev,
> +			       struct ethtool_channels *ch)
> +{
> +	struct i40evf_adapter *adapter = netdev_priv(netdev);
> +	int num_req = ch->combined_count;
> +
> +	if (num_req != adapter->num_active_queues &&
> +	    !(adapter->vf_res->vf_cap_flags &
> +	      VIRTCHNL_VF_OFFLOAD_REQ_QUEUES)) {
> +		dev_info(&adapter->pdev->dev, "PF is not capable of queue negotiation.\n");
> +		return -EINVAL;
> +	}
> +
> +	/* All of these should have already been checked by ethtool before this
> +	 * even gets to us, but just to be sure.
> +	 */
> +	if (num_req <= 0 || num_req > I40EVF_MAX_REQ_QUEUES)
> +		return -EINVAL;
> +
> +	if (ch->rx_count || ch->tx_count || ch->other_count != NONQ_VECS)
> +		return -EINVAL;
> +
> +	adapter->num_req_queues = num_req;
> +	return i40evf_request_queues(adapter, num_req);
> +}
> +
> +/**
>    * i40evf_get_rxfh_key_size - get the RSS hash key size
>    * @netdev: network interface device structure
>    *
> @@ -785,6 +820,7 @@ static const struct ethtool_ops i40evf_ethtool_ops = {
>   	.get_rxfh		= i40evf_get_rxfh,
>   	.set_rxfh		= i40evf_set_rxfh,
>   	.get_channels		= i40evf_get_channels,
> +	.set_channels		= i40evf_set_channels,
>   	.get_rxfh_key_size	= i40evf_get_rxfh_key_size,
>   	.get_link_ksettings	= i40evf_get_link_ksettings,
>   };
> diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
> index a216fd2..a803c6b 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
> +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
> @@ -1189,9 +1189,18 @@ static int i40evf_alloc_queues(struct i40evf_adapter *adapter)
>   {
>   	int i, num_active_queues;
>   
> -	num_active_queues = min_t(int,
> -				  adapter->vsi_res->num_queue_pairs,
> -				  (int)(num_online_cpus()));
> +	/* If we're in reset reallocating queues we don't actually know yet for
> +	 * certain the PF gave us the number of queues we asked for but we'll
> +	 * assume it did.  Once basic reset is finished we'll confirm once we
> +	 * start negotiating config with PF.
> +	 */
> +	if (adapter->num_req_queues)
> +		num_active_queues = adapter->num_req_queues;
> +	else
> +		num_active_queues = min_t(int,
> +					  adapter->vsi_res->num_queue_pairs,
> +					  (int)(num_online_cpus()));
> +
>   
>   	adapter->tx_rings = kcalloc(num_active_queues,
>   				    sizeof(struct i40e_ring), GFP_KERNEL);
> @@ -1540,6 +1549,48 @@ static void i40evf_free_rss(struct i40evf_adapter *adapter)
>   }
>   
>   /**
> + * i40evf_reinit_interrupt_scheme - Reallocate queues and vectors
> + * @adapter: board private structure
> + *
> + * Returns 0 on success, negative on failure
> + **/
> +static int i40evf_reinit_interrupt_scheme(struct i40evf_adapter *adapter)
> +{
> +	struct net_device *netdev = adapter->netdev;
> +	int err;
> +
> +	if (netif_running(netdev))
> +		i40evf_free_traffic_irqs(adapter);
> +	i40evf_free_misc_irq(adapter);
> +	i40evf_reset_interrupt_capability(adapter);
> +	i40evf_free_q_vectors(adapter);
> +	i40evf_free_queues(adapter);
> +
> +	err =  i40evf_init_interrupt_scheme(adapter);
> +	if (err)
> +		goto err;
> +
> +	netif_tx_stop_all_queues(netdev);
> +
> +	err = i40evf_request_misc_irq(adapter);
> +	if (err)
> +		goto err;
> +
> +	set_bit(__I40E_VSI_DOWN, adapter->vsi.state);
> +
> +	err = i40evf_map_rings_to_vectors(adapter);
> +	if (err)
> +		goto err;
> +
> +	if (RSS_AQ(adapter))
> +		adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_RSS;
> +	else
> +		err = i40evf_init_rss(adapter);
> +err:
> +	return err;
> +}
> +
> +/**
>    * i40evf_watchdog_timer - Periodic call-back timer
>    * @data: pointer to adapter disguised as unsigned long
>    **/
> @@ -1885,8 +1936,15 @@ static void i40evf_reset_task(struct work_struct *work)
>   	if (err)
>   		dev_info(&adapter->pdev->dev, "Failed to init adminq: %d\n",
>   			 err);
> +	adapter->aq_required = 0;
>   
> -	adapter->aq_required = I40EVF_FLAG_AQ_GET_CONFIG;
> +	if (adapter->flags & I40EVF_FLAG_REINIT_ITR_NEEDED) {
> +		err = i40evf_reinit_interrupt_scheme(adapter);
> +		if (err)
> +			goto reset_err;
> +	}
> +
> +	adapter->aq_required |= I40EVF_FLAG_AQ_GET_CONFIG;
>   	adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS;
>   
>   	/* re-add all MAC filters */
> @@ -1916,6 +1974,15 @@ static void i40evf_reset_task(struct work_struct *work)
>   		if (err)
>   			goto reset_err;
>   
> +		if (adapter->flags & I40EVF_FLAG_REINIT_ITR_NEEDED) {
> +			err = i40evf_request_traffic_irqs(adapter,
> +							  netdev->name);
> +			if (err)
> +				goto reset_err;
> +
> +			adapter->flags &= ~I40EVF_FLAG_REINIT_ITR_NEEDED;
> +		}
> +
>   		i40evf_configure(adapter);
>   
>   		i40evf_up_complete(adapter);
> @@ -2432,9 +2499,9 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw)
>   int i40evf_process_config(struct i40evf_adapter *adapter)
>   {
>   	struct virtchnl_vf_resource *vfres = adapter->vf_res;
> +	int i, num_req_queues = adapter->num_req_queues;
>   	struct net_device *netdev = adapter->netdev;
>   	struct i40e_vsi *vsi = &adapter->vsi;
> -	int i;
>   	netdev_features_t hw_enc_features;
>   	netdev_features_t hw_features;
>   
> @@ -2448,6 +2515,23 @@ int i40evf_process_config(struct i40evf_adapter *adapter)
>   		return -ENODEV;
>   	}
>   
> +	if (num_req_queues &&
> +	    num_req_queues != adapter->vsi_res->num_queue_pairs) {
> +		/* Problem.  The PF gave us fewer queues than what we had
> +		 * negotiated in our request.  Need a reset to see if we can't
> +		 * get back to a working state.
> +		 */
> +		dev_err(&adapter->pdev->dev,
> +			"Requested %d queues, but PF only gave us %d.\n",
> +			num_req_queues,
> +			adapter->vsi_res->num_queue_pairs);
> +		adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
> +		adapter->num_req_queues = adapter->vsi_res->num_queue_pairs;
> +		i40evf_schedule_reset(adapter);
> +		return -ENODEV;
> +	}
> +	adapter->num_req_queues = 0;
> +
>   	hw_enc_features = NETIF_F_SG			|
>   			  NETIF_F_IP_CSUM		|
>   			  NETIF_F_IPV6_CSUM		|
> diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
> index 2bb0fe0..2bb81c3 100644
> --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
> +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
> @@ -160,7 +160,8 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter)
>   	       VIRTCHNL_VF_OFFLOAD_WB_ON_ITR |
>   	       VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2 |
>   	       VIRTCHNL_VF_OFFLOAD_ENCAP |
> -	       VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM;
> +	       VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM |
> +	       VIRTCHNL_VF_OFFLOAD_REQ_QUEUES;
>   
>   	adapter->current_op = VIRTCHNL_OP_GET_VF_RESOURCES;
>   	adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG;
> @@ -385,6 +386,32 @@ void i40evf_map_queues(struct i40evf_adapter *adapter)
>   }
>   
>   /**
> + * i40evf_request_queues
> + * @adapter: adapter structure
> + * @num: number of requested queues
> + *
> + * We get a default number of queues from the PF.  This enables us to request a
> + * different number.  Returns 0 on success, negative on failure
> + **/
> +int i40evf_request_queues(struct i40evf_adapter *adapter, int num)
> +{
> +	struct virtchnl_vf_res_request vfres;
> +
> +	if (adapter->current_op != VIRTCHNL_OP_UNKNOWN) {
> +		/* bail because we already have a command pending */
> +		dev_err(&adapter->pdev->dev, "Cannot request queues, command %d pending\n",
> +			adapter->current_op);
> +		return -EBUSY;
> +	}
> +
> +	vfres.num_queue_pairs = num;
> +
> +	adapter->current_op = VIRTCHNL_OP_REQUEST_QUEUES;
> +	return i40evf_send_pf_msg(adapter, VIRTCHNL_OP_REQUEST_QUEUES,
> +				  (u8 *)&vfres, sizeof(vfres));
> +}
> +
> +/**
>    * i40evf_add_ether_addrs
>    * @adapter: adapter structure
>    * @addrs: the MAC address filters to add (contiguous)
> @@ -1068,6 +1095,21 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
>   				 "Invalid message %d from PF\n", v_opcode);
>   		}
>   		break;
> +	case VIRTCHNL_OP_REQUEST_QUEUES: {
> +		struct virtchnl_vf_res_request *vfres =
> +			(struct virtchnl_vf_res_request *)msg;
> +		if (vfres->num_queue_pairs == adapter->num_req_queues) {
> +			adapter->flags |= I40EVF_FLAG_REINIT_ITR_NEEDED;
> +			i40evf_schedule_reset(adapter);
> +		} else {
> +			dev_info(&adapter->pdev->dev,
> +				 "Requested %d queues, PF can support %d\n",
> +				 adapter->num_req_queues,
> +				 vfres->num_queue_pairs);
> +			adapter->num_req_queues = 0;
> +		}
> +		}
> +		break;
>   	default:
>   		if (adapter->current_op && (v_opcode != adapter->current_op))
>   			dev_warn(&adapter->pdev->dev, "Expected response %d from PF, received %d\n",
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 08/12] i40evf: Enable VF to request an alternate queue allocation
  2017-08-07 17:19   ` Shannon Nelson
@ 2017-08-07 17:31     ` Brady, Alan
  2017-08-07 17:40       ` Shannon Nelson
  0 siblings, 1 reply; 19+ messages in thread
From: Brady, Alan @ 2017-08-07 17:31 UTC (permalink / raw)
  To: intel-wired-lan

> -----Original Message-----
> From: Intel-wired-lan [mailto:intel-wired-lan-bounces at osuosl.org] On Behalf Of
> Shannon Nelson
> Sent: Monday, August 7, 2017 10:19 AM
> To: Michael, Alice <alice.michael@intel.com>; intel-wired-lan at lists.osuosl.org
> Subject: Re: [Intel-wired-lan] [next PATCH S78-V4 08/12] i40evf: Enable VF to
> request an alternate queue allocation
> 
> On 8/4/2017 6:52 AM, Alice Michael wrote:
> > From: Alan Brady <alan.brady@intel.com>
> >
> > Currently the VF gets a default number of allocated queues from HW on
> > init and it could choose to enable or disable those allocated queues.
> > This makes it such that the VF can request more or less underlying
> > allocated queues from the PF.
> >
> > First the VF negotiates the number of queues it wants that can be
> > supported by the PF and if successful asks for a reset.  During reset
> > the PF will reallocate the HW queues for the VF and will then remap
> > the new queues.
> >
> > Signed-off-by: Alan Brady <alan.brady@intel.com>
> > ---
> >   drivers/net/ethernet/intel/i40evf/i40evf.h         |  4 +
> >   drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | 38 ++++++++-
> >   drivers/net/ethernet/intel/i40evf/i40evf_main.c    | 94
> ++++++++++++++++++++--
> >   .../net/ethernet/intel/i40evf/i40evf_virtchnl.c    | 44 +++++++++-
> >   4 files changed, 173 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h
> > b/drivers/net/ethernet/intel/i40evf/i40evf.h
> > index a1af9b1..de0af52 100644
> > --- a/drivers/net/ethernet/intel/i40evf/i40evf.h
> > +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h
> > @@ -102,6 +102,7 @@ struct i40e_vsi {
> >   #define I40E_TX_CTXTDESC(R, i) \
> >   	(&(((struct i40e_tx_context_desc *)((R)->desc))[i]))
> >   #define MAX_QUEUES 16
> > +#define I40EVF_MAX_REQ_QUEUES 4
> 
> Why can you only request 4 queues if a VF can have up to 16 queues?
> 

Hey Shannon,

Thanks for the feedback.  So the differentiation here comes down to vectors.  The hardware can support up to 16 queues for a VF, but currently we're limited to 4 traffic vectors (+1 misc vector).  So we want to limit the user's ability to request more queues than that as it provides no benefit to have more queues than vectors with just RSS.  However, there are other features which can use more than 4 queues and the differentiation should become clearer with future patches.

> [...]

-ATB

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [Intel-wired-lan] [next PATCH S78-V4 08/12] i40evf: Enable VF to request an alternate queue allocation
  2017-08-07 17:31     ` Brady, Alan
@ 2017-08-07 17:40       ` Shannon Nelson
  0 siblings, 0 replies; 19+ messages in thread
From: Shannon Nelson @ 2017-08-07 17:40 UTC (permalink / raw)
  To: intel-wired-lan

On 8/7/2017 10:31 AM, Brady, Alan wrote:
>> -----Original Message-----
>> From: Intel-wired-lan [mailto:intel-wired-lan-bounces at osuosl.org] On Behalf Of
>> Shannon Nelson
>> Sent: Monday, August 7, 2017 10:19 AM
>> To: Michael, Alice <alice.michael@intel.com>; intel-wired-lan at lists.osuosl.org
>> Subject: Re: [Intel-wired-lan] [next PATCH S78-V4 08/12] i40evf: Enable VF to
>> request an alternate queue allocation
>>
>> On 8/4/2017 6:52 AM, Alice Michael wrote:
>>> From: Alan Brady <alan.brady@intel.com>
>>>
>>> Currently the VF gets a default number of allocated queues from HW on
>>> init and it could choose to enable or disable those allocated queues.
>>> This makes it such that the VF can request more or less underlying
>>> allocated queues from the PF.
>>>
>>> First the VF negotiates the number of queues it wants that can be
>>> supported by the PF and if successful asks for a reset.  During reset
>>> the PF will reallocate the HW queues for the VF and will then remap
>>> the new queues.
>>>
>>> Signed-off-by: Alan Brady <alan.brady@intel.com>
>>> ---
>>>    drivers/net/ethernet/intel/i40evf/i40evf.h         |  4 +
>>>    drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | 38 ++++++++-
>>>    drivers/net/ethernet/intel/i40evf/i40evf_main.c    | 94
>> ++++++++++++++++++++--
>>>    .../net/ethernet/intel/i40evf/i40evf_virtchnl.c    | 44 +++++++++-
>>>    4 files changed, 173 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h
>>> b/drivers/net/ethernet/intel/i40evf/i40evf.h
>>> index a1af9b1..de0af52 100644
>>> --- a/drivers/net/ethernet/intel/i40evf/i40evf.h
>>> +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h
>>> @@ -102,6 +102,7 @@ struct i40e_vsi {
>>>    #define I40E_TX_CTXTDESC(R, i) \
>>>    	(&(((struct i40e_tx_context_desc *)((R)->desc))[i]))
>>>    #define MAX_QUEUES 16
>>> +#define I40EVF_MAX_REQ_QUEUES 4
>>
>> Why can you only request 4 queues if a VF can have up to 16 queues?
>>
> 
> Hey Shannon,
> 
> Thanks for the feedback.  So the differentiation here comes down to vectors.  The hardware can support up to 16 queues for a VF, but currently we're limited to 4 traffic vectors (+1 misc vector).  So we want to limit the user's ability to request more queues than that as it provides no benefit to have more queues than vectors with just RSS.  However, there are other features which can use more than 4 queues and the differentiation should become clearer with future patches.

You might stick a little comment in there, something like
#define I40EVF_MAX_REQ_QUEUES 4      /* no more than irq's available */

sln

> 
>> [...]
> 
> -ATB
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2017-08-07 17:40 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-04 13:52 [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior Alice Michael
2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 02/12] i40e: Fix reporting of supported link modes Alice Michael
2017-08-07 17:18   ` Shannon Nelson
2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 03/12] i40e: Add support for 'ethtool -m' Alice Michael
2017-08-07 17:19   ` Shannon Nelson
2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 04/12] i40e: don't hold spinlock while resetting VF Alice Michael
2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 05/12] i40e: drop i40e_pf *pf from i40e_vc_disable_vf() Alice Michael
2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 06/12] i40e: make use of i40e_vc_disable_vf Alice Michael
2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 07/12] i40e: ensure reset occurs when disabling VF Alice Michael
2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 08/12] i40evf: Enable VF to request an alternate queue allocation Alice Michael
2017-08-07 17:19   ` Shannon Nelson
2017-08-07 17:31     ` Brady, Alan
2017-08-07 17:40       ` Shannon Nelson
2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 09/12] i40e: make i40evf_map_rings_to_vectors void Alice Michael
2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 10/12] i40e: fix handling of vf_states variable Alice Michael
2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 11/12] i40e: fix client notify of VF reset Alice Michael
2017-08-04 13:52 ` [Intel-wired-lan] [next PATCH S78-V4 12/12] i40e: Stop dropping 802.1ad tags (eth proto 0x88a8) Alice Michael
2017-08-06  7:02 ` [Intel-wired-lan] [next PATCH S78-V4 01/12] i40e: use admin queue for setting LEDs behavior kbuild test robot
2017-08-07 17:18 ` Shannon Nelson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.