1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /**
3*4882a593Smuzhiyun * 1588 PTP support for Cadence GEM device.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2017 Cadence Design Systems - https://www.cadence.com
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Authors: Rafal Ozieblo <rafalo@cadence.com>
8*4882a593Smuzhiyun * Bartosz Folta <bfolta@cadence.com>
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/types.h>
12*4882a593Smuzhiyun #include <linux/clk.h>
13*4882a593Smuzhiyun #include <linux/device.h>
14*4882a593Smuzhiyun #include <linux/etherdevice.h>
15*4882a593Smuzhiyun #include <linux/platform_device.h>
16*4882a593Smuzhiyun #include <linux/time64.h>
17*4882a593Smuzhiyun #include <linux/ptp_classify.h>
18*4882a593Smuzhiyun #include <linux/if_ether.h>
19*4882a593Smuzhiyun #include <linux/if_vlan.h>
20*4882a593Smuzhiyun #include <linux/net_tstamp.h>
21*4882a593Smuzhiyun #include <linux/circ_buf.h>
22*4882a593Smuzhiyun #include <linux/spinlock.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include "macb.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define GEM_PTP_TIMER_NAME "gem-ptp-timer"
27*4882a593Smuzhiyun
macb_ptp_desc(struct macb * bp,struct macb_dma_desc * desc)28*4882a593Smuzhiyun static struct macb_dma_desc_ptp *macb_ptp_desc(struct macb *bp,
29*4882a593Smuzhiyun struct macb_dma_desc *desc)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun if (bp->hw_dma_cap == HW_DMA_CAP_PTP)
32*4882a593Smuzhiyun return (struct macb_dma_desc_ptp *)
33*4882a593Smuzhiyun ((u8 *)desc + sizeof(struct macb_dma_desc));
34*4882a593Smuzhiyun if (bp->hw_dma_cap == HW_DMA_CAP_64B_PTP)
35*4882a593Smuzhiyun return (struct macb_dma_desc_ptp *)
36*4882a593Smuzhiyun ((u8 *)desc + sizeof(struct macb_dma_desc)
37*4882a593Smuzhiyun + sizeof(struct macb_dma_desc_64));
38*4882a593Smuzhiyun return NULL;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
gem_tsu_get_time(struct ptp_clock_info * ptp,struct timespec64 * ts)41*4882a593Smuzhiyun static int gem_tsu_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun struct macb *bp = container_of(ptp, struct macb, ptp_clock_info);
44*4882a593Smuzhiyun unsigned long flags;
45*4882a593Smuzhiyun long first, second;
46*4882a593Smuzhiyun u32 secl, sech;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun spin_lock_irqsave(&bp->tsu_clk_lock, flags);
49*4882a593Smuzhiyun first = gem_readl(bp, TN);
50*4882a593Smuzhiyun secl = gem_readl(bp, TSL);
51*4882a593Smuzhiyun sech = gem_readl(bp, TSH);
52*4882a593Smuzhiyun second = gem_readl(bp, TN);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /* test for nsec rollover */
55*4882a593Smuzhiyun if (first > second) {
56*4882a593Smuzhiyun /* if so, use later read & re-read seconds
57*4882a593Smuzhiyun * (assume all done within 1s)
58*4882a593Smuzhiyun */
59*4882a593Smuzhiyun ts->tv_nsec = gem_readl(bp, TN);
60*4882a593Smuzhiyun secl = gem_readl(bp, TSL);
61*4882a593Smuzhiyun sech = gem_readl(bp, TSH);
62*4882a593Smuzhiyun } else {
63*4882a593Smuzhiyun ts->tv_nsec = first;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun spin_unlock_irqrestore(&bp->tsu_clk_lock, flags);
67*4882a593Smuzhiyun ts->tv_sec = (((u64)sech << GEM_TSL_SIZE) | secl)
68*4882a593Smuzhiyun & TSU_SEC_MAX_VAL;
69*4882a593Smuzhiyun return 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
gem_tsu_set_time(struct ptp_clock_info * ptp,const struct timespec64 * ts)72*4882a593Smuzhiyun static int gem_tsu_set_time(struct ptp_clock_info *ptp,
73*4882a593Smuzhiyun const struct timespec64 *ts)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun struct macb *bp = container_of(ptp, struct macb, ptp_clock_info);
76*4882a593Smuzhiyun unsigned long flags;
77*4882a593Smuzhiyun u32 ns, sech, secl;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun secl = (u32)ts->tv_sec;
80*4882a593Smuzhiyun sech = (ts->tv_sec >> GEM_TSL_SIZE) & ((1 << GEM_TSH_SIZE) - 1);
81*4882a593Smuzhiyun ns = ts->tv_nsec;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun spin_lock_irqsave(&bp->tsu_clk_lock, flags);
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /* TSH doesn't latch the time and no atomicity! */
86*4882a593Smuzhiyun gem_writel(bp, TN, 0); /* clear to avoid overflow */
87*4882a593Smuzhiyun gem_writel(bp, TSH, sech);
88*4882a593Smuzhiyun /* write lower bits 2nd, for synchronized secs update */
89*4882a593Smuzhiyun gem_writel(bp, TSL, secl);
90*4882a593Smuzhiyun gem_writel(bp, TN, ns);
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun spin_unlock_irqrestore(&bp->tsu_clk_lock, flags);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun return 0;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
gem_tsu_incr_set(struct macb * bp,struct tsu_incr * incr_spec)97*4882a593Smuzhiyun static int gem_tsu_incr_set(struct macb *bp, struct tsu_incr *incr_spec)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun unsigned long flags;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* tsu_timer_incr register must be written after
102*4882a593Smuzhiyun * the tsu_timer_incr_sub_ns register and the write operation
103*4882a593Smuzhiyun * will cause the value written to the tsu_timer_incr_sub_ns register
104*4882a593Smuzhiyun * to take effect.
105*4882a593Smuzhiyun */
106*4882a593Smuzhiyun spin_lock_irqsave(&bp->tsu_clk_lock, flags);
107*4882a593Smuzhiyun /* RegBit[15:0] = Subns[23:8]; RegBit[31:24] = Subns[7:0] */
108*4882a593Smuzhiyun gem_writel(bp, TISUBN, GEM_BF(SUBNSINCRL, incr_spec->sub_ns) |
109*4882a593Smuzhiyun GEM_BF(SUBNSINCRH, (incr_spec->sub_ns >>
110*4882a593Smuzhiyun GEM_SUBNSINCRL_SIZE)));
111*4882a593Smuzhiyun gem_writel(bp, TI, GEM_BF(NSINCR, incr_spec->ns));
112*4882a593Smuzhiyun spin_unlock_irqrestore(&bp->tsu_clk_lock, flags);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun return 0;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
gem_ptp_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)117*4882a593Smuzhiyun static int gem_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun struct macb *bp = container_of(ptp, struct macb, ptp_clock_info);
120*4882a593Smuzhiyun struct tsu_incr incr_spec;
121*4882a593Smuzhiyun bool neg_adj = false;
122*4882a593Smuzhiyun u32 word;
123*4882a593Smuzhiyun u64 adj;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun if (scaled_ppm < 0) {
126*4882a593Smuzhiyun neg_adj = true;
127*4882a593Smuzhiyun scaled_ppm = -scaled_ppm;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* Adjustment is relative to base frequency */
131*4882a593Smuzhiyun incr_spec.sub_ns = bp->tsu_incr.sub_ns;
132*4882a593Smuzhiyun incr_spec.ns = bp->tsu_incr.ns;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* scaling: unused(8bit) | ns(8bit) | fractions(16bit) */
135*4882a593Smuzhiyun word = ((u64)incr_spec.ns << GEM_SUBNSINCR_SIZE) + incr_spec.sub_ns;
136*4882a593Smuzhiyun adj = (u64)scaled_ppm * word;
137*4882a593Smuzhiyun /* Divide with rounding, equivalent to floating dividing:
138*4882a593Smuzhiyun * (temp / USEC_PER_SEC) + 0.5
139*4882a593Smuzhiyun */
140*4882a593Smuzhiyun adj += (USEC_PER_SEC >> 1);
141*4882a593Smuzhiyun adj >>= PPM_FRACTION; /* remove fractions */
142*4882a593Smuzhiyun adj = div_u64(adj, USEC_PER_SEC);
143*4882a593Smuzhiyun adj = neg_adj ? (word - adj) : (word + adj);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun incr_spec.ns = (adj >> GEM_SUBNSINCR_SIZE)
146*4882a593Smuzhiyun & ((1 << GEM_NSINCR_SIZE) - 1);
147*4882a593Smuzhiyun incr_spec.sub_ns = adj & ((1 << GEM_SUBNSINCR_SIZE) - 1);
148*4882a593Smuzhiyun gem_tsu_incr_set(bp, &incr_spec);
149*4882a593Smuzhiyun return 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
gem_ptp_adjtime(struct ptp_clock_info * ptp,s64 delta)152*4882a593Smuzhiyun static int gem_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun struct macb *bp = container_of(ptp, struct macb, ptp_clock_info);
155*4882a593Smuzhiyun struct timespec64 now, then = ns_to_timespec64(delta);
156*4882a593Smuzhiyun u32 adj, sign = 0;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun if (delta < 0) {
159*4882a593Smuzhiyun sign = 1;
160*4882a593Smuzhiyun delta = -delta;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun if (delta > TSU_NSEC_MAX_VAL) {
164*4882a593Smuzhiyun gem_tsu_get_time(&bp->ptp_clock_info, &now);
165*4882a593Smuzhiyun now = timespec64_add(now, then);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun gem_tsu_set_time(&bp->ptp_clock_info,
168*4882a593Smuzhiyun (const struct timespec64 *)&now);
169*4882a593Smuzhiyun } else {
170*4882a593Smuzhiyun adj = (sign << GEM_ADDSUB_OFFSET) | delta;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun gem_writel(bp, TA, adj);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun return 0;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
gem_ptp_enable(struct ptp_clock_info * ptp,struct ptp_clock_request * rq,int on)178*4882a593Smuzhiyun static int gem_ptp_enable(struct ptp_clock_info *ptp,
179*4882a593Smuzhiyun struct ptp_clock_request *rq, int on)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun return -EOPNOTSUPP;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun static const struct ptp_clock_info gem_ptp_caps_template = {
185*4882a593Smuzhiyun .owner = THIS_MODULE,
186*4882a593Smuzhiyun .name = GEM_PTP_TIMER_NAME,
187*4882a593Smuzhiyun .max_adj = 0,
188*4882a593Smuzhiyun .n_alarm = 0,
189*4882a593Smuzhiyun .n_ext_ts = 0,
190*4882a593Smuzhiyun .n_per_out = 0,
191*4882a593Smuzhiyun .n_pins = 0,
192*4882a593Smuzhiyun .pps = 1,
193*4882a593Smuzhiyun .adjfine = gem_ptp_adjfine,
194*4882a593Smuzhiyun .adjtime = gem_ptp_adjtime,
195*4882a593Smuzhiyun .gettime64 = gem_tsu_get_time,
196*4882a593Smuzhiyun .settime64 = gem_tsu_set_time,
197*4882a593Smuzhiyun .enable = gem_ptp_enable,
198*4882a593Smuzhiyun };
199*4882a593Smuzhiyun
gem_ptp_init_timer(struct macb * bp)200*4882a593Smuzhiyun static void gem_ptp_init_timer(struct macb *bp)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun u32 rem = 0;
203*4882a593Smuzhiyun u64 adj;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun bp->tsu_incr.ns = div_u64_rem(NSEC_PER_SEC, bp->tsu_rate, &rem);
206*4882a593Smuzhiyun if (rem) {
207*4882a593Smuzhiyun adj = rem;
208*4882a593Smuzhiyun adj <<= GEM_SUBNSINCR_SIZE;
209*4882a593Smuzhiyun bp->tsu_incr.sub_ns = div_u64(adj, bp->tsu_rate);
210*4882a593Smuzhiyun } else {
211*4882a593Smuzhiyun bp->tsu_incr.sub_ns = 0;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
gem_ptp_init_tsu(struct macb * bp)215*4882a593Smuzhiyun static void gem_ptp_init_tsu(struct macb *bp)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun struct timespec64 ts;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* 1. get current system time */
220*4882a593Smuzhiyun ts = ns_to_timespec64(ktime_to_ns(ktime_get_real()));
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /* 2. set ptp timer */
223*4882a593Smuzhiyun gem_tsu_set_time(&bp->ptp_clock_info, &ts);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun /* 3. set PTP timer increment value to BASE_INCREMENT */
226*4882a593Smuzhiyun gem_tsu_incr_set(bp, &bp->tsu_incr);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun gem_writel(bp, TA, 0);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
gem_ptp_clear_timer(struct macb * bp)231*4882a593Smuzhiyun static void gem_ptp_clear_timer(struct macb *bp)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun bp->tsu_incr.sub_ns = 0;
234*4882a593Smuzhiyun bp->tsu_incr.ns = 0;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, 0));
237*4882a593Smuzhiyun gem_writel(bp, TI, GEM_BF(NSINCR, 0));
238*4882a593Smuzhiyun gem_writel(bp, TA, 0);
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
gem_hw_timestamp(struct macb * bp,u32 dma_desc_ts_1,u32 dma_desc_ts_2,struct timespec64 * ts)241*4882a593Smuzhiyun static int gem_hw_timestamp(struct macb *bp, u32 dma_desc_ts_1,
242*4882a593Smuzhiyun u32 dma_desc_ts_2, struct timespec64 *ts)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun struct timespec64 tsu;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun ts->tv_sec = (GEM_BFEXT(DMA_SECH, dma_desc_ts_2) << GEM_DMA_SECL_SIZE) |
247*4882a593Smuzhiyun GEM_BFEXT(DMA_SECL, dma_desc_ts_1);
248*4882a593Smuzhiyun ts->tv_nsec = GEM_BFEXT(DMA_NSEC, dma_desc_ts_1);
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /* TSU overlapping workaround
251*4882a593Smuzhiyun * The timestamp only contains lower few bits of seconds,
252*4882a593Smuzhiyun * so add value from 1588 timer
253*4882a593Smuzhiyun */
254*4882a593Smuzhiyun gem_tsu_get_time(&bp->ptp_clock_info, &tsu);
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun /* If the top bit is set in the timestamp,
257*4882a593Smuzhiyun * but not in 1588 timer, it has rolled over,
258*4882a593Smuzhiyun * so subtract max size
259*4882a593Smuzhiyun */
260*4882a593Smuzhiyun if ((ts->tv_sec & (GEM_DMA_SEC_TOP >> 1)) &&
261*4882a593Smuzhiyun !(tsu.tv_sec & (GEM_DMA_SEC_TOP >> 1)))
262*4882a593Smuzhiyun ts->tv_sec -= GEM_DMA_SEC_TOP;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun ts->tv_sec += ((~GEM_DMA_SEC_MASK) & tsu.tv_sec);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun return 0;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
gem_ptp_rxstamp(struct macb * bp,struct sk_buff * skb,struct macb_dma_desc * desc)269*4882a593Smuzhiyun void gem_ptp_rxstamp(struct macb *bp, struct sk_buff *skb,
270*4882a593Smuzhiyun struct macb_dma_desc *desc)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
273*4882a593Smuzhiyun struct macb_dma_desc_ptp *desc_ptp;
274*4882a593Smuzhiyun struct timespec64 ts;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun if (GEM_BFEXT(DMA_RXVALID, desc->addr)) {
277*4882a593Smuzhiyun desc_ptp = macb_ptp_desc(bp, desc);
278*4882a593Smuzhiyun /* Unlikely but check */
279*4882a593Smuzhiyun if (!desc_ptp) {
280*4882a593Smuzhiyun dev_warn_ratelimited(&bp->pdev->dev,
281*4882a593Smuzhiyun "Timestamp not supported in BD\n");
282*4882a593Smuzhiyun return;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun gem_hw_timestamp(bp, desc_ptp->ts_1, desc_ptp->ts_2, &ts);
285*4882a593Smuzhiyun memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
286*4882a593Smuzhiyun shhwtstamps->hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
gem_tstamp_tx(struct macb * bp,struct sk_buff * skb,struct macb_dma_desc_ptp * desc_ptp)290*4882a593Smuzhiyun static void gem_tstamp_tx(struct macb *bp, struct sk_buff *skb,
291*4882a593Smuzhiyun struct macb_dma_desc_ptp *desc_ptp)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun struct skb_shared_hwtstamps shhwtstamps;
294*4882a593Smuzhiyun struct timespec64 ts;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun gem_hw_timestamp(bp, desc_ptp->ts_1, desc_ptp->ts_2, &ts);
297*4882a593Smuzhiyun memset(&shhwtstamps, 0, sizeof(shhwtstamps));
298*4882a593Smuzhiyun shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
299*4882a593Smuzhiyun skb_tstamp_tx(skb, &shhwtstamps);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
gem_ptp_txstamp(struct macb_queue * queue,struct sk_buff * skb,struct macb_dma_desc * desc)302*4882a593Smuzhiyun int gem_ptp_txstamp(struct macb_queue *queue, struct sk_buff *skb,
303*4882a593Smuzhiyun struct macb_dma_desc *desc)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun unsigned long tail = READ_ONCE(queue->tx_ts_tail);
306*4882a593Smuzhiyun unsigned long head = queue->tx_ts_head;
307*4882a593Smuzhiyun struct macb_dma_desc_ptp *desc_ptp;
308*4882a593Smuzhiyun struct gem_tx_ts *tx_timestamp;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun if (!GEM_BFEXT(DMA_TXVALID, desc->ctrl))
311*4882a593Smuzhiyun return -EINVAL;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun if (CIRC_SPACE(head, tail, PTP_TS_BUFFER_SIZE) == 0)
314*4882a593Smuzhiyun return -ENOMEM;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun desc_ptp = macb_ptp_desc(queue->bp, desc);
317*4882a593Smuzhiyun /* Unlikely but check */
318*4882a593Smuzhiyun if (!desc_ptp)
319*4882a593Smuzhiyun return -EINVAL;
320*4882a593Smuzhiyun skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
321*4882a593Smuzhiyun tx_timestamp = &queue->tx_timestamps[head];
322*4882a593Smuzhiyun tx_timestamp->skb = skb;
323*4882a593Smuzhiyun /* ensure ts_1/ts_2 is loaded after ctrl (TX_USED check) */
324*4882a593Smuzhiyun dma_rmb();
325*4882a593Smuzhiyun tx_timestamp->desc_ptp.ts_1 = desc_ptp->ts_1;
326*4882a593Smuzhiyun tx_timestamp->desc_ptp.ts_2 = desc_ptp->ts_2;
327*4882a593Smuzhiyun /* move head */
328*4882a593Smuzhiyun smp_store_release(&queue->tx_ts_head,
329*4882a593Smuzhiyun (head + 1) & (PTP_TS_BUFFER_SIZE - 1));
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun schedule_work(&queue->tx_ts_task);
332*4882a593Smuzhiyun return 0;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
gem_tx_timestamp_flush(struct work_struct * work)335*4882a593Smuzhiyun static void gem_tx_timestamp_flush(struct work_struct *work)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun struct macb_queue *queue =
338*4882a593Smuzhiyun container_of(work, struct macb_queue, tx_ts_task);
339*4882a593Smuzhiyun unsigned long head, tail;
340*4882a593Smuzhiyun struct gem_tx_ts *tx_ts;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun /* take current head */
343*4882a593Smuzhiyun head = smp_load_acquire(&queue->tx_ts_head);
344*4882a593Smuzhiyun tail = queue->tx_ts_tail;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun while (CIRC_CNT(head, tail, PTP_TS_BUFFER_SIZE)) {
347*4882a593Smuzhiyun tx_ts = &queue->tx_timestamps[tail];
348*4882a593Smuzhiyun gem_tstamp_tx(queue->bp, tx_ts->skb, &tx_ts->desc_ptp);
349*4882a593Smuzhiyun /* cleanup */
350*4882a593Smuzhiyun dev_kfree_skb_any(tx_ts->skb);
351*4882a593Smuzhiyun /* remove old tail */
352*4882a593Smuzhiyun smp_store_release(&queue->tx_ts_tail,
353*4882a593Smuzhiyun (tail + 1) & (PTP_TS_BUFFER_SIZE - 1));
354*4882a593Smuzhiyun tail = queue->tx_ts_tail;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
gem_ptp_init(struct net_device * dev)358*4882a593Smuzhiyun void gem_ptp_init(struct net_device *dev)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun struct macb *bp = netdev_priv(dev);
361*4882a593Smuzhiyun struct macb_queue *queue;
362*4882a593Smuzhiyun unsigned int q;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun bp->ptp_clock_info = gem_ptp_caps_template;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun /* nominal frequency and maximum adjustment in ppb */
367*4882a593Smuzhiyun bp->tsu_rate = bp->ptp_info->get_tsu_rate(bp);
368*4882a593Smuzhiyun bp->ptp_clock_info.max_adj = bp->ptp_info->get_ptp_max_adj();
369*4882a593Smuzhiyun gem_ptp_init_timer(bp);
370*4882a593Smuzhiyun bp->ptp_clock = ptp_clock_register(&bp->ptp_clock_info, &dev->dev);
371*4882a593Smuzhiyun if (IS_ERR(bp->ptp_clock)) {
372*4882a593Smuzhiyun pr_err("ptp clock register failed: %ld\n",
373*4882a593Smuzhiyun PTR_ERR(bp->ptp_clock));
374*4882a593Smuzhiyun bp->ptp_clock = NULL;
375*4882a593Smuzhiyun return;
376*4882a593Smuzhiyun } else if (bp->ptp_clock == NULL) {
377*4882a593Smuzhiyun pr_err("ptp clock register failed\n");
378*4882a593Smuzhiyun return;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun spin_lock_init(&bp->tsu_clk_lock);
382*4882a593Smuzhiyun for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
383*4882a593Smuzhiyun queue->tx_ts_head = 0;
384*4882a593Smuzhiyun queue->tx_ts_tail = 0;
385*4882a593Smuzhiyun INIT_WORK(&queue->tx_ts_task, gem_tx_timestamp_flush);
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun gem_ptp_init_tsu(bp);
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun dev_info(&bp->pdev->dev, "%s ptp clock registered.\n",
391*4882a593Smuzhiyun GEM_PTP_TIMER_NAME);
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
gem_ptp_remove(struct net_device * ndev)394*4882a593Smuzhiyun void gem_ptp_remove(struct net_device *ndev)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun struct macb *bp = netdev_priv(ndev);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun if (bp->ptp_clock)
399*4882a593Smuzhiyun ptp_clock_unregister(bp->ptp_clock);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun gem_ptp_clear_timer(bp);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun dev_info(&bp->pdev->dev, "%s ptp clock unregistered.\n",
404*4882a593Smuzhiyun GEM_PTP_TIMER_NAME);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
gem_ptp_set_ts_mode(struct macb * bp,enum macb_bd_control tx_bd_control,enum macb_bd_control rx_bd_control)407*4882a593Smuzhiyun static int gem_ptp_set_ts_mode(struct macb *bp,
408*4882a593Smuzhiyun enum macb_bd_control tx_bd_control,
409*4882a593Smuzhiyun enum macb_bd_control rx_bd_control)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun gem_writel(bp, TXBDCTRL, GEM_BF(TXTSMODE, tx_bd_control));
412*4882a593Smuzhiyun gem_writel(bp, RXBDCTRL, GEM_BF(RXTSMODE, rx_bd_control));
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun return 0;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
gem_get_hwtst(struct net_device * dev,struct ifreq * rq)417*4882a593Smuzhiyun int gem_get_hwtst(struct net_device *dev, struct ifreq *rq)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun struct hwtstamp_config *tstamp_config;
420*4882a593Smuzhiyun struct macb *bp = netdev_priv(dev);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun tstamp_config = &bp->tstamp_config;
423*4882a593Smuzhiyun if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0)
424*4882a593Smuzhiyun return -EOPNOTSUPP;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun if (copy_to_user(rq->ifr_data, tstamp_config, sizeof(*tstamp_config)))
427*4882a593Smuzhiyun return -EFAULT;
428*4882a593Smuzhiyun else
429*4882a593Smuzhiyun return 0;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun
gem_ptp_set_one_step_sync(struct macb * bp,u8 enable)432*4882a593Smuzhiyun static int gem_ptp_set_one_step_sync(struct macb *bp, u8 enable)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun u32 reg_val;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun reg_val = macb_readl(bp, NCR);
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (enable)
439*4882a593Smuzhiyun macb_writel(bp, NCR, reg_val | MACB_BIT(OSSMODE));
440*4882a593Smuzhiyun else
441*4882a593Smuzhiyun macb_writel(bp, NCR, reg_val & ~MACB_BIT(OSSMODE));
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun return 0;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun
gem_set_hwtst(struct net_device * dev,struct ifreq * ifr,int cmd)446*4882a593Smuzhiyun int gem_set_hwtst(struct net_device *dev, struct ifreq *ifr, int cmd)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun enum macb_bd_control tx_bd_control = TSTAMP_DISABLED;
449*4882a593Smuzhiyun enum macb_bd_control rx_bd_control = TSTAMP_DISABLED;
450*4882a593Smuzhiyun struct hwtstamp_config *tstamp_config;
451*4882a593Smuzhiyun struct macb *bp = netdev_priv(dev);
452*4882a593Smuzhiyun u32 regval;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun tstamp_config = &bp->tstamp_config;
455*4882a593Smuzhiyun if ((bp->hw_dma_cap & HW_DMA_CAP_PTP) == 0)
456*4882a593Smuzhiyun return -EOPNOTSUPP;
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun if (copy_from_user(tstamp_config, ifr->ifr_data,
459*4882a593Smuzhiyun sizeof(*tstamp_config)))
460*4882a593Smuzhiyun return -EFAULT;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun /* reserved for future extensions */
463*4882a593Smuzhiyun if (tstamp_config->flags)
464*4882a593Smuzhiyun return -EINVAL;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun switch (tstamp_config->tx_type) {
467*4882a593Smuzhiyun case HWTSTAMP_TX_OFF:
468*4882a593Smuzhiyun break;
469*4882a593Smuzhiyun case HWTSTAMP_TX_ONESTEP_SYNC:
470*4882a593Smuzhiyun if (gem_ptp_set_one_step_sync(bp, 1) != 0)
471*4882a593Smuzhiyun return -ERANGE;
472*4882a593Smuzhiyun fallthrough;
473*4882a593Smuzhiyun case HWTSTAMP_TX_ON:
474*4882a593Smuzhiyun tx_bd_control = TSTAMP_ALL_FRAMES;
475*4882a593Smuzhiyun break;
476*4882a593Smuzhiyun default:
477*4882a593Smuzhiyun return -ERANGE;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun switch (tstamp_config->rx_filter) {
481*4882a593Smuzhiyun case HWTSTAMP_FILTER_NONE:
482*4882a593Smuzhiyun break;
483*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
484*4882a593Smuzhiyun break;
485*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
486*4882a593Smuzhiyun break;
487*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V2_EVENT:
488*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
489*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
490*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V2_SYNC:
491*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
492*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
493*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
494*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
495*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
496*4882a593Smuzhiyun rx_bd_control = TSTAMP_ALL_PTP_FRAMES;
497*4882a593Smuzhiyun tstamp_config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
498*4882a593Smuzhiyun regval = macb_readl(bp, NCR);
499*4882a593Smuzhiyun macb_writel(bp, NCR, (regval | MACB_BIT(SRTSM)));
500*4882a593Smuzhiyun break;
501*4882a593Smuzhiyun case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
502*4882a593Smuzhiyun case HWTSTAMP_FILTER_ALL:
503*4882a593Smuzhiyun rx_bd_control = TSTAMP_ALL_FRAMES;
504*4882a593Smuzhiyun tstamp_config->rx_filter = HWTSTAMP_FILTER_ALL;
505*4882a593Smuzhiyun break;
506*4882a593Smuzhiyun default:
507*4882a593Smuzhiyun tstamp_config->rx_filter = HWTSTAMP_FILTER_NONE;
508*4882a593Smuzhiyun return -ERANGE;
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun if (gem_ptp_set_ts_mode(bp, tx_bd_control, rx_bd_control) != 0)
512*4882a593Smuzhiyun return -ERANGE;
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun if (copy_to_user(ifr->ifr_data, tstamp_config, sizeof(*tstamp_config)))
515*4882a593Smuzhiyun return -EFAULT;
516*4882a593Smuzhiyun else
517*4882a593Smuzhiyun return 0;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520