return -EOPNOTSUPP;
 }
 
+static void tg3_hwclock_to_timestamp(struct tg3 *tp, u64 hwclock,
+                                    struct skb_shared_hwtstamps *timestamp)
+{
+       memset(timestamp, 0, sizeof(struct skb_shared_hwtstamps));
+       timestamp->hwtstamp  = ns_to_ktime((hwclock & TG3_TSTAMP_MASK) +
+                                          tp->ptp_adjust);
+}
+
+static void tg3_read_tx_tstamp(struct tg3 *tp, u64 *hwclock)
+{
+       *hwclock = tr32(TG3_TX_TSTAMP_LSB);
+       *hwclock |= (u64)tr32(TG3_TX_TSTAMP_MSB) << 32;
+}
+
+static long tg3_ptp_ts_aux_work(struct ptp_clock_info *ptp)
+{
+       struct tg3 *tp = container_of(ptp, struct tg3, ptp_info);
+       struct skb_shared_hwtstamps timestamp;
+       u64 hwclock;
+
+       if (tp->ptp_txts_retrycnt > 2)
+               goto done;
+
+       tg3_read_tx_tstamp(tp, &hwclock);
+
+       if (hwclock != tp->pre_tx_ts) {
+               tg3_hwclock_to_timestamp(tp, hwclock, ×tamp);
+               skb_tstamp_tx(tp->tx_tstamp_skb, ×tamp);
+               goto done;
+       }
+       tp->ptp_txts_retrycnt++;
+       return HZ / 10;
+done:
+       dev_consume_skb_any(tp->tx_tstamp_skb);
+       tp->tx_tstamp_skb = NULL;
+       tp->ptp_txts_retrycnt = 0;
+       tp->pre_tx_ts = 0;
+       return -1;
+}
+
 static const struct ptp_clock_info tg3_ptp_caps = {
        .owner          = THIS_MODULE,
        .name           = "tg3 clock",
        .pps            = 0,
        .adjfine        = tg3_ptp_adjfine,
        .adjtime        = tg3_ptp_adjtime,
+       .do_aux_work    = tg3_ptp_ts_aux_work,
        .gettimex64     = tg3_ptp_gettimex,
        .settime64      = tg3_ptp_settime,
        .enable         = tg3_ptp_enable,
 };
 
-static void tg3_hwclock_to_timestamp(struct tg3 *tp, u64 hwclock,
-                                    struct skb_shared_hwtstamps *timestamp)
-{
-       memset(timestamp, 0, sizeof(struct skb_shared_hwtstamps));
-       timestamp->hwtstamp  = ns_to_ktime((hwclock & TG3_TSTAMP_MASK) +
-                                          tp->ptp_adjust);
-}
-
 /* tp->lock must be held */
 static void tg3_ptp_init(struct tg3 *tp)
 {
        ptp_clock_unregister(tp->ptp_clock);
        tp->ptp_clock = NULL;
        tp->ptp_adjust = 0;
+       dev_consume_skb_any(tp->tx_tstamp_skb);
+       tp->tx_tstamp_skb = NULL;
 }
 
 static inline int tg3_irq_sync(struct tg3 *tp)
 
        while (sw_idx != hw_idx) {
                struct tg3_tx_ring_info *ri = &tnapi->tx_buffers[sw_idx];
+               bool complete_skb_later = false;
                struct sk_buff *skb = ri->skb;
                int i, tx_bug = 0;
 
 
                if (tnapi->tx_ring[sw_idx].len_flags & TXD_FLAG_HWTSTAMP) {
                        struct skb_shared_hwtstamps timestamp;
-                       u64 hwclock = tr32(TG3_TX_TSTAMP_LSB);
-                       hwclock |= (u64)tr32(TG3_TX_TSTAMP_MSB) << 32;
-
-                       tg3_hwclock_to_timestamp(tp, hwclock, ×tamp);
+                       u64 hwclock;
 
-                       skb_tstamp_tx(skb, ×tamp);
+                       tg3_read_tx_tstamp(tp, &hwclock);
+                       if (hwclock != tp->pre_tx_ts) {
+                               tg3_hwclock_to_timestamp(tp, hwclock, ×tamp);
+                               skb_tstamp_tx(skb, ×tamp);
+                               tp->pre_tx_ts = 0;
+                       } else {
+                               tp->tx_tstamp_skb = skb;
+                               complete_skb_later = true;
+                       }
                }
 
                dma_unmap_single(&tp->pdev->dev, dma_unmap_addr(ri, mapping),
                pkts_compl++;
                bytes_compl += skb->len;
 
-               dev_consume_skb_any(skb);
+               if (!complete_skb_later)
+                       dev_consume_skb_any(skb);
+               else
+                       ptp_schedule_worker(tp->ptp_clock, 0);
 
                if (unlikely(tx_bug)) {
                        tg3_tx_recover(tp);
 
        if ((unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) &&
            tg3_flag(tp, TX_TSTAMP_EN)) {
-               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
-               base_flags |= TXD_FLAG_HWTSTAMP;
+               tg3_full_lock(tp, 0);
+               if (!tp->pre_tx_ts) {
+                       skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+                       base_flags |= TXD_FLAG_HWTSTAMP;
+                       tg3_read_tx_tstamp(tp, &tp->pre_tx_ts);
+               }
+               tg3_full_unlock(tp);
        }
 
        len = skb_headlen(skb);