]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
igb: cleanup some of the code related to hw timestamping
authorAlexander Duyck <alexander.h.duyck@intel.com>
Tue, 27 Oct 2009 23:46:01 +0000 (23:46 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 28 Oct 2009 10:25:33 +0000 (03:25 -0700)
The code for the hw timestamping is a bit bulky and making some of the
functions difficult to read.  In order to clean things up a bit I am moving
the timestamping operations into seperate functions.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/igb/e1000_82575.h
drivers/net/igb/e1000_defines.h
drivers/net/igb/e1000_regs.h
drivers/net/igb/igb.h
drivers/net/igb/igb_main.c

index 9418683ed006d978c889001f0597cfe365c4ae68..cbe475747d1ad0231137fbc3f74909cfd4edb9fe 100644 (file)
@@ -66,6 +66,8 @@ extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
     E1000_EICR_RX_QUEUE3)
 
 /* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */
+#define E1000_IMIREXT_SIZE_BP     0x00001000  /* Packet size bypass */
+#define E1000_IMIREXT_CTRL_BP     0x00080000  /* Bypass check of ctrl bits */
 
 /* Receive Descriptor - Advanced */
 union e1000_adv_rx_desc {
@@ -98,6 +100,7 @@ union e1000_adv_rx_desc {
 
 #define E1000_RXDADV_HDRBUFLEN_MASK      0x7FE0
 #define E1000_RXDADV_HDRBUFLEN_SHIFT     5
+#define E1000_RXDADV_STAT_TS             0x10000 /* Pkt was time stamped */
 
 /* Transmit Descriptor - Advanced */
 union e1000_adv_tx_desc {
@@ -167,6 +170,17 @@ struct e1000_adv_tx_context_desc {
 #define E1000_DCA_TXCTRL_CPUID_SHIFT 24 /* Tx CPUID now in the last byte */
 #define E1000_DCA_RXCTRL_CPUID_SHIFT 24 /* Rx CPUID now in the last byte */
 
+/* ETQF register bit definitions */
+#define E1000_ETQF_FILTER_ENABLE   (1 << 26)
+#define E1000_ETQF_1588            (1 << 30)
+
+/* FTQF register bit definitions */
+#define E1000_FTQF_VF_BP               0x00008000
+#define E1000_FTQF_1588_TIME_STAMP     0x08000000
+#define E1000_FTQF_MASK                0xF0000000
+#define E1000_FTQF_MASK_PROTO_BP       0x10000000
+#define E1000_FTQF_MASK_SOURCE_PORT_BP 0x80000000
+
 #define E1000_NVM_APME_82575          0x0400
 #define MAX_NUM_VFS                   8
 
index cb916833f303126beb0b35c4584ae91d0949be3c..48fcab03b752ab1234b806bb78f983c28b38c304 100644 (file)
 /* Flow Control */
 #define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
 
+#define E1000_TSYNCTXCTL_VALID    0x00000001 /* tx timestamp valid */
+#define E1000_TSYNCTXCTL_ENABLED  0x00000010 /* enable tx timestampping */
+
+#define E1000_TSYNCRXCTL_VALID      0x00000001 /* rx timestamp valid */
+#define E1000_TSYNCRXCTL_TYPE_MASK  0x0000000E /* rx type mask */
+#define E1000_TSYNCRXCTL_TYPE_L2_V2       0x00
+#define E1000_TSYNCRXCTL_TYPE_L4_V1       0x02
+#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2    0x04
+#define E1000_TSYNCRXCTL_TYPE_ALL         0x08
+#define E1000_TSYNCRXCTL_TYPE_EVENT_V2    0x0A
+#define E1000_TSYNCRXCTL_ENABLED    0x00000010 /* enable rx timestampping */
+
+#define E1000_TSYNCRXCFG_PTP_V1_CTRLT_MASK   0x000000FF
+#define E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE       0x00
+#define E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE  0x01
+#define E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE   0x02
+#define E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE 0x03
+#define E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE 0x04
+
+#define E1000_TSYNCRXCFG_PTP_V2_MSGID_MASK               0x00000F00
+#define E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE                 0x0000
+#define E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE            0x0100
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE       0x0200
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE      0x0300
+#define E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE             0x0800
+#define E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE           0x0900
+#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE  0x0A00
+#define E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE             0x0B00
+#define E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE           0x0C00
+#define E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE           0x0D00
+
+#define E1000_TIMINCA_16NS_SHIFT 24
+
 /* PCI Express Control */
 #define E1000_GCR_CMPL_TMOUT_MASK       0x0000F000
 #define E1000_GCR_CMPL_TMOUT_10ms       0x00001000
index e06c3b706b15650046e5c4671c0c2301fc9b66f4..24f2c24d0309563d2731f98ed0cbf5c71ca10d34 100644 (file)
 #define E1000_FCRTV    0x02460  /* Flow Control Refresh Timer Value - RW */
 
 /* IEEE 1588 TIMESYNCH */
-#define E1000_TSYNCTXCTL 0x0B614
-#define E1000_TSYNCTXCTL_VALID (1<<0)
-#define E1000_TSYNCTXCTL_ENABLED (1<<4)
-#define E1000_TSYNCRXCTL 0x0B620
-#define E1000_TSYNCRXCTL_VALID (1<<0)
-#define E1000_TSYNCRXCTL_ENABLED (1<<4)
-enum {
-       E1000_TSYNCRXCTL_TYPE_L2_V2 = 0,
-       E1000_TSYNCRXCTL_TYPE_L4_V1 = (1<<1),
-       E1000_TSYNCRXCTL_TYPE_L2_L4_V2 = (1<<2),
-       E1000_TSYNCRXCTL_TYPE_ALL = (1<<3),
-       E1000_TSYNCRXCTL_TYPE_EVENT_V2 = (1<<3) | (1<<1),
-};
-#define E1000_TSYNCRXCFG 0x05F50
-enum {
-       E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE = 0<<0,
-       E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE = 1<<0,
-       E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE = 2<<0,
-       E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE = 3<<0,
-       E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE = 4<<0,
-
-       E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE = 0<<8,
-       E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE = 1<<8,
-       E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE = 2<<8,
-       E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE = 3<<8,
-       E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE = 8<<8,
-       E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE = 9<<8,
-       E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE = 0xA<<8,
-       E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE = 0xB<<8,
-       E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE = 0xC<<8,
-       E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE = 0xD<<8,
-};
-#define E1000_SYSTIML 0x0B600
-#define E1000_SYSTIMH 0x0B604
-#define E1000_TIMINCA 0x0B608
-
-#define E1000_RXMTRL     0x0B634
-#define E1000_RXSTMPL 0x0B624
-#define E1000_RXSTMPH 0x0B628
-#define E1000_RXSATRL 0x0B62C
-#define E1000_RXSATRH 0x0B630
-
-#define E1000_TXSTMPL 0x0B618
-#define E1000_TXSTMPH 0x0B61C
-
-#define E1000_ETQF0   0x05CB0
-#define E1000_ETQF1   0x05CB4
-#define E1000_ETQF2   0x05CB8
-#define E1000_ETQF3   0x05CBC
-#define E1000_ETQF4   0x05CC0
-#define E1000_ETQF5   0x05CC4
-#define E1000_ETQF6   0x05CC8
-#define E1000_ETQF7   0x05CCC
+#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */
+#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */
+#define E1000_TSYNCRXCFG 0x05F50 /* Time Sync Rx Configuration - RW */
+#define E1000_RXSTMPL    0x0B624 /* Rx timestamp Low - RO */
+#define E1000_RXSTMPH    0x0B628 /* Rx timestamp High - RO */
+#define E1000_RXSATRL    0x0B62C /* Rx timestamp attribute low - RO */
+#define E1000_RXSATRH    0x0B630 /* Rx timestamp attribute high - RO */
+#define E1000_TXSTMPL    0x0B618 /* Tx timestamp value Low - RO */
+#define E1000_TXSTMPH    0x0B61C /* Tx timestamp value High - RO */
+#define E1000_SYSTIML    0x0B600 /* System time register Low - RO */
+#define E1000_SYSTIMH    0x0B604 /* System time register High - RO */
+#define E1000_TIMINCA    0x0B608 /* Increment attributes register - RW */
 
 /* Filtering Registers */
 #define E1000_SAQF(_n) (0x5980 + 4 * (_n))
index bef8cdc1c22500e177f2bbc1f53f7814f3edcc67..1a0ae57dcee373a0ea343569263857a324ed28cb 100644 (file)
@@ -323,6 +323,7 @@ struct igb_adapter {
 #define IGB_FLAG_QUAD_PORT_A       (1 << 2)
 #define IGB_FLAG_QUEUE_PAIRS       (1 << 3)
 
+#define IGB_82576_TSYNC_SHIFT 19
 enum e1000_state_t {
        __IGB_TESTING,
        __IGB_RESETTING,
index 5724ac8c1ca945360301a7b3cf3b8b9f2d911ebe..7e628bad17d59b5eae010f4bde29bfc824ef7e23 100644 (file)
@@ -219,38 +219,6 @@ MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
-/**
- * Scale the NIC clock cycle by a large factor so that
- * relatively small clock corrections can be added or
- * substracted at each clock tick. The drawbacks of a
- * large factor are a) that the clock register overflows
- * more quickly (not such a big deal) and b) that the
- * increment per tick has to fit into 24 bits.
- *
- * Note that
- *   TIMINCA = IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS *
- *             IGB_TSYNC_SCALE
- *   TIMINCA += TIMINCA * adjustment [ppm] / 1e9
- *
- * The base scale factor is intentionally a power of two
- * so that the division in %struct timecounter can be done with
- * a shift.
- */
-#define IGB_TSYNC_SHIFT (19)
-#define IGB_TSYNC_SCALE (1<<IGB_TSYNC_SHIFT)
-
-/**
- * The duration of one clock cycle of the NIC.
- *
- * @todo This hard-coded value is part of the specification and might change
- * in future hardware revisions. Add revision check.
- */
-#define IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS 16
-
-#if (IGB_TSYNC_SCALE * IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS) >= (1<<24)
-# error IGB_TSYNC_SCALE and/or IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS are too large to fit into TIMINCA
-#endif
-
 /**
  * igb_read_clock - read raw cycle counter (to be used by time counter)
  */
@@ -259,11 +227,11 @@ static cycle_t igb_read_clock(const struct cyclecounter *tc)
        struct igb_adapter *adapter =
                container_of(tc, struct igb_adapter, cycles);
        struct e1000_hw *hw = &adapter->hw;
-       u64 stamp;
-
-       stamp =  rd32(E1000_SYSTIML);
-       stamp |= (u64)rd32(E1000_SYSTIMH) << 32ULL;
+       u64 stamp = 0;
+       int shift = 0;
 
+       stamp |= (u64)rd32(E1000_SYSTIML) << shift;
+       stamp |= (u64)rd32(E1000_SYSTIMH) << (shift + 32);
        return stamp;
 }
 
@@ -1669,59 +1637,58 @@ static int __devinit igb_probe(struct pci_dev *pdev,
                dev_info(&pdev->dev, "DCA enabled\n");
                igb_setup_dca(adapter);
        }
-#endif
 
-       /*
-        * Initialize hardware timer: we keep it running just in case
-        * that some program needs it later on.
-        */
-       memset(&adapter->cycles, 0, sizeof(adapter->cycles));
-       adapter->cycles.read = igb_read_clock;
-       adapter->cycles.mask = CLOCKSOURCE_MASK(64);
-       adapter->cycles.mult = 1;
-       adapter->cycles.shift = IGB_TSYNC_SHIFT;
-       wr32(E1000_TIMINCA,
-            (1<<24) |
-            IGB_TSYNC_CYCLE_TIME_IN_NANOSECONDS * IGB_TSYNC_SCALE);
-#if 0
-       /*
-        * Avoid rollover while we initialize by resetting the time counter.
-        */
-       wr32(E1000_SYSTIML, 0x00000000);
-       wr32(E1000_SYSTIMH, 0x00000000);
-#else
-       /*
-        * Set registers so that rollover occurs soon to test this.
-        */
-       wr32(E1000_SYSTIML, 0x00000000);
-       wr32(E1000_SYSTIMH, 0xFF800000);
 #endif
-       wrfl();
-       timecounter_init(&adapter->clock,
-                        &adapter->cycles,
-                        ktime_to_ns(ktime_get_real()));
 
-       /*
-        * Synchronize our NIC clock against system wall clock. NIC
-        * time stamp reading requires ~3us per sample, each sample
-        * was pretty stable even under load => only require 10
-        * samples for each offset comparison.
-        */
-       memset(&adapter->compare, 0, sizeof(adapter->compare));
-       adapter->compare.source = &adapter->clock;
-       adapter->compare.target = ktime_get_real;
-       adapter->compare.num_samples = 10;
-       timecompare_update(&adapter->compare, 0);
-
-#ifdef DEBUG
-       {
-               char buffer[160];
-               printk(KERN_DEBUG
-                       "igb: %s: hw %p initialized timer\n",
-                       igb_get_time_str(adapter, buffer),
-                       &adapter->hw);
+       switch (hw->mac.type) {
+       case e1000_82576:
+               /*
+                * Initialize hardware timer: we keep it running just in case
+                * that some program needs it later on.
+                */
+               memset(&adapter->cycles, 0, sizeof(adapter->cycles));
+               adapter->cycles.read = igb_read_clock;
+               adapter->cycles.mask = CLOCKSOURCE_MASK(64);
+               adapter->cycles.mult = 1;
+               /**
+                * Scale the NIC clock cycle by a large factor so that
+                * relatively small clock corrections can be added or
+                * substracted at each clock tick. The drawbacks of a large
+                * factor are a) that the clock register overflows more quickly
+                * (not such a big deal) and b) that the increment per tick has
+                * to fit into 24 bits.  As a result we need to use a shift of
+                * 19 so we can fit a value of 16 into the TIMINCA register.
+                */
+               adapter->cycles.shift = IGB_82576_TSYNC_SHIFT;
+               wr32(E1000_TIMINCA,
+                               (1 << E1000_TIMINCA_16NS_SHIFT) |
+                               (16 << IGB_82576_TSYNC_SHIFT));
+
+               /* Set registers so that rollover occurs soon to test this. */
+               wr32(E1000_SYSTIML, 0x00000000);
+               wr32(E1000_SYSTIMH, 0xFF800000);
+               wrfl();
+
+               timecounter_init(&adapter->clock,
+                                &adapter->cycles,
+                                ktime_to_ns(ktime_get_real()));
+               /*
+                * Synchronize our NIC clock against system wall clock. NIC
+                * time stamp reading requires ~3us per sample, each sample
+                * was pretty stable even under load => only require 10
+                * samples for each offset comparison.
+                */
+               memset(&adapter->compare, 0, sizeof(adapter->compare));
+               adapter->compare.source = &adapter->clock;
+               adapter->compare.target = ktime_get_real;
+               adapter->compare.num_samples = 10;
+               timecompare_update(&adapter->compare, 0);
+               break;
+       case e1000_82575:
+               /* 82575 does not support timesync */
+       default:
+               break;
        }
-#endif
 
        dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n");
        /* print bus type/speed/width info */
@@ -3596,7 +3563,7 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb,
        u8 hdr_len = 0;
        int count = 0;
        int tso = 0;
-       union skb_shared_tx *shtx;
+       union skb_shared_tx *shtx = skb_tx(skb);
 
        /* need: 1 descriptor per page,
         *       + 2 desc gap to keep tail from touching head,
@@ -3608,16 +3575,6 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb,
                return NETDEV_TX_BUSY;
        }
 
-       /*
-        * TODO: check that there currently is no other packet with
-        * time stamping in the queue
-        *
-        * When doing time stamping, keep the connection to the socket
-        * a while longer: it is still needed by skb_hwtstamp_tx(),
-        * called either in igb_tx_hwtstamp() or by our caller when
-        * doing software time stamping.
-        */
-       shtx = skb_tx(skb);
        if (unlikely(shtx->hardware)) {
                shtx->in_progress = 1;
                tx_flags |= IGB_TX_FLAGS_TSTAMP;
@@ -4633,37 +4590,54 @@ static int igb_poll(struct napi_struct *napi, int budget)
 }
 
 /**
- * igb_hwtstamp - utility function which checks for TX time stamp
+ * igb_systim_to_hwtstamp - convert system time value to hw timestamp
  * @adapter: board private structure
+ * @shhwtstamps: timestamp structure to update
+ * @regval: unsigned 64bit system time value.
+ *
+ * We need to convert the system time value stored in the RX/TXSTMP registers
+ * into a hwtstamp which can be used by the upper level timestamping functions
+ */
+static void igb_systim_to_hwtstamp(struct igb_adapter *adapter,
+                                   struct skb_shared_hwtstamps *shhwtstamps,
+                                   u64 regval)
+{
+       u64 ns;
+
+       ns = timecounter_cyc2time(&adapter->clock, regval);
+       timecompare_update(&adapter->compare, ns);
+       memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
+       shhwtstamps->hwtstamp = ns_to_ktime(ns);
+       shhwtstamps->syststamp = timecompare_transform(&adapter->compare, ns);
+}
+
+/**
+ * igb_tx_hwtstamp - utility function which checks for TX time stamp
+ * @q_vector: pointer to q_vector containing needed info
  * @skb: packet that was just sent
  *
  * 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.
  */
-static void igb_tx_hwtstamp(struct igb_adapter *adapter, struct sk_buff *skb)
+static void igb_tx_hwtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb)
 {
+       struct igb_adapter *adapter = q_vector->adapter;
        union skb_shared_tx *shtx = skb_tx(skb);
        struct e1000_hw *hw = &adapter->hw;
+       struct skb_shared_hwtstamps shhwtstamps;
+       u64 regval;
 
-       if (unlikely(shtx->hardware)) {
-               u32 valid = rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID;
-               if (valid) {
-                       u64 regval = rd32(E1000_TXSTMPL);
-                       u64 ns;
-                       struct skb_shared_hwtstamps shhwtstamps;
-
-                       memset(&shhwtstamps, 0, sizeof(shhwtstamps));
-                       regval |= (u64)rd32(E1000_TXSTMPH) << 32;
-                       ns = timecounter_cyc2time(&adapter->clock,
-                                                 regval);
-                       timecompare_update(&adapter->compare, ns);
-                       shhwtstamps.hwtstamp = ns_to_ktime(ns);
-                       shhwtstamps.syststamp =
-                               timecompare_transform(&adapter->compare, ns);
-                       skb_tstamp_tx(skb, &shhwtstamps);
-               }
-       }
+       /* if skb does not support hw timestamp or TX stamp not valid exit */
+       if (likely(!shtx->hardware) ||
+           !(rd32(E1000_TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID))
+               return;
+
+       regval = rd32(E1000_TXSTMPL);
+       regval |= (u64)rd32(E1000_TXSTMPH) << 32;
+
+       igb_systim_to_hwtstamp(adapter, &shhwtstamps, regval);
+       skb_tstamp_tx(skb, &shhwtstamps);
 }
 
 /**
@@ -4706,7 +4680,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
                                total_packets += segs;
                                total_bytes += bytecount;
 
-                               igb_tx_hwtstamp(adapter, skb);
+                               igb_tx_hwtstamp(q_vector, skb);
                        }
 
                        igb_unmap_and_free_tx_resource(tx_ring, buffer_info);
@@ -4831,6 +4805,34 @@ static inline void igb_rx_checksum_adv(struct igb_ring *ring,
        dev_dbg(&ring->pdev->dev, "cksum success: bits %08X\n", status_err);
 }
 
+static inline void igb_rx_hwtstamp(struct igb_q_vector *q_vector, u32 staterr,
+                                   struct sk_buff *skb)
+{
+       struct igb_adapter *adapter = q_vector->adapter;
+       struct e1000_hw *hw = &adapter->hw;
+       u64 regval;
+
+       /*
+        * If this bit is set, then the RX registers contain the time stamp. No
+        * other packet will be time stamped until we read these registers, so
+        * read the registers to make them available again. Because only one
+        * packet can be time stamped at a time, we know that the register
+        * values must belong to this one here and therefore we don't need to
+        * compare any of the additional attributes stored for it.
+        *
+        * If nothing went wrong, then it should have a skb_shared_tx that we
+        * can turn into a skb_shared_hwtstamps.
+        */
+       if (likely(!(staterr & E1000_RXDADV_STAT_TS)))
+               return;
+       if (!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID))
+               return;
+
+       regval = rd32(E1000_RXSTMPL);
+       regval |= (u64)rd32(E1000_RXSTMPH) << 32;
+
+       igb_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval);
+}
 static inline u16 igb_get_hlen(struct igb_ring *rx_ring,
                                union e1000_adv_rx_desc *rx_desc)
 {
@@ -4848,10 +4850,8 @@ static inline u16 igb_get_hlen(struct igb_ring *rx_ring,
 static bool igb_clean_rx_irq_adv(struct igb_q_vector *q_vector,
                                  int *work_done, int budget)
 {
-       struct igb_adapter *adapter = q_vector->adapter;
        struct igb_ring *rx_ring = q_vector->rx_ring;
        struct net_device *netdev = rx_ring->netdev;
-       struct e1000_hw *hw = &adapter->hw;
        struct pci_dev *pdev = rx_ring->pdev;
        union e1000_adv_rx_desc *rx_desc , *next_rxd;
        struct igb_buffer *buffer_info , *next_buffer;
@@ -4930,52 +4930,12 @@ static bool igb_clean_rx_irq_adv(struct igb_q_vector *q_vector,
                        goto next_desc;
                }
 send_up:
-               /*
-                * If this bit is set, then the RX registers contain
-                * the time stamp. No other packet will be time
-                * stamped until we read these registers, so read the
-                * registers to make them available again. Because
-                * only one packet can be time stamped at a time, we
-                * know that the register values must belong to this
-                * one here and therefore we don't need to compare
-                * any of the additional attributes stored for it.
-                *
-                * If nothing went wrong, then it should have a
-                * skb_shared_tx that we can turn into a
-                * skb_shared_hwtstamps.
-                *
-                * TODO: can time stamping be triggered (thus locking
-                * the registers) without the packet reaching this point
-                * here? In that case RX time stamping would get stuck.
-                *
-                * TODO: in "time stamp all packets" mode this bit is
-                * not set. Need a global flag for this mode and then
-                * always read the registers. Cannot be done without
-                * a race condition.
-                */
-               if (unlikely(staterr & E1000_RXD_STAT_TS)) {
-                       u64 regval;
-                       u64 ns;
-                       struct skb_shared_hwtstamps *shhwtstamps =
-                               skb_hwtstamps(skb);
-
-                       WARN(!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID),
-                            "igb: no RX time stamp available for time stamped packet");
-                       regval = rd32(E1000_RXSTMPL);
-                       regval |= (u64)rd32(E1000_RXSTMPH) << 32;
-                       ns = timecounter_cyc2time(&adapter->clock, regval);
-                       timecompare_update(&adapter->compare, ns);
-                       memset(shhwtstamps, 0, sizeof(*shhwtstamps));
-                       shhwtstamps->hwtstamp = ns_to_ktime(ns);
-                       shhwtstamps->syststamp =
-                               timecompare_transform(&adapter->compare, ns);
-               }
-
                if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
                        dev_kfree_skb_irq(skb);
                        goto next_desc;
                }
 
+               igb_rx_hwtstamp(q_vector, staterr, skb);
                total_bytes += skb->len;
                total_packets++;
 
@@ -5161,13 +5121,11 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev,
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        struct hwtstamp_config config;
-       u32 tsync_tx_ctl_bit = E1000_TSYNCTXCTL_ENABLED;
-       u32 tsync_rx_ctl_bit = E1000_TSYNCRXCTL_ENABLED;
-       u32 tsync_rx_ctl_type = 0;
+       u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
+       u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
        u32 tsync_rx_cfg = 0;
-       int is_l4 = 0;
-       int is_l2 = 0;
-       short port = 319; /* PTP */
+       bool is_l4 = false;
+       bool is_l2 = false;
        u32 regval;
 
        if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
@@ -5179,10 +5137,8 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev,
 
        switch (config.tx_type) {
        case HWTSTAMP_TX_OFF:
-               tsync_tx_ctl_bit = 0;
-               break;
+               tsync_tx_ctl = 0;
        case HWTSTAMP_TX_ON:
-               tsync_tx_ctl_bit = E1000_TSYNCTXCTL_ENABLED;
                break;
        default:
                return -ERANGE;
@@ -5190,7 +5146,7 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev,
 
        switch (config.rx_filter) {
        case HWTSTAMP_FILTER_NONE:
-               tsync_rx_ctl_bit = 0;
+               tsync_rx_ctl = 0;
                break;
        case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
        case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
@@ -5201,86 +5157,97 @@ static int igb_hwtstamp_ioctl(struct net_device *netdev,
                 * possible to time stamp both Sync and Delay_Req messages
                 * => fall back to time stamping all packets
                 */
-               tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_ALL;
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
                config.rx_filter = HWTSTAMP_FILTER_ALL;
                break;
        case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
-               tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L4_V1;
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
                tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE;
-               is_l4 = 1;
+               is_l4 = true;
                break;
        case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
-               tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L4_V1;
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1;
                tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE;
-               is_l4 = 1;
+               is_l4 = true;
                break;
        case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
        case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
-               tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
                tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE;
-               is_l2 = 1;
-               is_l4 = 1;
+               is_l2 = true;
+               is_l4 = true;
                config.rx_filter = HWTSTAMP_FILTER_SOME;
                break;
        case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
        case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
-               tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L2_L4_V2;
                tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE;
-               is_l2 = 1;
-               is_l4 = 1;
+               is_l2 = true;
+               is_l4 = true;
                config.rx_filter = HWTSTAMP_FILTER_SOME;
                break;
        case HWTSTAMP_FILTER_PTP_V2_EVENT:
        case HWTSTAMP_FILTER_PTP_V2_SYNC:
        case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
-               tsync_rx_ctl_type = E1000_TSYNCRXCTL_TYPE_EVENT_V2;
+               tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
                config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
-               is_l2 = 1;
+               is_l2 = true;
                break;
        default:
                return -ERANGE;
        }
 
+       if (hw->mac.type == e1000_82575) {
+               if (tsync_rx_ctl | tsync_tx_ctl)
+                       return -EINVAL;
+               return 0;
+       }
+
        /* enable/disable TX */
        regval = rd32(E1000_TSYNCTXCTL);
-       regval = (regval & ~E1000_TSYNCTXCTL_ENABLED) | tsync_tx_ctl_bit;
+       regval &= ~E1000_TSYNCTXCTL_ENABLED;
+       regval |= tsync_tx_ctl;
        wr32(E1000_TSYNCTXCTL, regval);
 
-       /* enable/disable RX, define which PTP packets are time stamped */
+       /* enable/disable RX */
        regval = rd32(E1000_TSYNCRXCTL);
-       regval = (regval & ~E1000_TSYNCRXCTL_ENABLED) | tsync_rx_ctl_bit;
-       regval = (regval & ~0xE) | tsync_rx_ctl_type;
+       regval &= ~(E1000_TSYNCRXCTL_ENABLED | E1000_TSYNCRXCTL_TYPE_MASK);
+       regval |= tsync_rx_ctl;
        wr32(E1000_TSYNCRXCTL, regval);
-       wr32(E1000_TSYNCRXCFG, tsync_rx_cfg);
 
-       /*
-        * Ethertype Filter Queue Filter[0][15:0] = 0x88F7
-        *                                          (Ethertype to filter on)
-        * Ethertype Filter Queue Filter[0][26] = 0x1 (Enable filter)
-        * Ethertype Filter Queue Filter[0][30] = 0x1 (Enable Timestamping)
-        */
-       wr32(E1000_ETQF0, is_l2 ? 0x440088f7 : 0);
-
-       /* L4 Queue Filter[0]: only filter by source and destination port */
-       wr32(E1000_SPQF0, htons(port));
-       wr32(E1000_IMIREXT(0), is_l4 ?
-            ((1<<12) | (1<<19) /* bypass size and control flags */) : 0);
-       wr32(E1000_IMIR(0), is_l4 ?
-            (htons(port)
-             | (0<<16) /* immediate interrupt disabled */
-             | 0 /* (1<<17) bit cleared: do not bypass
-                    destination port check */)
-               : 0);
-       wr32(E1000_FTQF0, is_l4 ?
-            (0x11 /* UDP */
-             | (1<<15) /* VF not compared */
-             | (1<<27) /* Enable Timestamping */
-             | (7<<28) /* only source port filter enabled,
-                          source/target address and protocol
-                          masked */)
-            : ((1<<15) | (15<<28) /* all mask bits set = filter not
-                                     enabled */));
+       /* define which PTP packets are time stamped */
+       wr32(E1000_TSYNCRXCFG, tsync_rx_cfg);
 
+       /* define ethertype filter for timestamped packets */
+       if (is_l2)
+               wr32(E1000_ETQF(3),
+                               (E1000_ETQF_FILTER_ENABLE | /* enable filter */
+                                E1000_ETQF_1588 | /* enable timestamping */
+                                ETH_P_1588));     /* 1588 eth protocol type */
+       else
+               wr32(E1000_ETQF(3), 0);
+
+#define PTP_PORT 319
+       /* L4 Queue Filter[3]: filter by destination port and protocol */
+       if (is_l4) {
+               u32 ftqf = (IPPROTO_UDP /* UDP */
+                       | E1000_FTQF_VF_BP /* VF not compared */
+                       | E1000_FTQF_1588_TIME_STAMP /* Enable Timestamping */
+                       | E1000_FTQF_MASK); /* mask all inputs */
+               ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */
+
+               wr32(E1000_IMIR(3), htons(PTP_PORT));
+               wr32(E1000_IMIREXT(3),
+                    (E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP));
+               if (hw->mac.type == e1000_82576) {
+                       /* enable source port check */
+                       wr32(E1000_SPQF(3), htons(PTP_PORT));
+                       ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
+               }
+               wr32(E1000_FTQF(3), ftqf);
+       } else {
+               wr32(E1000_FTQF(3), E1000_FTQF_MASK);
+       }
        wrfl();
 
        adapter->hwtstamp_config = config;