ice: Add advanced power mgmt for WoL
Add callbacks needed to support advanced power management for Wake on LAN. Also make ice_pf_state_is_nominal function available for all configurations not just CONFIG_PCI_IOV. Signed-off-by: Akeem G Abodunrin <akeem.g.abodunrin@intel.com> Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
This commit is contained in:
Родитель
81aed6475d
Коммит
769c500dcc
|
@ -423,6 +423,8 @@ struct ice_pf {
|
|||
u16 empr_count; /* EMP reset count */
|
||||
u16 pfr_count; /* PF reset count */
|
||||
|
||||
u8 wol_ena : 1; /* software state of WoL */
|
||||
u32 wakeup_reason; /* last wakeup reason */
|
||||
struct ice_hw_port_stats stats;
|
||||
struct ice_hw_port_stats stats_prev;
|
||||
struct ice_hw hw;
|
||||
|
@ -568,6 +570,7 @@ int ice_schedule_reset(struct ice_pf *pf, enum ice_reset_req reset);
|
|||
void ice_print_link_msg(struct ice_vsi *vsi, bool isup);
|
||||
const char *ice_stat_str(enum ice_status stat_err);
|
||||
const char *ice_aq_str(enum ice_aq_err aq_err);
|
||||
bool ice_is_wol_supported(struct ice_pf *pf);
|
||||
int
|
||||
ice_fdir_write_fltr(struct ice_pf *pf, struct ice_fdir_fltr *input, bool add,
|
||||
bool is_tun);
|
||||
|
|
|
@ -3322,6 +3322,58 @@ static int ice_set_channels(struct net_device *dev, struct ethtool_channels *ch)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_get_wol - get current Wake on LAN configuration
|
||||
* @netdev: network interface device structure
|
||||
* @wol: Ethtool structure to retrieve WoL settings
|
||||
*/
|
||||
static void ice_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct ice_netdev_priv *np = netdev_priv(netdev);
|
||||
struct ice_pf *pf = np->vsi->back;
|
||||
|
||||
if (np->vsi->type != ICE_VSI_PF)
|
||||
netdev_warn(netdev, "Wake on LAN is not supported on this interface!\n");
|
||||
|
||||
/* Get WoL settings based on the HW capability */
|
||||
if (ice_is_wol_supported(pf)) {
|
||||
wol->supported = WAKE_MAGIC;
|
||||
wol->wolopts = pf->wol_ena ? WAKE_MAGIC : 0;
|
||||
} else {
|
||||
wol->supported = 0;
|
||||
wol->wolopts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_set_wol - set Wake on LAN on supported device
|
||||
* @netdev: network interface device structure
|
||||
* @wol: Ethtool structure to set WoL
|
||||
*/
|
||||
static int ice_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct ice_netdev_priv *np = netdev_priv(netdev);
|
||||
struct ice_vsi *vsi = np->vsi;
|
||||
struct ice_pf *pf = vsi->back;
|
||||
|
||||
if (vsi->type != ICE_VSI_PF || !ice_is_wol_supported(pf))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* only magic packet is supported */
|
||||
if (wol->wolopts && wol->wolopts != WAKE_MAGIC)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Set WoL only if there is a new value */
|
||||
if (pf->wol_ena != !!wol->wolopts) {
|
||||
pf->wol_ena = !!wol->wolopts;
|
||||
device_set_wakeup_enable(ice_pf_to_dev(pf), pf->wol_ena);
|
||||
netdev_dbg(netdev, "WoL magic packet %sabled\n",
|
||||
pf->wol_ena ? "en" : "dis");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum ice_container_type {
|
||||
ICE_RX_CONTAINER,
|
||||
ICE_TX_CONTAINER,
|
||||
|
@ -3805,6 +3857,8 @@ static const struct ethtool_ops ice_ethtool_ops = {
|
|||
.get_drvinfo = ice_get_drvinfo,
|
||||
.get_regs_len = ice_get_regs_len,
|
||||
.get_regs = ice_get_regs,
|
||||
.get_wol = ice_get_wol,
|
||||
.set_wol = ice_set_wol,
|
||||
.get_msglevel = ice_get_msglevel,
|
||||
.set_msglevel = ice_set_msglevel,
|
||||
.self_test = ice_self_test,
|
||||
|
@ -3847,6 +3901,8 @@ static const struct ethtool_ops ice_ethtool_safe_mode_ops = {
|
|||
.get_drvinfo = ice_get_drvinfo,
|
||||
.get_regs_len = ice_get_regs_len,
|
||||
.get_regs = ice_get_regs,
|
||||
.get_wol = ice_get_wol,
|
||||
.set_wol = ice_set_wol,
|
||||
.get_msglevel = ice_get_msglevel,
|
||||
.set_msglevel = ice_set_msglevel,
|
||||
.get_link = ethtool_op_get_link,
|
||||
|
|
|
@ -367,6 +367,15 @@
|
|||
#define VSIQF_FD_CNT_FD_GCNT_M ICE_M(0x3FFF, 0)
|
||||
#define VSIQF_HKEY_MAX_INDEX 12
|
||||
#define VSIQF_HLUT_MAX_INDEX 15
|
||||
#define PFPM_APM 0x000B8080
|
||||
#define PFPM_APM_APME_M BIT(0)
|
||||
#define PFPM_WUFC 0x0009DC00
|
||||
#define PFPM_WUFC_MAG_M BIT(1)
|
||||
#define PFPM_WUS 0x0009DB80
|
||||
#define PFPM_WUS_LNKC_M BIT(0)
|
||||
#define PFPM_WUS_MAG_M BIT(1)
|
||||
#define PFPM_WUS_MNG_M BIT(3)
|
||||
#define PFPM_WUS_FW_RST_WK_M BIT(31)
|
||||
#define VFINT_DYN_CTLN(_i) (0x00003800 + ((_i) * 4))
|
||||
#define VFINT_DYN_CTLN_CLEARPBA_M BIT(1)
|
||||
#define PRTRPB_RDPC 0x000AC260
|
||||
|
|
|
@ -1467,6 +1467,30 @@ static void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi)
|
|||
vsi_num, ice_stat_str(status));
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_pf_state_is_nominal - checks the PF for nominal state
|
||||
* @pf: pointer to PF to check
|
||||
*
|
||||
* Check the PF's state for a collection of bits that would indicate
|
||||
* the PF is in a state that would inhibit normal operation for
|
||||
* driver functionality.
|
||||
*
|
||||
* Returns true if PF is in a nominal state, false otherwise
|
||||
*/
|
||||
bool ice_pf_state_is_nominal(struct ice_pf *pf)
|
||||
{
|
||||
DECLARE_BITMAP(check_bits, __ICE_STATE_NBITS) = { 0 };
|
||||
|
||||
if (!pf)
|
||||
return false;
|
||||
|
||||
bitmap_set(check_bits, 0, __ICE_STATE_NOMINAL_CHECK_BITS);
|
||||
if (bitmap_intersects(pf->state, check_bits, __ICE_STATE_NBITS))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_update_eth_stats - Update VSI-specific ethernet statistics counters
|
||||
* @vsi: the VSI to be updated
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
const char *ice_vsi_type_str(enum ice_vsi_type vsi_type);
|
||||
|
||||
bool ice_pf_state_is_nominal(struct ice_pf *pf);
|
||||
|
||||
void ice_update_eth_stats(struct ice_vsi *vsi);
|
||||
|
||||
int ice_vsi_cfg_rxqs(struct ice_vsi *vsi);
|
||||
|
|
|
@ -1129,10 +1129,15 @@ static void ice_service_task_complete(struct ice_pf *pf)
|
|||
/**
|
||||
* ice_service_task_stop - stop service task and cancel works
|
||||
* @pf: board private structure
|
||||
*
|
||||
* Return 0 if the __ICE_SERVICE_DIS bit was not already set,
|
||||
* 1 otherwise.
|
||||
*/
|
||||
static void ice_service_task_stop(struct ice_pf *pf)
|
||||
static int ice_service_task_stop(struct ice_pf *pf)
|
||||
{
|
||||
set_bit(__ICE_SERVICE_DIS, pf->state);
|
||||
int ret;
|
||||
|
||||
ret = test_and_set_bit(__ICE_SERVICE_DIS, pf->state);
|
||||
|
||||
if (pf->serv_tmr.function)
|
||||
del_timer_sync(&pf->serv_tmr);
|
||||
|
@ -1140,6 +1145,7 @@ static void ice_service_task_stop(struct ice_pf *pf)
|
|||
cancel_work_sync(&pf->serv_task);
|
||||
|
||||
clear_bit(__ICE_SERVICE_SCHED, pf->state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2940,6 +2946,27 @@ static int ice_init_interrupt_scheme(struct ice_pf *pf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_is_wol_supported - get NVM state of WoL
|
||||
* @pf: board private structure
|
||||
*
|
||||
* Check if WoL is supported based on the HW configuration.
|
||||
* Returns true if NVM supports and enables WoL for this port, false otherwise
|
||||
*/
|
||||
bool ice_is_wol_supported(struct ice_pf *pf)
|
||||
{
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
u16 wol_ctrl;
|
||||
|
||||
/* A bit set to 1 in the NVM Software Reserved Word 2 (WoL control
|
||||
* word) indicates WoL is not supported on the corresponding PF ID.
|
||||
*/
|
||||
if (ice_read_sr_word(hw, ICE_SR_NVM_WOL_CFG, &wol_ctrl))
|
||||
return false;
|
||||
|
||||
return !(BIT(hw->pf_id) & wol_ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_vsi_recfg_qs - Change the number of queues on a VSI
|
||||
* @vsi: VSI being changed
|
||||
|
@ -3287,6 +3314,33 @@ dflt_pkg_load:
|
|||
release_firmware(firmware);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_print_wake_reason - show the wake up cause in the log
|
||||
* @pf: pointer to the PF struct
|
||||
*/
|
||||
static void ice_print_wake_reason(struct ice_pf *pf)
|
||||
{
|
||||
u32 wus = pf->wakeup_reason;
|
||||
const char *wake_str;
|
||||
|
||||
/* if no wake event, nothing to print */
|
||||
if (!wus)
|
||||
return;
|
||||
|
||||
if (wus & PFPM_WUS_LNKC_M)
|
||||
wake_str = "Link\n";
|
||||
else if (wus & PFPM_WUS_MAG_M)
|
||||
wake_str = "Magic Packet\n";
|
||||
else if (wus & PFPM_WUS_MNG_M)
|
||||
wake_str = "Management\n";
|
||||
else if (wus & PFPM_WUS_FW_RST_WK_M)
|
||||
wake_str = "Firmware Reset\n";
|
||||
else
|
||||
wake_str = "Unknown\n";
|
||||
|
||||
dev_info(ice_pf_to_dev(pf), "Wake reason: %s", wake_str);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_probe - Device initialization routine
|
||||
* @pdev: PCI device information struct
|
||||
|
@ -3470,6 +3524,18 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
|
|||
|
||||
ice_verify_cacheline_size(pf);
|
||||
|
||||
/* Save wakeup reason register for later use */
|
||||
pf->wakeup_reason = rd32(hw, PFPM_WUS);
|
||||
|
||||
/* check for a power management event */
|
||||
ice_print_wake_reason(pf);
|
||||
|
||||
/* clear wake status, all bits */
|
||||
wr32(hw, PFPM_WUS, U32_MAX);
|
||||
|
||||
/* Disable WoL at init, wait for user to enable */
|
||||
device_set_wakeup_enable(dev, false);
|
||||
|
||||
/* If no DDP driven features have to be setup, we are done with probe */
|
||||
if (ice_is_safe_mode(pf))
|
||||
goto probe_done;
|
||||
|
@ -3514,9 +3580,72 @@ err_init_pf_unroll:
|
|||
err_exit_unroll:
|
||||
ice_devlink_unregister(pf);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_set_wake - enable or disable Wake on LAN
|
||||
* @pf: pointer to the PF struct
|
||||
*
|
||||
* Simple helper for WoL control
|
||||
*/
|
||||
static void ice_set_wake(struct ice_pf *pf)
|
||||
{
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
bool wol = pf->wol_ena;
|
||||
|
||||
/* clear wake state, otherwise new wake events won't fire */
|
||||
wr32(hw, PFPM_WUS, U32_MAX);
|
||||
|
||||
/* enable / disable APM wake up, no RMW needed */
|
||||
wr32(hw, PFPM_APM, wol ? PFPM_APM_APME_M : 0);
|
||||
|
||||
/* set magic packet filter enabled */
|
||||
wr32(hw, PFPM_WUFC, wol ? PFPM_WUFC_MAG_M : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_setup_magic_mc_wake - setup device to wake on multicast magic packet
|
||||
* @pf: pointer to the PF struct
|
||||
*
|
||||
* Issue firmware command to enable multicast magic wake, making
|
||||
* sure that any locally administered address (LAA) is used for
|
||||
* wake, and that PF reset doesn't undo the LAA.
|
||||
*/
|
||||
static void ice_setup_mc_magic_wake(struct ice_pf *pf)
|
||||
{
|
||||
struct device *dev = ice_pf_to_dev(pf);
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
enum ice_status status;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
struct ice_vsi *vsi;
|
||||
u8 flags;
|
||||
|
||||
if (!pf->wol_ena)
|
||||
return;
|
||||
|
||||
vsi = ice_get_main_vsi(pf);
|
||||
if (!vsi)
|
||||
return;
|
||||
|
||||
/* Get current MAC address in case it's an LAA */
|
||||
if (vsi->netdev)
|
||||
ether_addr_copy(mac_addr, vsi->netdev->dev_addr);
|
||||
else
|
||||
ether_addr_copy(mac_addr, vsi->port_info->mac.perm_addr);
|
||||
|
||||
flags = ICE_AQC_MAN_MAC_WR_MC_MAG_EN |
|
||||
ICE_AQC_MAN_MAC_UPDATE_LAA_WOL |
|
||||
ICE_AQC_MAN_MAC_WR_WOL_LAA_PFR_KEEP;
|
||||
|
||||
status = ice_aq_manage_mac_write(hw, mac_addr, flags, NULL);
|
||||
if (status)
|
||||
dev_err(dev, "Failed to enable Multicast Magic Packet wake, err %s aq_err %s\n",
|
||||
ice_stat_str(status),
|
||||
ice_aq_str(hw->adminq.sq_last_status));
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_remove - Device removal routine
|
||||
* @pdev: PCI device information struct
|
||||
|
@ -3546,8 +3675,10 @@ static void ice_remove(struct pci_dev *pdev)
|
|||
mutex_destroy(&(&pf->hw)->fdir_fltr_lock);
|
||||
if (!ice_is_safe_mode(pf))
|
||||
ice_remove_arfs(pf);
|
||||
ice_setup_mc_magic_wake(pf);
|
||||
ice_devlink_destroy_port(pf);
|
||||
ice_vsi_release_all(pf);
|
||||
ice_set_wake(pf);
|
||||
ice_free_irq_msix_misc(pf);
|
||||
ice_for_each_vsi(pf, i) {
|
||||
if (!pf->vsi[i])
|
||||
|
@ -3567,8 +3698,230 @@ static void ice_remove(struct pci_dev *pdev)
|
|||
pci_wait_for_pending_transaction(pdev);
|
||||
ice_clear_interrupt_scheme(pf);
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_shutdown - PCI callback for shutting down device
|
||||
* @pdev: PCI device information struct
|
||||
*/
|
||||
static void ice_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
struct ice_pf *pf = pci_get_drvdata(pdev);
|
||||
|
||||
ice_remove(pdev);
|
||||
|
||||
if (system_state == SYSTEM_POWER_OFF) {
|
||||
pci_wake_from_d3(pdev, pf->wol_ena);
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/**
|
||||
* ice_prepare_for_shutdown - prep for PCI shutdown
|
||||
* @pf: board private structure
|
||||
*
|
||||
* Inform or close all dependent features in prep for PCI device shutdown
|
||||
*/
|
||||
static void ice_prepare_for_shutdown(struct ice_pf *pf)
|
||||
{
|
||||
struct ice_hw *hw = &pf->hw;
|
||||
u32 v;
|
||||
|
||||
/* Notify VFs of impending reset */
|
||||
if (ice_check_sq_alive(hw, &hw->mailboxq))
|
||||
ice_vc_notify_reset(pf);
|
||||
|
||||
dev_dbg(ice_pf_to_dev(pf), "Tearing down internal switch for shutdown\n");
|
||||
|
||||
/* disable the VSIs and their queues that are not already DOWN */
|
||||
ice_pf_dis_all_vsi(pf, false);
|
||||
|
||||
ice_for_each_vsi(pf, v)
|
||||
if (pf->vsi[v])
|
||||
pf->vsi[v]->vsi_num = 0;
|
||||
|
||||
ice_shutdown_all_ctrlq(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_reinit_interrupt_scheme - Reinitialize interrupt scheme
|
||||
* @pf: board private structure to reinitialize
|
||||
*
|
||||
* This routine reinitialize interrupt scheme that was cleared during
|
||||
* power management suspend callback.
|
||||
*
|
||||
* This should be called during resume routine to re-allocate the q_vectors
|
||||
* and reacquire interrupts.
|
||||
*/
|
||||
static int ice_reinit_interrupt_scheme(struct ice_pf *pf)
|
||||
{
|
||||
struct device *dev = ice_pf_to_dev(pf);
|
||||
int ret, v;
|
||||
|
||||
/* Since we clear MSIX flag during suspend, we need to
|
||||
* set it back during resume...
|
||||
*/
|
||||
|
||||
ret = ice_init_interrupt_scheme(pf);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to re-initialize interrupt %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Remap vectors and rings, after successful re-init interrupts */
|
||||
ice_for_each_vsi(pf, v) {
|
||||
if (!pf->vsi[v])
|
||||
continue;
|
||||
|
||||
ret = ice_vsi_alloc_q_vectors(pf->vsi[v]);
|
||||
if (ret)
|
||||
goto err_reinit;
|
||||
ice_vsi_map_rings_to_vectors(pf->vsi[v]);
|
||||
}
|
||||
|
||||
ret = ice_req_irq_msix_misc(pf);
|
||||
if (ret) {
|
||||
dev_err(dev, "Setting up misc vector failed after device suspend %d\n",
|
||||
ret);
|
||||
goto err_reinit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_reinit:
|
||||
while (v--)
|
||||
if (pf->vsi[v])
|
||||
ice_vsi_free_q_vectors(pf->vsi[v]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_suspend
|
||||
* @dev: generic device information structure
|
||||
*
|
||||
* Power Management callback to quiesce the device and prepare
|
||||
* for D3 transition.
|
||||
*/
|
||||
static int ice_suspend(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct ice_pf *pf;
|
||||
int disabled, v;
|
||||
|
||||
pf = pci_get_drvdata(pdev);
|
||||
|
||||
if (!ice_pf_state_is_nominal(pf)) {
|
||||
dev_err(dev, "Device is not ready, no need to suspend it\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Stop watchdog tasks until resume completion.
|
||||
* Even though it is most likely that the service task is
|
||||
* disabled if the device is suspended or down, the service task's
|
||||
* state is controlled by a different state bit, and we should
|
||||
* store and honor whatever state that bit is in at this point.
|
||||
*/
|
||||
disabled = ice_service_task_stop(pf);
|
||||
|
||||
/* Already suspended?, then there is nothing to do */
|
||||
if (test_and_set_bit(__ICE_SUSPENDED, pf->state)) {
|
||||
if (!disabled)
|
||||
ice_service_task_restart(pf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (test_bit(__ICE_DOWN, pf->state) ||
|
||||
ice_is_reset_in_progress(pf->state)) {
|
||||
dev_err(dev, "can't suspend device in reset or already down\n");
|
||||
if (!disabled)
|
||||
ice_service_task_restart(pf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ice_setup_mc_magic_wake(pf);
|
||||
|
||||
ice_prepare_for_shutdown(pf);
|
||||
|
||||
ice_set_wake(pf);
|
||||
|
||||
/* Free vectors, clear the interrupt scheme and release IRQs
|
||||
* for proper hibernation, especially with large number of CPUs.
|
||||
* Otherwise hibernation might fail when mapping all the vectors back
|
||||
* to CPU0.
|
||||
*/
|
||||
ice_free_irq_msix_misc(pf);
|
||||
ice_for_each_vsi(pf, v) {
|
||||
if (!pf->vsi[v])
|
||||
continue;
|
||||
ice_vsi_free_q_vectors(pf->vsi[v]);
|
||||
}
|
||||
ice_clear_interrupt_scheme(pf);
|
||||
|
||||
pci_wake_from_d3(pdev, pf->wol_ena);
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_resume - PM callback for waking up from D3
|
||||
* @dev: generic device information structure
|
||||
*/
|
||||
static int ice_resume(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
enum ice_reset_req reset_type;
|
||||
struct ice_pf *pf;
|
||||
struct ice_hw *hw;
|
||||
int ret;
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
pci_save_state(pdev);
|
||||
|
||||
if (!pci_device_is_present(pdev))
|
||||
return -ENODEV;
|
||||
|
||||
ret = pci_enable_device_mem(pdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Cannot enable device after suspend\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pf = pci_get_drvdata(pdev);
|
||||
hw = &pf->hw;
|
||||
|
||||
pf->wakeup_reason = rd32(hw, PFPM_WUS);
|
||||
ice_print_wake_reason(pf);
|
||||
|
||||
/* We cleared the interrupt scheme when we suspended, so we need to
|
||||
* restore it now to resume device functionality.
|
||||
*/
|
||||
ret = ice_reinit_interrupt_scheme(pf);
|
||||
if (ret)
|
||||
dev_err(dev, "Cannot restore interrupt scheme: %d\n", ret);
|
||||
|
||||
clear_bit(__ICE_DOWN, pf->state);
|
||||
/* Now perform PF reset and rebuild */
|
||||
reset_type = ICE_RESET_PFR;
|
||||
/* re-enable service task for reset, but allow reset to schedule it */
|
||||
clear_bit(__ICE_SERVICE_DIS, pf->state);
|
||||
|
||||
if (ice_schedule_reset(pf, reset_type))
|
||||
dev_err(dev, "Reset during resume failed.\n");
|
||||
|
||||
clear_bit(__ICE_SUSPENDED, pf->state);
|
||||
ice_service_task_restart(pf);
|
||||
|
||||
/* Restart the service task */
|
||||
mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/**
|
||||
* ice_pci_err_detected - warning that PCI error has been detected
|
||||
* @pdev: PCI device information struct
|
||||
|
@ -3734,6 +4087,8 @@ static const struct pci_device_id ice_pci_tbl[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(pci, ice_pci_tbl);
|
||||
|
||||
static __maybe_unused SIMPLE_DEV_PM_OPS(ice_pm_ops, ice_suspend, ice_resume);
|
||||
|
||||
static const struct pci_error_handlers ice_pci_err_handler = {
|
||||
.error_detected = ice_pci_err_detected,
|
||||
.slot_reset = ice_pci_err_slot_reset,
|
||||
|
@ -3747,6 +4102,10 @@ static struct pci_driver ice_driver = {
|
|||
.id_table = ice_pci_tbl,
|
||||
.probe = ice_probe,
|
||||
.remove = ice_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.driver.pm = &ice_pm_ops,
|
||||
#endif /* CONFIG_PM */
|
||||
.shutdown = ice_shutdown,
|
||||
.sriov_configure = ice_sriov_configure,
|
||||
.err_handler = &ice_pci_err_handler
|
||||
};
|
||||
|
|
|
@ -172,8 +172,7 @@ void ice_release_nvm(struct ice_hw *hw)
|
|||
*
|
||||
* Reads one 16 bit word from the Shadow RAM using the ice_read_sr_word_aq.
|
||||
*/
|
||||
static enum ice_status
|
||||
ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)
|
||||
enum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data)
|
||||
{
|
||||
enum ice_status status;
|
||||
|
||||
|
|
|
@ -13,4 +13,5 @@ ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
|
|||
enum ice_status
|
||||
ice_read_pba_string(struct ice_hw *hw, u8 *pba_num, u32 pba_num_size);
|
||||
enum ice_status ice_init_nvm(struct ice_hw *hw);
|
||||
enum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data);
|
||||
#endif /* _ICE_NVM_H_ */
|
||||
|
|
|
@ -709,6 +709,7 @@ struct ice_hw_port_stats {
|
|||
|
||||
/* Checksum and Shadow RAM pointers */
|
||||
#define ICE_SR_BOOT_CFG_PTR 0x132
|
||||
#define ICE_SR_NVM_WOL_CFG 0x19
|
||||
#define ICE_NVM_OROM_VER_OFF 0x02
|
||||
#define ICE_SR_PBA_BLOCK_PTR 0x16
|
||||
#define ICE_SR_NVM_DEV_STARTER_VER 0x18
|
||||
|
|
|
@ -1592,31 +1592,6 @@ err_unroll_intr:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_pf_state_is_nominal - checks the PF for nominal state
|
||||
* @pf: pointer to PF to check
|
||||
*
|
||||
* Check the PF's state for a collection of bits that would indicate
|
||||
* the PF is in a state that would inhibit normal operation for
|
||||
* driver functionality.
|
||||
*
|
||||
* Returns true if PF is in a nominal state.
|
||||
* Returns false otherwise
|
||||
*/
|
||||
static bool ice_pf_state_is_nominal(struct ice_pf *pf)
|
||||
{
|
||||
DECLARE_BITMAP(check_bits, __ICE_STATE_NBITS) = { 0 };
|
||||
|
||||
if (!pf)
|
||||
return false;
|
||||
|
||||
bitmap_set(check_bits, 0, __ICE_STATE_NOMINAL_CHECK_BITS);
|
||||
if (bitmap_intersects(pf->state, check_bits, __ICE_STATE_NBITS))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ice_pci_sriov_ena - Enable or change number of VFs
|
||||
* @pf: pointer to the PF structure
|
||||
|
|
Загрузка…
Ссылка в новой задаче