i40e/i40evf: fix incorrect default ITR values on driver load
[linux-2.6-microblaze.git] / drivers / net / ethernet / intel / i40e / i40e_main.c
index 6498da8..d4b0cc3 100644 (file)
@@ -599,6 +599,20 @@ static void i40e_stat_update32(struct i40e_hw *hw, u32 reg,
                *stat = (u32)((new_data + BIT_ULL(32)) - *offset);
 }
 
+/**
+ * i40e_stat_update_and_clear32 - read and clear hw reg, update a 32 bit stat
+ * @hw: ptr to the hardware info
+ * @reg: the hw reg to read and clear
+ * @stat: ptr to the stat
+ **/
+static void i40e_stat_update_and_clear32(struct i40e_hw *hw, u32 reg, u64 *stat)
+{
+       u32 new_data = rd32(hw, reg);
+
+       wr32(hw, reg, 1); /* must write a nonzero value to clear register */
+       *stat += new_data;
+}
+
 /**
  * i40e_update_eth_stats - Update VSI-specific ethernet statistics counters.
  * @vsi: the VSI to be updated
@@ -1040,18 +1054,15 @@ static void i40e_update_pf_stats(struct i40e_pf *pf)
                           &osd->rx_jabber, &nsd->rx_jabber);
 
        /* FDIR stats */
-       i40e_stat_update32(hw,
-                          I40E_GLQF_PCNT(I40E_FD_ATR_STAT_IDX(pf->hw.pf_id)),
-                          pf->stat_offsets_loaded,
-                          &osd->fd_atr_match, &nsd->fd_atr_match);
-       i40e_stat_update32(hw,
-                          I40E_GLQF_PCNT(I40E_FD_SB_STAT_IDX(pf->hw.pf_id)),
-                          pf->stat_offsets_loaded,
-                          &osd->fd_sb_match, &nsd->fd_sb_match);
-       i40e_stat_update32(hw,
-                     I40E_GLQF_PCNT(I40E_FD_ATR_TUNNEL_STAT_IDX(pf->hw.pf_id)),
-                     pf->stat_offsets_loaded,
-                     &osd->fd_atr_tunnel_match, &nsd->fd_atr_tunnel_match);
+       i40e_stat_update_and_clear32(hw,
+                       I40E_GLQF_PCNT(I40E_FD_ATR_STAT_IDX(hw->pf_id)),
+                       &nsd->fd_atr_match);
+       i40e_stat_update_and_clear32(hw,
+                       I40E_GLQF_PCNT(I40E_FD_SB_STAT_IDX(hw->pf_id)),
+                       &nsd->fd_sb_match);
+       i40e_stat_update_and_clear32(hw,
+                       I40E_GLQF_PCNT(I40E_FD_ATR_TUNNEL_STAT_IDX(hw->pf_id)),
+                       &nsd->fd_atr_tunnel_match);
 
        val = rd32(hw, I40E_PRTPM_EEE_STAT);
        nsd->tx_lpi_status =
@@ -1765,11 +1776,6 @@ static void i40e_set_rx_mode(struct net_device *netdev)
                vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
                vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
        }
-
-       /* schedule our worker thread which will take care of
-        * applying the new filter changes
-        */
-       i40e_service_event_schedule(vsi->back);
 }
 
 /**
@@ -2874,14 +2880,15 @@ static void i40e_vsi_free_rx_resources(struct i40e_vsi *vsi)
 static void i40e_config_xps_tx_ring(struct i40e_ring *ring)
 {
        struct i40e_vsi *vsi = ring->vsi;
+       int cpu;
 
        if (!ring->q_vector || !ring->netdev)
                return;
 
        if ((vsi->tc_config.numtc <= 1) &&
-           !test_and_set_bit(__I40E_TX_XPS_INIT_DONE, &ring->state)) {
-               netif_set_xps_queue(ring->netdev,
-                                   get_cpu_mask(ring->q_vector->v_idx),
+           !test_and_set_bit(__I40E_TX_XPS_INIT_DONE, ring->state)) {
+               cpu = cpumask_local_spread(ring->q_vector->v_idx, -1);
+               netif_set_xps_queue(ring->netdev, get_cpu_mask(cpu),
                                    ring->queue_index);
        }
 
@@ -2998,7 +3005,7 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
        struct i40e_hmc_obj_rxq rx_ctx;
        i40e_status err = 0;
 
-       ring->state = 0;
+       bitmap_zero(ring->state, __I40E_RING_STATE_NBITS);
 
        /* clear the context structure first */
        memset(&rx_ctx, 0, sizeof(rx_ctx));
