diff options
Diffstat (limited to 'drivers/net/ethernet/intel/i40e/i40e_main.c')
| -rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_main.c | 284 | 
1 files changed, 197 insertions, 87 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 56ecd6c3f236..b5399357a667 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -5,6 +5,7 @@  #include <linux/of_net.h>  #include <linux/pci.h>  #include <linux/bpf.h> +#include <generated/utsrelease.h>  /* Local includes */  #include "i40e.h" @@ -23,15 +24,6 @@ const char i40e_driver_name[] = "i40e";  static const char i40e_driver_string[] =  			"Intel(R) Ethernet Connection XL710 Network Driver"; -#define DRV_KERN "-k" - -#define DRV_VERSION_MAJOR 2 -#define DRV_VERSION_MINOR 8 -#define DRV_VERSION_BUILD 20 -#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ -	     __stringify(DRV_VERSION_MINOR) "." \ -	     __stringify(DRV_VERSION_BUILD)    DRV_KERN -const char i40e_driver_version_str[] = DRV_VERSION;  static const char i40e_copyright[] = "Copyright (c) 2013 - 2019 Intel Corporation.";  /* a bit of forward declarations */ @@ -54,7 +46,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf);  static int i40e_veb_get_bw_info(struct i40e_veb *veb);  static int i40e_get_capabilities(struct i40e_pf *pf,  				 enum i40e_admin_queue_opc list_type); - +static bool i40e_is_total_port_shutdown_enabled(struct i40e_pf *pf);  /* i40e_pci_tbl - PCI Device ID Table   * @@ -101,7 +93,6 @@ MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all), Debug mask (0x8XXXXXXX  MODULE_AUTHOR("Intel Corporation, <[email protected]>");  MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");  MODULE_LICENSE("GPL v2"); -MODULE_VERSION(DRV_VERSION);  static struct workqueue_struct *i40e_wq; @@ -820,6 +811,25 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)  		rx_p += packets;  		rx_buf += p->rx_stats.alloc_buff_failed;  		rx_page += p->rx_stats.alloc_page_failed; + +		if (i40e_enabled_xdp_vsi(vsi)) { +			/* locate XDP ring */ +			p = READ_ONCE(vsi->xdp_rings[q]); +			if (!p) +				continue; + +			do { +				start = u64_stats_fetch_begin_irq(&p->syncp); +				packets = p->stats.packets; +				bytes = p->stats.bytes; +			} while (u64_stats_fetch_retry_irq(&p->syncp, start)); +			tx_b += bytes; +			tx_p += packets; +			tx_restart += p->tx_stats.restart_queue; +			tx_busy += p->tx_stats.tx_busy; +			tx_linearize += p->tx_stats.tx_linearize; +			tx_force_wb += p->tx_stats.tx_force_wb; +		}  	}  	rcu_read_unlock();  	vsi->tx_restart = tx_restart; @@ -1826,7 +1836,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,  						       num_tc_qps);  					break;  				} -				/* fall through */ +				fallthrough;  			case I40E_VSI_FDIR:  			case I40E_VSI_SRIOV:  			case I40E_VSI_VMDQ2: @@ -6501,8 +6511,7 @@ out:  	return err;  }  #endif /* CONFIG_I40E_DCB */ -#define SPEED_SIZE 14 -#define FC_SIZE 8 +  /**   * i40e_print_link_message - print link up or down   * @vsi: the VSI for which link needs a message @@ -6690,21 +6699,6 @@ static void i40e_vsi_reinit_locked(struct i40e_vsi *vsi)  }  /** - * i40e_up - Bring the connection back up after being down - * @vsi: the VSI being configured - **/ -int i40e_up(struct i40e_vsi *vsi) -{ -	int err; - -	err = i40e_vsi_configure(vsi); -	if (!err) -		err = i40e_up_complete(vsi); - -	return err; -} - -/**   * i40e_force_link_state - Force the link status   * @pf: board private structure   * @is_up: whether the link state should be forced up or down @@ -6713,6 +6707,7 @@ static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up)  {  	struct i40e_aq_get_phy_abilities_resp abilities;  	struct i40e_aq_set_phy_config config = {0}; +	bool non_zero_phy_type = is_up;  	struct i40e_hw *hw = &pf->hw;  	i40e_status err;  	u64 mask; @@ -6748,8 +6743,11 @@ static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up)  	/* If link needs to go up, but was not forced to go down,  	 * and its speed values are OK, no need for a flap +	 * if non_zero_phy_type was set, still need to force up  	 */ -	if (is_up && abilities.phy_type != 0 && abilities.link_speed != 0) +	if (pf->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED) +		non_zero_phy_type = true; +	else if (is_up && abilities.phy_type != 0 && abilities.link_speed != 0)  		return I40E_SUCCESS;  	/* To force link we need to set bits for all supported PHY types, @@ -6757,10 +6755,18 @@ static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up)  	 * across two fields.  	 */  	mask = I40E_PHY_TYPES_BITMASK; -	config.phy_type = is_up ? cpu_to_le32((u32)(mask & 0xffffffff)) : 0; -	config.phy_type_ext = is_up ? (u8)((mask >> 32) & 0xff) : 0; +	config.phy_type = +		non_zero_phy_type ? cpu_to_le32((u32)(mask & 0xffffffff)) : 0; +	config.phy_type_ext = +		non_zero_phy_type ? (u8)((mask >> 32) & 0xff) : 0;  	/* Copy the old settings, except of phy_type */  	config.abilities = abilities.abilities; +	if (pf->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED) { +		if (is_up) +			config.abilities |= I40E_AQ_PHY_ENABLE_LINK; +		else +			config.abilities &= ~(I40E_AQ_PHY_ENABLE_LINK); +	}  	if (abilities.link_speed != 0)  		config.link_speed = abilities.link_speed;  	else @@ -6791,12 +6797,32 @@ static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up)  		i40e_update_link_info(hw);  	} -	i40e_aq_set_link_restart_an(hw, true, NULL); +	i40e_aq_set_link_restart_an(hw, is_up, NULL);  	return I40E_SUCCESS;  }  /** + * i40e_up - Bring the connection back up after being down + * @vsi: the VSI being configured + **/ +int i40e_up(struct i40e_vsi *vsi) +{ +	int err; + +	if (vsi->type == I40E_VSI_MAIN && +	    (vsi->back->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED || +	     vsi->back->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED)) +		i40e_force_link_state(vsi->back, true); + +	err = i40e_vsi_configure(vsi); +	if (!err) +		err = i40e_up_complete(vsi); + +	return err; +} + +/**   * i40e_down - Shutdown the connection processing   * @vsi: the VSI being stopped   **/ @@ -6814,7 +6840,8 @@ void i40e_down(struct i40e_vsi *vsi)  	i40e_vsi_disable_irq(vsi);  	i40e_vsi_stop_rings(vsi);  	if (vsi->type == I40E_VSI_MAIN && -	    vsi->back->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED) +	   (vsi->back->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED || +	    vsi->back->flags & I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED))  		i40e_force_link_state(vsi->back, false);  	i40e_napi_disable_all(vsi); @@ -8959,13 +8986,6 @@ u32 i40e_get_current_atr_cnt(struct i40e_pf *pf)  	return i40e_get_current_fd_count(pf) - pf->fdir_pf_active_filters;  } -/* We can see up to 256 filter programming desc in transit if the filters are - * being applied really fast; before we see the first - * filter miss error on Rx queue 0. Accumulating enough error messages before - * reacting will make sure we don't cause flush too often. - */ -#define I40E_MAX_FD_PROGRAM_ERROR 256 -  /**   * i40e_fdir_reinit_subtask - Worker thread to reinit FDIR filter table   * @pf: board private structure @@ -9860,11 +9880,11 @@ static void i40e_send_version(struct i40e_pf *pf)  {  	struct i40e_driver_version dv; -	dv.major_version = DRV_VERSION_MAJOR; -	dv.minor_version = DRV_VERSION_MINOR; -	dv.build_version = DRV_VERSION_BUILD; +	dv.major_version = 0xff; +	dv.minor_version = 0xff; +	dv.build_version = 0xff;  	dv.subbuild_version = 0; -	strlcpy(dv.driver_string, DRV_VERSION, sizeof(dv.driver_string)); +	strlcpy(dv.driver_string, UTS_RELEASE, sizeof(dv.driver_string));  	i40e_aq_send_driver_version(&pf->hw, &dv, NULL);  } @@ -11855,6 +11875,58 @@ bw_commit_out:  }  /** + * i40e_is_total_port_shutdown_enabled - read NVM and return value + * if total port shutdown feature is enabled for this PF + * @pf: board private structure + **/ +static bool i40e_is_total_port_shutdown_enabled(struct i40e_pf *pf) +{ +#define I40E_TOTAL_PORT_SHUTDOWN_ENABLED	BIT(4) +#define I40E_FEATURES_ENABLE_PTR		0x2A +#define I40E_CURRENT_SETTING_PTR		0x2B +#define I40E_LINK_BEHAVIOR_WORD_OFFSET		0x2D +#define I40E_LINK_BEHAVIOR_WORD_LENGTH		0x1 +#define I40E_LINK_BEHAVIOR_OS_FORCED_ENABLED	BIT(0) +#define I40E_LINK_BEHAVIOR_PORT_BIT_LENGTH	4 +	i40e_status read_status = I40E_SUCCESS; +	u16 sr_emp_sr_settings_ptr = 0; +	u16 features_enable = 0; +	u16 link_behavior = 0; +	bool ret = false; + +	read_status = i40e_read_nvm_word(&pf->hw, +					 I40E_SR_EMP_SR_SETTINGS_PTR, +					 &sr_emp_sr_settings_ptr); +	if (read_status) +		goto err_nvm; +	read_status = i40e_read_nvm_word(&pf->hw, +					 sr_emp_sr_settings_ptr + +					 I40E_FEATURES_ENABLE_PTR, +					 &features_enable); +	if (read_status) +		goto err_nvm; +	if (I40E_TOTAL_PORT_SHUTDOWN_ENABLED & features_enable) { +		read_status = i40e_read_nvm_module_data(&pf->hw, +							I40E_SR_EMP_SR_SETTINGS_PTR, +							I40E_CURRENT_SETTING_PTR, +							I40E_LINK_BEHAVIOR_WORD_OFFSET, +							I40E_LINK_BEHAVIOR_WORD_LENGTH, +							&link_behavior); +		if (read_status) +			goto err_nvm; +		link_behavior >>= (pf->hw.port * I40E_LINK_BEHAVIOR_PORT_BIT_LENGTH); +		ret = I40E_LINK_BEHAVIOR_OS_FORCED_ENABLED & link_behavior; +	} +	return ret; + +err_nvm: +	dev_warn(&pf->pdev->dev, +		 "total-port-shutdown feature is off due to read nvm error: %s\n", +		 i40e_stat_str(&pf->hw, read_status)); +	return ret; +} + +/**   * i40e_sw_init - Initialize general software structures (struct i40e_pf)   * @pf: board private structure to initialize   * @@ -12029,6 +12101,16 @@ static int i40e_sw_init(struct i40e_pf *pf)  	pf->tx_timeout_recovery_level = 1; +	if (pf->hw.mac.type != I40E_MAC_X722 && +	    i40e_is_total_port_shutdown_enabled(pf)) { +		/* Link down on close must be on when total port shutdown +		 * is enabled for a given port +		 */ +		pf->flags |= (I40E_FLAG_TOTAL_PORT_SHUTDOWN_ENABLED | +			      I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED); +		dev_info(&pf->pdev->dev, +			 "total-port-shutdown was enabled, link-down-on-close is forced on\n"); +	}  	mutex_init(&pf->switch_mutex);  sw_init_done: @@ -12841,9 +12923,6 @@ static int i40e_xdp(struct net_device *dev,  	switch (xdp->command) {  	case XDP_SETUP_PROG:  		return i40e_xdp_setup(vsi, xdp->prog); -	case XDP_QUERY_PROG: -		xdp->prog_id = vsi->xdp_prog ? vsi->xdp_prog->aux->id : 0; -		return 0;  	case XDP_SETUP_XSK_UMEM:  		return i40e_xsk_umem_setup(vsi, xdp->xsk.umem,  					   xdp->xsk.queue_id); @@ -13703,8 +13782,7 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,  		/* Setup DCB netlink interface */  		i40e_dcbnl_setup(vsi);  #endif /* CONFIG_I40E_DCB */ -		/* fall through */ - +		fallthrough;  	case I40E_VSI_FDIR:  		/* set up vectors and rings if needed */  		ret = i40e_vsi_setup_vectors(vsi); @@ -13720,7 +13798,6 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,  		i40e_vsi_reset_stats(vsi);  		break; -  	default:  		/* no netdev or rings for the other VSI types */  		break; @@ -14574,28 +14651,17 @@ void i40e_set_fec_in_flags(u8 fec_cfg, u32 *flags)   **/  static bool i40e_check_recovery_mode(struct i40e_pf *pf)  { -	u32 val = rd32(&pf->hw, I40E_GL_FWSTS) & I40E_GL_FWSTS_FWS1B_MASK; -	bool is_recovery_mode = false; - -	if (pf->hw.mac.type == I40E_MAC_XL710) -		is_recovery_mode = -		val == I40E_XL710_GL_FWSTS_FWS1B_REC_MOD_CORER_MASK || -		val == I40E_XL710_GL_FWSTS_FWS1B_REC_MOD_GLOBR_MASK || -		val == I40E_XL710_GL_FWSTS_FWS1B_REC_MOD_TRANSITION_MASK || -		val == I40E_XL710_GL_FWSTS_FWS1B_REC_MOD_NVM_MASK; -	if (pf->hw.mac.type == I40E_MAC_X722) -		is_recovery_mode = -		val == I40E_X722_GL_FWSTS_FWS1B_REC_MOD_CORER_MASK || -		val == I40E_X722_GL_FWSTS_FWS1B_REC_MOD_GLOBR_MASK; -	if (is_recovery_mode) { -		dev_notice(&pf->pdev->dev, "Firmware recovery mode detected. Limiting functionality.\n"); -		dev_notice(&pf->pdev->dev, "Refer to the Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n"); +	u32 val = rd32(&pf->hw, I40E_GL_FWSTS); + +	if (val & I40E_GL_FWSTS_FWS1B_MASK) { +		dev_crit(&pf->pdev->dev, "Firmware recovery mode detected. Limiting functionality.\n"); +		dev_crit(&pf->pdev->dev, "Refer to the Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n");  		set_bit(__I40E_RECOVERY_MODE, pf->state);  		return true;  	} -	if (test_and_clear_bit(__I40E_RECOVERY_MODE, pf->state)) -		dev_info(&pf->pdev->dev, "Reinitializing in normal mode with full functionality.\n"); +	if (test_bit(__I40E_RECOVERY_MODE, pf->state)) +		dev_info(&pf->pdev->dev, "Please do Power-On Reset to initialize adapter in normal mode with full functionality.\n");  	return false;  } @@ -14623,29 +14689,68 @@ static bool i40e_check_recovery_mode(struct i40e_pf *pf)   **/  static i40e_status i40e_pf_loop_reset(struct i40e_pf *pf)  { -	const unsigned short MAX_CNT = 1000; -	const unsigned short MSECS = 10; +	/* wait max 10 seconds for PF reset to succeed */ +	const unsigned long time_end = jiffies + 10 * HZ; +  	struct i40e_hw *hw = &pf->hw;  	i40e_status ret; -	int cnt; -	for (cnt = 0; cnt < MAX_CNT; ++cnt) { +	ret = i40e_pf_reset(hw); +	while (ret != I40E_SUCCESS && time_before(jiffies, time_end)) { +		usleep_range(10000, 20000);  		ret = i40e_pf_reset(hw); -		if (!ret) -			break; -		msleep(MSECS);  	} -	if (cnt == MAX_CNT) { +	if (ret == I40E_SUCCESS) +		pf->pfr_count++; +	else  		dev_info(&pf->pdev->dev, "PF reset failed: %d\n", ret); -		return ret; -	} -	pf->pfr_count++;  	return ret;  }  /** + * i40e_check_fw_empr - check if FW issued unexpected EMP Reset + * @pf: board private structure + * + * Check FW registers to determine if FW issued unexpected EMP Reset. + * Every time when unexpected EMP Reset occurs the FW increments + * a counter of unexpected EMP Resets. When the counter reaches 10 + * the FW should enter the Recovery mode + * + * Returns true if FW issued unexpected EMP Reset + **/ +static bool i40e_check_fw_empr(struct i40e_pf *pf) +{ +	const u32 fw_sts = rd32(&pf->hw, I40E_GL_FWSTS) & +			   I40E_GL_FWSTS_FWS1B_MASK; +	return (fw_sts > I40E_GL_FWSTS_FWS1B_EMPR_0) && +	       (fw_sts <= I40E_GL_FWSTS_FWS1B_EMPR_10); +} + +/** + * i40e_handle_resets - handle EMP resets and PF resets + * @pf: board private structure + * + * Handle both EMP resets and PF resets and conclude whether there are + * any issues regarding these resets. If there are any issues then + * generate log entry. + * + * Return 0 if NIC is healthy or negative value when there are issues + * with resets + **/ +static i40e_status i40e_handle_resets(struct i40e_pf *pf) +{ +	const i40e_status pfr = i40e_pf_loop_reset(pf); +	const bool is_empr = i40e_check_fw_empr(pf); + +	if (is_empr || pfr != I40E_SUCCESS) +		dev_crit(&pf->pdev->dev, "Entering recovery mode due to repeated FW resets. This may take several minutes. Refer to the Intel(R) Ethernet Adapters and Devices User Guide.\n"); + +	return is_empr ? I40E_ERR_RESET_FAILED : pfr; +} + +/**   * i40e_init_recovery_mode - initialize subsystems needed in recovery mode   * @pf: board private structure   * @hw: ptr to the hardware info @@ -14881,11 +14986,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  		goto err_pf_reset;  	} -	err = i40e_pf_loop_reset(pf); -	if (err) { -		dev_info(&pdev->dev, "Initial pf_reset failed: %d\n", err); +	err = i40e_handle_resets(pf); +	if (err)  		goto err_pf_reset; -	}  	i40e_check_recovery_mode(pf); @@ -15281,6 +15384,14 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  			i40e_stat_str(&pf->hw, err),  			i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); +	/* make sure the MFS hasn't been set lower than the default */ +#define MAX_FRAME_SIZE_DEFAULT 0x2600 +	val = (rd32(&pf->hw, I40E_PRTGL_SAH) & +	       I40E_PRTGL_SAH_MFS_MASK) >> I40E_PRTGL_SAH_MFS_SHIFT; +	if (val < MAX_FRAME_SIZE_DEFAULT) +		dev_warn(&pdev->dev, "MFS for port %x has been set below the default: %x\n", +			 i, val); +  	/* Add a filter to drop all Flow control frames from any VSI from being  	 * transmitted. By doing so we stop a malicious VF from sending out  	 * PAUSE or PFC frames and potentially controlling traffic for other @@ -15474,7 +15585,7 @@ unmap:   * remediation.   **/  static pci_ers_result_t i40e_pci_error_detected(struct pci_dev *pdev, -						enum pci_channel_state error) +						pci_channel_state_t error)  {  	struct i40e_pf *pf = pci_get_drvdata(pdev); @@ -15791,8 +15902,7 @@ static struct pci_driver i40e_driver = {   **/  static int __init i40e_init_module(void)  { -	pr_info("%s: %s - version %s\n", i40e_driver_name, -		i40e_driver_string, i40e_driver_version_str); +	pr_info("%s: %s\n", i40e_driver_name, i40e_driver_string);  	pr_info("%s: %s\n", i40e_driver_name, i40e_copyright);  	/* There is no need to throttle the number of active tasks because  |