#define MAX_FLEX_FILTER                        32
 
+#define IGC_MAX_TX_TSTAMP_REGS         4
+
 enum igc_mac_filter_type {
        IGC_MAC_FILTER_TYPE_DST = 0,
        IGC_MAC_FILTER_TYPE_SRC
        u64 other_packets;
 };
 
+struct igc_tx_timestamp_request {
+       struct sk_buff *skb;   /* reference to the packet being timestamped */
+       unsigned long start;   /* when the tstamp request started (jiffies) */
+       u32 mask;              /* _TSYNCTXCTL_TXTT_{X} bit for this request */
+       u32 regl;              /* which TXSTMPL_{X} register should be used */
+       u32 regh;              /* which TXSTMPH_{X} register should be used */
+       u32 flags;             /* flags that should be added to the tx_buffer */
+};
+
 struct igc_ring_container {
        struct igc_ring *ring;          /* pointer to linked list of rings */
        unsigned int total_bytes;       /* total bytes processed this int */
         * ptp_tx_lock.
         */
        spinlock_t ptp_tx_lock;
-       struct sk_buff *ptp_tx_skb;
+       struct igc_tx_timestamp_request tx_tstamp[IGC_MAX_TX_TSTAMP_REGS];
        struct hwtstamp_config tstamp_config;
-       unsigned long ptp_tx_start;
        unsigned int ptp_flags;
        /* System time value lock */
        spinlock_t tmreg_lock;
        /* olinfo flags */
        IGC_TX_FLAGS_IPV4       = 0x10,
        IGC_TX_FLAGS_CSUM       = 0x20,
+
+       IGC_TX_FLAGS_TSTAMP_1   = 0x100,
+       IGC_TX_FLAGS_TSTAMP_2   = 0x200,
+       IGC_TX_FLAGS_TSTAMP_3   = 0x400,
 };
 
 enum igc_boards {
 
        cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSO,
                                 (IGC_ADVTXD_DCMD_TSE));
 
-       /* set timestamp bit if present */
+       /* set timestamp bit if present, will select the register set
+        * based on the _TSTAMP(_X) bit.
+        */
        cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP,
                                 (IGC_ADVTXD_MAC_TSTAMP));
 
+       cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_1,
+                                (IGC_ADVTXD_TSTAMP_REG_1));
+
+       cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_2,
+                                (IGC_ADVTXD_TSTAMP_REG_2));
+
+       cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_3,
+                                (IGC_ADVTXD_TSTAMP_REG_3));
+
        /* insert frame checksum */
        cmd_type ^= IGC_SET_FLAG(skb->no_fcs, 1, IGC_ADVTXD_DCMD_IFCS);
 
        return 1;
 }
 
+static bool igc_request_tx_tstamp(struct igc_adapter *adapter, struct sk_buff *skb, u32 *flags)
+{
+       int i;
+
+       for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
+               struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
+
+               if (tstamp->skb)
+                       continue;
+
+               tstamp->skb = skb_get(skb);
+               tstamp->start = jiffies;
+               *flags = tstamp->flags;
+
+               return true;
+       }
+
+       return false;
+}
+
 static netdev_tx_t igc_xmit_frame_ring(struct sk_buff *skb,
                                       struct igc_ring *tx_ring)
 {
                 * timestamping request.
                 */
                unsigned long flags;
+               u32 tstamp_flags;
 
                spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
-               if (!adapter->ptp_tx_skb) {
+               if (igc_request_tx_tstamp(adapter, skb, &tstamp_flags)) {
                        skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
-                       tx_flags |= IGC_TX_FLAGS_TSTAMP;
-
-                       adapter->ptp_tx_skb = skb_get(skb);
-                       adapter->ptp_tx_start = jiffies;
+                       tx_flags |= IGC_TX_FLAGS_TSTAMP | tstamp_flags;
                } else {
                        adapter->tx_hwtstamp_skipped++;
                }
 
 static void igc_ptp_clear_tx_tstamp(struct igc_adapter *adapter)
 {
        unsigned long flags;
+       int i;
 
        spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
 
-       dev_kfree_skb_any(adapter->ptp_tx_skb);
-       adapter->ptp_tx_skb = NULL;
+       for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
+               struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
+
+               dev_kfree_skb_any(tstamp->skb);
+               tstamp->skb = NULL;
+       }
 
        spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
 }
 }
 
 /* Requires adapter->ptp_tx_lock held by caller. */