@@ -3471,6 +3478,7 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)
        int tx_int_idx = 0;
        int vector, err;
        int irq_num;
+       int cpu;
 
        for (vector = 0; vector < q_vectors; vector++) {
                struct i40e_q_vector *q_vector = vsi->q_vectors[vector];
@@ -3506,10 +3514,14 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)
                q_vector->affinity_notify.notify = i40e_irq_affinity_notify;
                q_vector->affinity_notify.release = i40e_irq_affinity_release;
                irq_set_affinity_notifier(irq_num, &q_vector->affinity_notify);
-               /* get_cpu_mask returns a static constant mask with
-                * a permanent lifetime so it's ok to use here.
+               /* Spread affinity hints out across online CPUs.
+                *
+                * get_cpu_mask returns a static constant mask with
+                * a permanent lifetime so it's ok to pass to
+                * irq_set_affinity_hint without making a copy.
                 */
-               irq_set_affinity_hint(irq_num, get_cpu_mask(q_vector->v_idx));
+               cpu = cpumask_local_spread(q_vector->v_idx, -1);
+               irq_set_affinity_hint(irq_num, get_cpu_mask(cpu));
        }
 
        vsi->irqs_ready = true;
@@ -3593,14 +3605,20 @@ static int i40e_vsi_enable_irq(struct i40e_vsi *vsi)
 }
 
 /**
- * i40e_stop_misc_vector - Stop the vector that handles non-queue events
+ * i40e_free_misc_vector - Free the vector that handles non-queue events
  * @pf: board private structure
  **/
-static void i40e_stop_misc_vector(struct i40e_pf *pf)
+static void i40e_free_misc_vector(struct i40e_pf *pf)
 {
        /* Disable ICR 0 */
        wr32(&pf->hw, I40E_PFINT_ICR0_ENA, 0);
        i40e_flush(&pf->hw);
+
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED && pf->msix_entries) {
+               synchronize_irq(pf->msix_entries[0].vector);
+               free_irq(pf->msix_entries[0].vector, pf);
+               clear_bit(__I40E_MISC_IRQ_REQUESTED, pf->state);
+       }
 }
 
 /**
@@ -4455,11 +4473,7 @@ static void i40e_clear_interrupt_scheme(struct i40e_pf *pf)
 {
        int i;
 
-       i40e_stop_misc_vector(pf);
-       if (pf->flags & I40E_FLAG_MSIX_ENABLED && pf->msix_entries) {
-               synchronize_irq(pf->msix_entries[0].vector);
-               free_irq(pf->msix_entries[0].vector, pf);
-       }
+       i40e_free_misc_vector(pf);
 
        i40e_put_lump(pf->irq_pile, pf->iwarp_base_vector,
                      I40E_IWARP_IRQ_PILE_ID);
@@ -5346,13 +5360,14 @@ out:
 void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
 {
        enum i40e_aq_link_speed new_speed;
+       struct i40e_pf *pf = vsi->back;
        char *speed = "Unknown";
        char *fc = "Unknown";
        char *fec = "";
        char *req_fec = "";
        char *an = "";
 
-       new_speed = vsi->back->hw.phy.link_info.link_speed;
+       new_speed = pf->hw.phy.link_info.link_speed;
 
        if ((vsi->current_isup == isup) && (vsi->current_speed == new_speed))
                return;
@@ -5366,13 +5381,13 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
        /* Warn user if link speed on NPAR enabled partition is not at
         * least 10GB
         */
-       if (vsi->back->hw.func_caps.npar_enable &&
-           (vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_1GB ||
-            vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_100MB))
+       if (pf->hw.func_caps.npar_enable &&
+           (pf->hw.phy.link_info.link_speed == I40E_LINK_SPEED_1GB ||
+            pf->hw.phy.link_info.link_speed == I40E_LINK_SPEED_100MB))
                netdev_warn(vsi->netdev,
                            "The partition detected link speed that is less than 10Gbps\n");
 
