summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorFugang Duan <B38611@freescale.com>2013-11-19 12:59:18 +0800
committerFugang Duan <B38611@freescale.com>2013-11-22 16:53:06 +0800
commit430dc3830e80a749666f9eb2aa9feba55823c6eb (patch)
tree622259633189cf3813d30112b94ee67b556a5756 /drivers/net
parent92a24bffe9b79787e9881ffc6ede7e5e3df308f7 (diff)
ENGR00288569: net:fec_ptp: fix the potential issue for storing timestamp
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>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/freescale/fec.h19
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c41
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c46
3 files changed, 61 insertions, 45 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 8072287d0e89..ff6d7c32ae87 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -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{
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index a7ac199ea1c2..a51dc18ed0bf 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -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);
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 2d6997bea89a..2b4a567ac27d 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -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 */