unsigned long hung_detected; /* Set/Reset for hung_detection logic */
 
        cpumask_t affinity_mask;
+       struct irq_affinity_notify affinity_notify;
+
        struct rcu_head rcu;    /* to avoid race with update stats on free */
        char name[I40E_INT_NAME_STR_LEN];
        bool arm_wb_state;
 
        return IRQ_HANDLED;
 }
 
+/**
+ * i40e_irq_affinity_notify - Callback for affinity changes
+ * @notify: context as to what irq was changed
+ * @mask: the new affinity mask
+ *
+ * This is a callback function used by the irq_set_affinity_notifier function
+ * so that we may register to receive changes to the irq affinity masks.
+ **/
+static void i40e_irq_affinity_notify(struct irq_affinity_notify *notify,
+                                    const cpumask_t *mask)
+{
+       struct i40e_q_vector *q_vector =
+               container_of(notify, struct i40e_q_vector, affinity_notify);
+
+       q_vector->affinity_mask = *mask;
+}
+
+/**
+ * i40e_irq_affinity_release - Callback for affinity notifier release
+ * @ref: internal core kernel usage
+ *
+ * This is a callback function used by the irq_set_affinity_notifier function
+ * to inform the current notification subscriber that they will no longer
+ * receive notifications.
+ **/
+static void i40e_irq_affinity_release(struct kref *ref) {}
+
 /**
  * i40e_vsi_request_irq_msix - Initialize MSI-X interrupts
  * @vsi: the VSI being configured
        int rx_int_idx = 0;
        int tx_int_idx = 0;
        int vector, err;
+       int irq_num;
 
        for (vector = 0; vector < q_vectors; vector++) {
                struct i40e_q_vector *q_vector = vsi->q_vectors[vector];
 
+               irq_num = pf->msix_entries[base + vector].vector;
+
                if (q_vector->tx.ring && q_vector->rx.ring) {
                        snprintf(q_vector->name, sizeof(q_vector->name) - 1,
                                 "%s-%s-%d", basename, "TxRx", rx_int_idx++);
                        /* skip this unused q_vector */
                        continue;
                }
-               err = request_irq(pf->msix_entries[base + vector].vector,
+               err = request_irq(irq_num,
                                  vsi->irq_handler,
                                  0,
                                  q_vector->name,
                                 "MSIX request_irq failed, error: %d\n", err);
                        goto free_queue_irqs;
                }
+
+               /* register for affinity change notifications */
+               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);
                /* assign the mask for this irq */