-       switch (vsi->back->hw.phy.link_info.link_speed) {
+       switch (pf->hw.phy.link_info.link_speed) {
        case I40E_LINK_SPEED_40GB:
                speed = "40 G";
                break;
@@ -5395,7 +5410,7 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
                break;
        }
 
-       switch (vsi->back->hw.fc.current_mode) {
+       switch (pf->hw.fc.current_mode) {
        case I40E_FC_FULL:
                fc = "RX/TX";
                break;
@@ -5410,18 +5425,18 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
                break;
        }
 
-       if (vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_25GB) {
+       if (pf->hw.phy.link_info.link_speed == I40E_LINK_SPEED_25GB) {
                req_fec = ", Requested FEC: None";
                fec = ", FEC: None";
                an = ", Autoneg: False";
 
-               if (vsi->back->hw.phy.link_info.an_info & I40E_AQ_AN_COMPLETED)
+               if (pf->hw.phy.link_info.an_info & I40E_AQ_AN_COMPLETED)
                        an = ", Autoneg: True";
 
-               if (vsi->back->hw.phy.link_info.fec_info &
+               if (pf->hw.phy.link_info.fec_info &
                    I40E_AQ_CONFIG_FEC_KR_ENA)
                        fec = ", FEC: CL74 FC-FEC/BASE-R";
-               else if (vsi->back->hw.phy.link_info.fec_info &
+               else if (pf->hw.phy.link_info.fec_info &
                         I40E_AQ_CONFIG_FEC_RS_ENA)
                        fec = ", FEC: CL108 RS-FEC";
 
@@ -5470,15 +5485,6 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
                i40e_print_link_message(vsi, true);
                netif_tx_start_all_queues(vsi->netdev);
                netif_carrier_on(vsi->netdev);
-       } else if (vsi->netdev) {
-               i40e_print_link_message(vsi, false);
-               /* need to check for qualified module here*/
-               if ((pf->hw.phy.link_info.link_info &
-                       I40E_AQ_MEDIA_AVAILABLE) &&
-                   (!(pf->hw.phy.link_info.an_info &
-                       I40E_AQ_QUALIFIED_MODULE)))
-                       netdev_err(vsi->netdev,
-                                  "the driver failed to link because an unqualified module was detected.");
        }
 
        /* replay FDIR SB filters */
@@ -6226,6 +6232,7 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
                                hlist_del(&filter->fdir_node);
                                kfree(filter);
                                pf->fdir_pf_active_filters--;
+                               pf->fd_inv = 0;
                        }
                }
        }
@@ -6429,8 +6436,7 @@ static void i40e_link_event(struct i40e_pf *pf)
             new_link == netif_carrier_ok(vsi->netdev)))
                return;
 
-       if (!test_bit(__I40E_VSI_DOWN, vsi->state))
-               i40e_print_link_message(vsi, new_link);
+       i40e_print_link_message(vsi, new_link);
 
        /* Notify the base of the switch tree connected to
         * the link.  Floating VEBs are not notified.
@@ -6553,12 +6559,26 @@ static void i40e_handle_link_event(struct i40e_pf *pf,
         */
        i40e_link_event(pf);
 
