]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00288569: net:fec_ptp: fix the potential issue for storing timestamp
authorFugang Duan <B38611@freescale.com>
Tue, 19 Nov 2013 04:59:18 +0000 (12:59 +0800)
committerFugang Duan <B38611@freescale.com>
Fri, 22 Nov 2013 08:53:06 +0000 (16:53 +0800)
The timestamps generated in the i.MX drivers are generated by the
nanoseconds part coming from the 1588 clock. But the number of seconds
are maintained in a private structure of the interface. Those are
updated in a 1588 clock rollover interrupt.

The timestamp is generated right before a rollover of a second and the
timestamp value is constructed afterwards. Therefore the bigger part of
the timestamp is wrong (the second).

commit:54181c1d83e04b18e63c7723ac80f974b760e019
Suggested solution (pseudo-code):
    If( actual-time.nsec < timestamp.nsec )
        Timestamp.sec = fpp->prtc -1;
    Else
        Timestamp.sec = fpp->prtc;

But it is not perfect and there still exist potenitial second sync issue.
So, the patch Suggested solution (pseudo-code):
    If( actual-time.nsec < timestamp.nsec &&
!FEC_IEVENT[TS_TIMER] )
        Timestamp.sec = fpp->prtc -1;
    Else
        Timestamp.sec = fpp->prtc;

Signed-off-by: Fugang Duan <B38611@freescale.com>
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fec_ptp.c

index 8072287d0e895ef8dbab505d013ca74a7347b0d3..ff6d7c32ae87c26ecbae40f592aa1b25d336e942 100644 (file)
@@ -262,6 +262,23 @@ struct bufdesc_ex {
 #define FALSE                  0
 #define TRUE                   1
 
+/* Interrupt events/masks. */
+#define FEC_ENET_HBERR  ((uint)0x80000000)      /* Heartbeat error */
+#define FEC_ENET_BABR   ((uint)0x40000000)      /* Babbling receiver */
+#define FEC_ENET_BABT   ((uint)0x20000000)      /* Babbling transmitter */
+#define FEC_ENET_GRA    ((uint)0x10000000)      /* Graceful stop complete */
+#define FEC_ENET_TXF    ((uint)0x08000000)      /* Full frame transmitted */
+#define FEC_ENET_TXB    ((uint)0x04000000)      /* A buffer was transmitted */
+#define FEC_ENET_RXF    ((uint)0x02000000)      /* Full frame received */
+#define FEC_ENET_RXB    ((uint)0x01000000)      /* A buffer was received */
+#define FEC_ENET_MII    ((uint)0x00800000)      /* MII interrupt */
+#define FEC_ENET_EBERR  ((uint)0x00400000)      /* SDMA bus error */
+#define FEC_ENET_TS_AVAIL       ((uint)0x00010000)
+#define FEC_ENET_TS_TIMER       ((uint)0x00008000)
+
+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII | FEC_ENET_TS_TIMER)
+#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
+
 /* IEEE 1588 definition */
 #define FEC_T_PERIOD_ONE_SEC           0x3B9ACA00
 
