aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/freescale
diff options
context:
space:
mode:
authorFrank Li <Frank.Li@freescale.com>2012-10-30 14:25:31 -0400
committerDavid S. Miller <davem@davemloft.net>2012-11-01 12:28:44 -0400
commit6605b730c061f67c44113391e5af5125d0672e99 (patch)
treef590a2528231b7ca20a9ca32457eb0128e1e107c /drivers/net/ethernet/freescale
parentd6e0d9fcbb01edc7a342b15f077a217d46f3b608 (diff)
FEC: Add time stamping code and a PTP hardware clock
This patch adds a driver for the FEC(MX6) that offers time stamping and a PTP haderware clock. Because FEC\ENET(MX6) hardware frequency adjustment is complex, we have implemented this in software by changing the multiplication factor of the timecounter. Signed-off-by: Frank Li <Frank.Li@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r--drivers/net/ethernet/freescale/Kconfig9
-rw-r--r--drivers/net/ethernet/freescale/Makefile1
-rw-r--r--drivers/net/ethernet/freescale/fec.c88
-rw-r--r--drivers/net/ethernet/freescale/fec.h38
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c385
5 files changed, 520 insertions, 1 deletions
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index feff51664dcf..ff3be53d0169 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -92,4 +92,13 @@ config GIANFAR
92 This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx, 92 This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
93 and MPC86xx family of chips, and the FEC on the 8540. 93 and MPC86xx family of chips, and the FEC on the 8540.
94 94
95config FEC_PTP
96 bool "PTP Hardware Clock (PHC)"
97 depends on FEC
98 select PPS
99 select PTP_1588_CLOCK
100 --help---
101 Say Y here if you want to use PTP Hardware Clock (PHC) in the
102 driver. Only the basic clock operations have been implemented.
103
95endif # NET_VENDOR_FREESCALE 104endif # NET_VENDOR_FREESCALE
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
index 3d1839afff65..d4d19b3d00ae 100644
--- a/drivers/net/ethernet/freescale/Makefile
+++ b/drivers/net/ethernet/freescale/Makefile
@@ -3,6 +3,7 @@
3# 3#
4 4
5obj-$(CONFIG_FEC) += fec.o 5obj-$(CONFIG_FEC) += fec.o
6obj-$(CONFIG_FEC_PTP) += fec_ptp.o
6obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o 7obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
7ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) 8ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
8 obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o 9 obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index d0e1b331e8e6..2665162ff4e5 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -280,6 +280,17 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
280 | BD_ENET_TX_LAST | BD_ENET_TX_TC); 280 | BD_ENET_TX_LAST | BD_ENET_TX_TC);
281 bdp->cbd_sc = status; 281 bdp->cbd_sc = status;
282 282
283#ifdef CONFIG_FEC_PTP
284 bdp->cbd_bdu = 0;
285 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
286 fep->hwts_tx_en)) {
287 bdp->cbd_esc = (BD_ENET_TX_TS | BD_ENET_TX_INT);
288 skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
289 } else {
290
291 bdp->cbd_esc = BD_ENET_TX_INT;
292 }
293#endif
283 /* Trigger transmission start */ 294 /* Trigger transmission start */
284 writel(0, fep->hwp + FEC_X_DES_ACTIVE); 295 writel(0, fep->hwp + FEC_X_DES_ACTIVE);
285 296
@@ -437,10 +448,17 @@ fec_restart(struct net_device *ndev, int duplex)
437 writel(1 << 8, fep->hwp + FEC_X_WMRK); 448 writel(1 << 8, fep->hwp + FEC_X_WMRK);
438 } 449 }
439 450
451#ifdef CONFIG_FEC_PTP
452 ecntl |= (1 << 4);
453#endif
454
440 /* And last, enable the transmit and receive processing */ 455 /* And last, enable the transmit and receive processing */
441 writel(ecntl, fep->hwp + FEC_ECNTRL); 456 writel(ecntl, fep->hwp + FEC_ECNTRL);
442 writel(0, fep->hwp + FEC_R_DES_ACTIVE); 457 writel(0, fep->hwp + FEC_R_DES_ACTIVE);
443 458
459#ifdef CONFIG_FEC_PTP
460 fec_ptp_start_cyclecounter(ndev);
461#endif
444 /* Enable interrupts we wish to service */ 462 /* Enable interrupts we wish to service */
445 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); 463 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
446} 464}
@@ -526,6 +544,19 @@ fec_enet_tx(struct net_device *ndev)
526 ndev->stats.tx_packets++; 544 ndev->stats.tx_packets++;
527 } 545 }
528 546
547#ifdef CONFIG_FEC_PTP
548 if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
549 struct skb_shared_hwtstamps shhwtstamps;
550 unsigned long flags;
551
552 memset(&shhwtstamps, 0, sizeof(shhwtstamps));
553 spin_lock_irqsave(&fep->tmreg_lock, flags);
554 shhwtstamps.hwtstamp = ns_to_ktime(
555 timecounter_cyc2time(&fep->tc, bdp->ts));
556 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
557 skb_tstamp_tx(skb, &shhwtstamps);
558 }
559#endif
529 if (status & BD_ENET_TX_READY) 560 if (status & BD_ENET_TX_READY)
530 printk("HEY! Enet xmit interrupt and TX_READY.\n"); 561 printk("HEY! Enet xmit interrupt and TX_READY.\n");
531 562
@@ -652,6 +683,21 @@ fec_enet_rx(struct net_device *ndev)
652 skb_put(skb, pkt_len - 4); /* Make room */ 683 skb_put(skb, pkt_len - 4); /* Make room */
653 skb_copy_to_linear_data(skb, data, pkt_len - 4); 684 skb_copy_to_linear_data(skb, data, pkt_len - 4);
654 skb->protocol = eth_type_trans(skb, ndev); 685 skb->protocol = eth_type_trans(skb, ndev);
686#ifdef CONFIG_FEC_PTP
687 /* Get receive timestamp from the skb */
688 if (fep->hwts_rx_en) {
689 struct skb_shared_hwtstamps *shhwtstamps =
690 skb_hwtstamps(skb);
691 unsigned long flags;
692
693 memset(shhwtstamps, 0, sizeof(*shhwtstamps));
694
695 spin_lock_irqsave(&fep->tmreg_lock, flags);
696 shhwtstamps->hwtstamp = ns_to_ktime(
697 timecounter_cyc2time(&fep->tc, bdp->ts));
698 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
699 }
700#endif
655 if (!skb_defer_rx_timestamp(skb)) 701 if (!skb_defer_rx_timestamp(skb))
656 netif_rx(skb); 702 netif_rx(skb);
657 } 703 }
@@ -666,6 +712,12 @@ rx_processing_done:
666 status |= BD_ENET_RX_EMPTY; 712 status |= BD_ENET_RX_EMPTY;
667 bdp->cbd_sc = status; 713 bdp->cbd_sc = status;
668 714
715#ifdef CONFIG_FEC_PTP
716 bdp->cbd_esc = BD_ENET_RX_INT;
717 bdp->cbd_prot = 0;
718 bdp->cbd_bdu = 0;
719#endif
720
669 /* Update BD pointer to next entry */ 721 /* Update BD pointer to next entry */
670 if (status & BD_ENET_RX_WRAP) 722 if (status & BD_ENET_RX_WRAP)
671 bdp = fep->rx_bd_base; 723 bdp = fep->rx_bd_base;
@@ -1105,6 +1157,10 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
1105 if (!phydev) 1157 if (!phydev)
1106 return -ENODEV; 1158 return -ENODEV;
1107 1159
1160#ifdef CONFIG_FEC_PTP
1161 if (cmd == SIOCSHWTSTAMP)
1162 return fec_ptp_ioctl(ndev, rq, cmd);
1163#endif
1108 return phy_mii_ioctl(phydev, rq, cmd); 1164 return phy_mii_ioctl(phydev, rq, cmd);
1109} 1165}
1110 1166
@@ -1151,6 +1207,9 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
1151 bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, 1207 bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data,
1152 FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); 1208 FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
1153 bdp->cbd_sc = BD_ENET_RX_EMPTY; 1209 bdp->cbd_sc = BD_ENET_RX_EMPTY;
1210#ifdef CONFIG_FEC_PTP
1211 bdp->cbd_esc = BD_ENET_RX_INT;
1212#endif
1154 bdp++; 1213 bdp++;
1155 } 1214 }
1156 1215
@@ -1164,6 +1223,10 @@ static int fec_enet_alloc_buffers(struct net_device *ndev)
1164 1223
1165 bdp->cbd_sc = 0; 1224 bdp->cbd_sc = 0;
1166 bdp->cbd_bufaddr = 0; 1225 bdp->cbd_bufaddr = 0;
1226
1227#ifdef CONFIG_FEC_PTP
1228 bdp->cbd_esc = BD_ENET_RX_INT;
1229#endif
1167 bdp++; 1230 bdp++;
1168 } 1231 }
1169 1232
@@ -1565,9 +1628,19 @@ fec_probe(struct platform_device *pdev)
1565 goto failed_clk; 1628 goto failed_clk;
1566 } 1629 }
1567 1630
1631#ifdef CONFIG_FEC_PTP
1632 fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
1633 if (IS_ERR(fep->clk_ptp)) {
1634 ret = PTR_ERR(fep->clk_ptp);
1635 goto failed_clk;
1636 }
1637#endif
1638
1568 clk_prepare_enable(fep->clk_ahb); 1639 clk_prepare_enable(fep->clk_ahb);
1569 clk_prepare_enable(fep->clk_ipg); 1640 clk_prepare_enable(fep->clk_ipg);
1570 1641#ifdef CONFIG_FEC_PTP
1642 clk_prepare_enable(fep->clk_ptp);
1643#endif
1571 reg_phy = devm_regulator_get(&pdev->dev, "phy"); 1644 reg_phy = devm_regulator_get(&pdev->dev, "phy");
1572 if (!IS_ERR(reg_phy)) { 1645 if (!IS_ERR(reg_phy)) {
1573 ret = regulator_enable(reg_phy); 1646 ret = regulator_enable(reg_phy);
@@ -1595,6 +1668,10 @@ fec_probe(struct platform_device *pdev)
1595 if (ret) 1668 if (ret)
1596 goto failed_register; 1669 goto failed_register;
1597 1670
1671#ifdef CONFIG_FEC_PTP
1672 fec_ptp_init(ndev, pdev);
1673#endif
1674
1598 return 0; 1675 return 0;
1599 1676
1600failed_register: 1677failed_register:
@@ -1604,6 +1681,9 @@ failed_init:
1604failed_regulator: 1681failed_regulator:
1605 clk_disable_unprepare(fep->clk_ahb); 1682 clk_disable_unprepare(fep->clk_ahb);
1606 clk_disable_unprepare(fep->clk_ipg); 1683 clk_disable_unprepare(fep->clk_ipg);
1684#ifdef CONFIG_FEC_PTP
1685 clk_disable_unprepare(fep->clk_ptp);
1686#endif
1607failed_pin: 1687failed_pin:
1608failed_clk: 1688failed_clk:
1609 for (i = 0; i < FEC_IRQ_NUM; i++) { 1689 for (i = 0; i < FEC_IRQ_NUM; i++) {
@@ -1636,6 +1716,12 @@ fec_drv_remove(struct platform_device *pdev)
1636 if (irq > 0) 1716 if (irq > 0)
1637 free_irq(irq, ndev); 1717 free_irq(irq, ndev);
1638 } 1718 }
1719#ifdef CONFIG_FEC_PTP
1720 del_timer_sync(&fep->time_keep);
1721 clk_disable_unprepare(fep->clk_ptp);
1722 if (fep->ptp_clock)
1723 ptp_clock_unregister(fep->ptp_clock);
1724#endif
1639 clk_disable_unprepare(fep->clk_ahb); 1725 clk_disable_unprepare(fep->clk_ahb);
1640 clk_disable_unprepare(fep->clk_ipg); 1726 clk_disable_unprepare(fep->clk_ipg);
1641 iounmap(fep->hwp); 1727 iounmap(fep->hwp);
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index e803812975df..c5a3bc1475c7 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -13,6 +13,12 @@
13#define FEC_H 13#define FEC_H
14/****************************************************************************/ 14/****************************************************************************/
15 15
16#ifdef CONFIG_FEC_PTP
17#include <linux/clocksource.h>
18#include <linux/net_tstamp.h>
19#include <linux/ptp_clock_kernel.h>
20#endif
21
16#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ 22#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
17 defined(CONFIG_M520x) || defined(CONFIG_M532x) || \ 23 defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
18 defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28) 24 defined(CONFIG_ARCH_MXC) || defined(CONFIG_SOC_IMX28)
@@ -88,6 +94,13 @@ struct bufdesc {
88 unsigned short cbd_datlen; /* Data length */ 94 unsigned short cbd_datlen; /* Data length */
89 unsigned short cbd_sc; /* Control and status info */ 95 unsigned short cbd_sc; /* Control and status info */
90 unsigned long cbd_bufaddr; /* Buffer address */ 96 unsigned long cbd_bufaddr; /* Buffer address */
97#ifdef CONFIG_FEC_PTP
98 unsigned long cbd_esc;
99 unsigned long cbd_prot;
100 unsigned long cbd_bdu;
101 unsigned long ts;
102 unsigned short res0[4];
103#endif
91}; 104};
92#else 105#else
93struct bufdesc { 106struct bufdesc {
@@ -190,6 +203,9 @@ struct fec_enet_private {
190 203
191 struct clk *clk_ipg; 204 struct clk *clk_ipg;
192 struct clk *clk_ahb; 205 struct clk *clk_ahb;
206#ifdef CONFIG_FEC_PTP
207 struct clk *clk_ptp;
208#endif
193 209
194 /* The saved address of a sent-in-place packet/buffer, for skfree(). */ 210 /* The saved address of a sent-in-place packet/buffer, for skfree(). */
195 unsigned char *tx_bounce[TX_RING_SIZE]; 211 unsigned char *tx_bounce[TX_RING_SIZE];
@@ -227,7 +243,29 @@ struct fec_enet_private {
227 int full_duplex; 243 int full_duplex;
228 struct completion mdio_done; 244 struct completion mdio_done;
229 int irq[FEC_IRQ_NUM]; 245 int irq[FEC_IRQ_NUM];
246
247#ifdef CONFIG_FEC_PTP
248 struct ptp_clock *ptp_clock;
249 struct ptp_clock_info ptp_caps;
250 unsigned long last_overflow_check;
251 spinlock_t tmreg_lock;
252 struct cyclecounter cc;
253 struct timecounter tc;
254 int rx_hwtstamp_filter;
255 u32 base_incval;
256 u32 cycle_speed;
257 int hwts_rx_en;
258 int hwts_tx_en;
259 struct timer_list time_keep;
260#endif
261
230}; 262};
231 263
264#ifdef CONFIG_FEC_PTP
265void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev);
266void fec_ptp_start_cyclecounter(struct net_device *ndev);
267int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd);
268#endif
269
232/****************************************************************************/ 270/****************************************************************************/
233#endif /* FEC_H */ 271#endif /* FEC_H */
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
new file mode 100644
index 000000000000..5352140468ce
--- /dev/null
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -0,0 +1,385 @@
1/*
2 * Fast Ethernet Controller (ENET) PTP driver for MX6x.
3 *
4 * Copyright (C) 2012 Freescale Semiconductor, Inc.
5 *
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,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include <linux/module.h>
21#include <linux/kernel.h>
22#include <linux/string.h>
23#include <linux/ptrace.h>
24#include <linux/errno.h>
25#include <linux/ioport.h>
26#include <linux/slab.h>
27#include <linux/interrupt.h>
28#include <linux/pci.h>
29#include <linux/init.h>
30#include <linux/delay.h>
31#include <linux/netdevice.h>
32#include <linux/etherdevice.h>
33#include <linux/skbuff.h>
34#include <linux/spinlock.h>
35#include <linux/workqueue.h>
36#include <linux/bitops.h>
37#include <linux/io.h>
38#include <linux/irq.h>
39#include <linux/clk.h>
40#include <linux/platform_device.h>
41#include <linux/phy.h>
42#include <linux/fec.h>
43#include <linux/of.h>
44#include <linux/of_device.h>
45#include <linux/of_gpio.h>
46#include <linux/of_net.h>
47
48#include "fec.h"
49
50/* FEC 1588 register bits */
51#define FEC_T_CTRL_SLAVE 0x00002000
52#define FEC_T_CTRL_CAPTURE 0x00000800
53#define FEC_T_CTRL_RESTART 0x00000200
54#define FEC_T_CTRL_PERIOD_RST 0x00000030
55#define FEC_T_CTRL_PERIOD_EN 0x00000010
56#define FEC_T_CTRL_ENABLE 0x00000001
57
58#define FEC_T_INC_MASK 0x0000007f
59#define FEC_T_INC_OFFSET 0
60#define FEC_T_INC_CORR_MASK 0x00007f00
61#define FEC_T_INC_CORR_OFFSET 8
62
63#define FEC_ATIME_CTRL 0x400
64#define FEC_ATIME 0x404
65#define FEC_ATIME_EVT_OFFSET 0x408
66#define FEC_ATIME_EVT_PERIOD 0x40c
67#define FEC_ATIME_CORR 0x410
68#define FEC_ATIME_INC 0x414
69#define FEC_TS_TIMESTAMP 0x418
70
71#define FEC_CC_MULT (1 << 31)
72/**
73 * fec_ptp_read - read raw cycle counter (to be used by time counter)
74 * @cc: the cyclecounter structure
75 *
76 * this function reads the cyclecounter registers and is called by the
77 * cyclecounter structure used to construct a ns counter from the
78 * arbitrary fixed point registers
79 */
80static cycle_t fec_ptp_read(const struct cyclecounter *cc)
81{
82 struct fec_enet_private *fep =
83 container_of(cc, struct fec_enet_private, cc);
84 u32 tempval;
85
86 tempval = readl(fep->hwp + FEC_ATIME_CTRL);
87 tempval |= FEC_T_CTRL_CAPTURE;
88 writel(tempval, fep->hwp + FEC_ATIME_CTRL);
89
90 return readl(fep->hwp + FEC_ATIME);
91}
92
93/**
94 * fec_ptp_start_cyclecounter - create the cycle counter from hw
95 * @ndev: network device
96 *
97 * this function initializes the timecounter and cyclecounter
98 * structures for use in generated a ns counter from the arbitrary
99 * fixed point cycles registers in the hardware.
100 */
101void fec_ptp_start_cyclecounter(struct net_device *ndev)
102{
103 struct fec_enet_private *fep = netdev_priv(ndev);
104 unsigned long flags;
105 int inc;
106
107 inc = 1000000000 / clk_get_rate(fep->clk_ptp);
108
109 /* grab the ptp lock */
110 spin_lock_irqsave(&fep->tmreg_lock, flags);
111
112 /* 1ns counter */
113 writel(inc << FEC_T_INC_OFFSET, fep->hwp + FEC_ATIME_INC);
114
115 /* use free running count */
116 writel(0, fep->hwp + FEC_ATIME_EVT_PERIOD);
117
118 writel(FEC_T_CTRL_ENABLE, fep->hwp + FEC_ATIME_CTRL);
119
120 memset(&fep->cc, 0, sizeof(fep->cc));
121 fep->cc.read = fec_ptp_read;
122 fep->cc.mask = CLOCKSOURCE_MASK(32);
123 fep->cc.shift = 31;
124 fep->cc.mult = FEC_CC_MULT;
125
126 /* reset the ns time counter */
127 timecounter_init(&fep->tc, &fep->cc, ktime_to_ns(ktime_get_real()));
128
129 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
130}
131
132/**
133 * fec_ptp_adjfreq - adjust ptp cycle frequency
134 * @ptp: the ptp clock structure
135 * @ppb: parts per billion adjustment from base
136 *
137 * Adjust the frequency of the ptp cycle counter by the
138 * indicated ppb from the base frequency.
139 *
140 * Because ENET hardware frequency adjust is complex,
141 * using software method to do that.
142 */
143static int fec_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
144{
145 u64 diff;
146 unsigned long flags;
147 int neg_adj = 0;
148
149 struct fec_enet_private *fep =
150 container_of(ptp, struct fec_enet_private, ptp_caps);
151
152 if (ppb < 0) {
153 ppb = -ppb;
154 neg_adj = 1;
155 }
156
157 spin_lock_irqsave(&fep->tmreg_lock, flags);
158 /*
159 * dummy read to set cycle_last in tc to now.
160 * So use adjusted mult to calculate when next call
161 * timercounter_read.
162 */
163 timecounter_read(&fep->tc);
164 fep->cc.mult = FEC_CC_MULT;
165 diff = fep->cc.mult;
166 diff *= ppb;
167 diff = div_u64(diff, 1000000000ULL);
168
169 if (neg_adj)
170 fep->cc.mult -= diff;
171 else
172 fep->cc.mult += diff;
173
174 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
175
176 return 0;
177}
178
179/**
180 * fec_ptp_adjtime
181 * @ptp: the ptp clock structure
182 * @delta: offset to adjust the cycle counter by
183 *
184 * adjust the timer by resetting the timecounter structure.
185 */
186static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
187{
188 struct fec_enet_private *fep =
189 container_of(ptp, struct fec_enet_private, ptp_caps);
190 unsigned long flags;
191 u64 now;
192
193 spin_lock_irqsave(&fep->tmreg_lock, flags);
194
195 now = timecounter_read(&fep->tc);
196 now += delta;
197
198 /* reset the timecounter */
199 timecounter_init(&fep->tc, &fep->cc, now);
200
201 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
202
203 return 0;
204}
205
206/**
207 * fec_ptp_gettime
208 * @ptp: the ptp clock structure
209 * @ts: timespec structure to hold the current time value
210 *
211 * read the timecounter and return the correct value on ns,
212 * after converting it into a struct timespec.
213 */
214static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
215{
216 struct fec_enet_private *adapter =
217 container_of(ptp, struct fec_enet_private, ptp_caps);
218 u64 ns;
219 u32 remainder;
220 unsigned long flags;
221
222 spin_lock_irqsave(&adapter->tmreg_lock, flags);
223 ns = timecounter_read(&adapter->tc);
224 spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
225
226 ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder);
227 ts->tv_nsec = remainder;
228
229 return 0;
230}
231
232/**
233 * fec_ptp_settime
234 * @ptp: the ptp clock structure
235 * @ts: the timespec containing the new time for the cycle counter
236 *
237 * reset the timecounter to use a new base value instead of the kernel
238 * wall timer value.
239 */
240static int fec_ptp_settime(struct ptp_clock_info *ptp,
241 const struct timespec *ts)
242{
243 struct fec_enet_private *fep =
244 container_of(ptp, struct fec_enet_private, ptp_caps);
245
246 u64 ns;
247 unsigned long flags;
248
249 ns = ts->tv_sec * 1000000000ULL;
250 ns += ts->tv_nsec;
251
252 spin_lock_irqsave(&fep->tmreg_lock, flags);
253 timecounter_init(&fep->tc, &fep->cc, ns);
254 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
255 return 0;
256}
257
258/**
259 * fec_ptp_enable
260 * @ptp: the ptp clock structure
261 * @rq: the requested feature to change
262 * @on: whether to enable or disable the feature
263 *
264 */
265static int fec_ptp_enable(struct ptp_clock_info *ptp,
266 struct ptp_clock_request *rq, int on)
267{
268 return -EOPNOTSUPP;
269}
270
271/**
272 * fec_ptp_hwtstamp_ioctl - control hardware time stamping
273 * @ndev: pointer to net_device
274 * @ifreq: ioctl data
275 * @cmd: particular ioctl requested
276 */
277int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
278{
279 struct fec_enet_private *fep = netdev_priv(ndev);
280
281 struct hwtstamp_config config;
282
283 if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
284 return -EFAULT;
285
286 /* reserved for future extensions */
287 if (config.flags)
288 return -EINVAL;
289
290 switch (config.tx_type) {
291 case HWTSTAMP_TX_OFF:
292 fep->hwts_tx_en = 0;
293 break;
294 case HWTSTAMP_TX_ON:
295 fep->hwts_tx_en = 1;
296 break;
297 default:
298 return -ERANGE;
299 }
300
301 switch (config.rx_filter) {
302 case HWTSTAMP_FILTER_NONE:
303 if (fep->hwts_rx_en)
304 fep->hwts_rx_en = 0;
305 config.rx_filter = HWTSTAMP_FILTER_NONE;
306 break;
307
308 default:
309 /*
310 * register RXMTRL must be set in order to do V1 packets,
311 * therefore it is not possible to time stamp both V1 Sync and
312 * Delay_Req messages and hardware does not support
313 * timestamping all packets => return error
314 */
315 fep->hwts_rx_en = 1;
316 config.rx_filter = HWTSTAMP_FILTER_ALL;
317 break;
318 }
319
320 return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
321 -EFAULT : 0;
322}
323
324/**
325 * fec_time_keep - call timecounter_read every second to avoid timer overrun
326 * because ENET just support 32bit counter, will timeout in 4s
327 */
328static void fec_time_keep(unsigned long _data)
329{
330 struct fec_enet_private *fep = (struct fec_enet_private *)_data;
331 u64 ns;
332 unsigned long flags;
333
334 spin_lock_irqsave(&fep->tmreg_lock, flags);
335 ns = timecounter_read(&fep->tc);
336 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
337
338 mod_timer(&fep->time_keep, jiffies + HZ);
339}
340
341/**
342 * fec_ptp_init
343 * @ndev: The FEC network adapter
344 *
345 * This function performs the required steps for enabling ptp
346 * support. If ptp support has already been loaded it simply calls the
347 * cyclecounter init routine and exits.
348 */
349
350void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev)
351{
352 struct fec_enet_private *fep = netdev_priv(ndev);
353
354 fep->ptp_caps.owner = THIS_MODULE;
355 snprintf(fep->ptp_caps.name, 16, "fec ptp");
356
357 fep->ptp_caps.max_adj = 250000000;
358 fep->ptp_caps.n_alarm = 0;
359 fep->ptp_caps.n_ext_ts = 0;
360 fep->ptp_caps.n_per_out = 0;
361 fep->ptp_caps.pps = 0;
362 fep->ptp_caps.adjfreq = fec_ptp_adjfreq;
363 fep->ptp_caps.adjtime = fec_ptp_adjtime;
364 fep->ptp_caps.gettime = fec_ptp_gettime;
365 fep->ptp_caps.settime = fec_ptp_settime;
366 fep->ptp_caps.enable = fec_ptp_enable;
367
368 spin_lock_init(&fep->tmreg_lock);
369
370 fec_ptp_start_cyclecounter(ndev);
371
372 init_timer(&fep->time_keep);
373 fep->time_keep.data = (unsigned long)fep;
374 fep->time_keep.function = fec_time_keep;
375 fep->time_keep.expires = jiffies + HZ;
376 add_timer(&fep->time_keep);
377
378 fep->ptp_clock = ptp_clock_register(&fep->ptp_caps, &pdev->dev);
379 if (IS_ERR(fep->ptp_clock)) {
380 fep->ptp_clock = NULL;
381 pr_err("ptp_clock_register failed\n");
382 } else {
383 pr_info("registered PHC device on %s\n", ndev->name);
384 }
385}