-       /* check for unqualified module, if link is down */
-       if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
-           (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
-           (!(status->link_info & I40E_AQ_LINK_UP)))
+       /* Check if module meets thermal requirements */
+       if (status->phy_type == I40E_PHY_TYPE_NOT_SUPPORTED_HIGH_TEMP) {
+               dev_err(&pf->pdev->dev,
+                       "Rx/Tx is disabled on this device because the module does not meet thermal requirements.\n");
                dev_err(&pf->pdev->dev,
-                       "The driver failed to link because an unqualified module was detected.\n");
+                       "Refer to the Intel(R) Ethernet Adapters and Devices User Guide for a list of supported modules.\n");
+       } else {
+               /* check for unqualified module, if link is down, suppress
+                * the message if link was forced to be down.
+                */
+               if ((status->link_info & I40E_AQ_MEDIA_AVAILABLE) &&
+                   (!(status->an_info & I40E_AQ_QUALIFIED_MODULE)) &&
+                   (!(status->link_info & I40E_AQ_LINK_UP)) &&
+                   (!(pf->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED))) {
+                       dev_err(&pf->pdev->dev,
+                               "Rx/Tx is disabled on this device because an unsupported SFP module type was detected.\n");
+                       dev_err(&pf->pdev->dev,
+                               "Refer to the Intel(R) Ethernet Adapters and Devices User Guide for a list of supported modules.\n");
+               }
+       }
 }
 
 /**
@@ -8350,6 +8370,57 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)
        return 0;
 }
 
+#ifdef CONFIG_PM
+/**
+ * i40e_restore_interrupt_scheme - Restore the interrupt scheme
+ * @pf: private board data structure
+ *
+ * Restore the interrupt scheme that was cleared when we suspended the
+ * device. This should be called during resume to re-allocate the q_vectors
+ * and reacquire IRQs.
+ */
+static int i40e_restore_interrupt_scheme(struct i40e_pf *pf)
+{
+       int err, i;
+
+       /* We cleared the MSI and MSI-X flags when disabling the old interrupt
+        * scheme. We need to re-enabled them here in order to attempt to
+        * re-acquire the MSI or MSI-X vectors
+        */
+       pf->flags |= (I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED);
+
+       err = i40e_init_interrupt_scheme(pf);
+       if (err)
+               return err;
+
+       /* Now that we've re-acquired IRQs, we need to remap the vectors and
+        * rings together again.
+        */
+       for (i = 0; i < pf->num_alloc_vsi; i++) {
+               if (pf->vsi[i]) {
+                       err = i40e_vsi_alloc_q_vectors(pf->vsi[i]);
+                       if (err)
+                               goto err_unwind;
+                       i40e_vsi_map_rings_to_vectors(pf->vsi[i]);
+               }
+       }
+
+       err = i40e_setup_misc_vector(pf);
+       if (err)
+               goto err_unwind;
+
+       return 0;
+
+err_unwind:
+       while (i--) {
+               if (pf->vsi[i])
+                       i40e_vsi_free_q_vectors(pf->vsi[i]);
+       }
+
+       return err;
+}
+#endif /* CONFIG_PM */
+
 /**
  * i40e_setup_misc_vector - Setup the misc vector to handle non queue events
  * @pf: board private structure
@@ -8363,13 +8434,12 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
        struct i40e_hw *hw = &pf->hw;
        int err = 0;
 
-       /* Only request the irq if this is the first time through, and
-        * not when we're rebuilding after a Reset
-        */
-       if (!test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) {
+       /* Only request the IRQ once, the first time through. */
+       if (!test_and_set_bit(__I40E_MISC_IRQ_REQUESTED, pf->state)) {
                err = request_irq(pf->msix_entries[0].vector,
                                  i40e_intr, 0, pf->int_name, pf);
                if (err) {
+                       clear_bit(__I40E_MISC_IRQ_REQUESTED, pf->state);
                        dev_info(&pf->pdev->dev,
                                 "request_irq for %s failed: %d\n",
                                 pf->int_name, err);
@@ -8913,8 +8983,8 @@ static int i40e_sw_init(struct i40e_pf *pf)
                    I40E_FLAG_MSIX_ENABLED;
 
        /* Set default ITR */
-       pf->rx_itr_default = I40E_ITR_DYNAMIC | I40E_ITR_RX_DEF;
-       pf->tx_itr_default = I40E_ITR_DYNAMIC | I40E_ITR_TX_DEF;
+       pf->rx_itr_default = I40E_ITR_RX_DEF;
+       pf->tx_itr_default = I40E_ITR_TX_DEF;
 
        /* Depending on PF configurations, it is possible that the RSS
         * maximum might end up larger than the available queues
@@ -9014,6 +9084,11 @@ static int i40e_sw_init(struct i40e_pf *pf)
            (pf->hw.aq.fw_maj_ver >= 5)))
                pf->hw_features |= I40E_HW_USE_SET_LLDP_MIB;
 
+       /* Enable PTP L4 if FW > v6.0 */
+       if (pf->hw.mac.type == I40E_MAC_XL710 &&
+           pf->hw.aq.fw_maj_ver >= 6)
+               pf->hw_features |= I40E_HW_PTP_L4_CAPABLE;
+
        if (pf->hw.func_caps.vmdq) {
                pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI;
                pf->flags |= I40E_FLAG_VMDQ_ENABLED;
@@ -9849,6 +9924,31 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
 
                enabled_tc = i40e_pf_get_tc_map(pf);
 
+               /* Source pruning is enabled by default, so the flag is
+                * negative logic - if it's set, we need to fiddle with
+                * the VSI to disable source pruning.
+                */
+               if (pf->flags & I40E_FLAG_SOURCE_PRUNING_DISABLED) {
+                       memset(&ctxt, 0, sizeof(ctxt));
+                       ctxt.seid = pf->main_vsi_seid;
+                       ctxt.pf_num = pf->hw.pf_id;
+                       ctxt.vf_num = 0;
+                       ctxt.info.valid_sections |=
+                                    cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
+                       ctxt.info.switch_id =
+                                  cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB);
+                       ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
+                       if (ret) {
+                               dev_info(&pf->pdev->dev,
+                                        "update vsi failed, err %s aq_err %s\n",
+                                        i40e_stat_str(&pf->hw, ret),
+                                        i40e_aq_str(&pf->hw,
+                                                    pf->hw.aq.asq_last_status));
+                               ret = -ENOENT;
+                               goto err;
+                       }
+               }
+
                /* MFP mode setup queue map and update VSI */
                if ((pf->flags & I40E_FLAG_MFP_ENABLED) &&
                    !(pf->hw.func_caps.iscsi)) { /* NIC type PF */
@@ -11039,6 +11139,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
 static void i40e_determine_queue_usage(struct i40e_pf *pf)
 {
        int queues_left;
+       int q_max;
 
        pf->num_lan_qps = 0;
 
@@ -11085,10 +11186,12 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
                                        I40E_FLAG_DCB_ENABLED);
                        dev_info(&pf->pdev->dev, "not enough queues for DCB. DCB is disabled.\n");
                }
-               pf->num_lan_qps = max_t(int, pf->rss_size_max,
-                                       num_online_cpus());
-               pf->num_lan_qps = min_t(int, pf->num_lan_qps,
-                                       pf->hw.func_caps.num_tx_qp);
+
+               /* limit lan qps to the smaller of qps, cpus or msix */
+               q_max = max_t(int, pf->rss_size_max, num_online_cpus());
+               q_max = min_t(int, q_max, pf->hw.func_caps.num_tx_qp);
+               q_max = min_t(int, q_max, pf->hw.func_caps.num_msix_vectors);
+               pf->num_lan_qps = q_max;
 
                queues_left -= pf->num_lan_qps;
        }
@@ -11304,6 +11407,13 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        hw->bus.bus_id = pdev->bus->number;
        pf->instance = pfs_found;
 
+       /* Select something other than the 802.1ad ethertype for the
+        * switch to use internally and drop on ingress.
+        */
+       hw->switch_tag = 0xffff;
+       hw->first_tag = ETH_P_8021AD;
+       hw->second_tag = ETH_P_8021Q;
+
        INIT_LIST_HEAD(&pf->l3_flex_pit_list);
        INIT_LIST_HEAD(&pf->l4_flex_pit_list);
 
@@ -11380,11 +11490,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                 i40e_nvm_version_str(hw));
 
        if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
-           hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
+           hw->aq.api_min_ver > I40E_FW_MINOR_VERSION(hw))
                dev_info(&pdev->dev,
                         "The driver for the device detected a newer version of the NVM image than expected. Please install the most recent version of the network driver.\n");