-static void igc_ptp_tx_timeout(struct igc_adapter *adapter)
+static void igc_ptp_tx_timeout(struct igc_adapter *adapter,
+                              struct igc_tx_timestamp_request *tstamp)
 {
-       struct igc_hw *hw = &adapter->hw;
-
-       dev_kfree_skb_any(adapter->ptp_tx_skb);
-       adapter->ptp_tx_skb = NULL;
+       dev_kfree_skb_any(tstamp->skb);
+       tstamp->skb = NULL;
        adapter->tx_hwtstamp_timeouts++;
-       /* Clear the tx valid bit in TSYNCTXCTL register to enable interrupt. */
-       rd32(IGC_TXSTMPH);
+
        netdev_warn(adapter->netdev, "Tx timestamp timeout\n");
 }
 
 void igc_ptp_tx_hang(struct igc_adapter *adapter)
 {
+       struct igc_tx_timestamp_request *tstamp;
+       struct igc_hw *hw = &adapter->hw;
        unsigned long flags;
+       bool found = false;
+       int i;
 
        spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
 
-       if (!adapter->ptp_tx_skb)
-               goto unlock;
+       for (i = 0; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
+               tstamp = &adapter->tx_tstamp[i];
+
+               if (!tstamp->skb)
+                       continue;
 
-       if (time_is_after_jiffies(adapter->ptp_tx_start + IGC_PTP_TX_TIMEOUT))
-               goto unlock;
+               if (time_is_after_jiffies(tstamp->start + IGC_PTP_TX_TIMEOUT))
+                       continue;
 
-       igc_ptp_tx_timeout(adapter);
+               igc_ptp_tx_timeout(adapter, tstamp);
+               found = true;
+       }
+
+       if (found) {
+               /* Reading the high register of the first set of timestamp registers
+                * clears all the equivalent bits in the TSYNCTXCTL register.
+                */
+               rd32(IGC_TXSTMPH_0);
+       }
 
-unlock:
        spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
 }
 
