xref: /linux/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ptp.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
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  */
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 
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  */
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  */
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  */
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 
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 
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 /**
19729bbf5d7SRahul Lakkireddy  * cxgb4_ptp_adjfreq - Adjust frequency of PHC cycle counter
1989c33e420SAtul Gupta  * @ptp: ptp clock structure
1999c33e420SAtul Gupta  * @ppb: Desired frequency change in parts per billion
2009c33e420SAtul Gupta  *
2019c33e420SAtul Gupta  * Adjust the frequency of the PHC cycle counter by the indicated ppb from
2029c33e420SAtul Gupta  * the base frequency.
2039c33e420SAtul Gupta  */
2049c33e420SAtul Gupta static int cxgb4_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
2059c33e420SAtul Gupta {
2069c33e420SAtul Gupta 	struct adapter *adapter = (struct adapter *)container_of(ptp,
2079c33e420SAtul Gupta 				   struct adapter, ptp_clock_info);
2089c33e420SAtul Gupta 	struct fw_ptp_cmd c;
2099c33e420SAtul Gupta 	int err;
2109c33e420SAtul Gupta 
2119c33e420SAtul Gupta 	memset(&c, 0, sizeof(c));
2129c33e420SAtul Gupta 	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
2139c33e420SAtul Gupta 				     FW_CMD_REQUEST_F |
2149c33e420SAtul Gupta 				     FW_CMD_WRITE_F |
2159c33e420SAtul Gupta 				     FW_PTP_CMD_PORTID_V(0));
2169c33e420SAtul Gupta 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
2179c33e420SAtul Gupta 	c.u.ts.sc = FW_PTP_SC_ADJ_FREQ;
2189c33e420SAtul Gupta 	c.u.ts.sign = (ppb < 0) ? 1 : 0;
2199c33e420SAtul Gupta 	if (ppb < 0)
2209c33e420SAtul Gupta 		ppb = -ppb;
2219c33e420SAtul Gupta 	c.u.ts.ppb = cpu_to_be32(ppb);
2229c33e420SAtul Gupta 
2239c33e420SAtul Gupta 	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
2249c33e420SAtul Gupta 	if (err < 0)
2259c33e420SAtul Gupta 		dev_err(adapter->pdev_dev,
2269c33e420SAtul Gupta 			"PTP: %s error %d\n", __func__, -err);
2279c33e420SAtul Gupta 
2289c33e420SAtul Gupta 	return err;
2299c33e420SAtul Gupta }
2309c33e420SAtul Gupta 
2319c33e420SAtul Gupta /**
2329c33e420SAtul Gupta  * cxgb4_ptp_fineadjtime - Shift the time of the hardware clock
23329bbf5d7SRahul Lakkireddy  * @adapter: board private structure
2349c33e420SAtul Gupta  * @delta: Desired change in nanoseconds
2359c33e420SAtul Gupta  *
2369c33e420SAtul Gupta  * Adjust the timer by resetting the timecounter structure.
2379c33e420SAtul Gupta  */
2389c33e420SAtul Gupta static int  cxgb4_ptp_fineadjtime(struct adapter *adapter, s64 delta)
2399c33e420SAtul Gupta {
2409c33e420SAtul Gupta 	struct fw_ptp_cmd c;
2419c33e420SAtul Gupta 	int err;
2429c33e420SAtul Gupta 
2439c33e420SAtul Gupta 	memset(&c, 0, sizeof(c));
2449c33e420SAtul Gupta 	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
2459c33e420SAtul Gupta 			     FW_CMD_REQUEST_F |
2469c33e420SAtul Gupta 			     FW_CMD_WRITE_F |
2479c33e420SAtul Gupta 			     FW_PTP_CMD_PORTID_V(0));
2489c33e420SAtul Gupta 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
2499c33e420SAtul Gupta 	c.u.ts.sc = FW_PTP_SC_ADJ_FTIME;
25050e0d28dSRaju Rangoju 	c.u.ts.sign = (delta < 0) ? 1 : 0;
25150e0d28dSRaju Rangoju 	if (delta < 0)
25250e0d28dSRaju Rangoju 		delta = -delta;
2539c33e420SAtul Gupta 	c.u.ts.tm = cpu_to_be64(delta);
2549c33e420SAtul Gupta 
2559c33e420SAtul Gupta 	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
2569c33e420SAtul Gupta 	if (err < 0)
2579c33e420SAtul Gupta 		dev_err(adapter->pdev_dev,
2589c33e420SAtul Gupta 			"PTP: %s error %d\n", __func__, -err);
2599c33e420SAtul Gupta 	return err;
2609c33e420SAtul Gupta }
2619c33e420SAtul Gupta 
2629c33e420SAtul Gupta /**
2639c33e420SAtul Gupta  * cxgb4_ptp_adjtime - Shift the time of the hardware clock
2649c33e420SAtul Gupta  * @ptp: ptp clock structure
2659c33e420SAtul Gupta  * @delta: Desired change in nanoseconds
2669c33e420SAtul Gupta  *
2679c33e420SAtul Gupta  * Adjust the timer by resetting the timecounter structure.
2689c33e420SAtul Gupta  */
2699c33e420SAtul Gupta static int cxgb4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
2709c33e420SAtul Gupta {
2719c33e420SAtul Gupta 	struct adapter *adapter =
2729c33e420SAtul Gupta 		(struct adapter *)container_of(ptp, struct adapter,
2739c33e420SAtul Gupta 					       ptp_clock_info);
2749c33e420SAtul Gupta 	struct fw_ptp_cmd c;
2759c33e420SAtul Gupta 	s64 sign = 1;
2769c33e420SAtul Gupta 	int err;
2779c33e420SAtul Gupta 
2789c33e420SAtul Gupta 	if (delta < 0)
2799c33e420SAtul Gupta 		sign = -1;
2809c33e420SAtul Gupta 
2819c33e420SAtul Gupta 	if (delta * sign > PTP_CLOCK_MAX_ADJTIME) {
2829c33e420SAtul Gupta 		memset(&c, 0, sizeof(c));
2839c33e420SAtul Gupta 		c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
2849c33e420SAtul Gupta 					     FW_CMD_REQUEST_F |
2859c33e420SAtul Gupta 					     FW_CMD_WRITE_F |
2869c33e420SAtul Gupta 					     FW_PTP_CMD_PORTID_V(0));
2879c33e420SAtul Gupta 		c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
2889c33e420SAtul Gupta 		c.u.ts.sc = FW_PTP_SC_ADJ_TIME;
2899c33e420SAtul Gupta 		c.u.ts.sign = (delta < 0) ? 1 : 0;
2909c33e420SAtul Gupta 		if (delta < 0)
2919c33e420SAtul Gupta 			delta = -delta;
2929c33e420SAtul Gupta 		c.u.ts.tm = cpu_to_be64(delta);
2939c33e420SAtul Gupta 
2949c33e420SAtul Gupta 		err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
2959c33e420SAtul Gupta 		if (err < 0)
2969c33e420SAtul Gupta 			dev_err(adapter->pdev_dev,
2979c33e420SAtul Gupta 				"PTP: %s error %d\n", __func__, -err);
2989c33e420SAtul Gupta 	} else {
2999c33e420SAtul Gupta 		err = cxgb4_ptp_fineadjtime(adapter, delta);
3009c33e420SAtul Gupta 	}
3019c33e420SAtul Gupta 
3029c33e420SAtul Gupta 	return err;
3039c33e420SAtul Gupta }
3049c33e420SAtul Gupta 
3059c33e420SAtul Gupta /**
3069c33e420SAtul Gupta  * cxgb4_ptp_gettime - Reads the current time from the hardware clock
3079c33e420SAtul Gupta  * @ptp: ptp clock structure
3089c33e420SAtul Gupta  * @ts: timespec structure to hold the current time value
3099c33e420SAtul Gupta  *
3109c33e420SAtul Gupta  * Read the timecounter and return the correct value in ns after converting
3119c33e420SAtul Gupta  * it into a struct timespec.
3129c33e420SAtul Gupta  */
3139c33e420SAtul Gupta static int cxgb4_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
3149c33e420SAtul Gupta {
315bd019427SRahul Lakkireddy 	struct adapter *adapter = container_of(ptp, struct adapter,
316bd019427SRahul Lakkireddy 					       ptp_clock_info);
3179c33e420SAtul Gupta 	u64 ns;
3189c33e420SAtul Gupta 
319bd019427SRahul Lakkireddy 	ns = t4_read_reg(adapter, T5_PORT_REG(0, MAC_PORT_PTP_SUM_LO_A));
320bd019427SRahul Lakkireddy 	ns |= (u64)t4_read_reg(adapter,
321bd019427SRahul Lakkireddy 			       T5_PORT_REG(0, MAC_PORT_PTP_SUM_HI_A)) << 32;
3229c33e420SAtul Gupta 
3239c33e420SAtul Gupta 	/* convert to timespec*/
3249c33e420SAtul Gupta 	*ts = ns_to_timespec64(ns);
325bd019427SRahul Lakkireddy 	return 0;
3269c33e420SAtul Gupta }
3279c33e420SAtul Gupta 
3289c33e420SAtul Gupta /**
3299c33e420SAtul Gupta  *  cxgb4_ptp_settime - Set the current time on the hardware clock
3309c33e420SAtul Gupta  *  @ptp: ptp clock structure
3319c33e420SAtul Gupta  *  @ts: timespec containing the new time for the cycle counter
3329c33e420SAtul Gupta  *
3339c33e420SAtul Gupta  *  Reset value to new base value instead of the kernel
3349c33e420SAtul Gupta  *  wall timer value.
3359c33e420SAtul Gupta  */
3369c33e420SAtul Gupta static int cxgb4_ptp_settime(struct ptp_clock_info *ptp,
3379c33e420SAtul Gupta 			     const struct timespec64 *ts)
3389c33e420SAtul Gupta {
3399c33e420SAtul Gupta 	struct adapter *adapter = (struct adapter *)container_of(ptp,
3409c33e420SAtul Gupta 				   struct adapter, ptp_clock_info);
3419c33e420SAtul Gupta 	struct fw_ptp_cmd c;
3429c33e420SAtul Gupta 	u64 ns;
3439c33e420SAtul Gupta 	int err;
3449c33e420SAtul Gupta 
3459c33e420SAtul Gupta 	memset(&c, 0, sizeof(c));
3469c33e420SAtul Gupta 	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
3479c33e420SAtul Gupta 				     FW_CMD_REQUEST_F |
3489c33e420SAtul Gupta 				     FW_CMD_WRITE_F |
3499c33e420SAtul Gupta 				     FW_PTP_CMD_PORTID_V(0));
3509c33e420SAtul Gupta 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
3519c33e420SAtul Gupta 	c.u.ts.sc = FW_PTP_SC_SET_TIME;
3529c33e420SAtul Gupta 
3539c33e420SAtul Gupta 	ns = timespec64_to_ns(ts);
3549c33e420SAtul Gupta 	c.u.ts.tm = cpu_to_be64(ns);
3559c33e420SAtul Gupta 
3569c33e420SAtul Gupta 	err =  t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
3579c33e420SAtul Gupta 	if (err < 0)
3589c33e420SAtul Gupta 		dev_err(adapter->pdev_dev,
3599c33e420SAtul Gupta 			"PTP: %s error %d\n", __func__, -err);
3609c33e420SAtul Gupta 
3619c33e420SAtul Gupta 	return err;
3629c33e420SAtul Gupta }
3639c33e420SAtul Gupta 
3649c33e420SAtul Gupta static void cxgb4_init_ptp_timer(struct adapter *adapter)
3659c33e420SAtul Gupta {
3669c33e420SAtul Gupta 	struct fw_ptp_cmd c;
3679c33e420SAtul Gupta 	int err;
3689c33e420SAtul Gupta 
3699c33e420SAtul Gupta 	memset(&c, 0, sizeof(c));
3709c33e420SAtul Gupta 	c.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PTP_CMD) |
3719c33e420SAtul Gupta 				     FW_CMD_REQUEST_F |
3729c33e420SAtul Gupta 				     FW_CMD_WRITE_F |
3739c33e420SAtul Gupta 				     FW_PTP_CMD_PORTID_V(0));
3749c33e420SAtul Gupta 	c.retval_len16 = cpu_to_be32(FW_CMD_LEN16_V(sizeof(c) / 16));
3759c33e420SAtul Gupta 	c.u.scmd.sc = FW_PTP_SC_INIT_TIMER;
3769c33e420SAtul Gupta 
3779c33e420SAtul Gupta 	err = t4_wr_mbox(adapter, adapter->mbox, &c, sizeof(c), NULL);
3789c33e420SAtul Gupta 	if (err < 0)
3799c33e420SAtul Gupta 		dev_err(adapter->pdev_dev,
3809c33e420SAtul Gupta 			"PTP: %s error %d\n", __func__, -err);
3819c33e420SAtul Gupta }
3829c33e420SAtul Gupta 
3839c33e420SAtul Gupta /**
3849c33e420SAtul Gupta  * cxgb4_ptp_enable - enable or disable an ancillary feature
3859c33e420SAtul Gupta  * @ptp: ptp clock structure
3869c33e420SAtul Gupta  * @request: Desired resource to enable or disable
3879c33e420SAtul Gupta  * @on: Caller passes one to enable or zero to disable
3889c33e420SAtul Gupta  *
3899c33e420SAtul Gupta  * Enable (or disable) ancillary features of the PHC subsystem.
3909c33e420SAtul Gupta  * Currently, no ancillary features are supported.
3919c33e420SAtul Gupta  */
3929c33e420SAtul Gupta static int cxgb4_ptp_enable(struct ptp_clock_info __always_unused *ptp,
3939c33e420SAtul Gupta 			    struct ptp_clock_request __always_unused *request,
3949c33e420SAtul Gupta 			    int __always_unused on)
3959c33e420SAtul Gupta {
3969c33e420SAtul Gupta 	return -ENOTSUPP;
3979c33e420SAtul Gupta }
3989c33e420SAtul Gupta 
3999c33e420SAtul Gupta static const struct ptp_clock_info cxgb4_ptp_clock_info = {
4009c33e420SAtul Gupta 	.owner          = THIS_MODULE,
4019c33e420SAtul Gupta 	.name           = "cxgb4_clock",
4029c33e420SAtul Gupta 	.max_adj        = MAX_PTP_FREQ_ADJ,
4039c33e420SAtul Gupta 	.n_alarm        = 0,
4049c33e420SAtul Gupta 	.n_ext_ts       = 0,
4059c33e420SAtul Gupta 	.n_per_out      = 0,
4069c33e420SAtul Gupta 	.pps            = 0,
4079c33e420SAtul Gupta 	.adjfreq        = cxgb4_ptp_adjfreq,
4089c33e420SAtul Gupta 	.adjtime        = cxgb4_ptp_adjtime,
4099c33e420SAtul Gupta 	.gettime64      = cxgb4_ptp_gettime,
4109c33e420SAtul Gupta 	.settime64      = cxgb4_ptp_settime,
4119c33e420SAtul Gupta 	.enable         = cxgb4_ptp_enable,
4129c33e420SAtul Gupta };
4139c33e420SAtul Gupta 
4149c33e420SAtul Gupta /**
4159c33e420SAtul Gupta  * cxgb4_ptp_init - initialize PTP for devices which support it
4169c33e420SAtul Gupta  * @adapter: board private structure
4179c33e420SAtul Gupta  *
4189c33e420SAtul Gupta  * This function performs the required steps for enabling PTP support.
4199c33e420SAtul Gupta  */
4209c33e420SAtul Gupta void cxgb4_ptp_init(struct adapter *adapter)
4219c33e420SAtul Gupta {
4229c33e420SAtul Gupta 	struct timespec64 now;
4239c33e420SAtul Gupta 	 /* no need to create a clock device if we already have one */
4249c33e420SAtul Gupta 	if (!IS_ERR_OR_NULL(adapter->ptp_clock))
4259c33e420SAtul Gupta 		return;
4269c33e420SAtul Gupta 
4279c33e420SAtul Gupta 	adapter->ptp_tx_skb = NULL;
4289c33e420SAtul Gupta 	adapter->ptp_clock_info = cxgb4_ptp_clock_info;
4299c33e420SAtul Gupta 	spin_lock_init(&adapter->ptp_lock);
4309c33e420SAtul Gupta 
4319c33e420SAtul Gupta 	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info,
4329c33e420SAtul Gupta 						&adapter->pdev->dev);
43340fbbce0SGanesh Goudar 	if (IS_ERR_OR_NULL(adapter->ptp_clock)) {
43440fbbce0SGanesh Goudar 		adapter->ptp_clock = NULL;
4359c33e420SAtul Gupta 		dev_err(adapter->pdev_dev,
4369c33e420SAtul Gupta 			"PTP %s Clock registration has failed\n", __func__);
4379c33e420SAtul Gupta 		return;
4389c33e420SAtul Gupta 	}
4399c33e420SAtul Gupta 
4409c33e420SAtul Gupta 	now = ktime_to_timespec64(ktime_get_real());
4419c33e420SAtul Gupta 	cxgb4_init_ptp_timer(adapter);
4429c33e420SAtul Gupta 	if (cxgb4_ptp_settime(&adapter->ptp_clock_info, &now) < 0) {
4439c33e420SAtul Gupta 		ptp_clock_unregister(adapter->ptp_clock);
4449c33e420SAtul Gupta 		adapter->ptp_clock = NULL;
4459c33e420SAtul Gupta 	}
4469c33e420SAtul Gupta }
4479c33e420SAtul Gupta 
4489c33e420SAtul Gupta /**
449*e0333b1bSYang Shen  * cxgb4_ptp_stop - disable PTP device and stop the overflow check
4509c33e420SAtul Gupta  * @adapter: board private structure
4519c33e420SAtul Gupta  *
4529c33e420SAtul Gupta  * Stop the PTP support.
4539c33e420SAtul Gupta  */
4549c33e420SAtul Gupta void cxgb4_ptp_stop(struct adapter *adapter)
4559c33e420SAtul Gupta {
4569c33e420SAtul Gupta 	if (adapter->ptp_tx_skb) {
4579c33e420SAtul Gupta 		dev_kfree_skb_any(adapter->ptp_tx_skb);
4589c33e420SAtul Gupta 		adapter->ptp_tx_skb = NULL;
4599c33e420SAtul Gupta 	}
4609c33e420SAtul Gupta 
4619c33e420SAtul Gupta 	if (adapter->ptp_clock) {
4629c33e420SAtul Gupta 		ptp_clock_unregister(adapter->ptp_clock);
4639c33e420SAtul Gupta 		adapter->ptp_clock = NULL;
4649c33e420SAtul Gupta 	}
4659c33e420SAtul Gupta }
466