diff options
Diffstat (limited to 'drivers/net/ethernet/intel/i40e/i40e_main.c')
| -rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_main.c | 258 | 
1 files changed, 141 insertions, 117 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 1f188c052828..284c3fad5a6e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -11171,6 +11171,8 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit,  	ret = i40e_reset(pf);  	if (!ret)  		i40e_rebuild(pf, reinit, lock_acquired); +	else +		dev_err(&pf->pdev->dev, "%s: i40e_reset() FAILED", __func__);  }  /** @@ -16335,6 +16337,139 @@ unmap:  }  /** + * i40e_enable_mc_magic_wake - enable multicast magic packet wake up + * using the mac_address_write admin q function + * @pf: pointer to i40e_pf struct + **/ +static void i40e_enable_mc_magic_wake(struct i40e_pf *pf) +{ +	struct i40e_vsi *main_vsi = i40e_pf_get_main_vsi(pf); +	struct i40e_hw *hw = &pf->hw; +	u8 mac_addr[6]; +	u16 flags = 0; +	int ret; + +	/* Get current MAC address in case it's an LAA */ +	if (main_vsi && main_vsi->netdev) { +		ether_addr_copy(mac_addr, main_vsi->netdev->dev_addr); +	} else { +		dev_err(&pf->pdev->dev, +			"Failed to retrieve MAC address; using default\n"); +		ether_addr_copy(mac_addr, hw->mac.addr); +	} + +	/* The FW expects the mac address write cmd to first be called with +	 * one of these flags before calling it again with the multicast +	 * enable flags. +	 */ +	flags = I40E_AQC_WRITE_TYPE_LAA_WOL; + +	if (hw->func_caps.flex10_enable && hw->partition_id != 1) +		flags = I40E_AQC_WRITE_TYPE_LAA_ONLY; + +	ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL); +	if (ret) { +		dev_err(&pf->pdev->dev, +			"Failed to update MAC address registers; cannot enable Multicast Magic packet wake up"); +		return; +	} + +	flags = I40E_AQC_MC_MAG_EN +			| I40E_AQC_WOL_PRESERVE_ON_PFR +			| I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG; +	ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL); +	if (ret) +		dev_err(&pf->pdev->dev, +			"Failed to enable Multicast Magic Packet wake up\n"); +} + +/** + * i40e_io_suspend - suspend all IO operations + * @pf: pointer to i40e_pf struct + * + **/ +static int i40e_io_suspend(struct i40e_pf *pf) +{ +	struct i40e_hw *hw = &pf->hw; + +	set_bit(__I40E_DOWN, pf->state); + +	/* Ensure service task will not be running */ +	del_timer_sync(&pf->service_timer); +	cancel_work_sync(&pf->service_task); + +	/* Client close must be called explicitly here because the timer +	 * has been stopped. +	 */ +	i40e_notify_client_of_netdev_close(pf, false); + +	if (test_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, pf->hw.caps) && +	    pf->wol_en) +		i40e_enable_mc_magic_wake(pf); + +	/* Since we're going to destroy queues during the +	 * i40e_clear_interrupt_scheme() we should hold the RTNL lock for this +	 * whole section +	 */ +	rtnl_lock(); + +	i40e_prep_for_reset(pf); + +	wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0)); +	wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0)); + +	/* Clear the interrupt scheme and release our IRQs so that the system +	 * can safely hibernate even when there are a large number of CPUs. +	 * Otherwise hibernation might fail when mapping all the vectors back +	 * to CPU0. +	 */ +	i40e_clear_interrupt_scheme(pf); + +	rtnl_unlock(); + +	return 0; +} + +/** + * i40e_io_resume - resume IO operations + * @pf: pointer to i40e_pf struct + * + **/ +static int i40e_io_resume(struct i40e_pf *pf) +{ +	struct device *dev = &pf->pdev->dev; +	int err; + +	/* We need to hold the RTNL lock prior to restoring interrupt schemes, +	 * since we're going to be restoring queues +	 */ +	rtnl_lock(); + +	/* We cleared the interrupt scheme when we suspended, so we need to +	 * restore it now to resume device functionality. +	 */ +	err = i40e_restore_interrupt_scheme(pf); +	if (err) { +		dev_err(dev, "Cannot restore interrupt scheme: %d\n", +			err); +	} + +	clear_bit(__I40E_DOWN, pf->state); +	i40e_reset_and_rebuild(pf, false, true); + +	rtnl_unlock(); + +	/* Clear suspended state last after everything is recovered */ +	clear_bit(__I40E_SUSPENDED, pf->state); + +	/* Restart the service task */ +	mod_timer(&pf->service_timer, +		  round_jiffies(jiffies + pf->service_timer_period)); + +	return 0; +} + +/**   * i40e_pci_error_detected - warning that something funky happened in PCI land   * @pdev: PCI device information struct   * @error: the type of PCI error @@ -16358,7 +16493,7 @@ static pci_ers_result_t i40e_pci_error_detected(struct pci_dev *pdev,  	/* shutdown all operations */  	if (!test_bit(__I40E_SUSPENDED, pf->state)) -		i40e_prep_for_reset(pf); +		i40e_io_suspend(pf);  	/* Request a slot reset */  	return PCI_ERS_RESULT_NEED_RESET; @@ -16380,7 +16515,8 @@ static pci_ers_result_t i40e_pci_error_slot_reset(struct pci_dev *pdev)  	u32 reg;  	dev_dbg(&pdev->dev, "%s\n", __func__); -	if (pci_enable_device_mem(pdev)) { +	/* enable I/O and memory of the device  */ +	if (pci_enable_device(pdev)) {  		dev_info(&pdev->dev,  			 "Cannot re-enable PCI device after reset.\n");  		result = PCI_ERS_RESULT_DISCONNECT; @@ -16443,54 +16579,7 @@ static void i40e_pci_error_resume(struct pci_dev *pdev)  	if (test_bit(__I40E_SUSPENDED, pf->state))  		return; -	i40e_handle_reset_warning(pf, false); -} - -/** - * i40e_enable_mc_magic_wake - enable multicast magic packet wake up - * using the mac_address_write admin q function - * @pf: pointer to i40e_pf struct - **/ -static void i40e_enable_mc_magic_wake(struct i40e_pf *pf) -{ -	struct i40e_vsi *main_vsi = i40e_pf_get_main_vsi(pf); -	struct i40e_hw *hw = &pf->hw; -	u8 mac_addr[6]; -	u16 flags = 0; -	int ret; - -	/* Get current MAC address in case it's an LAA */ -	if (main_vsi && main_vsi->netdev) { -		ether_addr_copy(mac_addr, main_vsi->netdev->dev_addr); -	} else { -		dev_err(&pf->pdev->dev, -			"Failed to retrieve MAC address; using default\n"); -		ether_addr_copy(mac_addr, hw->mac.addr); -	} - -	/* The FW expects the mac address write cmd to first be called with -	 * one of these flags before calling it again with the multicast -	 * enable flags. -	 */ -	flags = I40E_AQC_WRITE_TYPE_LAA_WOL; - -	if (hw->func_caps.flex10_enable && hw->partition_id != 1) -		flags = I40E_AQC_WRITE_TYPE_LAA_ONLY; - -	ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL); -	if (ret) { -		dev_err(&pf->pdev->dev, -			"Failed to update MAC address registers; cannot enable Multicast Magic packet wake up"); -		return; -	} - -	flags = I40E_AQC_MC_MAG_EN -			| I40E_AQC_WOL_PRESERVE_ON_PFR -			| I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG; -	ret = i40e_aq_mac_address_write(hw, flags, mac_addr, NULL); -	if (ret) -		dev_err(&pf->pdev->dev, -			"Failed to enable Multicast Magic Packet wake up\n"); +	i40e_io_resume(pf);  }  /** @@ -16552,48 +16641,11 @@ static void i40e_shutdown(struct pci_dev *pdev)  static int i40e_suspend(struct device *dev)  {  	struct i40e_pf *pf = dev_get_drvdata(dev); -	struct i40e_hw *hw = &pf->hw;  	/* If we're already suspended, then there is nothing to do */  	if (test_and_set_bit(__I40E_SUSPENDED, pf->state))  		return 0; - -	set_bit(__I40E_DOWN, pf->state); - -	/* Ensure service task will not be running */ -	del_timer_sync(&pf->service_timer); -	cancel_work_sync(&pf->service_task); - -	/* Client close must be called explicitly here because the timer -	 * has been stopped. -	 */ -	i40e_notify_client_of_netdev_close(pf, false); - -	if (test_bit(I40E_HW_CAP_WOL_MC_MAGIC_PKT_WAKE, pf->hw.caps) && -	    pf->wol_en) -		i40e_enable_mc_magic_wake(pf); - -	/* Since we're going to destroy queues during the -	 * i40e_clear_interrupt_scheme() we should hold the RTNL lock for this -	 * whole section -	 */ -	rtnl_lock(); - -	i40e_prep_for_reset(pf); - -	wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0)); -	wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0)); - -	/* Clear the interrupt scheme and release our IRQs so that the system -	 * can safely hibernate even when there are a large number of CPUs. -	 * Otherwise hibernation might fail when mapping all the vectors back -	 * to CPU0. -	 */ -	i40e_clear_interrupt_scheme(pf); - -	rtnl_unlock(); - -	return 0; +	return i40e_io_suspend(pf);  }  /** @@ -16603,39 +16655,11 @@ static int i40e_suspend(struct device *dev)  static int i40e_resume(struct device *dev)  {  	struct i40e_pf *pf = dev_get_drvdata(dev); -	int err;  	/* If we're not suspended, then there is nothing to do */  	if (!test_bit(__I40E_SUSPENDED, pf->state))  		return 0; - -	/* We need to hold the RTNL lock prior to restoring interrupt schemes, -	 * since we're going to be restoring queues -	 */ -	rtnl_lock(); - -	/* We cleared the interrupt scheme when we suspended, so we need to -	 * restore it now to resume device functionality. -	 */ -	err = i40e_restore_interrupt_scheme(pf); -	if (err) { -		dev_err(dev, "Cannot restore interrupt scheme: %d\n", -			err); -	} - -	clear_bit(__I40E_DOWN, pf->state); -	i40e_reset_and_rebuild(pf, false, true); - -	rtnl_unlock(); - -	/* Clear suspended state last after everything is recovered */ -	clear_bit(__I40E_SUSPENDED, pf->state); - -	/* Restart the service task */ -	mod_timer(&pf->service_timer, -		  round_jiffies(jiffies + pf->service_timer_period)); - -	return 0; +	return i40e_io_resume(pf);  }  static const struct pci_error_handlers i40e_err_handler = {  |