1a4569504SAtul Gupta /*
2a4569504SAtul Gupta  * cxgb4_ptp.c:Chelsio PTP support for T5/T6
3a4569504SAtul Gupta  *
4a4569504SAtul Gupta  * Copyright (c) 2003-2017 Chelsio Communications, Inc. All rights reserved.
5a4569504SAtul Gupta  *
6a4569504SAtul Gupta  * This software is available to you under a choice of one of two
7a4569504SAtul Gupta  * licenses.  You may choose to be licensed under the terms of the GNU
8a4569504SAtul Gupta  * General Public License (GPL) Version 2, available from the file
9a4569504SAtul Gupta  * COPYING in the main directory of this source tree, or the
10a4569504SAtul Gupta  * OpenIB.org BSD license below:
11a4569504SAtul Gupta  *
12a4569504SAtul Gupta  *     Redistribution and use in source and binary forms, with or
13a4569504SAtul Gupta  *     without modification, are permitted provided that the following
14a4569504SAtul Gupta  *     conditions are met:
15a4569504SAtul Gupta  *
16a4569504SAtul Gupta  *      - Redistributions of source code must retain the above
17a4569504SAtul Gupta  *        copyright notice, this list of conditions and the following
18a4569504SAtul Gupta  *        disclaimer.
19a4569504SAtul Gupta  *
20a4569504SAtul Gupta  *      - Redistributions in binary form must reproduce the above
21a4569504SAtul Gupta  *        copyright notice, this list of conditions and the following
22a4569504SAtul Gupta  *        disclaimer in the documentation and/or other materials
23a4569504SAtul Gupta  *        provided with the distribution.
24a4569504SAtul Gupta  *
25a4569504SAtul Gupta  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26a4569504SAtul Gupta  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27a4569504SAtul Gupta  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28a4569504SAtul Gupta  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29a4569504SAtul Gupta  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30a4569504SAtul Gupta  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31a4569504SAtul Gupta  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32a4569504SAtul Gupta  * SOFTWARE.
33a4569504SAtul Gupta  *
34a4569504SAtul Gupta  * Written by: Atul Gupta (atul.gupta@chelsio.com)
35a4569504SAtul Gupta  */
36a4569504SAtul Gupta 
37a4569504SAtul Gupta #include <linux/module.h>
38a4569504SAtul Gupta #include <linux/net_tstamp.h>
39a4569504SAtul Gupta #include <linux/skbuff.h>
40a4569504SAtul Gupta #include <linux/netdevice.h>
41a4569504SAtul Gupta #include <linux/pps_kernel.h>
42a4569504SAtul Gupta #include <linux/ptp_clock_kernel.h>
43a4569504SAtul Gupta #include <linux/ptp_classify.h>
44a4569504SAtul Gupta #include <linux/udp.h>
45a4569504SAtul Gupta 
46a4569504SAtul Gupta #include "cxgb4.h"
47a4569504SAtul Gupta #include "t4_hw.h"
48a4569504SAtul Gupta #include "t4_regs.h"
49a4569504SAtul Gupta #include "t4_msg.h"
50a4569504SAtul Gupta #include "t4fw_api.h"
51a4569504SAtul Gupta #include "cxgb4_ptp.h"
52a4569504SAtul Gupta 
53a4569504SAtul Gupta /**
54a4569504SAtul Gupta  * cxgb4_ptp_is_ptp_tx - determine whether TX packet is PTP or not
55a4569504SAtul Gupta  * @skb: skb of outgoing ptp request
56a4569504SAtul Gupta  *
57a4569504SAtul Gupta  */
cxgb4_ptp_is_ptp_tx(struct sk_buff * skb)58a4569504SAtul Gupta bool cxgb4_ptp_is_ptp_tx(struct sk_buff *skb)
59a4569504SAtul Gupta {
60a4569504SAtul Gupta 	struct udphdr *uh;
61a4569504SAtul Gupta 
62a4569504SAtul Gupta 	uh = udp_hdr(skb);
63a4569504SAtul Gupta 	return skb->len >= PTP_MIN_LENGTH &&
64a4569504SAtul Gupta 		skb->len <= PTP_IN_TRANSMIT_PACKET_MAXNUM &&
65a4569504SAtul Gupta 		likely(skb->protocol == htons(ETH_P_IP)) &&
66a4569504SAtul Gupta 		ip_hdr(skb)->protocol == IPPROTO_UDP &&
67a4569504SAtul Gupta 		uh->dest == htons(PTP_EVENT_PORT);
68a4569504SAtul Gupta }
69a4569504SAtul Gupta 
is_ptp_enabled(struct sk_buff * skb,struct net_device * dev)70a4569504SAtul Gupta bool is_ptp_enabled(struct sk_buff *skb, struct net_device *dev)
71a4569504SAtul Gupta {
72a4569504SAtul Gupta 	struct port_info *pi;
73a4569504SAtul Gupta 
74a4569504SAtul Gupta 	pi = netdev_priv(dev);
75a4569504SAtul Gupta 	return (pi->ptp_enable && cxgb4_xmit_with_hwtstamp(skb) &&
76a4569504SAtul Gupta 		cxgb4_ptp_is_ptp_tx(skb));
77a4569504SAtul Gupta }
78a4569504SAtul Gupta 
79a4569504SAtul Gupta /**
80a4569504SAtul Gupta  * cxgb4_ptp_is_ptp_rx - determine whether RX packet is PTP or not
81a4569504SAtul Gupta  * @skb: skb of incoming ptp request
82a4569504SAtul Gupta  *
83a4569504SAtul Gupta  */
cxgb4_ptp_is_ptp_rx(struct sk_buff * skb)84a4569504SAtul Gupta bool cxgb4_ptp_is_ptp_rx(struct sk_buff *skb)
85a4569504SAtul Gupta {
86a4569504SAtul Gupta 	struct udphdr *uh = (struct udphdr *)(skb->data + ETH_HLEN +
87a4569504SAtul Gupta 					      IPV4_HLEN(skb->data));
88a4569504SAtul Gupta 
89a4569504SAtul Gupta 	return  uh->dest == htons(PTP_EVENT_PORT) &&
90a4569504SAtul Gupta 		uh->source == htons(PTP_EVENT_PORT);
91a4569504SAtul Gupta }
92a4569504SAtul Gupta 
93a4569504SAtul Gupta /**
94a4569504SAtul Gupta  * cxgb4_ptp_read_hwstamp - read timestamp for TX event PTP message
95a4569504SAtul Gupta  * @adapter: board private structure
96a4569504SAtul Gupta  * @pi: port private structure
97a4569504SAtul Gupta  *
98a4569504SAtul Gupta  */
cxgb4_ptp_read_hwstamp(struct adapter * adapter,struct port_info * pi)99a4569504SAtul Gupta void cxgb4_ptp_read_hwstamp(struct adapter *adapter, struct port_info *pi)
100a4569504SAtul Gupta {
101a4569504SAtul Gupta 	struct skb_shared_hwtstamps *skb_ts = NULL;
102a4569504SAtul Gupta 	u64 tx_ts;
103a4569504SAtul Gupta 
104a4569504SAtul Gupta 	skb_ts = skb_hwtstamps(adapter->ptp_tx_skb);
105a4569504SAtul Gupta 
106a4569504SAtul Gupta 	tx_ts = t4_read_reg(adapter,
107a4569504SAtul Gupta 			    T5_PORT_REG(pi->port_id, MAC_PORT_TX_TS_VAL_LO));
108a4569504SAtul Gupta 
109a4569504SAtul Gupta 	tx_ts |= (u64)t4_read_reg(adapter,
110a4569504SAtul Gupta 				  T5_PORT_REG(pi->port_id,
111a4569504SAtul Gupta 					      MAC_PORT_TX_TS_VAL_HI)) << 32;
112a4569504SAtul Gupta 	skb_ts->hwtstamp = ns_to_ktime(tx_ts);
113a4569504SAtul Gupta 	skb_tstamp_tx(adapter->ptp_tx_skb, skb_ts);
114a4569504SAtul Gupta 	dev_kfree_skb_any(adapter->ptp_tx_skb);
115a4569504SAtul Gupta 	spin_lock(&adapter->ptp_lock);
116a4569504SAtul Gupta 	adapter->ptp_tx_skb = NULL;
117a4569504SAtul Gupta 	spin_unlock(&adapter->ptp_lock);
118a4569504SAtul Gupta }
119a4569504SAtul Gupta 
120a4569504SAtul Gupta /**
121a4569504SAtul Gupta  * cxgb4_ptprx_timestamping - Enable Timestamp for RX PTP event message
122a4569504SAtul Gupta  * @pi: port private structure
123a4569504SAtul Gupta  * @port: pot number
124a4569504SAtul Gupta  * @mode: RX mode
125a4569504SAtul Gupta  *
126a4569504SAtul Gupta  */
cxgb4_ptprx_timestamping(struct port_info * pi,u8 port,u16 mode)127a4569504SAtul Gupta int cxgb4_ptprx_timestamping(struct port_info *pi, u8 port, u16 mode)
128a4569504SAtul Gupta {
129a4569504SAtul Gupta 	struct adapter *adapter = pi->adapter;
130a4569504SAtul Gupta 	struct fw_ptp_cmd c;
131a4569504SAtul Gupta 	int err;
132a4569504SAtul Gupta 
133a4569504SAtul Gupta 	memset(&c, 0, sizeof(c));
134a4569504SAtul Gupta 	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
135a4569504SAtul Gupta 				     FW_CMD_REQUEST_F |
136a4569504SAtul Gupta 				     FW_CMD_WRITE_F |
137a4569504SAtul Gupta 				     FW_PTP_CMD_PORTID_V(port));
138a4569504SAtul Gupta 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
139a4569504SAtul Gupta 	c.u.init.sc = FW_PTP_SC_RXTIME_STAMP;
140a4569504SAtul Gupta 	c.u.init.mode = cpu_to_be16(mode);
141a4569504SAtul Gupta 
142a4569504SAtul Gupta 	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
143a4569504SAtul Gupta 	if (err < 0)
144a4569504SAtul Gupta 		dev_err(adapter->pdev_dev,
145a4569504SAtul Gupta 			"PTP: %s error %d\n", __func__, -err);
146a4569504SAtul Gupta 	return err;
147a4569504SAtul Gupta }
148a4569504SAtul Gupta 
cxgb4_ptp_txtype(struct adapter * adapter,u8 port)149a4569504SAtul Gupta int cxgb4_ptp_txtype(struct adapter *adapter, u8 port)
150a4569504SAtul Gupta {
151a4569504SAtul Gupta 	struct fw_ptp_cmd c;
152a4569504SAtul Gupta 	int err;
153a4569504SAtul Gupta 
154a4569504SAtul Gupta 	memset(&c, 0, sizeof(c));
155a4569504SAtul Gupta 	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
156a4569504SAtul Gupta 				     FW_CMD_REQUEST_F |
157a4569504SAtul Gupta 				     FW_CMD_WRITE_F |
158a4569504SAtul Gupta 				     FW_PTP_CMD_PORTID_V(port));
159a4569504SAtul Gupta 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
160a4569504SAtul Gupta 	c.u.init.sc = FW_PTP_SC_TX_TYPE;
161a4569504SAtul Gupta 	c.u.init.mode = cpu_to_be16(PTP_TS_NONE);
162a4569504SAtul Gupta 
163a4569504SAtul Gupta 	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
164a4569504SAtul Gupta 	if (err < 0)
165a4569504SAtul Gupta 		dev_err(adapter->pdev_dev,
166a4569504SAtul Gupta 			"PTP: %s error %d\n", __func__, -err);
167a4569504SAtul Gupta 
168a4569504SAtul Gupta 	return err;
169a4569504SAtul Gupta }
170a4569504SAtul Gupta 
cxgb4_ptp_redirect_rx_packet(struct adapter * adapter,struct port_info * pi)171a4569504SAtul Gupta int cxgb4_ptp_redirect_rx_packet(struct adapter *adapter, struct port_info *pi)
172a4569504SAtul Gupta {
173a4569504SAtul Gupta 	struct sge *s = &adapter->sge;
174a4569504SAtul Gupta 	struct sge_eth_rxq *receive_q =  &s->ethrxq[pi->first_qset];
175a4569504SAtul Gupta 	struct fw_ptp_cmd c;
176a4569504SAtul Gupta 	int err;
177a4569504SAtul Gupta 
178a4569504SAtul Gupta 	memset(&c, 0, sizeof(c));
179a4569504SAtul Gupta 	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
180a4569504SAtul Gupta 				     FW_CMD_REQUEST_F |
181a4569504SAtul Gupta 				     FW_CMD_WRITE_F |
182a4569504SAtul Gupta 				     FW_PTP_CMD_PORTID_V(pi->port_id));
183a4569504SAtul Gupta 
184a4569504SAtul Gupta 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
185a4569504SAtul Gupta 	c.u.init.sc = FW_PTP_SC_RDRX_TYPE;
186a4569504SAtul Gupta 	c.u.init.txchan = pi->tx_chan;
187a4569504SAtul Gupta 	c.u.init.absid = cpu_to_be16(receive_q->rspq.abs_id);
188a4569504SAtul Gupta 
189a4569504SAtul Gupta 	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
190a4569504SAtul Gupta 	if (err < 0)
191a4569504SAtul Gupta 		dev_err(adapter->pdev_dev,
192a4569504SAtul Gupta 			"PTP: %s error %d\n", __func__, -err);
193a4569504SAtul Gupta 	return err;
194a4569504SAtul Gupta }
1959c33e420SAtul Gupta 
1969c33e420SAtul Gupta /**
197*e2bd9c76SJacob Keller  * cxgb4_ptp_adjfine - Adjust frequency of PHC cycle counter
1989c33e420SAtul Gupta  * @ptp: ptp clock structure
199*e2bd9c76SJacob Keller  * @scaled_ppm: Desired frequency in scaled parts per billion
2009c33e420SAtul Gupta  *
201*e2bd9c76SJacob Keller  * Adjust the frequency of the PHC cycle counter by the indicated amount from
2029c33e420SAtul Gupta  * the base frequency.
203*e2bd9c76SJacob Keller  *
204*e2bd9c76SJacob Keller  * Scaled parts per million is ppm with a 16-bit binary fractional field.
2059c33e420SAtul Gupta  */
cxgb4_ptp_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)206*e2bd9c76SJacob Keller static int cxgb4_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
2079c33e420SAtul Gupta {
2089c33e420SAtul Gupta 	struct adapter *adapter = (struct adapter *)container_of(ptp,
2099c33e420SAtul Gupta 				   struct adapter, ptp_clock_info);
210*e2bd9c76SJacob Keller 	s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
2119c33e420SAtul Gupta 	struct fw_ptp_cmd c;
2129c33e420SAtul Gupta 	int err;
2139c33e420SAtul Gupta 
2149c33e420SAtul Gupta 	memset(&c, 0, sizeof(c));
2159c33e420SAtul Gupta 	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
2169c33e420SAtul Gupta 				     FW_CMD_REQUEST_F |
2179c33e420SAtul Gupta 				     FW_CMD_WRITE_F |
2189c33e420SAtul Gupta 				     FW_PTP_CMD_PORTID_V(0));
2199c33e420SAtul Gupta 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
2209c33e420SAtul Gupta 	c.u.ts.sc = FW_PTP_SC_ADJ_FREQ;
2219c33e420SAtul Gupta 	c.u.ts.sign = (ppb < 0) ? 1 : 0;
2229c33e420SAtul Gupta 	if (ppb < 0)
2239c33e420SAtul Gupta 		ppb = -ppb;
2249c33e420SAtul Gupta 	c.u.ts.ppb = cpu_to_be32(ppb);
2259c33e420SAtul Gupta 
2269c33e420SAtul Gupta 	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
2279c33e420SAtul Gupta 	if (err < 0)
2289c33e420SAtul Gupta 		dev_err(adapter->pdev_dev,
2299c33e420SAtul Gupta 			"PTP: %s error %d\n", __func__, -err);
2309c33e420SAtul Gupta 
2319c33e420SAtul Gupta 	return err;
2329c33e420SAtul Gupta }
2339c33e420SAtul Gupta 
2349c33e420SAtul Gupta /**
2359c33e420SAtul Gupta  * cxgb4_ptp_fineadjtime - Shift the time of the hardware clock
23629bbf5d7SRahul Lakkireddy  * @adapter: board private structure
2379c33e420SAtul Gupta  * @delta: Desired change in nanoseconds
2389c33e420SAtul Gupta  *
2399c33e420SAtul Gupta  * Adjust the timer by resetting the timecounter structure.
2409c33e420SAtul Gupta  */
cxgb4_ptp_fineadjtime(struct adapter * adapter,s64 delta)2419c33e420SAtul Gupta static int  cxgb4_ptp_fineadjtime(struct adapter *adapter, s64 delta)
2429c33e420SAtul Gupta {
2439c33e420SAtul Gupta 	struct fw_ptp_cmd c;
2449c33e420SAtul Gupta 	int err;
2459c33e420SAtul Gupta 
2469c33e420SAtul Gupta 	memset(&c, 0, sizeof(c));
2479c33e420SAtul Gupta 	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
2489c33e420SAtul Gupta 			     FW_CMD_REQUEST_F |
2499c33e420SAtul Gupta 			     FW_CMD_WRITE_F |
2509c33e420SAtul Gupta 			     FW_PTP_CMD_PORTID_V(0));
2519c33e420SAtul Gupta 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
2529c33e420SAtul Gupta 	c.u.ts.sc = FW_PTP_SC_ADJ_FTIME;
25350e0d28dSRaju Rangoju 	c.u.ts.sign = (delta < 0) ? 1 : 0;
25450e0d28dSRaju Rangoju 	if (delta < 0)
25550e0d28dSRaju Rangoju 		delta = -delta;
2569c33e420SAtul Gupta 	c.u.ts.tm = cpu_to_be64(delta);
2579c33e420SAtul Gupta 
2589c33e420SAtul Gupta 	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
2599c33e420SAtul Gupta 	if (err < 0)
2609c33e420SAtul Gupta 		dev_err(adapter->pdev_dev,
2619c33e420SAtul Gupta 			"PTP: %s error %d\n", __func__, -err);
2629c33e420SAtul Gupta 	return err;
2639c33e420SAtul Gupta }
2649c33e420SAtul Gupta 
2659c33e420SAtul Gupta /**
2669c33e420SAtul Gupta  * cxgb4_ptp_adjtime - Shift the time of the hardware clock
2679c33e420SAtul Gupta  * @ptp: ptp clock structure
2689c33e420SAtul Gupta  * @delta: Desired change in nanoseconds
2699c33e420SAtul Gupta  *
2709c33e420SAtul Gupta  * Adjust the timer by resetting the timecounter structure.
2719c33e420SAtul Gupta  */
cxgb4_ptp_adjtime(struct ptp_clock_info * ptp,s64 delta)2729c33e420SAtul Gupta static int cxgb4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
2739c33e420SAtul Gupta {
2749c33e420SAtul Gupta 	struct adapter *adapter =
2759c33e420SAtul Gupta 		(struct adapter *)container_of(ptp, struct adapter,
2769c33e420SAtul Gupta 					       ptp_clock_info);
2779c33e420SAtul Gupta 	struct fw_ptp_cmd c;
2789c33e420SAtul Gupta 	s64 sign = 1;
2799c33e420SAtul Gupta 	int err;
2809c33e420SAtul Gupta 
2819c33e420SAtul Gupta 	if (delta < 0)
2829c33e420SAtul Gupta 		sign = -1;
2839c33e420SAtul Gupta 
2849c33e420SAtul Gupta 	if (delta * sign > PTP_CLOCK_MAX_ADJTIME) {
2859c33e420SAtul Gupta 		memset(&c, 0, sizeof(c));
2869c33e420SAtul Gupta 		c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
2879c33e420SAtul Gupta 					     FW_CMD_REQUEST_F |
2889c33e420SAtul Gupta 					     FW_CMD_WRITE_F |
2899c33e420SAtul Gupta 					     FW_PTP_CMD_PORTID_V(0));
2909c33e420SAtul Gupta 		c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
2919c33e420SAtul Gupta 		c.u.ts.sc = FW_PTP_SC_ADJ_TIME;
2929c33e420SAtul Gupta 		c.u.ts.sign = (delta < 0) ? 1 : 0;
2939c33e420SAtul Gupta 		if (delta < 0)
2949c33e420SAtul Gupta 			delta = -delta;
2959c33e420SAtul Gupta 		c.u.ts.tm = cpu_to_be64(delta);
2969c33e420SAtul Gupta 
2979c33e420SAtul Gupta 		err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
2989c33e420SAtul Gupta 		if (err < 0)
2999c33e420SAtul Gupta 			dev_err(adapter->pdev_dev,
3009c33e420SAtul Gupta 				"PTP: %s error %d\n", __func__, -err);
3019c33e420SAtul Gupta 	} else {
3029c33e420SAtul Gupta 		err = cxgb4_ptp_fineadjtime(adapter, delta);
3039c33e420SAtul Gupta 	}
3049c33e420SAtul Gupta 
3059c33e420SAtul Gupta 	return err;
3069c33e420SAtul Gupta }
3079c33e420SAtul Gupta 
3089c33e420SAtul Gupta /**
3099c33e420SAtul Gupta  * cxgb4_ptp_gettime - Reads the current time from the hardware clock
3109c33e420SAtul Gupta  * @ptp: ptp clock structure
3119c33e420SAtul Gupta  * @ts: timespec structure to hold the current time value
3129c33e420SAtul Gupta  *
3139c33e420SAtul Gupta  * Read the timecounter and return the correct value in ns after converting
3149c33e420SAtul Gupta  * it into a struct timespec.
3159c33e420SAtul Gupta  */
cxgb4_ptp_gettime(struct ptp_clock_info * ptp,struct timespec64 * ts)3169c33e420SAtul Gupta static int cxgb4_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
3179c33e420SAtul Gupta {
318bd019427SRahul Lakkireddy 	struct adapter *adapter = container_of(ptp, struct adapter,
319bd019427SRahul Lakkireddy 					       ptp_clock_info);
3209c33e420SAtul Gupta 	u64 ns;
3219c33e420SAtul Gupta 
322bd019427SRahul Lakkireddy 	ns = t4_read_reg(adapter, T5_PORT_REG(0, MAC_PORT_PTP_SUM_LO_A));
323bd019427SRahul Lakkireddy 	ns |= (u64)t4_read_reg(adapter,
324bd019427SRahul Lakkireddy 			       T5_PORT_REG(0, MAC_PORT_PTP_SUM_HI_A)) << 32;
3259c33e420SAtul Gupta 
3269c33e420SAtul Gupta 	/* convert to timespec*/
3279c33e420SAtul Gupta 	*ts = ns_to_timespec64(ns);
328bd019427SRahul Lakkireddy 	return 0;
3299c33e420SAtul Gupta }
3309c33e420SAtul Gupta 
3319c33e420SAtul Gupta /**
3329c33e420SAtul Gupta  *  cxgb4_ptp_settime - Set the current time on the hardware clock
3339c33e420SAtul Gupta  *  @ptp: ptp clock structure
3349c33e420SAtul Gupta  *  @ts: timespec containing the new time for the cycle counter
3359c33e420SAtul Gupta  *
3369c33e420SAtul Gupta  *  Reset value to new base value instead of the kernel
3379c33e420SAtul Gupta  *  wall timer value.
3389c33e420SAtul Gupta  */
cxgb4_ptp_settime(struct ptp_clock_info * ptp,const struct timespec64 * ts)3399c33e420SAtul Gupta static int cxgb4_ptp_settime(struct ptp_clock_info *ptp,
3409c33e420SAtul Gupta 			     const struct timespec64 *ts)
3419c33e420SAtul Gupta {
3429c33e420SAtul Gupta 	struct adapter *adapter = (struct adapter *)container_of(ptp,
3439c33e420SAtul Gupta 				   struct adapter, ptp_clock_info);
3449c33e420SAtul Gupta 	struct fw_ptp_cmd c;
3459c33e420SAtul Gupta 	u64 ns;
3469c33e420SAtul Gupta 	int err;
3479c33e420SAtul Gupta 
3489c33e420SAtul Gupta 	memset(&c, 0, sizeof(c));
3499c33e420SAtul Gupta 	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
3509c33e420SAtul Gupta 				     FW_CMD_REQUEST_F |
3519c33e420SAtul Gupta 				     FW_CMD_WRITE_F |
3529c33e420SAtul Gupta 				     FW_PTP_CMD_PORTID_V(0));
3539c33e420SAtul Gupta 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
3549c33e420SAtul Gupta 	c.u.ts.sc = FW_PTP_SC_SET_TIME;
3559c33e420SAtul Gupta 
3569c33e420SAtul Gupta 	ns = timespec64_to_ns(ts);
3579c33e420SAtul Gupta 	c.u.ts.tm = cpu_to_be64(ns);
3589c33e420SAtul Gupta 
3599c33e420SAtul Gupta 	err =  t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
3609c33e420SAtul Gupta 	if (err < 0)
3619c33e420SAtul Gupta 		dev_err(adapter->pdev_dev,
3629c33e420SAtul Gupta 			"PTP: %s error %d\n", __func__, -err);
3639c33e420SAtul Gupta 
3649c33e420SAtul Gupta 	return err;
3659c33e420SAtul Gupta }
3669c33e420SAtul Gupta 
cxgb4_init_ptp_timer(struct adapter * adapter)3679c33e420SAtul Gupta static void cxgb4_init_ptp_timer(struct adapter *adapter)
3689c33e420SAtul Gupta {
3699c33e420SAtul Gupta 	struct fw_ptp_cmd c;
3709c33e420SAtul Gupta 	int err;
3719c33e420SAtul Gupta 
3729c33e420SAtul Gupta 	memset(&c, 0, sizeof(c));
3739c33e420SAtul Gupta 	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
3749c33e420SAtul Gupta 				     FW_CMD_REQUEST_F |
3759c33e420SAtul Gupta 				     FW_CMD_WRITE_F |
3769c33e420SAtul Gupta 				     FW_PTP_CMD_PORTID_V(0));
3779c33e420SAtul Gupta 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
3789c33e420SAtul Gupta 	c.u.scmd.sc = FW_PTP_SC_INIT_TIMER;
3799c33e420SAtul Gupta 
3809c33e420SAtul Gupta 	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
3819c33e420SAtul Gupta 	if (err < 0)
3829c33e420SAtul Gupta 		dev_err(adapter->pdev_dev,
3839c33e420SAtul Gupta 			"PTP: %s error %d\n", __func__, -err);
3849c33e420SAtul Gupta }
3859c33e420SAtul Gupta 
3869c33e420SAtul Gupta /**
3879c33e420SAtul Gupta  * cxgb4_ptp_enable - enable or disable an ancillary feature
3889c33e420SAtul Gupta  * @ptp: ptp clock structure
3899c33e420SAtul Gupta  * @request: Desired resource to enable or disable
3909c33e420SAtul Gupta  * @on: Caller passes one to enable or zero to disable
3919c33e420SAtul Gupta  *
3929c33e420SAtul Gupta  * Enable (or disable) ancillary features of the PHC subsystem.
3939c33e420SAtul Gupta  * Currently, no ancillary features are supported.
3949c33e420SAtul Gupta  */
cxgb4_ptp_enable(struct ptp_clock_info __always_unused * ptp,struct ptp_clock_request __always_unused * request,int __always_unused on)3959c33e420SAtul Gupta static int cxgb4_ptp_enable(struct ptp_clock_info __always_unused *ptp,
3969c33e420SAtul Gupta 			    struct ptp_clock_request __always_unused *request,
3979c33e420SAtul Gupta 			    int __always_unused on)
3989c33e420SAtul Gupta {
3999c33e420SAtul Gupta 	return -ENOTSUPP;
4009c33e420SAtul Gupta }
4019c33e420SAtul Gupta 
4029c33e420SAtul Gupta static const struct ptp_clock_info cxgb4_ptp_clock_info = {
4039c33e420SAtul Gupta 	.owner          = THIS_MODULE,
4049c33e420SAtul Gupta 	.name           = "cxgb4_clock",
4059c33e420SAtul Gupta 	.max_adj        = MAX_PTP_FREQ_ADJ,
4069c33e420SAtul Gupta 	.n_alarm        = 0,
4079c33e420SAtul Gupta 	.n_ext_ts       = 0,
4089c33e420SAtul Gupta 	.n_per_out      = 0,
4099c33e420SAtul Gupta 	.pps            = 0,
410*e2bd9c76SJacob Keller 	.adjfine        = cxgb4_ptp_adjfine,
4119c33e420SAtul Gupta 	.adjtime        = cxgb4_ptp_adjtime,
4129c33e420SAtul Gupta 	.gettime64      = cxgb4_ptp_gettime,
4139c33e420SAtul Gupta 	.settime64      = cxgb4_ptp_settime,
4149c33e420SAtul Gupta 	.enable         = cxgb4_ptp_enable,
4159c33e420SAtul Gupta };
4169c33e420SAtul Gupta 
4179c33e420SAtul Gupta /**
4189c33e420SAtul Gupta  * cxgb4_ptp_init - initialize PTP for devices which support it
4199c33e420SAtul Gupta  * @adapter: board private structure
4209c33e420SAtul Gupta  *
4219c33e420SAtul Gupta  * This function performs the required steps for enabling PTP support.
4229c33e420SAtul Gupta  */
cxgb4_ptp_init(struct adapter * adapter)4239c33e420SAtul Gupta void cxgb4_ptp_init(struct adapter *adapter)
4249c33e420SAtul Gupta {
4259c33e420SAtul Gupta 	struct timespec64 now;
4269c33e420SAtul Gupta 	 /* no need to create a clock device if we already have one */
4279c33e420SAtul Gupta 	if (!IS_ERR_OR_NULL(adapter->ptp_clock))
4289c33e420SAtul Gupta 		return;
4299c33e420SAtul Gupta 
4309c33e420SAtul Gupta 	adapter->ptp_tx_skb = NULL;
4319c33e420SAtul Gupta 	adapter->ptp_clock_info = cxgb4_ptp_clock_info;
4329c33e420SAtul Gupta 	spin_lock_init(&adapter->ptp_lock);
4339c33e420SAtul Gupta 
4349c33e420SAtul Gupta 	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info,
4359c33e420SAtul Gupta 						&adapter->pdev->dev);
43640fbbce0SGanesh Goudar 	if (IS_ERR_OR_NULL(adapter->ptp_clock)) {
43740fbbce0SGanesh Goudar 		adapter->ptp_clock = NULL;
4389c33e420SAtul Gupta 		dev_err(adapter->pdev_dev,
4399c33e420SAtul Gupta 			"PTP %s Clock registration has failed\n", __func__);
4409c33e420SAtul Gupta 		return;
4419c33e420SAtul Gupta 	}
4429c33e420SAtul Gupta 
4439c33e420SAtul Gupta 	now = ktime_to_timespec64(ktime_get_real());
4449c33e420SAtul Gupta 	cxgb4_init_ptp_timer(adapter);
4459c33e420SAtul Gupta 	if (cxgb4_ptp_settime(&adapter->ptp_clock_info, &now) < 0) {
4469c33e420SAtul Gupta 		ptp_clock_unregister(adapter->ptp_clock);
4479c33e420SAtul Gupta 		adapter->ptp_clock = NULL;
4489c33e420SAtul Gupta 	}
4499c33e420SAtul Gupta }
4509c33e420SAtul Gupta 
4519c33e420SAtul Gupta /**
452e0333b1bSYang Shen  * cxgb4_ptp_stop - disable PTP device and stop the overflow check
4539c33e420SAtul Gupta  * @adapter: board private structure
4549c33e420SAtul Gupta  *
4559c33e420SAtul Gupta  * Stop the PTP support.
4569c33e420SAtul Gupta  */
cxgb4_ptp_stop(struct adapter * adapter)4579c33e420SAtul Gupta void cxgb4_ptp_stop(struct adapter *adapter)
4589c33e420SAtul Gupta {
4599c33e420SAtul Gupta 	if (adapter->ptp_tx_skb) {
4609c33e420SAtul Gupta 		dev_kfree_skb_any(adapter->ptp_tx_skb);
4619c33e420SAtul Gupta 		adapter->ptp_tx_skb = NULL;
4629c33e420SAtul Gupta 	}
4639c33e420SAtul Gupta 
4649c33e420SAtul Gupta 	if (adapter->ptp_clock) {
4659c33e420SAtul Gupta 		ptp_clock_unregister(adapter->ptp_clock);
4669c33e420SAtul Gupta 		adapter->ptp_clock = NULL;
4679c33e420SAtul Gupta 	}
4689c33e420SAtul Gupta }
469