+static void igc_ptp_tx_reg_to_stamp(struct igc_adapter *adapter,
+                                   struct igc_tx_timestamp_request *tstamp, u64 regval)
+{
+       struct skb_shared_hwtstamps shhwtstamps;
+       struct sk_buff *skb;
+       int adjust = 0;
+
+       skb = tstamp->skb;
+       if (!skb)
+               return;
+
+       if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval))
+               return;
+
+       switch (adapter->link_speed) {
+       case SPEED_10:
+               adjust = IGC_I225_TX_LATENCY_10;
+               break;
+       case SPEED_100:
+               adjust = IGC_I225_TX_LATENCY_100;
+               break;
+       case SPEED_1000:
+               adjust = IGC_I225_TX_LATENCY_1000;
+               break;
+       case SPEED_2500:
+               adjust = IGC_I225_TX_LATENCY_2500;
+               break;
+       }
+
+       shhwtstamps.hwtstamp =
+               ktime_add_ns(shhwtstamps.hwtstamp, adjust);
+
+       tstamp->skb = NULL;
+
+       skb_tstamp_tx(skb, &shhwtstamps);
+       dev_kfree_skb_any(skb);
+}
+
 /**
  * igc_ptp_tx_hwtstamp - utility function which checks for TX time stamp
  * @adapter: Board private structure
  *
- * If we were asked to do hardware stamping and such a time stamp is
- * available, then it must have been for this skb here because we only
- * allow only one such packet into the queue.
+ * Check against the ready mask for which of the timestamp register
+ * sets are ready to be retrieved, then retrieve that and notify the
+ * rest of the stack.
  *
  * Context: Expects adapter->ptp_tx_lock to be held by caller.
  */
 static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
 {
-       struct sk_buff *skb = adapter->ptp_tx_skb;
-       struct skb_shared_hwtstamps shhwtstamps;
        struct igc_hw *hw = &adapter->hw;
-       u32 tsynctxctl;
-       int adjust = 0;
        u64 regval;
+       u32 mask;
+       int i;
 
-       if (WARN_ON_ONCE(!skb))
-               return;
-
-       tsynctxctl = rd32(IGC_TSYNCTXCTL);
-       tsynctxctl &= IGC_TSYNCTXCTL_TXTT_0;
-       if (tsynctxctl) {
+       mask = rd32(IGC_TSYNCTXCTL) & IGC_TSYNCTXCTL_TXTT_ANY;
+       if (mask & IGC_TSYNCTXCTL_TXTT_0) {
                regval = rd32(IGC_TXSTMPL);
                regval |= (u64)rd32(IGC_TXSTMPH) << 32;
        } else {
                txstmpl_new = rd32(IGC_TXSTMPL);
 
                if (txstmpl_old == txstmpl_new)
-                       return;
+                       goto done;
 
                regval = txstmpl_new;
                regval |= (u64)rd32(IGC_TXSTMPH) << 32;
        }
-       if (igc_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval))
-               return;
 
-       switch (adapter->link_speed) {
-       case SPEED_10:
-               adjust = IGC_I225_TX_LATENCY_10;
-               break;
-       case SPEED_100:
-               adjust = IGC_I225_TX_LATENCY_100;
-               break;
-       case SPEED_1000:
-               adjust = IGC_I225_TX_LATENCY_1000;
-               break;
-       case SPEED_2500:
-               adjust = IGC_I225_TX_LATENCY_2500;
-               break;
-       }
+       igc_ptp_tx_reg_to_stamp(adapter, &adapter->tx_tstamp[0], regval);
 
-       shhwtstamps.hwtstamp =
-               ktime_add_ns(shhwtstamps.hwtstamp, adjust);
+done:
+       /* Now that the problematic first register was handled, we can
+        * use retrieve the timestamps from the other registers
+        * (starting from '1') with less complications.
+        */
+       for (i = 1; i < IGC_MAX_TX_TSTAMP_REGS; i++) {
+               struct igc_tx_timestamp_request *tstamp = &adapter->tx_tstamp[i];
 
-       adapter->ptp_tx_skb = NULL;
+               if (!(tstamp->mask & mask))
+                       continue;
 
-       /* Notify the stack and free the skb after we've unlocked */
-       skb_tstamp_tx(skb, &shhwtstamps);
-       dev_kfree_skb_any(skb);
+               regval = rd32(tstamp->regl);
+               regval |= (u64)rd32(tstamp->regh) << 32;
+
+               igc_ptp_tx_reg_to_stamp(adapter, tstamp, regval);
+       }
 }
 
 /**
 
        spin_lock_irqsave(&adapter->ptp_tx_lock, flags);
 
-       if (!adapter->ptp_tx_skb)
-               goto unlock;
-
        igc_ptp_tx_hwtstamp(adapter);
 
-unlock:
        spin_unlock_irqrestore(&adapter->ptp_tx_lock, flags);
 }
 
 void igc_ptp_init(struct igc_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
+       struct igc_tx_timestamp_request *tstamp;
        struct igc_hw *hw = &adapter->hw;
        int i;
 
+       tstamp = &adapter->tx_tstamp[0];
+       tstamp->mask = IGC_TSYNCTXCTL_TXTT_0;
+       tstamp->regl = IGC_TXSTMPL_0;
+       tstamp->regh = IGC_TXSTMPH_0;
+       tstamp->flags = 0;
+
+       tstamp = &adapter->tx_tstamp[1];
+       tstamp->mask = IGC_TSYNCTXCTL_TXTT_1;
+       tstamp->regl = IGC_TXSTMPL_1;
+       tstamp->regh = IGC_TXSTMPH_1;
+       tstamp->flags = IGC_TX_FLAGS_TSTAMP_1;
+
+       tstamp = &adapter->tx_tstamp[2];
+       tstamp->mask = IGC_TSYNCTXCTL_TXTT_2;
+       tstamp->regl = IGC_TXSTMPL_2;
+       tstamp->regh = IGC_TXSTMPH_2;
+       tstamp->flags = IGC_TX_FLAGS_TSTAMP_2;
+
+       tstamp = &adapter->tx_tstamp[3];
+       tstamp->mask = IGC_TSYNCTXCTL_TXTT_3;
+       tstamp->regl = IGC_TXSTMPL_3;
+       tstamp->regh = IGC_TXSTMPH_3;
+       tstamp->flags = IGC_TX_FLAGS_TSTAMP_3;
+
        switch (hw->mac.type) {
        case igc_i225:
                for (i = 0; i < IGC_N_SDP; i++) {