-               irq_set_affinity_hint(pf->msix_entries[base + vector].vector,
-                                     &q_vector->affinity_mask);
+               irq_set_affinity_hint(irq_num, &q_vector->affinity_mask);
        }
 
        vsi->irqs_ready = true;
 free_queue_irqs:
        while (vector) {
                vector--;
-               irq_set_affinity_hint(pf->msix_entries[base + vector].vector,
-                                     NULL);
-               free_irq(pf->msix_entries[base + vector].vector,
-                        &(vsi->q_vectors[vector]));
+               irq_num = pf->msix_entries[base + vector].vector;
+               irq_set_affinity_notifier(irq_num, NULL);
+               irq_set_affinity_hint(irq_num, NULL);
+               free_irq(irq_num, &vsi->q_vectors[vector]);
        }
        return err;
 }
 
                vsi->irqs_ready = false;
                for (i = 0; i < vsi->num_q_vectors; i++) {
-                       u16 vector = i + base;
+                       int irq_num;
+                       u16 vector;
+
+                       vector = i + base;
+                       irq_num = pf->msix_entries[vector].vector;
 
                        /* free only the irqs that were actually requested */
                        if (!vsi->q_vectors[i] ||
                            !vsi->q_vectors[i]->num_ringpairs)
                                continue;
 
+                       /* clear the affinity notifier in the IRQ descriptor */
+                       irq_set_affinity_notifier(irq_num, NULL);
                        /* clear the affinity_mask in the IRQ descriptor */
-                       irq_set_affinity_hint(pf->msix_entries[vector].vector,
-                                             NULL);
-                       synchronize_irq(pf->msix_entries[vector].vector);
-                       free_irq(pf->msix_entries[vector].vector,
-                                vsi->q_vectors[i]);
+                       irq_set_affinity_hint(irq_num, NULL);
+                       synchronize_irq(irq_num);
+                       free_irq(irq_num, vsi->q_vectors[i]);
 
                        /* Tear down the interrupt queue link list
                         *
 
 
        /* If work not completed, return budget and polling will return */
        if (!clean_complete) {
+               const cpumask_t *aff_mask = &q_vector->affinity_mask;
+               int cpu_id = smp_processor_id();
+
+               /* It is possible that the interrupt affinity has changed but,
+                * if the cpu is pegged at 100%, polling will never exit while
+                * traffic continues and the interrupt will be stuck on this
+                * cpu.  We check to make sure affinity is correct before we
+                * continue to poll, otherwise we must stop polling so the
+                * interrupt can move to the correct cpu.
+                */
+               if (likely(cpumask_test_cpu(cpu_id, aff_mask) ||
+                          !(vsi->back->flags & I40E_FLAG_MSIX_ENABLED))) {
 tx_only:
-               if (arm_wb) {
-                       q_vector->tx.ring[0].tx_stats.tx_force_wb++;
-                       i40e_enable_wb_on_itr(vsi, q_vector);
+                       if (arm_wb) {
+                               q_vector->tx.ring[0].tx_stats.tx_force_wb++;
+                               i40e_enable_wb_on_itr(vsi, q_vector);
+                       }
+                       return budget;
                }
-               return budget;
        }
 
        if (vsi->back->flags & I40E_TXR_FLAGS_WB_ON_ITR)
 
        /* Work is done so exit the polling mode and re-enable the interrupt */
        napi_complete_done(napi, work_done);
-       if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
-               i40e_update_enable_itr(vsi, q_vector);
-       } else { /* Legacy mode */
+
+       /* If we're prematurely stopping polling to fix the interrupt
+        * affinity we want to make sure polling starts back up so we
+        * issue a call to i40e_force_wb which triggers a SW interrupt.
+        */
+       if (!clean_complete)
+               i40e_force_wb(vsi, q_vector);
+       else if (!(vsi->back->flags & I40E_FLAG_MSIX_ENABLED))
                i40e_irq_dynamic_enable_icr0(vsi->back, false);
-       }
+       else
+               i40e_update_enable_itr(vsi, q_vector);
+
        return 0;
 }
 
 
 
        /* If work not completed, return budget and polling will return */
        if (!clean_complete) {
+               const cpumask_t *aff_mask = &q_vector->affinity_mask;
+               int cpu_id = smp_processor_id();
+
+               /* It is possible that the interrupt affinity has changed but,
+                * if the cpu is pegged at 100%, polling will never exit while
+                * traffic continues and the interrupt will be stuck on this
+                * cpu.  We check to make sure affinity is correct before we
+                * continue to poll, otherwise we must stop polling so the
+                * interrupt can move to the correct cpu.
+                */
+               if (likely(cpumask_test_cpu(cpu_id, aff_mask))) {
 tx_only:
-               if (arm_wb) {
-                       q_vector->tx.ring[0].tx_stats.tx_force_wb++;
-                       i40e_enable_wb_on_itr(vsi, q_vector);
+                       if (arm_wb) {
+                               q_vector->tx.ring[0].tx_stats.tx_force_wb++;
+                               i40e_enable_wb_on_itr(vsi, q_vector);
+                       }
+                       return budget;
                }
-               return budget;
        }
 
        if (vsi->back->flags & I40E_TXR_FLAGS_WB_ON_ITR)
 
        /* Work is done so exit the polling mode and re-enable the interrupt */
        napi_complete_done(napi, work_done);
-       i40e_update_enable_itr(vsi, q_vector);
+
+       /* If we're prematurely stopping polling to fix the interrupt
+        * affinity we want to make sure polling starts back up so we
+        * issue a call to i40evf_force_wb which triggers a SW interrupt.
+        */
+       if (!clean_complete)
+               i40evf_force_wb(vsi, q_vector);
+       else
+               i40e_update_enable_itr(vsi, q_vector);
+
        return 0;
 }
 
 
        int v_idx;      /* vector index in list */
        char name[IFNAMSIZ + 9];
        bool arm_wb_state;