-       else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
-                hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1))
+       else if (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver < 4)
                dev_info(&pdev->dev,
                         "The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n");
 
@@ -11936,6 +12045,28 @@ static pci_ers_result_t i40e_pci_error_slot_reset(struct pci_dev *pdev)
        return result;
 }
 
+/**
+ * i40e_pci_error_reset_prepare - prepare device driver for pci reset
+ * @pdev: PCI device information struct
+ */
+static void i40e_pci_error_reset_prepare(struct pci_dev *pdev)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+
+       i40e_prep_for_reset(pf, false);
+}
+
+/**
+ * i40e_pci_error_reset_done - pci reset done, device driver reset can begin
+ * @pdev: PCI device information struct
+ */
+static void i40e_pci_error_reset_done(struct pci_dev *pdev)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+
+       i40e_reset_and_rebuild(pf, false, false);
+}
+
 /**
  * i40e_pci_error_resume - restart operations after PCI error recovery
  * @pdev: PCI device information struct
@@ -12048,18 +12179,25 @@ static void i40e_shutdown(struct pci_dev *pdev)
 
 #ifdef CONFIG_PM
 /**
- * i40e_suspend - PCI callback for moving to D3
- * @pdev: PCI device information struct
+ * i40e_suspend - PM callback for moving to D3
+ * @dev: generic device information structure
  **/
