From f34e308b671cbd9293da3bad82efe177822fe93f Mon Sep 17 00:00:00 2001 From: Michal Kosiarz Date: Wed, 27 Dec 2017 08:14:40 -0500 Subject: i40e: Add returning AQ critical error to SW The FW has the ability to return a critical error on every AQ command. When this critical error occurs then we need to send the correct response to the caller. Signed-off-by: Michal Kosiarz Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 13 +++++++++---- drivers/net/ethernet/intel/i40e/i40e_common.c | 2 ++ drivers/net/ethernet/intel/i40e/i40e_status.h | 1 + drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 13 +++++++++---- drivers/net/ethernet/intel/i40evf/i40e_common.c | 2 ++ drivers/net/ethernet/intel/i40evf/i40e_status.h | 1 + 6 files changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index d9670cd8743f..c4fa06dd0a2e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -907,10 +907,15 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, /* update the error if time out occurred */ if ((!cmd_completed) && (!details->async && !details->postpone)) { - i40e_debug(hw, - I40E_DEBUG_AQ_MESSAGE, - "AQTX: Writeback timeout.\n"); - status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; + if (rd32(hw, hw->aq.asq.len) & I40E_GL_ATQLEN_ATQCRIT_MASK) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "AQTX: AQ Critical error.\n"); + status = I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR; + } else { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "AQTX: Writeback timeout.\n"); + status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; + } } asq_send_command_error: diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index ee6052ecd215..c690e9c64c48 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -278,6 +278,8 @@ const char *i40e_stat_str(struct i40e_hw *hw, i40e_status stat_err) return "I40E_NOT_SUPPORTED"; case I40E_ERR_FIRMWARE_API_VERSION: return "I40E_ERR_FIRMWARE_API_VERSION"; + case I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR: + return "I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR"; } snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err); diff --git a/drivers/net/ethernet/intel/i40e/i40e_status.h b/drivers/net/ethernet/intel/i40e/i40e_status.h index 5f9cac55aa55..afb72e711d43 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_status.h +++ b/drivers/net/ethernet/intel/i40e/i40e_status.h @@ -95,6 +95,7 @@ enum i40e_status_code { I40E_ERR_NOT_READY = -63, I40E_NOT_SUPPORTED = -64, I40E_ERR_FIRMWARE_API_VERSION = -65, + I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR = -66, }; #endif /* _I40E_STATUS_H_ */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index 8b0d4b255dea..ae3a74067425 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -837,10 +837,15 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, /* update the error if time out occurred */ if ((!cmd_completed) && (!details->async && !details->postpone)) { - i40e_debug(hw, - I40E_DEBUG_AQ_MESSAGE, - "AQTX: Writeback timeout.\n"); - status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; + if (rd32(hw, hw->aq.asq.len) & I40E_VF_ATQLEN1_ATQCRIT_MASK) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "AQTX: AQ Critical error.\n"); + status = I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR; + } else { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, + "AQTX: Writeback timeout.\n"); + status = I40E_ERR_ADMIN_QUEUE_TIMEOUT; + } } asq_send_command_error: diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index a94648429a5b..67bf5cebb76f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -284,6 +284,8 @@ const char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err) return "I40E_NOT_SUPPORTED"; case I40E_ERR_FIRMWARE_API_VERSION: return "I40E_ERR_FIRMWARE_API_VERSION"; + case I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR: + return "I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR"; } snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_status.h b/drivers/net/ethernet/intel/i40evf/i40e_status.h index 7fa7a41915c1..5b222246e08b 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_status.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_status.h @@ -95,6 +95,7 @@ enum i40e_status_code { I40E_ERR_NOT_READY = -63, I40E_NOT_SUPPORTED = -64, I40E_ERR_FIRMWARE_API_VERSION = -65, + I40E_ERR_ADMIN_QUEUE_CRITICAL_ERROR = -66, }; #endif /* _I40E_STATUS_H_ */ -- cgit v1.2.3-59-g8ed1b From ca6e1d0abe863ac24c437ea407be84acd8aa373b Mon Sep 17 00:00:00 2001 From: Patryk Małek Date: Wed, 27 Dec 2017 07:32:31 -0500 Subject: i40e: Fix for adding multiple ethtool filters on the same location MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch reorders i40e_add_del_fdir and i40e_update_ethtool_fdir_entry calls so that we first remove an already existing filter (inside i40e_update_ethtool_fdir_entry using i40e_add_del_fdir) and then we add a new one with i40e_add_del_fdir. After applying this patch, creating multiple identical filters (with the same location) one after another doesn't revert their behavior but behaves correctly. Signed-off-by: Patryk Małek Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 34173f821fd9..2cbd564e437a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -3939,19 +3939,19 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi, input->flex_offset = userdef.flex_offset; } - ret = i40e_add_del_fdir(vsi, input, true); - if (ret) - goto free_input; - /* Add the input filter to the fdir_input_list, possibly replacing * a previous filter. Do not free the input structure after adding it * to the list as this would cause a use-after-free bug. */ i40e_update_ethtool_fdir_entry(vsi, input, fsp->location, NULL); - + ret = i40e_add_del_fdir(vsi, input, true); + if (ret) + goto remove_sw_rule; return 0; -free_input: +remove_sw_rule: + hlist_del(&input->fdir_node); + pf->fdir_pf_active_filters--; kfree(input); return ret; } -- cgit v1.2.3-59-g8ed1b From e0f60a815cb3505c37620048568553f82ee159ba Mon Sep 17 00:00:00 2001 From: Paweł Jabłoński Date: Wed, 27 Dec 2017 07:32:32 -0500 Subject: i40evf: Allow turning off offloads when the VF has VLAN set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds back the capability to turn off offloads when VF has VLAN set. The commit 0a3b4f702fb1 ("i40evf: enable support for VF VLAN tag stripping control") adds the i40evf_set_features function and changes the 'turn off' flow for offloads. This patch adds that capability back by moving checking the VLAN option for VF to the next statement. Signed-off-by: Paweł Jabłoński Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 8934f784e96f..d59bf060196b 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2344,13 +2344,19 @@ static int i40evf_set_features(struct net_device *netdev, { struct i40evf_adapter *adapter = netdev_priv(netdev); - if (!VLAN_ALLOWED(adapter)) + /* Don't allow changing VLAN_RX flag when VLAN is set for VF + * and return an error in this case + */ + if (VLAN_ALLOWED(adapter)) { + if (features & NETIF_F_HW_VLAN_CTAG_RX) + adapter->aq_required |= + I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING; + else + adapter->aq_required |= + I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING; + } else if ((netdev->features ^ features) & NETIF_F_HW_VLAN_CTAG_RX) { return -EINVAL; - - if (features & NETIF_F_HW_VLAN_CTAG_RX) - adapter->aq_required |= I40EVF_FLAG_AQ_ENABLE_VLAN_STRIPPING; - else - adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_VLAN_STRIPPING; + } return 0; } -- cgit v1.2.3-59-g8ed1b From b5b5f370886d3331700b048a0b0ac0399f7ebed5 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 27 Dec 2017 08:15:51 -0500 Subject: i40e/i40evf: Use ring pointers to clean up _set_itr_per_queue This change cleans up the i40e/i40evf_set_itr_per_queue function by dropping all the unneeded pointer chases. Instead we can just pull out the pointers for the Tx and Rx rings and use them throughout the function. Signed-off-by: Alexander Duyck Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 22 +++++++++-------- drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c | 28 +++++++++++----------- 2 files changed, 26 insertions(+), 24 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 2cbd564e437a..dd6996e65396 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2305,6 +2305,8 @@ static void i40e_set_itr_per_queue(struct i40e_vsi *vsi, struct ethtool_coalesce *ec, int queue) { + struct i40e_ring *rx_ring = vsi->rx_rings[queue]; + struct i40e_ring *tx_ring = vsi->tx_rings[queue]; struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; struct i40e_q_vector *q_vector; @@ -2312,26 +2314,26 @@ static void i40e_set_itr_per_queue(struct i40e_vsi *vsi, intrl = i40e_intrl_usec_to_reg(vsi->int_rate_limit); - vsi->rx_rings[queue]->rx_itr_setting = ec->rx_coalesce_usecs; - vsi->tx_rings[queue]->tx_itr_setting = ec->tx_coalesce_usecs; + rx_ring->rx_itr_setting = ec->rx_coalesce_usecs; + tx_ring->tx_itr_setting = ec->tx_coalesce_usecs; if (ec->use_adaptive_rx_coalesce) - vsi->rx_rings[queue]->rx_itr_setting |= I40E_ITR_DYNAMIC; + rx_ring->rx_itr_setting |= I40E_ITR_DYNAMIC; else - vsi->rx_rings[queue]->rx_itr_setting &= ~I40E_ITR_DYNAMIC; + rx_ring->rx_itr_setting &= ~I40E_ITR_DYNAMIC; if (ec->use_adaptive_tx_coalesce) - vsi->tx_rings[queue]->tx_itr_setting |= I40E_ITR_DYNAMIC; + tx_ring->tx_itr_setting |= I40E_ITR_DYNAMIC; else - vsi->tx_rings[queue]->tx_itr_setting &= ~I40E_ITR_DYNAMIC; + tx_ring->tx_itr_setting &= ~I40E_ITR_DYNAMIC; - q_vector = vsi->rx_rings[queue]->q_vector; - q_vector->rx.itr = ITR_TO_REG(vsi->rx_rings[queue]->rx_itr_setting); + q_vector = rx_ring->q_vector; + q_vector->rx.itr = ITR_TO_REG(rx_ring->rx_itr_setting); vector = vsi->base_vector + q_vector->v_idx; wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1), q_vector->rx.itr); - q_vector = vsi->tx_rings[queue]->q_vector; - q_vector->tx.itr = ITR_TO_REG(vsi->tx_rings[queue]->tx_itr_setting); + q_vector = tx_ring->q_vector; + q_vector->tx.itr = ITR_TO_REG(tx_ring->tx_itr_setting); vector = vsi->base_vector + q_vector->v_idx; wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1), q_vector->tx.itr); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c index da006fa3fec1..e2d8aa19d205 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c @@ -512,31 +512,31 @@ static void i40evf_set_itr_per_queue(struct i40evf_adapter *adapter, struct ethtool_coalesce *ec, int queue) { + struct i40e_ring *rx_ring = &adapter->rx_rings[queue]; + struct i40e_ring *tx_ring = &adapter->tx_rings[queue]; struct i40e_vsi *vsi = &adapter->vsi; struct i40e_hw *hw = &adapter->hw; struct i40e_q_vector *q_vector; u16 vector; - adapter->rx_rings[queue].rx_itr_setting = ec->rx_coalesce_usecs; - adapter->tx_rings[queue].tx_itr_setting = ec->tx_coalesce_usecs; + rx_ring->rx_itr_setting = ec->rx_coalesce_usecs; + tx_ring->tx_itr_setting = ec->tx_coalesce_usecs; - if (ec->use_adaptive_rx_coalesce) - adapter->rx_rings[queue].rx_itr_setting |= I40E_ITR_DYNAMIC; - else - adapter->rx_rings[queue].rx_itr_setting &= ~I40E_ITR_DYNAMIC; + rx_ring->rx_itr_setting |= I40E_ITR_DYNAMIC; + if (!ec->use_adaptive_rx_coalesce) + rx_ring->rx_itr_setting ^= I40E_ITR_DYNAMIC; - if (ec->use_adaptive_tx_coalesce) - adapter->tx_rings[queue].tx_itr_setting |= I40E_ITR_DYNAMIC; - else - adapter->tx_rings[queue].tx_itr_setting &= ~I40E_ITR_DYNAMIC; + tx_ring->tx_itr_setting |= I40E_ITR_DYNAMIC; + if (!ec->use_adaptive_tx_coalesce) + tx_ring->tx_itr_setting ^= I40E_ITR_DYNAMIC; - q_vector = adapter->rx_rings[queue].q_vector; - q_vector->rx.itr = ITR_TO_REG(adapter->rx_rings[queue].rx_itr_setting); + q_vector = rx_ring->q_vector; + q_vector->rx.itr = ITR_TO_REG(rx_ring->rx_itr_setting); vector = vsi->base_vector + q_vector->v_idx; wr32(hw, I40E_VFINT_ITRN1(I40E_RX_ITR, vector - 1), q_vector->rx.itr); - q_vector = adapter->tx_rings[queue].q_vector; - q_vector->tx.itr = ITR_TO_REG(adapter->tx_rings[queue].tx_itr_setting); + q_vector = tx_ring->q_vector; + q_vector->tx.itr = ITR_TO_REG(tx_ring->tx_itr_setting); vector = vsi->base_vector + q_vector->v_idx; wr32(hw, I40E_VFINT_ITRN1(I40E_TX_ITR, vector - 1), q_vector->tx.itr); -- cgit v1.2.3-59-g8ed1b From b6a02a6fbfea3224db7e5ad0677824528e76bf6e Mon Sep 17 00:00:00 2001 From: Upasana Menon Date: Wed, 27 Dec 2017 08:17:07 -0500 Subject: i40e: Display LLDP information on vSphere Web Client This patch enables driver to display LLDP information on the vSphere Web Client with Intel adapters (X710, XL710) and Distributed Virtual Switch. Signed-off-by: Upasana Menon Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 12 ++++++++++ drivers/net/ethernet/intel/i40e/i40e_common.c | 27 ++++++++++++++++++++++ drivers/net/ethernet/intel/i40e/i40e_prototype.h | 4 ++++ .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 12 ++++++++++ 4 files changed, 55 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 0d471b0db0f4..a852775d3059 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -205,6 +205,7 @@ enum i40e_admin_queue_opc { /* DCB commands */ i40e_aqc_opc_dcb_ignore_pfc = 0x0301, i40e_aqc_opc_dcb_updated = 0x0302, + i40e_aqc_opc_set_dcb_parameters = 0x0303, /* TX scheduler */ i40e_aqc_opc_configure_vsi_bw_limit = 0x0400, @@ -2496,6 +2497,17 @@ struct i40e_aqc_lldp_start { I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_start); +/* Set DCB (direct 0x0303) */ +struct i40e_aqc_set_dcb_parameters { + u8 command; +#define I40E_AQ_DCB_SET_AGENT 0x1 +#define I40E_DCB_VALID 0x1 + u8 valid_flags; + u8 reserved[14]; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_set_dcb_parameters); + /* Get CEE DCBX Oper Config (0x0A07) * uses the generic descriptor struct * returns below as indirect response diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index c690e9c64c48..ef5a868aae46 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -3641,7 +3641,34 @@ i40e_status i40e_aq_start_lldp(struct i40e_hw *hw, i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_lldp_start); cmd->command = I40E_AQ_LLDP_AGENT_START; + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + return status; +} + +/** + * i40e_aq_set_dcb_parameters + * @hw: pointer to the hw struct + * @cmd_details: pointer to command details structure or NULL + * @dcb_enable: True if DCB configuration needs to be applied + * + **/ +enum i40e_status_code +i40e_aq_set_dcb_parameters(struct i40e_hw *hw, bool dcb_enable, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aqc_set_dcb_parameters *cmd = + (struct i40e_aqc_set_dcb_parameters *)&desc.params.raw; + i40e_status status; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_set_dcb_parameters); + + if (dcb_enable) { + cmd->valid_flags = I40E_DCB_VALID; + cmd->command = I40E_AQ_DCB_SET_AGENT; + } status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); return status; diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 187dd53e0056..83798b7841b9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -225,6 +225,10 @@ i40e_status i40e_aq_cfg_lldp_mib_change_event(struct i40e_hw *hw, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent, struct i40e_asq_cmd_details *cmd_details); +i40e_status i40e_aq_set_dcb_parameters(struct i40e_hw *hw, + bool dcb_enable, + struct i40e_asq_cmd_details + *cmd_details); i40e_status i40e_aq_start_lldp(struct i40e_hw *hw, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_get_cee_dcb_config(struct i40e_hw *hw, diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index b0e6454995b6..815de8d9c3fb 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -205,6 +205,7 @@ enum i40e_admin_queue_opc { /* DCB commands */ i40e_aqc_opc_dcb_ignore_pfc = 0x0301, i40e_aqc_opc_dcb_updated = 0x0302, + i40e_aqc_opc_set_dcb_parameters = 0x0303, /* TX scheduler */ i40e_aqc_opc_configure_vsi_bw_limit = 0x0400, @@ -2461,6 +2462,17 @@ struct i40e_aqc_lldp_start { I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_start); +/* Set DCB (direct 0x0303) */ +struct i40e_aqc_set_dcb_parameters { + u8 command; +#define I40E_AQ_DCB_SET_AGENT 0x1 +#define I40E_DCB_VALID 0x1 + u8 valid_flags; + u8 reserved[14]; +}; + +I40E_CHECK_CMD_LENGTH(i40e_aqc_set_dcb_parameters); + /* Apply MIB changes (0x0A07) * uses the generic struc as it contains no data */ -- cgit v1.2.3-59-g8ed1b From 60f481b9703867330dc6010868054f68f6d52f7a Mon Sep 17 00:00:00 2001 From: Alice Michael Date: Wed, 27 Dec 2017 08:17:50 -0500 Subject: i40e: change flags to use 64 bits As we have added more flags, we need to now use more bits and have over flooded the 32 bit size. So make it 64. Also change all the existing bits to unsigned long long bits. Signed-off-by: Alice Michael Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 67 +++++++++++++------------- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 4 +- 2 files changed, 36 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index e019baa905c5..46e9f4e0a02c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -508,39 +508,40 @@ struct i40e_pf { #define I40E_HW_PORT_ID_VALID BIT(17) #define I40E_HW_RESTART_AUTONEG BIT(18) - u32 flags; -#define I40E_FLAG_RX_CSUM_ENABLED BIT(0) -#define I40E_FLAG_MSI_ENABLED BIT(1) -#define I40E_FLAG_MSIX_ENABLED BIT(2) -#define I40E_FLAG_RSS_ENABLED BIT(3) -#define I40E_FLAG_VMDQ_ENABLED BIT(4) -#define I40E_FLAG_FILTER_SYNC BIT(5) -#define I40E_FLAG_SRIOV_ENABLED BIT(6) -#define I40E_FLAG_DCB_CAPABLE BIT(7) -#define I40E_FLAG_DCB_ENABLED BIT(8) -#define I40E_FLAG_FD_SB_ENABLED BIT(9) -#define I40E_FLAG_FD_ATR_ENABLED BIT(10) -#define I40E_FLAG_FD_SB_AUTO_DISABLED BIT(11) -#define I40E_FLAG_FD_ATR_AUTO_DISABLED BIT(12) -#define I40E_FLAG_MFP_ENABLED BIT(13) -#define I40E_FLAG_UDP_FILTER_SYNC BIT(14) -#define I40E_FLAG_HW_ATR_EVICT_ENABLED BIT(15) -#define I40E_FLAG_VEB_MODE_ENABLED BIT(16) -#define I40E_FLAG_VEB_STATS_ENABLED BIT(17) -#define I40E_FLAG_LINK_POLLING_ENABLED BIT(18) -#define I40E_FLAG_TRUE_PROMISC_SUPPORT BIT(19) -#define I40E_FLAG_TEMP_LINK_POLLING BIT(20) -#define I40E_FLAG_LEGACY_RX BIT(21) -#define I40E_FLAG_PTP BIT(22) -#define I40E_FLAG_IWARP_ENABLED BIT(23) -#define I40E_FLAG_SERVICE_CLIENT_REQUESTED BIT(24) -#define I40E_FLAG_CLIENT_L2_CHANGE BIT(25) -#define I40E_FLAG_CLIENT_RESET BIT(26) -#define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED BIT(27) -#define I40E_FLAG_SOURCE_PRUNING_DISABLED BIT(28) -#define I40E_FLAG_TC_MQPRIO BIT(29) -#define I40E_FLAG_FD_SB_INACTIVE BIT(30) -#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER BIT(31) + u64 flags; +#define I40E_FLAG_RX_CSUM_ENABLED BIT_ULL(0) +#define I40E_FLAG_MSI_ENABLED BIT_ULL(1) +#define I40E_FLAG_MSIX_ENABLED BIT_ULL(2) +#define I40E_FLAG_RSS_ENABLED BIT_ULL(3) +#define I40E_FLAG_VMDQ_ENABLED BIT_ULL(4) +#define I40E_FLAG_FILTER_SYNC BIT_ULL(5) +#define I40E_FLAG_SRIOV_ENABLED BIT_ULL(6) +#define I40E_FLAG_DCB_CAPABLE BIT_ULL(7) +#define I40E_FLAG_DCB_ENABLED BIT_ULL(8) +#define I40E_FLAG_FD_SB_ENABLED BIT_ULL(9) +#define I40E_FLAG_FD_ATR_ENABLED BIT_ULL(10) +#define I40E_FLAG_FD_SB_AUTO_DISABLED BIT_ULL(11) +#define I40E_FLAG_FD_ATR_AUTO_DISABLED BIT_ULL(12) +#define I40E_FLAG_MFP_ENABLED BIT_ULL(13) +#define I40E_FLAG_UDP_FILTER_SYNC BIT_ULL(14) +#define I40E_FLAG_HW_ATR_EVICT_ENABLED BIT_ULL(15) +#define I40E_FLAG_VEB_MODE_ENABLED BIT_ULL(16) +#define I40E_FLAG_VEB_STATS_ENABLED BIT_ULL(17) +#define I40E_FLAG_LINK_POLLING_ENABLED BIT_ULL(18) +#define I40E_FLAG_TRUE_PROMISC_SUPPORT BIT_ULL(19) +#define I40E_FLAG_TEMP_LINK_POLLING BIT_ULL(20) +#define I40E_FLAG_LEGACY_RX BIT_ULL(21) +#define I40E_FLAG_PTP BIT_ULL(22) +#define I40E_FLAG_IWARP_ENABLED BIT_ULL(23) +#define I40E_FLAG_SERVICE_CLIENT_REQUESTED BIT_ULL(24) +#define I40E_FLAG_CLIENT_L2_CHANGE BIT_ULL(25) +#define I40E_FLAG_CLIENT_RESET BIT_ULL(26) +#define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED BIT_ULL(27) +#define I40E_FLAG_SOURCE_PRUNING_DISABLED BIT_ULL(28) +#define I40E_FLAG_TC_MQPRIO BIT_ULL(29) +#define I40E_FLAG_FD_SB_INACTIVE BIT_ULL(30) +#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER BIT_ULL(31) +#define I40E_FLAG_DISABLE_FW_LLDP BIT_ULL(32) struct i40e_client_instance *cinst; bool stat_offsets_loaded; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index dd6996e65396..8b0062ec8edb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -4266,7 +4266,7 @@ static int i40e_set_priv_flags(struct net_device *dev, u32 flags) struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_vsi *vsi = np->vsi; struct i40e_pf *pf = vsi->back; - u32 orig_flags, new_flags, changed_flags; + u64 orig_flags, new_flags, changed_flags; u32 i, j; orig_flags = READ_ONCE(pf->flags); @@ -4323,7 +4323,7 @@ flags_complete: * originally. We'll just punt with an error and log something in the * message buffer. */ - if (cmpxchg(&pf->flags, orig_flags, new_flags) != orig_flags) { + if (cmpxchg64(&pf->flags, orig_flags, new_flags) != orig_flags) { dev_warn(&pf->pdev->dev, "Unable to update pf->flags as it was modified by another thread...\n"); return -EAGAIN; -- cgit v1.2.3-59-g8ed1b From c61c8fe1d592552c34b189963036efbf68b93940 Mon Sep 17 00:00:00 2001 From: Dave Ertman Date: Wed, 27 Dec 2017 08:18:21 -0500 Subject: i40e: Implement an ethtool private flag to stop LLDP in FW Implement the private flag disable-fw-lldp for ethtool to disable the processing of LLDP packets by the FW. This will stop the FW from consuming LLDPDU and cause them to be sent up the stack. The FW is also being configured to apply a default DCB configuration on link up. Toggling the value of this flag will also cause a PF reset. Disabling FW DCB will also disable DCBx. Signed-off-by: Dave Ertman Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 47 +++++++++++++++++++++++++- drivers/net/ethernet/intel/i40e/i40e_main.c | 14 ++++++-- 2 files changed, 58 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 8b0062ec8edb..03f7007d025e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -233,6 +233,7 @@ static const struct i40e_priv_flags i40e_gstrings_priv_flags[] = { I40E_PRIV_FLAG("legacy-rx", I40E_FLAG_LEGACY_RX, 0), I40E_PRIV_FLAG("disable-source-pruning", I40E_FLAG_SOURCE_PRUNING_DISABLED, 0), + I40E_PRIV_FLAG("disable-fw-lldp", I40E_FLAG_DISABLE_FW_LLDP, 0), }; #define I40E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_gstrings_priv_flags) @@ -4317,6 +4318,25 @@ flags_complete: !(pf->hw_features & I40E_HW_ATR_EVICT_CAPABLE)) return -EOPNOTSUPP; + /* Disable FW LLDP not supported if NPAR active or if FW + * API version < 1.7 + */ + if (new_flags & I40E_FLAG_DISABLE_FW_LLDP) { + if (pf->hw.func_caps.npar_enable) { + dev_warn(&pf->pdev->dev, + "Unable to stop FW LLDP if NPAR active\n"); + return -EOPNOTSUPP; + } + + if (pf->hw.aq.api_maj_ver < 1 || + (pf->hw.aq.api_maj_ver == 1 && + pf->hw.aq.api_min_ver < 7)) { + dev_warn(&pf->pdev->dev, + "FW ver does not support stopping FW LLDP\n"); + return -EOPNOTSUPP; + } + } + /* Compare and exchange the new flags into place. If we failed, that * is if cmpxchg returns anything but the old value, this means that * something else has modified the flags variable since we copied it @@ -4362,12 +4382,37 @@ flags_complete: } } + if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP) { + if (pf->flags & I40E_FLAG_DISABLE_FW_LLDP) { + struct i40e_dcbx_config *dcbcfg; + int i; + + i40e_aq_stop_lldp(&pf->hw, true, NULL); + i40e_aq_set_dcb_parameters(&pf->hw, true, NULL); + /* reset local_dcbx_config to default */ + dcbcfg = &pf->hw.local_dcbx_config; + dcbcfg->etscfg.willing = 1; + dcbcfg->etscfg.maxtcs = 0; + dcbcfg->etscfg.tcbwtable[0] = 100; + for (i = 1; i < I40E_MAX_TRAFFIC_CLASS; i++) + dcbcfg->etscfg.tcbwtable[i] = 0; + for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) + dcbcfg->etscfg.prioritytable[i] = 0; + dcbcfg->etscfg.tsatable[0] = I40E_IEEE_TSA_ETS; + dcbcfg->pfc.willing = 1; + dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS; + } else { + i40e_aq_start_lldp(&pf->hw, NULL); + } + } + /* Issue reset to cause things to take effect, as additional bits * are added we will need to create a mask of bits requiring reset */ if (changed_flags & (I40E_FLAG_VEB_STATS_ENABLED | I40E_FLAG_LEGACY_RX | - I40E_FLAG_SOURCE_PRUNING_DISABLED)) + I40E_FLAG_SOURCE_PRUNING_DISABLED | + I40E_FLAG_DISABLE_FW_LLDP)) i40e_do_reset(pf, BIT(__I40E_PF_RESET_REQUESTED), true); return 0; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 2703a92f3778..fdeaeb9d44e2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6320,8 +6320,11 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) struct i40e_hw *hw = &pf->hw; int err = 0; - /* Do not enable DCB for SW1 and SW2 images even if the FW is capable */ - if (pf->hw_features & I40E_HW_NO_DCB_SUPPORT) + /* Do not enable DCB for SW1 and SW2 images even if the FW is capable + * Also do not enable DCBx if FW LLDP agent is disabled + */ + if ((pf->hw_features & I40E_HW_NO_DCB_SUPPORT) || + (pf->flags & I40E_FLAG_DISABLE_FW_LLDP)) goto out; /* Get the initial DCB configuration */ @@ -9221,6 +9224,9 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired) goto end_core_reset; } + /* Enable FW to write a default DCB config on link-up */ + i40e_aq_set_dcb_parameters(hw, true, NULL); + #ifdef CONFIG_I40E_DCB ret = i40e_init_pf_dcb(pf); if (ret) { @@ -13543,6 +13549,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, pf); pci_save_state(pdev); + + /* Enable FW to write default DCB config on link-up */ + i40e_aq_set_dcb_parameters(hw, true, NULL); + #ifdef CONFIG_I40E_DCB err = i40e_init_pf_dcb(pf); if (err) { -- cgit v1.2.3-59-g8ed1b From 64e1dcbb581d31e411e10fa95d8963fb89d34bf2 Mon Sep 17 00:00:00 2001 From: Alan Brady Date: Wed, 27 Dec 2017 08:19:19 -0500 Subject: i40e: fix FW_LLDP flag on init Using ethtool --set-priv-flags disable-fw-lldp is persistent across reboots/reloads so we need some mechanism in the driver to detect if it's on or off on init so we can set the ethtool private flag appropriately. Without this, every time the driver is reloaded the flag will default to off regardless of whether it's on or off in FW. We detect this by first attempting to program DCB and if AQ fails returning I40E_AQ_RC_EPERM, we know that LLDP is disabled in FW. Signed-off-by: Alan Brady Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index fdeaeb9d44e2..ed0870ff4be2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6351,6 +6351,9 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) dev_dbg(&pf->pdev->dev, "DCBX offload is supported for this PF.\n"); } + } else if (pf->hw.aq.asq_last_status == I40E_AQ_RC_EPERM) { + dev_info(&pf->pdev->dev, "FW LLDP disabled for this PF.\n"); + pf->flags |= I40E_FLAG_DISABLE_FW_LLDP; } else { dev_info(&pf->pdev->dev, "Query for DCB configuration failed, err %s aq_err %s\n", -- cgit v1.2.3-59-g8ed1b From 5056716ca276fe8bbdcf8ad394a12fe26cb8845b Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Wed, 27 Dec 2017 08:21:03 -0500 Subject: i40e: cleanup unnecessary parens Clean up unnecessary parenthesis. Signed-off-by: Jeff Kirsher Tested-by: Andrew Bowers --- drivers/net/ethernet/intel/i40e/i40e_adminq.c | 2 +- drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index c4fa06dd0a2e..e78971605e0b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -976,7 +976,7 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw, } /* set next_to_use to head */ - ntu = (rd32(hw, hw->aq.arq.head) & I40E_PF_ARQH_ARQH_MASK); + ntu = rd32(hw, hw->aq.arq.head) & I40E_PF_ARQH_ARQH_MASK; if (ntu == ntc) { /* nothing to do - shouldn't need to update ring's values */ ret_code = I40E_ERR_ADMIN_QUEUE_NO_WORK; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index ae3a74067425..d1aab6b8bfb1 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -906,7 +906,7 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, } /* set next_to_use to head */ - ntu = (rd32(hw, hw->aq.arq.head) & I40E_VF_ARQH1_ARQH_MASK); + ntu = rd32(hw, hw->aq.arq.head) & I40E_VF_ARQH1_ARQH_MASK; if (ntu == ntc) { /* nothing to do - shouldn't need to update ring's values */ ret_code = I40E_ERR_ADMIN_QUEUE_NO_WORK; -- cgit v1.2.3-59-g8ed1b From 69399873b6b50b1e40c1e35f75572e079759b020 Mon Sep 17 00:00:00 2001 From: Avinash Dayanand Date: Wed, 27 Dec 2017 08:22:11 -0500 Subject: i40e: Fix kdump failure kdump fails in the system when used in conjunction with Ethernet driver X722/X710. This is mainly because when we are resource constrained i.e. when we have just one online_cpus, we are enabling VMDq and iWARP. It doesn't make sense to enable them with just one CPU and starve kdump for lack of IRQs. So don't enable VMDq or iWARP when we just have a single CPU. Signed-off-by: Avinash Dayanand Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ed0870ff4be2..db611433120a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -11069,13 +11069,13 @@ static int i40e_sw_init(struct i40e_pf *pf) pf->hw.aq.fw_maj_ver >= 6) pf->hw_features |= I40E_HW_PTP_L4_CAPABLE; - if (pf->hw.func_caps.vmdq) { + if (pf->hw.func_caps.vmdq && num_online_cpus() != 1) { pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI; pf->flags |= I40E_FLAG_VMDQ_ENABLED; pf->num_vmdq_qps = i40e_default_queues_per_vmdq(pf); } - if (pf->hw.func_caps.iwarp) { + if (pf->hw.func_caps.iwarp && num_online_cpus() != 1) { pf->flags |= I40E_FLAG_IWARP_ENABLED; /* IWARP needs one extra vector for CQP just like MISC.*/ pf->num_iwarp_msix = (int)num_online_cpus() + 1; -- cgit v1.2.3-59-g8ed1b From 02b4016bfe43d2d5ed043be7ffa56cda6a4d1100 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 27 Dec 2017 08:24:12 -0500 Subject: i40e: program fragmented IPv4 filter input set When implementing support for IP_USER_FLOW filters, we correctly programmed a filter for both the non fragmented IPv4/Other filter, as well as the fragmented IPv4 filters. However, we did not properly program the input set for fragmented IPv4 PCTYPE. This meant that the filters would almost certainly not match, unless the user specified all of the flow types. Add support to program the fragmented IPv4 filter input set. Since we always program these filters together, we'll assume that the two input sets must match, and will thus always program the input sets to the same value. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 10 ++++++++++ drivers/net/ethernet/intel/i40e/i40e_main.c | 3 +++ 2 files changed, 13 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 03f7007d025e..69644b621b45 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -3809,6 +3809,16 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi, i40e_write_fd_input_set(pf, index, new_mask); + /* IP_USER_FLOW filters match both IPv4/Other and IPv4/Fragmented + * frames. If we're programming the input set for IPv4/Other, we also + * need to program the IPv4/Fragmented input set. Since we don't have + * separate support, we'll always assume and enforce that the two flow + * types must have matching input sets. + */ + if (index == I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) + i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_FRAG_IPV4, + new_mask); + /* Add the new offset and update table, if necessary */ if (new_flex_offset) { err = i40e_add_flex_offset(&pf->l4_flex_pit_list, src_offset, diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index db611433120a..25087e21a051 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7680,6 +7680,9 @@ static void i40e_fdir_filter_exit(struct i40e_pf *pf) /* Reprogram the default input set for Other/IPv4 */ i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_OTHER, I40E_L3_SRC_MASK | I40E_L3_DST_MASK); + + i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_FRAG_IPV4, + I40E_L3_SRC_MASK | I40E_L3_DST_MASK); } /** -- cgit v1.2.3-59-g8ed1b From 443ee71ad212783183138c693c37c9f969fdba71 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 27 Dec 2017 08:25:32 -0500 Subject: i40e: disallow programming multiple filters with same criteria Our hardware does not allow situations where two filters might conflict when matching. Essentially hardware only programs one filter for each set of matching criteria. We don't support filters with overlapping input sets, because each flow type can only use a single input set. Additionally, different flow types will never have overlapping matches, because of how the hardware parses the flow type before checking matching criteria. For this reason, we do not need or use the location number when programming filters to hardware. In order to avoid confusing scenarios with filters that match the same criteria but program the flow to different queues, do not allow multiple filters that match identical criteria to be programmed. This ensures that we avoid odd scenarios when deleting filters, and when programming new filters that match the same criteria. Instead, users that wish to update the criteria for a filter must use the same location id, or must delete all the matching filters first. Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 87 ++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 69644b621b45..b35c61ccc64a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -3840,6 +3840,87 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi, return 0; } +/** + * i40e_match_fdir_filter - Return true of two filters match + * @a: pointer to filter struct + * @b: pointer to filter struct + * + * Returns true if the two filters match exactly the same criteria. I.e. they + * match the same flow type and have the same parameters. We don't need to + * check any input-set since all filters of the same flow type must use the + * same input set. + **/ +static bool i40e_match_fdir_filter(struct i40e_fdir_filter *a, + struct i40e_fdir_filter *b) +{ + /* The filters do not much if any of these criteria differ. */ + if (a->dst_ip != b->dst_ip || + a->src_ip != b->src_ip || + a->dst_port != b->dst_port || + a->src_port != b->src_port || + a->flow_type != b->flow_type || + a->ip4_proto != b->ip4_proto) + return false; + + return true; +} + +/** + * i40e_disallow_matching_filters - Check that new filters differ + * @vsi: pointer to the targeted VSI + * @input: new filter to check + * + * Due to hardware limitations, it is not possible for two filters that match + * similar criteria to be programmed at the same time. This is true for a few + * reasons: + * + * (a) all filters matching a particular flow type must use the same input + * set, that is they must match the same criteria. + * (b) different flow types will never match the same packet, as the flow type + * is decided by hardware before checking which rules apply. + * (c) hardware has no way to distinguish which order filters apply in. + * + * Due to this, we can't really support using the location data to order + * filters in the hardware parsing. It is technically possible for the user to + * request two filters matching the same criteria but which select different + * queues. In this case, rather than keep both filters in the list, we reject + * the 2nd filter when the user requests adding it. + * + * This avoids needing to track location for programming the filter to + * hardware, and ensures that we avoid some strange scenarios involving + * deleting filters which match the same criteria. + **/ +static int i40e_disallow_matching_filters(struct i40e_vsi *vsi, + struct i40e_fdir_filter *input) +{ + struct i40e_pf *pf = vsi->back; + struct i40e_fdir_filter *rule; + struct hlist_node *node2; + + /* Loop through every filter, and check that it doesn't match */ + hlist_for_each_entry_safe(rule, node2, + &pf->fdir_filter_list, fdir_node) { + /* Don't check the filters match if they share the same fd_id, + * since the new filter is actually just updating the target + * of the old filter. + */ + if (rule->fd_id == input->fd_id) + continue; + + /* If any filters match, then print a warning message to the + * kernel message buffer and bail out. + */ + if (i40e_match_fdir_filter(rule, input)) { + dev_warn(&pf->pdev->dev, + "Existing user defined filter %d already matches this flow.\n", + rule->fd_id); + return -EINVAL; + } + } + + return 0; +} + /** * i40e_add_fdir_ethtool - Add/Remove Flow Director filters * @vsi: pointer to the targeted VSI @@ -3952,6 +4033,11 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi, input->flex_offset = userdef.flex_offset; } + /* Avoid programming two filters with identical match criteria. */ + ret = i40e_disallow_matching_filters(vsi, input); + if (ret) + goto free_filter_memory; + /* Add the input filter to the fdir_input_list, possibly replacing * a previous filter. Do not free the input structure after adding it * to the list as this would cause a use-after-free bug. @@ -3965,6 +4051,7 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi, remove_sw_rule: hlist_del(&input->fdir_node); pf->fdir_pf_active_filters--; +free_filter_memory: kfree(input); return ret; } -- cgit v1.2.3-59-g8ed1b From 40339af33c703bacb336493157d43c86a8bf2fed Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 27 Dec 2017 08:26:33 -0500 Subject: i40e: fix reported mask for ntuple filters In commit 36777d9fa24c ("i40e: check current configured input set when adding ntuple filters") some code was added to report the input set mask for a given filter when reporting it to the user. This code is necessary so that the reported filter correctly displays that it is or is not masking certain fields. Unfortunately the code was incorrect. Development error accidentally swapped the mask values for the IPv4 addresses with the L4 port numbers. The port numbers are only 16bits wide while IPv4 addresses are 32 bits. Unfortunately we assigned only 16 bits to the IPv4 address masks. Additionally we assigned 32bit value 0xFFFFFFF to the TCP port numbers. This second part does not matter as the value would be truncated to 16bits regardless, but it is unnecessary. Fix the reported masks to properly report that the entire field is masked. Fixes: 36777d9fa24c ("i40e: check current configured input set when adding ntuple filters") Signed-off-by: Jacob Keller Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index b35c61ccc64a..2f5bee713fef 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2749,16 +2749,16 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf, no_input_set: if (input_set & I40E_L3_SRC_MASK) - fsp->m_u.tcp_ip4_spec.ip4src = htonl(0xFFFF); + fsp->m_u.tcp_ip4_spec.ip4src = htonl(0xFFFFFFFF); if (input_set & I40E_L3_DST_MASK) - fsp->m_u.tcp_ip4_spec.ip4dst = htonl(0xFFFF); + fsp->m_u.tcp_ip4_spec.ip4dst = htonl(0xFFFFFFFF); if (input_set & I40E_L4_SRC_MASK) - fsp->m_u.tcp_ip4_spec.psrc = htons(0xFFFFFFFF); + fsp->m_u.tcp_ip4_spec.psrc = htons(0xFFFF); if (input_set & I40E_L4_DST_MASK) - fsp->m_u.tcp_ip4_spec.pdst = htons(0xFFFFFFFF); + fsp->m_u.tcp_ip4_spec.pdst = htons(0xFFFF); if (rule->dest_ctl == I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET) fsp->ring_cookie = RX_CLS_FLOW_DISC; -- cgit v1.2.3-59-g8ed1b From a3f9fb5ef34e2f01a77a74c359e655b64cb1a6ae Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 29 Dec 2017 08:48:53 -0500 Subject: i40e/i40evf: Record ITR register location in the q_vector The drivers for i40e and i40evf had a reg_idx value stored in the q_vector that was going completely unused. I can only assume this was copied over from ixgbe and nobody knew how to use it. I'm going to make use of the value to avoid having to compute the vector and thus the register index for multiple paths throughout the drivers. Signed-off-by: Alexander Duyck Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 + drivers/net/ethernet/intel/i40e/i40e_txrx.c | 12 ++++-------- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 12 ++++-------- drivers/net/ethernet/intel/i40evf/i40evf.h | 4 ++-- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 1 + 5 files changed, 12 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 25087e21a051..827c082c4356 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -4122,6 +4122,7 @@ static void i40e_vsi_map_rings_to_vectors(struct i40e_vsi *vsi) num_ringpairs = DIV_ROUND_UP(qp_remaining, q_vectors - v_start); q_vector->num_ringpairs = num_ringpairs; + q_vector->reg_idx = q_vector->v_idx + vsi->base_vector - 1; q_vector->rx.count = 0; q_vector->tx.count = 0; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 8d2275830a40..e554aa6cf070 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -956,7 +956,7 @@ static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi, I40E_PFINT_DYN_CTLN_ITR_INDX_MASK; /* set noitr */ wr32(&vsi->back->hw, - I40E_PFINT_DYN_CTLN(q_vector->v_idx + vsi->base_vector - 1), + I40E_PFINT_DYN_CTLN(q_vector->reg_idx), val); } else { val = I40E_PFINT_DYN_CTL0_WB_ON_ITR_MASK | @@ -983,8 +983,7 @@ void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) /* allow 00 to be written to the index */ wr32(&vsi->back->hw, - I40E_PFINT_DYN_CTLN(q_vector->v_idx + - vsi->base_vector - 1), val); + I40E_PFINT_DYN_CTLN(q_vector->reg_idx), val); } else { u32 val = I40E_PFINT_DYN_CTL0_INTENA_MASK | I40E_PFINT_DYN_CTL0_ITR_INDX_MASK | /* set noitr */ @@ -2311,7 +2310,6 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, struct i40e_hw *hw = &vsi->back->hw; bool rx = false, tx = false; u32 rxval, txval; - int vector; int idx = q_vector->v_idx; int rx_itr_setting, tx_itr_setting; @@ -2321,8 +2319,6 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, return; } - vector = (q_vector->v_idx + vsi->base_vector); - /* avoid dynamic calculation if in countdown mode OR if * all dynamic is disabled */ @@ -2371,12 +2367,12 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, */ rxval |= BIT(31); /* don't check _DOWN because interrupt isn't being enabled */ - wr32(hw, INTREG(vector - 1), rxval); + wr32(hw, INTREG(q_vector->reg_idx), rxval); } enable_int: if (!test_bit(__I40E_VSI_DOWN, vsi->state)) - wr32(hw, INTREG(vector - 1), txval); + wr32(hw, INTREG(q_vector->reg_idx), txval); if (q_vector->itr_countdown) q_vector->itr_countdown--; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index c7831f7f7761..357d6051281f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -369,8 +369,7 @@ static void i40e_enable_wb_on_itr(struct i40e_vsi *vsi, I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK; /* set noitr */ wr32(&vsi->back->hw, - I40E_VFINT_DYN_CTLN1(q_vector->v_idx + - vsi->base_vector - 1), val); + I40E_VFINT_DYN_CTLN1(q_vector->reg_idx), val); q_vector->arm_wb_state = true; } @@ -389,7 +388,7 @@ void i40evf_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector) /* allow 00 to be written to the index */; wr32(&vsi->back->hw, - I40E_VFINT_DYN_CTLN1(q_vector->v_idx + vsi->base_vector - 1), + I40E_VFINT_DYN_CTLN1(q_vector->reg_idx), val); } @@ -1498,12 +1497,9 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, struct i40e_hw *hw = &vsi->back->hw; bool rx = false, tx = false; u32 rxval, txval; - int vector; int idx = q_vector->v_idx; int rx_itr_setting, tx_itr_setting; - vector = (q_vector->v_idx + vsi->base_vector); - /* avoid dynamic calculation if in countdown mode OR if * all dynamic is disabled */ @@ -1552,12 +1548,12 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, */ rxval |= BIT(31); /* don't check _DOWN because interrupt isn't being enabled */ - wr32(hw, INTREG(vector - 1), rxval); + wr32(hw, INTREG(q_vector->reg_idx), rxval); } enable_int: if (!test_bit(__I40E_VSI_DOWN, vsi->state)) - wr32(hw, INTREG(vector - 1), txval); + wr32(hw, INTREG(q_vector->reg_idx), txval); if (q_vector->itr_countdown) q_vector->itr_countdown--; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index 33c0ffcc8b13..9690c1ea019e 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -114,14 +114,14 @@ struct i40e_q_vector { struct i40evf_adapter *adapter; struct i40e_vsi *vsi; struct napi_struct napi; - unsigned long reg_idx; struct i40e_ring_container rx; struct i40e_ring_container tx; u32 ring_mask; u8 num_ringpairs; /* total number of ring pairs in vector */ #define ITR_COUNTDOWN_START 100 u8 itr_countdown; /* when 0 or 1 update ITR */ - int v_idx; /* vector index in list */ + u16 v_idx; /* index in the vsi->q_vector array. */ + u16 reg_idx; /* register index of the interrupt */ char name[IFNAMSIZ + 15]; bool arm_wb_state; cpumask_t affinity_mask; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index d59bf060196b..16989ad2ca90 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1387,6 +1387,7 @@ static int i40evf_alloc_q_vectors(struct i40evf_adapter *adapter) q_vector->adapter = adapter; q_vector->vsi = &adapter->vsi; q_vector->v_idx = q_idx; + q_vector->reg_idx = q_idx; cpumask_copy(&q_vector->affinity_mask, cpu_possible_mask); netif_napi_add(adapter->netdev, &q_vector->napi, i40evf_napi_poll, NAPI_POLL_WEIGHT); -- cgit v1.2.3-59-g8ed1b From 1563f2d2e01242f05dd523ffd56fe104bc1afd58 Mon Sep 17 00:00:00 2001 From: Paweł Jabłoński Date: Fri, 29 Dec 2017 08:49:10 -0500 Subject: i40e: Do not allow use more TC queue pairs than MSI-X vectors exist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch suppresses the message about invalid TC mapping and wrong selected TX queue. The root cause of this bug was setting too many TC queue pairs on huge multiprocessor machines. When quantity of the TC queue pairs is exceeding MSI-X vectors count then TX queue number can be selected beyond actual TX queues amount. Signed-off-by: Paweł Jabłoński Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 827c082c4356..f95ce9b5e4fb 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1818,6 +1818,10 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, num_tc_qps = qcount / numtc; num_tc_qps = min_t(int, num_tc_qps, i40e_pf_get_max_q_per_tc(pf)); + /* Do not allow use more TC queue pairs than MSI-X vectors exist */ + if (pf->flags & I40E_FLAG_MSIX_ENABLED) + num_tc_qps = min_t(int, num_tc_qps, pf->num_lan_msix); + /* Setup queue offset/count for all TCs for given VSI */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { /* See if the given TC is enabled for the given VSI */ -- cgit v1.2.3-59-g8ed1b