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>
#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
#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{
#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
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);
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;
}
}
- 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);
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 */
/* 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);
/* 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 */