-static int i40e_suspend(struct pci_dev *pdev, pm_message_t state)
+static int i40e_suspend(struct device *dev)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
        struct i40e_pf *pf = pci_get_drvdata(pdev);
        struct i40e_hw *hw = &pf->hw;
-       int retval = 0;
 
-       set_bit(__I40E_SUSPENDED, pf->state);
+       /* 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);
+
        if (pf->wol_en && (pf->hw_features & I40E_HW_WOL_MC_MAGIC_PKT_WAKE))
                i40e_enable_mc_magic_wake(pf);
 
@@ -12068,81 +12206,74 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t state)
        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));
 
-       i40e_stop_misc_vector(pf);
-       if (pf->msix_entries) {
-               synchronize_irq(pf->msix_entries[0].vector);
-               free_irq(pf->msix_entries[0].vector, pf);
-       }
-       retval = pci_save_state(pdev);
-       if (retval)
-               return retval;
-
-       pci_wake_from_d3(pdev, pf->wol_en);
-       pci_set_power_state(pdev, PCI_D3hot);
+       /* 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);
 
-       return retval;
+       return 0;
 }
 
 /**
- * i40e_resume - PCI callback for waking up from D3
- * @pdev: PCI device information struct
+ * i40e_resume - PM callback for waking up from D3
+ * @dev: generic device information structure
  **/
-static int i40e_resume(struct pci_dev *pdev)
+static int i40e_resume(struct device *dev)
 {
+       struct pci_dev *pdev = to_pci_dev(dev);
        struct i40e_pf *pf = pci_get_drvdata(pdev);
-       u32 err;
+       int err;
 
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
-       /* pci_restore_state() clears dev->state_saves, so
-        * call pci_save_state() again to restore it.
-        */
-       pci_save_state(pdev);
+       /* If we're not suspended, then there is nothing to do */
+       if (!test_bit(__I40E_SUSPENDED, pf->state))
+               return 0;
 
-       err = pci_enable_device_mem(pdev);
+       /* 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(&pdev->dev, "Cannot enable PCI device from suspend\n");
-               return err;
+               dev_err(&pdev->dev, "Cannot restore interrupt scheme: %d\n",
+                       err);
        }
-       pci_set_master(pdev);
 
-       /* no wakeup events while running */
-       pci_wake_from_d3(pdev, false);
-
-       /* handling the reset will rebuild the device state */
-       if (test_and_clear_bit(__I40E_SUSPENDED, pf->state)) {
-               clear_bit(__I40E_DOWN, pf->state);
-               if (pf->msix_entries) {
-                       err = request_irq(pf->msix_entries[0].vector,
-                                         i40e_intr, 0, pf->int_name, pf);
-                       if (err) {
-                               dev_err(&pf->pdev->dev,
-                                       "request_irq for %s failed: %d\n",
-                                       pf->int_name, err);
-                       }
-               }
-               i40e_reset_and_rebuild(pf, false, false);
-       }
+       clear_bit(__I40E_DOWN, pf->state);
+       i40e_reset_and_rebuild(pf, false, false);
+
+       /* 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;
 }
 
-#endif
+#endif /* CONFIG_PM */
+
 static const struct pci_error_handlers i40e_err_handler = {
        .error_detected = i40e_pci_error_detected,
        .slot_reset = i40e_pci_error_slot_reset,
+       .reset_prepare = i40e_pci_error_reset_prepare,
+       .reset_done = i40e_pci_error_reset_done,
        .resume = i40e_pci_error_resume,
 };
 
+static SIMPLE_DEV_PM_OPS(i40e_pm_ops, i40e_suspend, i40e_resume);
+
 static struct pci_driver i40e_driver = {
        .name     = i40e_driver_name,
        .id_table = i40e_pci_tbl,
        .probe    = i40e_probe,
        .remove   = i40e_remove,
 #ifdef CONFIG_PM
-       .suspend  = i40e_suspend,
-       .resume   = i40e_resume,
-#endif
+       .driver   = {
+               .pm = &i40e_pm_ops,
+       },
+#endif /* CONFIG_PM */
        .shutdown = i40e_shutdown,
        .err_handler = &i40e_err_handler,
        .sriov_configure = i40e_pci_sriov_configure,