-       cpumask_var_t affinity_mask;
+       cpumask_t affinity_mask;
+       struct irq_affinity_notify affinity_notify;
 };
 
 /* Helper macros to switch between ints/sec and what the register uses.
 
 }
 
 #endif
+/**
+ * i40evf_irq_affinity_notify - Callback for affinity changes
+ * @notify: context as to what irq was changed
+ * @mask: the new affinity mask
+ *
+ * This is a callback function used by the irq_set_affinity_notifier function
+ * so that we may register to receive changes to the irq affinity masks.
+ **/
+static void i40evf_irq_affinity_notify(struct irq_affinity_notify *notify,
+                                      const cpumask_t *mask)
+{
+       struct i40e_q_vector *q_vector =
+               container_of(notify, struct i40e_q_vector, affinity_notify);
+
+       q_vector->affinity_mask = *mask;
+}
+
+/**
+ * i40evf_irq_affinity_release - Callback for affinity notifier release
+ * @ref: internal core kernel usage
+ *
+ * This is a callback function used by the irq_set_affinity_notifier function
+ * to inform the current notification subscriber that they will no longer
+ * receive notifications.
+ **/
+static void i40evf_irq_affinity_release(struct kref *ref) {}
+
 /**
  * i40evf_request_traffic_irqs - Initialize MSI-X interrupts
  * @adapter: board private structure
 {
        int vector, err, q_vectors;
        int rx_int_idx = 0, tx_int_idx = 0;
+       int irq_num;
 
        i40evf_irq_disable(adapter);
        /* Decrement for Other and TCP Timer vectors */
 
        for (vector = 0; vector < q_vectors; vector++) {
                struct i40e_q_vector *q_vector = &adapter->q_vectors[vector];
+               irq_num = adapter->msix_entries[vector + NONQ_VECS].vector;
 
                if (q_vector->tx.ring && q_vector->rx.ring) {
                        snprintf(q_vector->name, sizeof(q_vector->name) - 1,
                        /* skip this unused q_vector */
                        continue;
                }
-               err = request_irq(
-                       adapter->msix_entries[vector + NONQ_VECS].vector,
-                       i40evf_msix_clean_rings,
-                       0,
-                       q_vector->name,
-                       q_vector);
+               err = request_irq(irq_num,
+                                 i40evf_msix_clean_rings,
+                                 0,
+                                 q_vector->name,
+                                 q_vector);
                if (err) {
                        dev_info(&adapter->pdev->dev,
                                 "Request_irq failed, error: %d\n", err);
                        goto free_queue_irqs;
                }
+               /* register for affinity change notifications */
+               q_vector->affinity_notify.notify = i40evf_irq_affinity_notify;
+               q_vector->affinity_notify.release =
+                                                  i40evf_irq_affinity_release;
+               irq_set_affinity_notifier(irq_num, &q_vector->affinity_notify);
                /* assign the mask for this irq */
-               irq_set_affinity_hint(
-                       adapter->msix_entries[vector + NONQ_VECS].vector,
-                       q_vector->affinity_mask);
+               irq_set_affinity_hint(irq_num, &q_vector->affinity_mask);
        }
 
        return 0;
 free_queue_irqs:
        while (vector) {
                vector--;
-               irq_set_affinity_hint(
-                       adapter->msix_entries[vector + NONQ_VECS].vector,
-                       NULL);
-               free_irq(adapter->msix_entries[vector + NONQ_VECS].vector,
-                        &adapter->q_vectors[vector]);
+               irq_num = adapter->msix_entries[vector + NONQ_VECS].vector;
+               irq_set_affinity_notifier(irq_num, NULL);
+               irq_set_affinity_hint(irq_num, NULL);
+               free_irq(irq_num, &adapter->q_vectors[vector]);
        }
        return err;
 }
  **/
 static void i40evf_free_traffic_irqs(struct i40evf_adapter *adapter)
 {
-       int i;
-       int q_vectors;
+       int vector, irq_num, q_vectors;
 
        q_vectors = adapter->num_msix_vectors - NONQ_VECS;
 
-       for (i = 0; i < q_vectors; i++) {
-               irq_set_affinity_hint(adapter->msix_entries[i+1].vector,
-                                     NULL);
-               free_irq(adapter->msix_entries[i+1].vector,
-                        &adapter->q_vectors[i]);
+       for (vector = 0; vector < q_vectors; vector++) {
+               irq_num = adapter->msix_entries[vector + NONQ_VECS].vector;
+               irq_set_affinity_notifier(irq_num, NULL);
+               irq_set_affinity_hint(irq_num, NULL);
+               free_irq(irq_num, &adapter->q_vectors[vector]);
        }
 }