aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/freescale
diff options
context:
space:
mode:
authorLuwei Zhou <b45643@freescale.com>2013-08-15 01:45:23 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:01:15 -0400
commit244281f46581a1716e99b6b6fe0aaf019e0d8b65 (patch)
tree5a693027e514981ca625fb4c92d2ea9bbbf87590 /drivers/net/ethernet/freescale
parent67b6e0869cbfd7ebbc8f91336f4131f5559eacd3 (diff)
ENGR00275371 net: fec: PTP: Add ptp support for IXXAT stack
These patch add ptp support for IXXAT stack. Cherry picked from commit 1c8839574ac87826f53b96f987975a9bb1d72915. Signed-off-by: Luwei Zhou <B45643@freescale.com>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r--drivers/net/ethernet/freescale/fec.h112
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c55
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c641
3 files changed, 753 insertions, 55 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index ea5c60d84889..888ff237338d 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -16,6 +16,9 @@
16#include <linux/clocksource.h> 16#include <linux/clocksource.h>
17#include <linux/net_tstamp.h> 17#include <linux/net_tstamp.h>
18#include <linux/ptp_clock_kernel.h> 18#include <linux/ptp_clock_kernel.h>
19#include <linux/netdevice.h>
20#include <linux/etherdevice.h>
21#include <linux/circ_buf.h>
19 22
20#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ 23#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
21 defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ 24 defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
@@ -256,6 +259,98 @@ struct bufdesc_ex {
256#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR) 259#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
257#define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR) 260#define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
258 261
262#define FALSE 0
263#define TRUE 1
264
265/* IEEE 1588 definition */
266#define FEC_T_PERIOD_ONE_SEC 0x3B9ACA00
267
268#define DEFAULT_PTP_RX_BUF_SZ 64
269#define DEFAULT_PTP_TX_BUF_SZ 64
270
271/* 1588stack API defines */
272#define PTP_ENBL_TXTS_IOCTL SIOCDEVPRIVATE
273#define PTP_DSBL_TXTS_IOCTL (SIOCDEVPRIVATE + 1)
274#define PTP_ENBL_RXTS_IOCTL (SIOCDEVPRIVATE + 2)
275#define PTP_DSBL_RXTS_IOCTL (SIOCDEVPRIVATE + 3)
276#define PTP_GET_TX_TIMESTAMP (SIOCDEVPRIVATE + 4)
277#define PTP_GET_RX_TIMESTAMP (SIOCDEVPRIVATE + 5)
278#define PTP_SET_RTC_TIME (SIOCDEVPRIVATE + 6)
279#define PTP_GET_CURRENT_TIME (SIOCDEVPRIVATE + 7)
280#define PTP_SET_COMPENSATION (SIOCDEVPRIVATE + 9)
281#define PTP_GET_ORIG_COMP (SIOCDEVPRIVATE + 10)
282#define PTP_FLUSH_TIMESTAMP (SIOCDEVPRIVATE + 11)
283
284/* IEEE1588 ptp head format */
285#define PTP_CTRL_OFFS 0x52
286#define PTP_SOURCE_PORT_LENGTH 10
287#define PTP_HEADER_SEQ_OFFS 30
288#define PTP_HEADER_CTL_OFFS 32
289#define PTP_SPID_OFFS 20
290#define PTP_HEADER_SZE 34
291#define PTP_EVENT_PORT 0x013F
292
293#define FEC_VLAN_TAG_LEN 0x04
294#define FEC_ETHTYPE_LEN 0x02
295
296/* 1588-2008 network protocol enumeration values */
297#define FEC_PTP_PROT_IPV4 1
298#define FEC_PTP_PROT_IPV6 2
299#define FEC_PTP_PROT_802_3 3
300#define FEC_PTP_PROT_DONTCARE 0xFFFF
301#define FEC_PACKET_TYPE_UDP 0x11
302
303#define FEC_PTP_ORIG_COMP 0x15555555
304#define FEC_PTP_SPINNER_2 2
305#define FEC_PTP_SPINNER_4 4
306
307/* PTP standard time representation structure */
308struct ptp_time{
309 u64 sec; /* seconds */
310 u32 nsec; /* nanoseconds */
311};
312
313/* struct needed to identify a timestamp */
314struct fec_ptp_ident {
315 u8 version;
316 u8 message_type;
317 u16 netw_prot;
318 u16 seq_id;
319 u8 spid[10];
320};
321
322/* interface for PTP driver command GET_TX_TIME */
323struct fec_ptp_ts_data {
324 struct fec_ptp_ident ident;
325 /* PTP timestamp */
326 struct ptp_time ts;
327};
328
329/* circular buffer for ptp timestamps over ioctl */
330struct fec_ptp_circular {
331 int front;
332 int end;
333 int size;
334 struct fec_ptp_ts_data *data_buf;
335};
336
337/* interface for PTP driver command SET_RTC_TIME/GET_CURRENT_TIME */
338struct ptp_rtc_time {
339 struct ptp_time rtc_time;
340};
341
342/* interface for PTP driver command SET_COMPENSATION */
343struct ptp_set_comp {
344 u32 drift;
345 bool o_ops;
346 u32 freq_compensation;
347};
348
349struct ptp_time_correct {
350 u32 corr_period;
351 u32 corr_inc;
352};
353
259struct fec_enet_delayed_work { 354struct fec_enet_delayed_work {
260 struct delayed_work delay_work; 355 struct delayed_work delay_work;
261 bool timeout; 356 bool timeout;
@@ -312,13 +407,19 @@ struct fec_enet_private {
312 int speed; 407 int speed;
313 struct completion mdio_done; 408 struct completion mdio_done;
314 int irq[FEC_IRQ_NUM]; 409 int irq[FEC_IRQ_NUM];
410 /* HW timestamping over ioctl enabled flag */
411 int hwts_tx_en_ioctl;
412 int hwts_rx_en_ioctl;
413 struct fec_ptp_circular tx_timestamps;
414 struct fec_ptp_circular rx_timestamps;
415 u64 prtc;
315 int bufdesc_ex; 416 int bufdesc_ex;
316 int pause_flag; 417 int pause_flag;
317 418
318 struct napi_struct napi; 419 struct napi_struct napi;
319 int csum_flags; 420 int csum_flags;
320 421
321 int phy_reset_gpio; 422 int phy_reset_gpio;
322 423
323 struct ptp_clock *ptp_clock; 424 struct ptp_clock *ptp_clock;
324 struct ptp_clock_info ptp_caps; 425 struct ptp_clock_info ptp_caps;
@@ -339,6 +440,15 @@ struct fec_enet_private {
339void fec_ptp_init(struct platform_device *pdev); 440void fec_ptp_init(struct platform_device *pdev);
340void fec_ptp_start_cyclecounter(struct net_device *ndev); 441void fec_ptp_start_cyclecounter(struct net_device *ndev);
341int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd); 442int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd);
443void fec_ptp_cleanup(struct fec_enet_private *priv);
444void fec_ptp_stop(struct net_device *ndev);
445int fec_ptp_do_txstamp(struct sk_buff *skb);
446void fec_ptp_store_txstamp(struct fec_enet_private *priv,
447 struct sk_buff *skb,
448 struct bufdesc *bdp);
449void fec_ptp_store_rxstamp(struct fec_enet_private *priv,
450 struct sk_buff *skb,
451 struct bufdesc *bdp);
342 452
343/****************************************************************************/ 453/****************************************************************************/
344#endif /* FEC_H */ 454#endif /* FEC_H */
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 86c35a8817cf..18a76fb8e595 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -197,6 +197,8 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
197#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ 197#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
198#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ 198#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
199#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ 199#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
200#define FEC_ENET_TS_AVAIL ((uint)0x00010000)
201#define FEC_ENET_TS_TIMER ((uint)0x00008000)
200 202
201#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII) 203#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
202#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF)) 204#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
@@ -369,7 +371,8 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
369 struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; 371 struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
370 ebdp->cbd_bdu = 0; 372 ebdp->cbd_bdu = 0;
371 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && 373 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
372 fep->hwts_tx_en)) { 374 fep->hwts_tx_en) || unlikely(fep->hwts_tx_en_ioctl &&
375 fec_ptp_do_txstamp(skb))) {
373 ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT); 376 ebdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
374 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 377 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
375 } else { 378 } else {
@@ -645,8 +648,13 @@ fec_restart(struct net_device *ndev, int duplex)
645 writel(ecntl, fep->hwp + FEC_ECNTRL); 648 writel(ecntl, fep->hwp + FEC_ECNTRL);
646 writel(0, fep->hwp + FEC_R_DES_ACTIVE); 649 writel(0, fep->hwp + FEC_R_DES_ACTIVE);
647 650
648 if (fep->bufdesc_ex) 651 if (fep->bufdesc_ex) {
649 fec_ptp_start_cyclecounter(ndev); 652 fec_ptp_start_cyclecounter(ndev);
653 /* Enable interrupts we wish to service */
654 writel(FEC_DEFAULT_IMASK | FEC_ENET_TS_AVAIL |
655 FEC_ENET_TS_TIMER, fep->hwp + FEC_IMASK);
656 } else
657 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
650 658
651 /* Enable interrupts we wish to service */ 659 /* Enable interrupts we wish to service */
652 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); 660 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
@@ -681,6 +689,11 @@ fec_stop(struct net_device *ndev)
681 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); 689 writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
682 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); 690 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
683 691
692 if (fep->bufdesc_ex && (fep->hwts_tx_en_ioctl ||
693 fep->hwts_rx_en_ioctl || fep->hwts_tx_en ||
694 fep->hwts_rx_en))
695 fec_ptp_stop(ndev);
696
684 /* We have to keep ENET enabled to have MII interrupt stay working */ 697 /* We have to keep ENET enabled to have MII interrupt stay working */
685 if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { 698 if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
686 writel(2, fep->hwp + FEC_ECNTRL); 699 writel(2, fep->hwp + FEC_ECNTRL);
@@ -775,8 +788,8 @@ fec_enet_tx(struct net_device *ndev)
775 ndev->stats.tx_bytes += bdp->cbd_datlen; 788 ndev->stats.tx_bytes += bdp->cbd_datlen;
776 } 789 }
777 790
778 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) && 791 if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) &&
779 fep->bufdesc_ex) { 792 fep->hwts_tx_en) && fep->bufdesc_ex) {
780 struct skb_shared_hwtstamps shhwtstamps; 793 struct skb_shared_hwtstamps shhwtstamps;
781 unsigned long flags; 794 unsigned long flags;
782 struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; 795 struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
@@ -787,7 +800,8 @@ fec_enet_tx(struct net_device *ndev)
787 timecounter_cyc2time(&fep->tc, ebdp->ts)); 800 timecounter_cyc2time(&fep->tc, ebdp->ts));
788 spin_unlock_irqrestore(&fep->tmreg_lock, flags); 801 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
789 skb_tstamp_tx(skb, &shhwtstamps); 802 skb_tstamp_tx(skb, &shhwtstamps);
790 } 803 } else if (unlikely(fep->hwts_tx_en_ioctl) && fep->bufdesc_ex)
804 fec_ptp_store_txstamp(fep, skb, bdp);
791 805
792 if (status & BD_ENET_TX_READY) 806 if (status & BD_ENET_TX_READY)
793 netdev_err(ndev, "HEY! Enet xmit interrupt and TX_READY\n"); 807 netdev_err(ndev, "HEY! Enet xmit interrupt and TX_READY\n");
@@ -944,8 +958,6 @@ fec_enet_rx(struct net_device *ndev, int budget)
944 data + payload_offset, 958 data + payload_offset,
945 pkt_len - 4 - (2 * ETH_ALEN)); 959 pkt_len - 4 - (2 * ETH_ALEN));
946 960
947 skb->protocol = eth_type_trans(skb, ndev);
948
949 /* Get receive timestamp from the skb */ 961 /* Get receive timestamp from the skb */
950 if (fep->hwts_rx_en && fep->bufdesc_ex) { 962 if (fep->hwts_rx_en && fep->bufdesc_ex) {
951 struct skb_shared_hwtstamps *shhwtstamps = 963 struct skb_shared_hwtstamps *shhwtstamps =
@@ -958,8 +970,11 @@ fec_enet_rx(struct net_device *ndev, int budget)
958 shhwtstamps->hwtstamp = ns_to_ktime( 970 shhwtstamps->hwtstamp = ns_to_ktime(
959 timecounter_cyc2time(&fep->tc, ebdp->ts)); 971 timecounter_cyc2time(&fep->tc, ebdp->ts));
960 spin_unlock_irqrestore(&fep->tmreg_lock, flags); 972 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
961 } 973 } else if (unlikely(fep->hwts_rx_en_ioctl) &&
974 fep->bufdesc_ex)
975 fec_ptp_store_rxstamp(fep, skb, bdp);
962 976
977 skb->protocol = eth_type_trans(skb, ndev);
963 if (fep->bufdesc_ex && 978 if (fep->bufdesc_ex &&
964 (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { 979 (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
965 if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) { 980 if (!(ebdp->cbd_esc & FLAG_RX_CSUM_ERROR)) {
@@ -1037,6 +1052,12 @@ fec_enet_interrupt(int irq, void *dev_id)
1037 } 1052 }
1038 } 1053 }
1039 1054
1055 if ((int_events & FEC_ENET_TS_TIMER) && fep->bufdesc_ex) {
1056 ret = IRQ_HANDLED;
1057 if (fep->hwts_tx_en_ioctl || fep->hwts_rx_en_ioctl)
1058 fep->prtc++;
1059 }
1060
1040 if (int_events & FEC_ENET_MII) { 1061 if (int_events & FEC_ENET_MII) {
1041 ret = IRQ_HANDLED; 1062 ret = IRQ_HANDLED;
1042 complete(&fep->mdio_done); 1063 complete(&fep->mdio_done);
@@ -1656,8 +1677,11 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
1656 if (!phydev) 1677 if (!phydev)
1657 return -ENODEV; 1678 return -ENODEV;
1658 1679
1659 if (cmd == SIOCSHWTSTAMP && fep->bufdesc_ex) 1680 if (((cmd == SIOCSHWTSTAMP) || ((cmd >= PTP_ENBL_TXTS_IOCTL) &&
1681 (cmd <= PTP_FLUSH_TIMESTAMP))) && fep->bufdesc_ex)
1660 return fec_ptp_ioctl(ndev, rq, cmd); 1682 return fec_ptp_ioctl(ndev, rq, cmd);
1683 else if (fep->bufdesc_ex)
1684 return -ENODEV;
1661 1685
1662 return phy_mii_ioctl(phydev, rq, cmd); 1686 return phy_mii_ioctl(phydev, rq, cmd);
1663} 1687}
@@ -2255,7 +2279,10 @@ fec_drv_remove(struct platform_device *pdev)
2255 cancel_delayed_work_sync(&(fep->delay_work.delay_work)); 2279 cancel_delayed_work_sync(&(fep->delay_work.delay_work));
2256 unregister_netdev(ndev); 2280 unregister_netdev(ndev);
2257 fec_enet_mii_remove(fep); 2281 fec_enet_mii_remove(fep);
2258 del_timer_sync(&fep->time_keep); 2282 if (fep->bufdesc_ex) {
2283 fec_ptp_cleanup(fep);
2284 del_timer_sync(&fep->time_keep);
2285 }
2259 for (i = 0; i < FEC_IRQ_NUM; i++) { 2286 for (i = 0; i < FEC_IRQ_NUM; i++) {
2260 int irq = platform_get_irq(pdev, i); 2287 int irq = platform_get_irq(pdev, i);
2261 if (irq > 0) 2288 if (irq > 0)
@@ -2263,9 +2290,11 @@ fec_drv_remove(struct platform_device *pdev)
2263 } 2290 }
2264 if (fep->reg_phy) 2291 if (fep->reg_phy)
2265 regulator_disable(fep->reg_phy); 2292 regulator_disable(fep->reg_phy);
2266 clk_disable_unprepare(fep->clk_ptp); 2293 if (fep->bufdesc_ex) {
2267 if (fep->ptp_clock) 2294 clk_disable_unprepare(fep->clk_ptp);
2268 ptp_clock_unregister(fep->ptp_clock); 2295 if (fep->ptp_clock)
2296 ptp_clock_unregister(fep->ptp_clock);
2297 }
2269 clk_disable_unprepare(fep->clk_enet_out); 2298 clk_disable_unprepare(fep->clk_enet_out);
2270 clk_disable_unprepare(fep->clk_ahb); 2299 clk_disable_unprepare(fep->clk_ahb);
2271 clk_disable_unprepare(fep->clk_ipg); 2300 clk_disable_unprepare(fep->clk_ipg);
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 5007e4f9fff9..06c679ebcd9c 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Fast Ethernet Controller (ENET) PTP driver for MX6x. 2 * Fast Ethernet Controller (ENET) PTP driver for MX6x.
3 * 3 *
4 * Copyright (C) 2012 Freescale Semiconductor, Inc. 4 * Copyright (C) 2012-2013 Freescale Semiconductor, Inc.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify it 6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License, 7 * under the terms and conditions of the GNU General Public License,
@@ -37,6 +37,9 @@
37#include <linux/workqueue.h> 37#include <linux/workqueue.h>
38#include <linux/bitops.h> 38#include <linux/bitops.h>
39#include <linux/io.h> 39#include <linux/io.h>
40#include <linux/vmalloc.h>
41#include <linux/ip.h>
42#include <linux/udp.h>
40#include <linux/irq.h> 43#include <linux/irq.h>
41#include <linux/clk.h> 44#include <linux/clk.h>
42#include <linux/platform_device.h> 45#include <linux/platform_device.h>
@@ -49,6 +52,7 @@
49 52
50#include "fec.h" 53#include "fec.h"
51 54
55
52/* FEC 1588 register bits */ 56/* FEC 1588 register bits */
53#define FEC_T_CTRL_SLAVE 0x00002000 57#define FEC_T_CTRL_SLAVE 0x00002000
54#define FEC_T_CTRL_CAPTURE 0x00000800 58#define FEC_T_CTRL_CAPTURE 0x00000800
@@ -71,6 +75,446 @@
71#define FEC_TS_TIMESTAMP 0x418 75#define FEC_TS_TIMESTAMP 0x418
72 76
73#define FEC_CC_MULT (1 << 31) 77#define FEC_CC_MULT (1 << 31)
78
79/* Alloc the ring resource */
80static int fec_ptp_init_circ(struct fec_ptp_circular *buf, int size)
81{
82 buf->data_buf = (struct fec_ptp_ts_data *)
83 vmalloc(size * sizeof(struct fec_ptp_ts_data));
84
85 if (!buf->data_buf)
86 return 1;
87 buf->front = 0;
88 buf->end = 0;
89 buf->size = size;
90 return 0;
91}
92
93static inline int fec_ptp_calc_index(int size, int curr_index, int offset)
94{
95 return (curr_index + offset) % size;
96}
97
98static int fec_ptp_is_empty(struct fec_ptp_circular *buf)
99{
100 return (buf->front == buf->end);
101}
102
103static int fec_ptp_nelems(struct fec_ptp_circular *buf)
104{
105 const int front = buf->front;
106 const int end = buf->end;
107 const int size = buf->size;
108 int n_items;
109
110 if (end > front)
111 n_items = end - front;
112 else if (end < front)
113 n_items = size - (front - end);
114 else
115 n_items = 0;
116
117 return n_items;
118}
119
120static int fec_ptp_is_full(struct fec_ptp_circular *buf)
121{
122 if (fec_ptp_nelems(buf) == (buf->size - 1))
123 return 1;
124 else
125 return 0;
126}
127
128static int fec_ptp_insert(struct fec_ptp_circular *ptp_buf,
129 struct fec_ptp_ts_data *data)
130{
131 struct fec_ptp_ts_data *tmp;
132
133 if (fec_ptp_is_full(ptp_buf))
134 ptp_buf->end = fec_ptp_calc_index(ptp_buf->size,
135 ptp_buf->end, 1);
136
137 tmp = (ptp_buf->data_buf + ptp_buf->end);
138 memcpy(tmp, data, sizeof(struct fec_ptp_ts_data));
139 ptp_buf->end = fec_ptp_calc_index(ptp_buf->size, ptp_buf->end, 1);
140
141 return 0;
142}
143
144static int fec_ptp_find_and_remove(struct fec_ptp_circular *ptp_buf,
145 struct fec_ptp_ident *ident, struct ptp_time *ts)
146{
147 int i;
148 int size = ptp_buf->size, end = ptp_buf->end;
149 struct fec_ptp_ident *tmp_ident;
150
151 if (fec_ptp_is_empty(ptp_buf))
152 return 1;
153
154 i = ptp_buf->front;
155 while (i != end) {
156 tmp_ident = &(ptp_buf->data_buf + i)->ident;
157 if (tmp_ident->version == ident->version) {
158 if (tmp_ident->message_type == ident->message_type) {
159 if ((tmp_ident->netw_prot == ident->netw_prot)
160 || (ident->netw_prot ==
161 FEC_PTP_PROT_DONTCARE)) {
162 if (tmp_ident->seq_id ==
163 ident->seq_id) {
164 int ret =
165 memcmp(tmp_ident->spid,
166 ident->spid,
167 PTP_SOURCE_PORT_LENGTH);
168 if (0 == ret)
169 break;
170 }
171 }
172 }
173 }
174 /* get next */
175 i = fec_ptp_calc_index(size, i, 1);
176 }
177
178 /* not found ? */
179 if (i == end) {
180 /* buffer full ? */
181 if (fec_ptp_is_full(ptp_buf))
182 /* drop one in front */
183 ptp_buf->front =
184 fec_ptp_calc_index(size, ptp_buf->front, 1);
185
186 return 1;
187 }
188 *ts = (ptp_buf->data_buf + i)->ts;
189 ptp_buf->front = fec_ptp_calc_index(size, ptp_buf->front, 1);
190
191 return 0;
192}
193
194/* 1588 Module intialization */
195void fec_ptp_start(struct net_device *ndev)
196{
197 struct fec_enet_private *fep = netdev_priv(ndev);
198 unsigned long flags;
199 int inc;
200
201 inc = FEC_T_PERIOD_ONE_SEC / clk_get_rate(fep->clk_ptp);
202
203 spin_lock_irqsave(&fep->tmreg_lock, flags);
204 /* Select 1588 Timer source and enable module for starting Tmr Clock */
205 writel(FEC_T_CTRL_RESTART, fep->hwp + FEC_ATIME_CTRL);
206 writel(inc << FEC_T_INC_OFFSET,
207 fep->hwp + FEC_ATIME_INC);
208 writel(FEC_T_PERIOD_ONE_SEC, fep->hwp + FEC_ATIME_EVT_PERIOD);
209 /* start counter */
210 writel(FEC_T_CTRL_PERIOD_RST | FEC_T_CTRL_ENABLE,
211 fep->hwp + FEC_ATIME_CTRL);
212 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
213}
214
215/* Cleanup routine for 1588 module.
216 * When PTP is disabled this routing is called */
217void fec_ptp_stop(struct net_device *ndev)
218{
219 struct fec_enet_private *priv = netdev_priv(ndev);
220
221 writel(0, priv->hwp + FEC_ATIME_CTRL);
222 writel(FEC_T_CTRL_RESTART, priv->hwp + FEC_ATIME_CTRL);
223}
224
225static void fec_get_curr_cnt(struct fec_enet_private *priv,
226 struct ptp_rtc_time *curr_time)
227{
228 u32 tempval;
229
230 tempval = readl(priv->hwp + FEC_ATIME_CTRL);
231 tempval |= FEC_T_CTRL_CAPTURE;
232
233 writel(tempval, priv->hwp + FEC_ATIME_CTRL);
234 curr_time->rtc_time.nsec = readl(priv->hwp + FEC_ATIME);
235 curr_time->rtc_time.sec = priv->prtc;
236
237 writel(tempval, priv->hwp + FEC_ATIME_CTRL);
238 tempval = readl(priv->hwp + FEC_ATIME);
239
240 if (tempval < curr_time->rtc_time.nsec) {
241 curr_time->rtc_time.nsec = tempval;
242 curr_time->rtc_time.sec = priv->prtc;
243 }
244}
245
246/* Set the 1588 timer counter registers */
247static void fec_set_1588cnt(struct fec_enet_private *priv,
248 struct ptp_rtc_time *fec_time)
249{
250 u32 tempval;
251 unsigned long flags;
252
253 spin_lock_irqsave(&priv->tmreg_lock, flags);
254 priv->prtc = fec_time->rtc_time.sec;
255
256 tempval = fec_time->rtc_time.nsec;
257 writel(tempval, priv->hwp + FEC_ATIME);
258 spin_unlock_irqrestore(&priv->tmreg_lock, flags);
259}
260
261/**
262 * Parse packets if they are PTP.
263 * The PTP header can be found in an IPv4, IPv6 or in an IEEE802.3
264 * ethernet frame. The function returns the position of the PTP packet
265 * or NULL, if no PTP found
266 */
267u8 *fec_ptp_parse_packet(struct sk_buff *skb, u16 *eth_type)
268{
269 u8 *position = skb->data + ETH_ALEN + ETH_ALEN;
270 u8 *ptp_loc = NULL;
271
272 *eth_type = *((u16 *)position);
273 /* Check if outer vlan tag is here */
274 if (ntohs(*eth_type) == ETH_P_8021Q) {
275 position += FEC_VLAN_TAG_LEN;
276 *eth_type = *((u16 *)position);
277 }
278
279 /* set position after ethertype */
280 position += FEC_ETHTYPE_LEN;
281 if (ETH_P_1588 == ntohs(*eth_type)) {
282 ptp_loc = position;
283 /* IEEE1588 event message which needs timestamping */
284 if ((ptp_loc[0] & 0xF) <= 3) {
285 if (skb->len >=
286 ((ptp_loc - skb->data) + PTP_HEADER_SZE))
287 return ptp_loc;
288 }
289 } else if (ETH_P_IP == ntohs(*eth_type)) {
290 u8 *ip_header, *prot, *udp_header;
291 u8 ip_version, ip_hlen;
292 ip_header = position;
293 ip_version = ip_header[0] >> 4; /* correct IP version? */
294 if (0x04 == ip_version) { /* IPv4 */
295 prot = ip_header + 9; /* protocol */
296 if (FEC_PACKET_TYPE_UDP == *prot) {
297 u16 udp_dstPort;
298 /* retrieve the size of the ip-header
299 * with the first byte of the ip-header:
300 * version ( 4 bits) + Internet header
301 * length (4 bits)
302 */
303 ip_hlen = (*ip_header & 0xf) * 4;
304 udp_header = ip_header + ip_hlen;
305 udp_dstPort = *((u16 *)(udp_header + 2));
306 /* check the destination port address
307 * ( 319 (0x013F) = PTP event port )
308 */
309 if (ntohs(udp_dstPort) == PTP_EVENT_PORT) {
310 ptp_loc = udp_header + 8;
311 /* long enough ? */
312 if (skb->len >= ((ptp_loc - skb->data)
313 + PTP_HEADER_SZE))
314 return ptp_loc;
315 }
316 }
317 }
318 } else if (ETH_P_IPV6 == ntohs(*eth_type)) {
319 u8 *ip_header, *udp_header, *prot;
320 u8 ip_version;
321 ip_header = position;
322 ip_version = ip_header[0] >> 4;
323 if (0x06 == ip_version) {
324 prot = ip_header + 6;
325 if (FEC_PACKET_TYPE_UDP == *prot) {
326 u16 udp_dstPort;
327 udp_header = ip_header + 40;
328 udp_dstPort = *((u16 *)(udp_header + 2));
329 /* check the destination port address
330 * ( 319 (0x013F) = PTP event port )
331 */
332 if (ntohs(udp_dstPort) == PTP_EVENT_PORT) {
333 ptp_loc = udp_header + 8;
334 /* long enough ? */
335 if (skb->len >= ((ptp_loc - skb->data)
336 + PTP_HEADER_SZE))
337 return ptp_loc;
338 }
339 }
340 }
341 }
342
343 return NULL; /* no PTP frame */
344}
345
346/* Set the BD to ptp */
347int fec_ptp_do_txstamp(struct sk_buff *skb)
348{
349 u8 *ptp_loc;
350 u16 eth_type;
351
352 ptp_loc = fec_ptp_parse_packet(skb, &eth_type);
353 if (ptp_loc != NULL)
354 return 1;
355
356 return 0;
357}
358
359void fec_ptp_store_txstamp(struct fec_enet_private *priv,
360 struct sk_buff *skb,
361 struct bufdesc *bdp)
362{
363 struct fec_ptp_ts_data tmp_tx_time;
364 struct bufdesc_ex *bdp_ex = NULL;
365 u8 *ptp_loc;
366 u16 eth_type;
367
368 bdp_ex = container_of(bdp, struct bufdesc_ex, desc);
369 ptp_loc = fec_ptp_parse_packet(skb, &eth_type);
370 if (ptp_loc != NULL) {
371 /* store identification data */
372 switch (ntohs(eth_type)) {
373 case ETH_P_IP:
374 tmp_tx_time.ident.netw_prot = FEC_PTP_PROT_IPV4;
375 break;
376 case ETH_P_IPV6:
377 tmp_tx_time.ident.netw_prot = FEC_PTP_PROT_IPV6;
378 break;
379 case ETH_P_1588:
380 tmp_tx_time.ident.netw_prot = FEC_PTP_PROT_802_3;
381 break;
382 default:
383 return;
384 }
385 tmp_tx_time.ident.version = (*(ptp_loc + 1)) & 0X0F;
386 tmp_tx_time.ident.message_type = (*(ptp_loc)) & 0x0F;
387 tmp_tx_time.ident.seq_id =
388 ntohs(*((u16 *)(ptp_loc + PTP_HEADER_SEQ_OFFS)));
389 memcpy(tmp_tx_time.ident.spid, &ptp_loc[PTP_SPID_OFFS],
390 PTP_SOURCE_PORT_LENGTH);
391 /* store tx timestamp */
392 tmp_tx_time.ts.sec = priv->prtc;
393 tmp_tx_time.ts.nsec = bdp_ex->ts;
394 /* insert timestamp in circular buffer */
395 fec_ptp_insert(&(priv->tx_timestamps), &tmp_tx_time);
396 }
397}
398
399void fec_ptp_store_rxstamp(struct fec_enet_private *priv,
400 struct sk_buff *skb,
401 struct bufdesc *bdp)
402{
403 struct fec_ptp_ts_data tmp_rx_time;
404 struct bufdesc_ex *bdp_ex = NULL;
405 u8 *ptp_loc;
406 u16 eth_type;
407
408 bdp_ex = container_of(bdp, struct bufdesc_ex, desc);
409 ptp_loc = fec_ptp_parse_packet(skb, &eth_type);
410 if (ptp_loc != NULL) {
411 /* store identification data */
412 tmp_rx_time.ident.version = (*(ptp_loc + 1)) & 0X0F;
413 tmp_rx_time.ident.message_type = (*(ptp_loc)) & 0x0F;
414 switch (ntohs(eth_type)) {
415 case ETH_P_IP:
416 tmp_rx_time.ident.netw_prot = FEC_PTP_PROT_IPV4;
417 break;
418 case ETH_P_IPV6:
419 tmp_rx_time.ident.netw_prot = FEC_PTP_PROT_IPV6;
420 break;
421 case ETH_P_1588:
422 tmp_rx_time.ident.netw_prot = FEC_PTP_PROT_802_3;
423 break;
424 default:
425 return;
426 }
427 tmp_rx_time.ident.seq_id =
428 ntohs(*((u16 *)(ptp_loc + PTP_HEADER_SEQ_OFFS)));
429 memcpy(tmp_rx_time.ident.spid, &ptp_loc[PTP_SPID_OFFS],
430 PTP_SOURCE_PORT_LENGTH);
431 /* store rx timestamp */
432 tmp_rx_time.ts.sec = priv->prtc;
433 tmp_rx_time.ts.nsec = bdp_ex->ts;
434
435 /* insert timestamp in circular buffer */
436 fec_ptp_insert(&(priv->rx_timestamps), &tmp_rx_time);
437 }
438}
439
440
441static void fec_handle_ptpdrift(struct fec_enet_private *priv,
442 struct ptp_set_comp *comp, struct ptp_time_correct *ptc)
443{
444 u32 ndrift;
445 u32 i, adj_inc, adj_period;
446 u32 tmp_current, tmp_winner;
447 u32 ptp_ts_clk, ptp_inc;
448
449 ptp_ts_clk = clk_get_rate(priv->clk_ptp);
450 ptp_inc = FEC_T_PERIOD_ONE_SEC / ptp_ts_clk;
451
452 ndrift = comp->drift;
453
454 if (ndrift == 0) {
455 ptc->corr_inc = 0;
456 ptc->corr_period = 0;
457 return;
458 } else if (ndrift >= ptp_ts_clk) {
459 ptc->corr_inc = (u32)(ndrift / ptp_ts_clk);
460 ptc->corr_period = 1;
461 return;
462 } else {
463 tmp_winner = 0xFFFFFFFF;
464 adj_inc = 1;
465
466 if (ndrift > (ptp_ts_clk / ptp_inc)) {
467 adj_inc = ptp_inc / FEC_PTP_SPINNER_2;
468 } else if (ndrift > (ptp_ts_clk /
469 (ptp_inc * FEC_PTP_SPINNER_4))) {
470 adj_inc = ptp_inc / FEC_PTP_SPINNER_4;
471 adj_period = FEC_PTP_SPINNER_2;
472 } else {
473 adj_inc = FEC_PTP_SPINNER_4;
474 adj_period = FEC_PTP_SPINNER_4;
475 }
476
477 for (i = 1; i < adj_inc; i++) {
478 tmp_current = (ptp_ts_clk * i) % ndrift;
479 if (tmp_current == 0) {
480 ptc->corr_inc = i;
481 ptc->corr_period = (u32)((ptp_ts_clk *
482 adj_period * i) / ndrift);
483 break;
484 } else if (tmp_current < tmp_winner) {
485 ptc->corr_inc = i;
486 ptc->corr_period = (u32)((ptp_ts_clk *
487 adj_period * i) / ndrift);
488 tmp_winner = tmp_current;
489 }
490 }
491 }
492}
493
494static void fec_set_drift(struct fec_enet_private *priv,
495 struct ptp_set_comp *comp)
496{
497 struct ptp_time_correct tc;
498 u32 tmp, corr_ns;
499 u32 ptp_inc;
500
501 memset(&tc, 0, sizeof(struct ptp_time_correct));
502 fec_handle_ptpdrift(priv, comp, &tc);
503 if (tc.corr_inc == 0)
504 return;
505
506 ptp_inc = FEC_T_PERIOD_ONE_SEC / clk_get_rate(priv->clk_ptp);
507 if (comp->o_ops == TRUE)
508 corr_ns = ptp_inc + tc.corr_inc;
509 else
510 corr_ns = ptp_inc - tc.corr_inc;
511
512 tmp = readl(priv->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK;
513 tmp |= corr_ns << FEC_T_INC_CORR_OFFSET;
514 writel(tmp, priv->hwp + FEC_ATIME_INC);
515 writel(tc.corr_period, priv->hwp + FEC_ATIME_CORR);
516}
517
74/** 518/**
75 * fec_ptp_read - read raw cycle counter (to be used by time counter) 519 * fec_ptp_read - read raw cycle counter (to be used by time counter)
76 * @cc: the cyclecounter structure 520 * @cc: the cyclecounter structure
@@ -106,18 +550,25 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev)
106 unsigned long flags; 550 unsigned long flags;
107 int inc; 551 int inc;
108 552
109 inc = 1000000000 / fep->cycle_speed; 553 inc = FEC_T_PERIOD_ONE_SEC / clk_get_rate(fep->clk_ptp);
110 554
111 /* grab the ptp lock */ 555 /* grab the ptp lock */
112 spin_lock_irqsave(&fep->tmreg_lock, flags); 556 spin_lock_irqsave(&fep->tmreg_lock, flags);
557 writel(FEC_T_CTRL_RESTART, fep->hwp + FEC_ATIME_CTRL);
113 558
114 /* 1ns counter */ 559 /* 1ns counter */
115 writel(inc << FEC_T_INC_OFFSET, fep->hwp + FEC_ATIME_INC); 560 writel(inc << FEC_T_INC_OFFSET, fep->hwp + FEC_ATIME_INC);
116 561
117 /* use free running count */ 562 if (fep->hwts_rx_en_ioctl || fep->hwts_tx_en_ioctl) {
118 writel(0, fep->hwp + FEC_ATIME_EVT_PERIOD); 563 writel(FEC_T_PERIOD_ONE_SEC, fep->hwp + FEC_ATIME_EVT_PERIOD);
119 564 /* start counter */
120 writel(FEC_T_CTRL_ENABLE, fep->hwp + FEC_ATIME_CTRL); 565 writel(FEC_T_CTRL_PERIOD_RST | FEC_T_CTRL_ENABLE,
566 fep->hwp + FEC_ATIME_CTRL);
567 } else if (fep->hwts_tx_en || fep->hwts_tx_en) {
568 /* use free running count */
569 writel(0, fep->hwp + FEC_ATIME_EVT_PERIOD);
570 writel(FEC_T_CTRL_ENABLE, fep->hwp + FEC_ATIME_CTRL);
571 }
121 572
122 memset(&fep->cc, 0, sizeof(fep->cc)); 573 memset(&fep->cc, 0, sizeof(fep->cc));
123 fep->cc.read = fec_ptp_read; 574 fep->cc.read = fec_ptp_read;
@@ -277,50 +728,140 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
277int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) 728int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
278{ 729{
279 struct fec_enet_private *fep = netdev_priv(ndev); 730 struct fec_enet_private *fep = netdev_priv(ndev);
280
281 struct hwtstamp_config config; 731 struct hwtstamp_config config;
282 732 struct ptp_rtc_time curr_time;
283 if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 733 struct ptp_time rx_time, tx_time;
284 return -EFAULT; 734 struct fec_ptp_ts_data p_ts;
285 735 struct fec_ptp_ts_data *p_ts_user;
286 /* reserved for future extensions */ 736 struct ptp_set_comp p_comp;
287 if (config.flags) 737 u32 freq_compensation;
288 return -EINVAL; 738 int retval = 0;
289 739
290 switch (config.tx_type) { 740 switch (cmd) {
291 case HWTSTAMP_TX_OFF: 741 case SIOCSHWTSTAMP:
742 if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
743 return -EFAULT;
744
745 /* reserved for future extensions */
746 if (config.flags)
747 return -EINVAL;
748
749 switch (config.tx_type) {
750 case HWTSTAMP_TX_OFF:
751 fep->hwts_tx_en = 0;
752 break;
753 case HWTSTAMP_TX_ON:
754 fep->hwts_tx_en = 1;
755 fep->hwts_tx_en_ioctl = 0;
756 break;
757 default:
758 return -ERANGE;
759 }
760
761 switch (config.rx_filter) {
762 case HWTSTAMP_FILTER_NONE:
763 if (fep->hwts_rx_en)
764 fep->hwts_rx_en = 0;
765 config.rx_filter = HWTSTAMP_FILTER_NONE;
766 break;
767
768 default:
769 /*
770 * register RXMTRL must be set in order
771 * to do V1 packets, therefore it is not
772 * possible to time stamp both V1 Sync and
773 * Delay_Req messages and hardware does not support
774 * timestamping all packets => return error
775 */
776 fep->hwts_rx_en = 1;
777 fep->hwts_rx_en_ioctl = 0;
778 config.rx_filter = HWTSTAMP_FILTER_ALL;
779 break;
780 }
781
782 fec_ptp_start_cyclecounter(ndev);
783 return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
784 -EFAULT : 0;
785 break;
786 case PTP_ENBL_TXTS_IOCTL:
787 case PTP_ENBL_RXTS_IOCTL:
788 fep->hwts_rx_en_ioctl = 1;
789 fep->hwts_tx_en_ioctl = 1;
790 fep->hwts_rx_en = 0;
292 fep->hwts_tx_en = 0; 791 fep->hwts_tx_en = 0;
792 fec_ptp_start_cyclecounter(ndev);
293 break; 793 break;
294 case HWTSTAMP_TX_ON: 794 case PTP_DSBL_RXTS_IOCTL:
295 fep->hwts_tx_en = 1; 795 case PTP_DSBL_TXTS_IOCTL:
796 fep->hwts_rx_en_ioctl = 0;
797 fep->hwts_tx_en_ioctl = 0;
296 break; 798 break;
297 default: 799 case PTP_GET_RX_TIMESTAMP:
298 return -ERANGE; 800 p_ts_user = (struct fec_ptp_ts_data *)ifr->ifr_data;
299 } 801 if (0 != copy_from_user(&p_ts.ident,
300 802 &p_ts_user->ident, sizeof(p_ts.ident)))
301 switch (config.rx_filter) { 803 return -EINVAL;
302 case HWTSTAMP_FILTER_NONE: 804 retval = fec_ptp_find_and_remove(&fep->rx_timestamps,
303 if (fep->hwts_rx_en) 805 &p_ts.ident, &rx_time);
304 fep->hwts_rx_en = 0; 806 if (retval == 0 &&
305 config.rx_filter = HWTSTAMP_FILTER_NONE; 807 copy_to_user((void __user *)(&p_ts_user->ts),
808 &rx_time, sizeof(rx_time)))
809 return -EFAULT;
306 break; 810 break;
307 811 case PTP_GET_TX_TIMESTAMP:
308 default: 812 p_ts_user = (struct fec_ptp_ts_data *)ifr->ifr_data;
309 /* 813 if (0 != copy_from_user(&p_ts.ident,
310 * register RXMTRL must be set in order to do V1 packets, 814 &p_ts_user->ident, sizeof(p_ts.ident)))
311 * therefore it is not possible to time stamp both V1 Sync and 815 return -EINVAL;
312 * Delay_Req messages and hardware does not support 816 retval = fec_ptp_find_and_remove(&fep->tx_timestamps,
313 * timestamping all packets => return error 817 &p_ts.ident, &tx_time);
314 */ 818 if (retval == 0 &&
315 fep->hwts_rx_en = 1; 819 copy_to_user((void __user *)(&p_ts_user->ts),
316 config.rx_filter = HWTSTAMP_FILTER_ALL; 820 &tx_time, sizeof(tx_time)))
821 retval = -EFAULT;
822 break;
823 case PTP_GET_CURRENT_TIME:
824 fec_get_curr_cnt(fep, &curr_time);
825 if (0 != copy_to_user(ifr->ifr_data,
826 &(curr_time.rtc_time),
827 sizeof(struct ptp_time)))
828 return -EFAULT;
829 break;
830 case PTP_SET_RTC_TIME:
831 if (0 != copy_from_user(&(curr_time.rtc_time),
832 ifr->ifr_data,
833 sizeof(struct ptp_time)))
834 return -EINVAL;
835 fec_set_1588cnt(fep, &curr_time);
317 break; 836 break;
837 case PTP_FLUSH_TIMESTAMP:
838 /* reset tx-timestamping buffer */
839 fep->tx_timestamps.front = 0;
840 fep->tx_timestamps.end = 0;
841 fep->tx_timestamps.size = (DEFAULT_PTP_TX_BUF_SZ + 1);
842 /* reset rx-timestamping buffer */
843 fep->rx_timestamps.front = 0;
844 fep->rx_timestamps.end = 0;
845 fep->rx_timestamps.size = (DEFAULT_PTP_RX_BUF_SZ + 1);
846 break;
847 case PTP_SET_COMPENSATION:
848 if (0 != copy_from_user(&p_comp, ifr->ifr_data,
849 sizeof(struct ptp_set_comp)))
850 return -EINVAL;
851 fec_set_drift(fep, &p_comp);
852 break;
853 case PTP_GET_ORIG_COMP:
854 freq_compensation = FEC_PTP_ORIG_COMP;
855 if (copy_to_user(ifr->ifr_data, &freq_compensation,
856 sizeof(freq_compensation)) > 0)
857 return -EFAULT;
858 break;
859 default:
860 return -EINVAL;
318 } 861 }
319 862
320 return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? 863 return retval;
321 -EFAULT : 0;
322} 864}
323
324/** 865/**
325 * fec_time_keep - call timecounter_read every second to avoid timer overrun 866 * fec_time_keep - call timecounter_read every second to avoid timer overrun
326 * because ENET just support 32bit counter, will timeout in 4s 867 * because ENET just support 32bit counter, will timeout in 4s
@@ -383,4 +924,22 @@ void fec_ptp_init(struct platform_device *pdev)
383 fep->ptp_clock = NULL; 924 fep->ptp_clock = NULL;
384 pr_err("ptp_clock_register failed\n"); 925 pr_err("ptp_clock_register failed\n");
385 } 926 }
927
928 /* initialize circular buffer for tx timestamps */
929 if (fec_ptp_init_circ(&(fep->tx_timestamps),
930 (DEFAULT_PTP_TX_BUF_SZ+1)))
931 pr_err("init tx circular buffer failed\n");
932 /* initialize circular buffer for rx timestamps */
933 if (fec_ptp_init_circ(&(fep->rx_timestamps),
934 (DEFAULT_PTP_RX_BUF_SZ+1)))
935 pr_err("init rx curcular buffer failed\n");
386} 936}
937
938void fec_ptp_cleanup(struct fec_enet_private *priv)
939{
940 if (priv->tx_timestamps.data_buf)
941 vfree(priv->tx_timestamps.data_buf);
942 if (priv->rx_timestamps.data_buf)
943 vfree(priv->rx_timestamps.data_buf);
944}
945