@@ -303,6 +320,8 @@ struct bufdesc_ex {
 #define FEC_PTP_ORIG_COMP              0x15555555
 #define FEC_PTP_SPINNER_2              2
 #define FEC_PTP_SPINNER_4              4
+#define FEC_PTP_TIMEOUT_TS             10
+#define FEC_PTP_TIMEOUT_EVENT          1000
 
 /* PTP standard time representation structure */
 struct ptp_time{
index a7ac199ea1c2e958563281263b740f82e41706db..a51dc18ed0bf0046df355de7773197633a52e859 100644 (file)
@@ -201,23 +201,6 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 #error "FEC: descriptor ring size constants too large"
 #endif
 
-/* Interrupt events/masks. */
-#define FEC_ENET_HBERR ((uint)0x80000000)      /* Heartbeat error */
-#define FEC_ENET_BABR  ((uint)0x40000000)      /* Babbling receiver */
-#define FEC_ENET_BABT  ((uint)0x20000000)      /* Babbling transmitter */
-#define FEC_ENET_GRA   ((uint)0x10000000)      /* Graceful stop complete */
-#define FEC_ENET_TXF   ((uint)0x08000000)      /* Full frame transmitted */
-#define FEC_ENET_TXB   ((uint)0x04000000)      /* A buffer was transmitted */
-#define FEC_ENET_RXF   ((uint)0x02000000)      /* Full frame received */
-#define FEC_ENET_RXB   ((uint)0x01000000)      /* A buffer was received */
-#define FEC_ENET_MII   ((uint)0x00800000)      /* MII interrupt */
-#define FEC_ENET_EBERR ((uint)0x00400000)      /* SDMA bus error */
-#define FEC_ENET_TS_AVAIL       ((uint)0x00010000)
-#define FEC_ENET_TS_TIMER       ((uint)0x00008000)
-
-#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
-#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
-
 /* The FEC stores dest/src/type/vlan, data, and checksum for receive packets.
  */
 #define PKT_MAXBUF_SIZE                1522
@@ -667,13 +650,8 @@ fec_restart(struct net_device *ndev, int duplex)
        writel(ecntl, fep->hwp + FEC_ECNTRL);
        writel(0, fep->hwp + FEC_R_DES_ACTIVE);
 
-       if (fep->bufdesc_ex) {
+       if (fep->bufdesc_ex)
                fec_ptp_start_cyclecounter(ndev);
-               /* Enable interrupts we wish to service */
-               writel(FEC_DEFAULT_IMASK | FEC_ENET_TS_AVAIL |
-                       FEC_ENET_TS_TIMER, fep->hwp + FEC_IMASK);
-       } else
-               writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 
        /* Enable interrupts we wish to service */
        writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
@@ -1061,7 +1039,16 @@ fec_enet_interrupt(int irq, void *dev_id)
 
        do {
                int_events = readl(fep->hwp + FEC_IEVENT);
-               writel(int_events, fep->hwp + FEC_IEVENT);
+               writel(int_events & (~FEC_ENET_TS_TIMER),
+                       fep->hwp + FEC_IEVENT);
+
+               if ((int_events & FEC_ENET_TS_TIMER) && fep->bufdesc_ex) {
+                       ret = IRQ_HANDLED;
+                       if (fep->hwts_tx_en_ioctl || fep->hwts_rx_en_ioctl)
+                               fep->prtc++;
+
+                       writel(FEC_ENET_TS_TIMER, fep->hwp + FEC_IEVENT);
+               }
 
                if (int_events & (FEC_ENET_RXF | FEC_ENET_TXF)) {
                        ret = IRQ_HANDLED;
@@ -1074,12 +1061,6 @@ fec_enet_interrupt(int irq, void *dev_id)
                        }
                }
 
-               if ((int_events & FEC_ENET_TS_TIMER) && fep->bufdesc_ex) {
-                       ret = IRQ_HANDLED;
-                       if (fep->hwts_tx_en_ioctl || fep->hwts_rx_en_ioctl)
-                               fep->prtc++;
-               }
-
                if (int_events & FEC_ENET_MII) {
                        ret = IRQ_HANDLED;
                        complete(&fep->mdio_done);
index 2d6997bea89a58d5e4326b8c4bb24ece246d62f6..2b4a567ac27d13c72693830292b73c7cd896f1d5 100644 (file)
@@ -225,22 +225,38 @@ void fec_ptp_stop(struct net_device *ndev)
 static void fec_get_curr_cnt(struct fec_enet_private *priv,
                        struct ptp_rtc_time *curr_time)
 {
-       u32 tempval;
+       u32 tempval, old_sec;
+       u32 timeout_event, timeout_ts = 0;
 
-       tempval = readl(priv->hwp + FEC_ATIME_CTRL);
-       tempval |= FEC_T_CTRL_CAPTURE;
+       do {
+               old_sec = priv->prtc;
+               timeout_event = 0;
+
+               tempval = readl(priv->hwp + FEC_ATIME_CTRL);
+               tempval |= FEC_T_CTRL_CAPTURE;
+               writel(tempval, priv->hwp + FEC_ATIME_CTRL);
 
-       writel(tempval, priv->hwp + FEC_ATIME_CTRL);
-       curr_time->rtc_time.nsec = readl(priv->hwp + FEC_ATIME);
-       curr_time->rtc_time.sec = priv->prtc;
+               curr_time->rtc_time.nsec = readl(priv->hwp + FEC_ATIME);
 
-       writel(tempval, priv->hwp + FEC_ATIME_CTRL);
-       tempval = readl(priv->hwp + FEC_ATIME);
+               while (readl(priv->hwp + FEC_IEVENT) & FEC_ENET_TS_TIMER) {
+                       timeout_event++;
+                       udelay(20);
+
+                       if (timeout_event >= FEC_PTP_TIMEOUT_EVENT)
+                               break;
+               }
 
-       if (tempval < curr_time->rtc_time.nsec) {
-               curr_time->rtc_time.nsec = tempval;
                curr_time->rtc_time.sec = priv->prtc;
-       }
+               timeout_ts++;
+
+               if (timeout_event >= FEC_PTP_TIMEOUT_EVENT)
+                       pr_err("timeout: TS TIMER event\n");
+
+       } while (old_sec != curr_time->rtc_time.sec &&
+                timeout_ts < FEC_PTP_TIMEOUT_TS);
+
+       if (timeout_ts >= FEC_PTP_TIMEOUT_TS)
+               pr_err("timeout: current timestamp unmatched\n");
 }
 
 /* Set the 1588 timer counter registers */
@@ -392,9 +408,9 @@ void fec_ptp_store_txstamp(struct fec_enet_private *priv,
                /* store tx timestamp */
                fec_get_curr_cnt(priv, &curr_time);
                if (curr_time.rtc_time.nsec < bdp_ex->ts)
-                       tmp_tx_time.ts.sec = priv->prtc - 1;
+                       tmp_tx_time.ts.sec = curr_time.rtc_time.sec - 1;
                else
-                       tmp_tx_time.ts.sec = priv->prtc;
+                       tmp_tx_time.ts.sec = curr_time.rtc_time.sec;
                tmp_tx_time.ts.nsec = bdp_ex->ts;
                /* insert timestamp in circular buffer */
                fec_ptp_insert(&(priv->tx_timestamps), &tmp_tx_time);
@@ -437,9 +453,9 @@ void fec_ptp_store_rxstamp(struct fec_enet_private *priv,
                /* store rx timestamp */
                fec_get_curr_cnt(priv, &curr_time);
                if (curr_time.rtc_time.nsec < bdp_ex->ts)
-                       tmp_rx_time.ts.sec = priv->prtc - 1;
+                       tmp_rx_time.ts.sec = curr_time.rtc_time.sec - 1;
                else
-                       tmp_rx_time.ts.sec = priv->prtc;
+                       tmp_rx_time.ts.sec = curr_time.rtc_time.sec;
                tmp_rx_time.ts.nsec = bdp_ex->ts;
 
                /* insert timestamp in circular buffer */