1118612d5SMichael Chan /* Broadcom NetXtreme-C/E network driver.
2118612d5SMichael Chan  *
3118612d5SMichael Chan  * Copyright (c) 2021 Broadcom Inc.
4118612d5SMichael Chan  *
5118612d5SMichael Chan  * This program is free software; you can redistribute it and/or modify
6118612d5SMichael Chan  * it under the terms of the GNU General Public License as published by
7118612d5SMichael Chan  * the Free Software Foundation.
8118612d5SMichael Chan  */
9118612d5SMichael Chan #include <linux/kernel.h>
10118612d5SMichael Chan #include <linux/errno.h>
11118612d5SMichael Chan #include <linux/pci.h>
12118612d5SMichael Chan #include <linux/netdevice.h>
13118612d5SMichael Chan #include <linux/etherdevice.h>
14118612d5SMichael Chan #include <linux/net_tstamp.h>
15118612d5SMichael Chan #include <linux/timekeeping.h>
1683bb623cSPavan Chebbi #include <linux/ptp_classify.h>
1785036aeeSPavan Chebbi #include <linux/clocksource.h>
18118612d5SMichael Chan #include "bnxt_hsi.h"
19118612d5SMichael Chan #include "bnxt.h"
203c8c20dbSEdwin Peer #include "bnxt_hwrm.h"
21118612d5SMichael Chan #include "bnxt_ptp.h"
22118612d5SMichael Chan 
bnxt_ptp_cfg_settime(struct bnxt * bp,u64 time)2324ac1ecdSPavan Chebbi static int bnxt_ptp_cfg_settime(struct bnxt *bp, u64 time)
2424ac1ecdSPavan Chebbi {
2524ac1ecdSPavan Chebbi 	struct hwrm_func_ptp_cfg_input *req;
2624ac1ecdSPavan Chebbi 	int rc;
2724ac1ecdSPavan Chebbi 
2824ac1ecdSPavan Chebbi 	rc = hwrm_req_init(bp, req, HWRM_FUNC_PTP_CFG);
2924ac1ecdSPavan Chebbi 	if (rc)
3024ac1ecdSPavan Chebbi 		return rc;
3124ac1ecdSPavan Chebbi 
3224ac1ecdSPavan Chebbi 	req->enables = cpu_to_le16(FUNC_PTP_CFG_REQ_ENABLES_PTP_SET_TIME);
3324ac1ecdSPavan Chebbi 	req->ptp_set_time = cpu_to_le64(time);
3424ac1ecdSPavan Chebbi 	return hwrm_req_send(bp, req);
3524ac1ecdSPavan Chebbi }
3624ac1ecdSPavan Chebbi 
bnxt_ptp_parse(struct sk_buff * skb,u16 * seq_id,u16 * hdr_off)379e266807SMichael Chan int bnxt_ptp_parse(struct sk_buff *skb, u16 *seq_id, u16 *hdr_off)
3883bb623cSPavan Chebbi {
3983bb623cSPavan Chebbi 	unsigned int ptp_class;
4083bb623cSPavan Chebbi 	struct ptp_header *hdr;
4183bb623cSPavan Chebbi 
4283bb623cSPavan Chebbi 	ptp_class = ptp_classify_raw(skb);
4383bb623cSPavan Chebbi 
4483bb623cSPavan Chebbi 	switch (ptp_class & PTP_CLASS_VMASK) {
4583bb623cSPavan Chebbi 	case PTP_CLASS_V1:
4683bb623cSPavan Chebbi 	case PTP_CLASS_V2:
4783bb623cSPavan Chebbi 		hdr = ptp_parse_header(skb, ptp_class);
4883bb623cSPavan Chebbi 		if (!hdr)
4983bb623cSPavan Chebbi 			return -EINVAL;
5083bb623cSPavan Chebbi 
519e266807SMichael Chan 		*hdr_off = (u8 *)hdr - skb->data;
5283bb623cSPavan Chebbi 		*seq_id	 = ntohs(hdr->sequence_id);
5383bb623cSPavan Chebbi 		return 0;
5483bb623cSPavan Chebbi 	default:
5583bb623cSPavan Chebbi 		return -ERANGE;
5683bb623cSPavan Chebbi 	}
5783bb623cSPavan Chebbi }
5883bb623cSPavan Chebbi 
bnxt_ptp_settime(struct ptp_clock_info * ptp_info,const struct timespec64 * ts)59118612d5SMichael Chan static int bnxt_ptp_settime(struct ptp_clock_info *ptp_info,
60118612d5SMichael Chan 			    const struct timespec64 *ts)
61118612d5SMichael Chan {
62118612d5SMichael Chan 	struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
63118612d5SMichael Chan 						ptp_info);
64118612d5SMichael Chan 	u64 ns = timespec64_to_ns(ts);
65118612d5SMichael Chan 
66131db499SVadim Fedorenko 	if (BNXT_PTP_USE_RTC(ptp->bp))
6724ac1ecdSPavan Chebbi 		return bnxt_ptp_cfg_settime(ptp->bp, ns);
6824ac1ecdSPavan Chebbi 
69118612d5SMichael Chan 	spin_lock_bh(&ptp->ptp_lock);
70118612d5SMichael Chan 	timecounter_init(&ptp->tc, &ptp->cc, ns);
71118612d5SMichael Chan 	spin_unlock_bh(&ptp->ptp_lock);
72118612d5SMichael Chan 	return 0;
73118612d5SMichael Chan }
74118612d5SMichael Chan 
75118612d5SMichael Chan /* Caller holds ptp_lock */
bnxt_refclk_read(struct bnxt * bp,struct ptp_system_timestamp * sts,u64 * ns)7630e96f48SMichael Chan static int bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts,
7730e96f48SMichael Chan 			    u64 *ns)
78118612d5SMichael Chan {
79118612d5SMichael Chan 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
80ddde5412SPavan Chebbi 	u32 high_before, high_now, low;
8130e96f48SMichael Chan 
8230e96f48SMichael Chan 	if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
8330e96f48SMichael Chan 		return -EIO;
84118612d5SMichael Chan 
85ddde5412SPavan Chebbi 	high_before = readl(bp->bar0 + ptp->refclk_mapped_regs[1]);
86118612d5SMichael Chan 	ptp_read_system_prets(sts);
87ddde5412SPavan Chebbi 	low = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
88118612d5SMichael Chan 	ptp_read_system_postts(sts);
89ddde5412SPavan Chebbi 	high_now = readl(bp->bar0 + ptp->refclk_mapped_regs[1]);
90ddde5412SPavan Chebbi 	if (high_now != high_before) {
91ddde5412SPavan Chebbi 		ptp_read_system_prets(sts);
92ddde5412SPavan Chebbi 		low = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
93ddde5412SPavan Chebbi 		ptp_read_system_postts(sts);
94ddde5412SPavan Chebbi 	}
95ddde5412SPavan Chebbi 	*ns = ((u64)high_now << 32) | low;
96ddde5412SPavan Chebbi 
9730e96f48SMichael Chan 	return 0;
98118612d5SMichael Chan }
99118612d5SMichael Chan 
bnxt_ptp_get_current_time(struct bnxt * bp)100390862f4SPavan Chebbi static void bnxt_ptp_get_current_time(struct bnxt *bp)
101390862f4SPavan Chebbi {
102390862f4SPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
103390862f4SPavan Chebbi 
104390862f4SPavan Chebbi 	if (!ptp)
105390862f4SPavan Chebbi 		return;
106390862f4SPavan Chebbi 	spin_lock_bh(&ptp->ptp_lock);
107390862f4SPavan Chebbi 	WRITE_ONCE(ptp->old_time, ptp->current_time);
10830e96f48SMichael Chan 	bnxt_refclk_read(bp, NULL, &ptp->current_time);
109390862f4SPavan Chebbi 	spin_unlock_bh(&ptp->ptp_lock);
110390862f4SPavan Chebbi }
111390862f4SPavan Chebbi 
bnxt_hwrm_port_ts_query(struct bnxt * bp,u32 flags,u64 * ts)11283bb623cSPavan Chebbi static int bnxt_hwrm_port_ts_query(struct bnxt *bp, u32 flags, u64 *ts)
11383bb623cSPavan Chebbi {
114bbf33d1dSEdwin Peer 	struct hwrm_port_ts_query_output *resp;
115bbf33d1dSEdwin Peer 	struct hwrm_port_ts_query_input *req;
11683bb623cSPavan Chebbi 	int rc;
11783bb623cSPavan Chebbi 
118bbf33d1dSEdwin Peer 	rc = hwrm_req_init(bp, req, HWRM_PORT_TS_QUERY);
119bbf33d1dSEdwin Peer 	if (rc)
120bbf33d1dSEdwin Peer 		return rc;
121bbf33d1dSEdwin Peer 
122bbf33d1dSEdwin Peer 	req->flags = cpu_to_le32(flags);
12383bb623cSPavan Chebbi 	if ((flags & PORT_TS_QUERY_REQ_FLAGS_PATH) ==
12483bb623cSPavan Chebbi 	    PORT_TS_QUERY_REQ_FLAGS_PATH_TX) {
125bbf33d1dSEdwin Peer 		req->enables = cpu_to_le16(BNXT_PTP_QTS_TX_ENABLES);
126bbf33d1dSEdwin Peer 		req->ptp_seq_id = cpu_to_le32(bp->ptp_cfg->tx_seqid);
127bbf33d1dSEdwin Peer 		req->ptp_hdr_offset = cpu_to_le16(bp->ptp_cfg->tx_hdr_off);
128bbf33d1dSEdwin Peer 		req->ts_req_timeout = cpu_to_le16(BNXT_PTP_QTS_TIMEOUT);
12983bb623cSPavan Chebbi 	}
130bbf33d1dSEdwin Peer 	resp = hwrm_req_hold(bp, req);
131bbf33d1dSEdwin Peer 
132bbf33d1dSEdwin Peer 	rc = hwrm_req_send(bp, req);
13383bb623cSPavan Chebbi 	if (!rc)
13483bb623cSPavan Chebbi 		*ts = le64_to_cpu(resp->ptp_msg_ts);
135bbf33d1dSEdwin Peer 	hwrm_req_drop(bp, req);
13683bb623cSPavan Chebbi 	return rc;
13783bb623cSPavan Chebbi }
13883bb623cSPavan Chebbi 
bnxt_ptp_gettimex(struct ptp_clock_info * ptp_info,struct timespec64 * ts,struct ptp_system_timestamp * sts)139118612d5SMichael Chan static int bnxt_ptp_gettimex(struct ptp_clock_info *ptp_info,
140118612d5SMichael Chan 			     struct timespec64 *ts,
141118612d5SMichael Chan 			     struct ptp_system_timestamp *sts)
142118612d5SMichael Chan {
143118612d5SMichael Chan 	struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
144118612d5SMichael Chan 						ptp_info);
145118612d5SMichael Chan 	u64 ns, cycles;
14630e96f48SMichael Chan 	int rc;
147118612d5SMichael Chan 
148118612d5SMichael Chan 	spin_lock_bh(&ptp->ptp_lock);
14930e96f48SMichael Chan 	rc = bnxt_refclk_read(ptp->bp, sts, &cycles);
15030e96f48SMichael Chan 	if (rc) {
15130e96f48SMichael Chan 		spin_unlock_bh(&ptp->ptp_lock);
15230e96f48SMichael Chan 		return rc;
15330e96f48SMichael Chan 	}
154118612d5SMichael Chan 	ns = timecounter_cyc2time(&ptp->tc, cycles);
155118612d5SMichael Chan 	spin_unlock_bh(&ptp->ptp_lock);
156118612d5SMichael Chan 	*ts = ns_to_timespec64(ns);
157118612d5SMichael Chan 
158118612d5SMichael Chan 	return 0;
159118612d5SMichael Chan }
160118612d5SMichael Chan 
161e7b0afb6SPavan Chebbi /* Caller holds ptp_lock */
bnxt_ptp_update_current_time(struct bnxt * bp)162e7b0afb6SPavan Chebbi void bnxt_ptp_update_current_time(struct bnxt *bp)
163e7b0afb6SPavan Chebbi {
164e7b0afb6SPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
165e7b0afb6SPavan Chebbi 
166e7b0afb6SPavan Chebbi 	bnxt_refclk_read(ptp->bp, NULL, &ptp->current_time);
167e7b0afb6SPavan Chebbi 	WRITE_ONCE(ptp->old_time, ptp->current_time);
168e7b0afb6SPavan Chebbi }
169e7b0afb6SPavan Chebbi 
bnxt_ptp_adjphc(struct bnxt_ptp_cfg * ptp,s64 delta)170e7b0afb6SPavan Chebbi static int bnxt_ptp_adjphc(struct bnxt_ptp_cfg *ptp, s64 delta)
171e7b0afb6SPavan Chebbi {
172e7b0afb6SPavan Chebbi 	struct hwrm_port_mac_cfg_input *req;
173e7b0afb6SPavan Chebbi 	int rc;
174e7b0afb6SPavan Chebbi 
175e7b0afb6SPavan Chebbi 	rc = hwrm_req_init(ptp->bp, req, HWRM_PORT_MAC_CFG);
176e7b0afb6SPavan Chebbi 	if (rc)
177e7b0afb6SPavan Chebbi 		return rc;
178e7b0afb6SPavan Chebbi 
179e7b0afb6SPavan Chebbi 	req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_PTP_ADJ_PHASE);
180e7b0afb6SPavan Chebbi 	req->ptp_adj_phase = cpu_to_le64(delta);
181e7b0afb6SPavan Chebbi 
182e7b0afb6SPavan Chebbi 	rc = hwrm_req_send(ptp->bp, req);
183e7b0afb6SPavan Chebbi 	if (rc) {
184e7b0afb6SPavan Chebbi 		netdev_err(ptp->bp->dev, "ptp adjphc failed. rc = %x\n", rc);
185e7b0afb6SPavan Chebbi 	} else {
186e7b0afb6SPavan Chebbi 		spin_lock_bh(&ptp->ptp_lock);
187e7b0afb6SPavan Chebbi 		bnxt_ptp_update_current_time(ptp->bp);
188e7b0afb6SPavan Chebbi 		spin_unlock_bh(&ptp->ptp_lock);
189e7b0afb6SPavan Chebbi 	}
190e7b0afb6SPavan Chebbi 
191e7b0afb6SPavan Chebbi 	return rc;
192e7b0afb6SPavan Chebbi }
193e7b0afb6SPavan Chebbi 
bnxt_ptp_adjtime(struct ptp_clock_info * ptp_info,s64 delta)194118612d5SMichael Chan static int bnxt_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
195118612d5SMichael Chan {
196118612d5SMichael Chan 	struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
197118612d5SMichael Chan 						ptp_info);
198118612d5SMichael Chan 
199131db499SVadim Fedorenko 	if (BNXT_PTP_USE_RTC(ptp->bp))
200e7b0afb6SPavan Chebbi 		return bnxt_ptp_adjphc(ptp, delta);
201e7b0afb6SPavan Chebbi 
202118612d5SMichael Chan 	spin_lock_bh(&ptp->ptp_lock);
203118612d5SMichael Chan 	timecounter_adjtime(&ptp->tc, delta);
204118612d5SMichael Chan 	spin_unlock_bh(&ptp->ptp_lock);
205118612d5SMichael Chan 	return 0;
206118612d5SMichael Chan }
207118612d5SMichael Chan 
bnxt_ptp_adjfine_rtc(struct bnxt * bp,long scaled_ppm)208131db499SVadim Fedorenko static int bnxt_ptp_adjfine_rtc(struct bnxt *bp, long scaled_ppm)
209118612d5SMichael Chan {
210a29c132fSJacob Keller 	s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
211131db499SVadim Fedorenko 	struct hwrm_port_mac_cfg_input *req;
212131db499SVadim Fedorenko 	int rc;
213a29c132fSJacob Keller 
214bbf33d1dSEdwin Peer 	rc = hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG);
215bbf33d1dSEdwin Peer 	if (rc)
216bbf33d1dSEdwin Peer 		return rc;
217bbf33d1dSEdwin Peer 
218bbf33d1dSEdwin Peer 	req->ptp_freq_adj_ppb = cpu_to_le32(ppb);
219bbf33d1dSEdwin Peer 	req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_PTP_FREQ_ADJ_PPB);
220131db499SVadim Fedorenko 	rc = hwrm_req_send(bp, req);
221118612d5SMichael Chan 	if (rc)
222131db499SVadim Fedorenko 		netdev_err(bp->dev,
223a29c132fSJacob Keller 			   "ptp adjfine failed. rc = %d\n", rc);
224118612d5SMichael Chan 	return rc;
225118612d5SMichael Chan }
226118612d5SMichael Chan 
bnxt_ptp_adjfine(struct ptp_clock_info * ptp_info,long scaled_ppm)227131db499SVadim Fedorenko static int bnxt_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
228131db499SVadim Fedorenko {
229131db499SVadim Fedorenko 	struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
230131db499SVadim Fedorenko 						ptp_info);
231131db499SVadim Fedorenko 	struct bnxt *bp = ptp->bp;
232131db499SVadim Fedorenko 
233a02c3313SPavan Chebbi 	if (!BNXT_MH(bp))
234131db499SVadim Fedorenko 		return bnxt_ptp_adjfine_rtc(bp, scaled_ppm);
235131db499SVadim Fedorenko 
236131db499SVadim Fedorenko 	spin_lock_bh(&ptp->ptp_lock);
237131db499SVadim Fedorenko 	timecounter_read(&ptp->tc);
238131db499SVadim Fedorenko 	ptp->cc.mult = adjust_by_scaled_ppm(ptp->cmult, scaled_ppm);
239131db499SVadim Fedorenko 	spin_unlock_bh(&ptp->ptp_lock);
240131db499SVadim Fedorenko 	return 0;
241131db499SVadim Fedorenko }
242131db499SVadim Fedorenko 
bnxt_ptp_pps_event(struct bnxt * bp,u32 data1,u32 data2)243099fdedaSPavan Chebbi void bnxt_ptp_pps_event(struct bnxt *bp, u32 data1, u32 data2)
244099fdedaSPavan Chebbi {
245099fdedaSPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
246099fdedaSPavan Chebbi 	struct ptp_clock_event event;
247099fdedaSPavan Chebbi 	u64 ns, pps_ts;
248099fdedaSPavan Chebbi 
249099fdedaSPavan Chebbi 	pps_ts = EVENT_PPS_TS(data2, data1);
250099fdedaSPavan Chebbi 	spin_lock_bh(&ptp->ptp_lock);
251099fdedaSPavan Chebbi 	ns = timecounter_cyc2time(&ptp->tc, pps_ts);
252099fdedaSPavan Chebbi 	spin_unlock_bh(&ptp->ptp_lock);
253099fdedaSPavan Chebbi 
254099fdedaSPavan Chebbi 	switch (EVENT_DATA2_PPS_EVENT_TYPE(data2)) {
255099fdedaSPavan Chebbi 	case ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_EVENT_TYPE_INTERNAL:
256099fdedaSPavan Chebbi 		event.pps_times.ts_real = ns_to_timespec64(ns);
257099fdedaSPavan Chebbi 		event.type = PTP_CLOCK_PPSUSR;
258099fdedaSPavan Chebbi 		event.index = EVENT_DATA2_PPS_PIN_NUM(data2);
259099fdedaSPavan Chebbi 		break;
260099fdedaSPavan Chebbi 	case ASYNC_EVENT_CMPL_PPS_TIMESTAMP_EVENT_DATA2_EVENT_TYPE_EXTERNAL:
261099fdedaSPavan Chebbi 		event.timestamp = ns;
262099fdedaSPavan Chebbi 		event.type = PTP_CLOCK_EXTTS;
263099fdedaSPavan Chebbi 		event.index = EVENT_DATA2_PPS_PIN_NUM(data2);
264099fdedaSPavan Chebbi 		break;
265099fdedaSPavan Chebbi 	}
266099fdedaSPavan Chebbi 
267099fdedaSPavan Chebbi 	ptp_clock_event(bp->ptp_cfg->ptp_clock, &event);
268099fdedaSPavan Chebbi }
269099fdedaSPavan Chebbi 
bnxt_ptp_cfg_pin(struct bnxt * bp,u8 pin,u8 usage)2709e518f25SPavan Chebbi static int bnxt_ptp_cfg_pin(struct bnxt *bp, u8 pin, u8 usage)
2719e518f25SPavan Chebbi {
272bbf33d1dSEdwin Peer 	struct hwrm_func_ptp_pin_cfg_input *req;
2739e518f25SPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
2749e518f25SPavan Chebbi 	u8 state = usage != BNXT_PPS_PIN_NONE;
2759e518f25SPavan Chebbi 	u8 *pin_state, *pin_usg;
2769e518f25SPavan Chebbi 	u32 enables;
2779e518f25SPavan Chebbi 	int rc;
2789e518f25SPavan Chebbi 
2799e518f25SPavan Chebbi 	if (!TSIO_PIN_VALID(pin)) {
2809e518f25SPavan Chebbi 		netdev_err(ptp->bp->dev, "1PPS: Invalid pin. Check pin-function configuration\n");
2819e518f25SPavan Chebbi 		return -EOPNOTSUPP;
2829e518f25SPavan Chebbi 	}
2839e518f25SPavan Chebbi 
284bbf33d1dSEdwin Peer 	rc = hwrm_req_init(ptp->bp, req, HWRM_FUNC_PTP_PIN_CFG);
285bbf33d1dSEdwin Peer 	if (rc)
286bbf33d1dSEdwin Peer 		return rc;
287bbf33d1dSEdwin Peer 
2889e518f25SPavan Chebbi 	enables = (FUNC_PTP_PIN_CFG_REQ_ENABLES_PIN0_STATE |
2899e518f25SPavan Chebbi 		   FUNC_PTP_PIN_CFG_REQ_ENABLES_PIN0_USAGE) << (pin * 2);
290bbf33d1dSEdwin Peer 	req->enables = cpu_to_le32(enables);
2919e518f25SPavan Chebbi 
292bbf33d1dSEdwin Peer 	pin_state = &req->pin0_state;
293bbf33d1dSEdwin Peer 	pin_usg = &req->pin0_usage;
2949e518f25SPavan Chebbi 
2959e518f25SPavan Chebbi 	*(pin_state + (pin * 2)) = state;
2969e518f25SPavan Chebbi 	*(pin_usg + (pin * 2)) = usage;
2979e518f25SPavan Chebbi 
298bbf33d1dSEdwin Peer 	rc = hwrm_req_send(ptp->bp, req);
2999e518f25SPavan Chebbi 	if (rc)
3009e518f25SPavan Chebbi 		return rc;
3019e518f25SPavan Chebbi 
3029e518f25SPavan Chebbi 	ptp->pps_info.pins[pin].usage = usage;
3039e518f25SPavan Chebbi 	ptp->pps_info.pins[pin].state = state;
3049e518f25SPavan Chebbi 
3059e518f25SPavan Chebbi 	return 0;
3069e518f25SPavan Chebbi }
3079e518f25SPavan Chebbi 
bnxt_ptp_cfg_event(struct bnxt * bp,u8 event)3089e518f25SPavan Chebbi static int bnxt_ptp_cfg_event(struct bnxt *bp, u8 event)
3099e518f25SPavan Chebbi {
310bbf33d1dSEdwin Peer 	struct hwrm_func_ptp_cfg_input *req;
311bbf33d1dSEdwin Peer 	int rc;
3129e518f25SPavan Chebbi 
313bbf33d1dSEdwin Peer 	rc = hwrm_req_init(bp, req, HWRM_FUNC_PTP_CFG);
314bbf33d1dSEdwin Peer 	if (rc)
315bbf33d1dSEdwin Peer 		return rc;
316bbf33d1dSEdwin Peer 
317bbf33d1dSEdwin Peer 	req->enables = cpu_to_le16(FUNC_PTP_CFG_REQ_ENABLES_PTP_PPS_EVENT);
318bbf33d1dSEdwin Peer 	req->ptp_pps_event = event;
319bbf33d1dSEdwin Peer 	return hwrm_req_send(bp, req);
3209e518f25SPavan Chebbi }
3219e518f25SPavan Chebbi 
bnxt_ptp_cfg_tstamp_filters(struct bnxt * bp)32211862689SPavan Chebbi void bnxt_ptp_cfg_tstamp_filters(struct bnxt *bp)
32311862689SPavan Chebbi {
32411862689SPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
32511862689SPavan Chebbi 	struct hwrm_port_mac_cfg_input *req;
32611862689SPavan Chebbi 
32711862689SPavan Chebbi 	if (!ptp || !ptp->tstamp_filters)
32811862689SPavan Chebbi 		return;
32911862689SPavan Chebbi 
33011862689SPavan Chebbi 	if (hwrm_req_init(bp, req, HWRM_PORT_MAC_CFG))
33111862689SPavan Chebbi 		goto out;
33266ed81dcSPavan Chebbi 
33366ed81dcSPavan Chebbi 	if (!(bp->fw_cap & BNXT_FW_CAP_RX_ALL_PKT_TS) && (ptp->tstamp_filters &
33466ed81dcSPavan Chebbi 	    (PORT_MAC_CFG_REQ_FLAGS_ALL_RX_TS_CAPTURE_ENABLE |
335ae8ffba8SVadim Fedorenko 	     PORT_MAC_CFG_REQ_FLAGS_ALL_RX_TS_CAPTURE_DISABLE))) {
33666ed81dcSPavan Chebbi 		ptp->tstamp_filters &= ~(PORT_MAC_CFG_REQ_FLAGS_ALL_RX_TS_CAPTURE_ENABLE |
337ae8ffba8SVadim Fedorenko 					 PORT_MAC_CFG_REQ_FLAGS_ALL_RX_TS_CAPTURE_DISABLE);
33866ed81dcSPavan Chebbi 		netdev_warn(bp->dev, "Unsupported FW for all RX pkts timestamp filter\n");
33966ed81dcSPavan Chebbi 	}
34066ed81dcSPavan Chebbi 
34111862689SPavan Chebbi 	req->flags = cpu_to_le32(ptp->tstamp_filters);
34211862689SPavan Chebbi 	req->enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_RX_TS_CAPTURE_PTP_MSG_TYPE);
34311862689SPavan Chebbi 	req->rx_ts_capture_ptp_msg_type = cpu_to_le16(ptp->rxctl);
34411862689SPavan Chebbi 
34566ed81dcSPavan Chebbi 	if (!hwrm_req_send(bp, req)) {
34666ed81dcSPavan Chebbi 		bp->ptp_all_rx_tstamp = !!(ptp->tstamp_filters &
34766ed81dcSPavan Chebbi 					   PORT_MAC_CFG_REQ_FLAGS_ALL_RX_TS_CAPTURE_ENABLE);
34811862689SPavan Chebbi 		return;
34966ed81dcSPavan Chebbi 	}
35011862689SPavan Chebbi 	ptp->tstamp_filters = 0;
35111862689SPavan Chebbi out:
35266ed81dcSPavan Chebbi 	bp->ptp_all_rx_tstamp = 0;
35311862689SPavan Chebbi 	netdev_warn(bp->dev, "Failed to configure HW packet timestamp filters\n");
35411862689SPavan Chebbi }
35511862689SPavan Chebbi 
bnxt_ptp_reapply_pps(struct bnxt * bp)3569e518f25SPavan Chebbi void bnxt_ptp_reapply_pps(struct bnxt *bp)
3579e518f25SPavan Chebbi {
3589e518f25SPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
3599e518f25SPavan Chebbi 	struct bnxt_pps *pps;
3609e518f25SPavan Chebbi 	u32 pin = 0;
3619e518f25SPavan Chebbi 	int rc;
3629e518f25SPavan Chebbi 
3639e518f25SPavan Chebbi 	if (!ptp || !(bp->fw_cap & BNXT_FW_CAP_PTP_PPS) ||
3649e518f25SPavan Chebbi 	    !(ptp->ptp_info.pin_config))
3659e518f25SPavan Chebbi 		return;
3669e518f25SPavan Chebbi 	pps = &ptp->pps_info;
3679e518f25SPavan Chebbi 	for (pin = 0; pin < BNXT_MAX_TSIO_PINS; pin++) {
3689e518f25SPavan Chebbi 		if (pps->pins[pin].state) {
3699e518f25SPavan Chebbi 			rc = bnxt_ptp_cfg_pin(bp, pin, pps->pins[pin].usage);
3709e518f25SPavan Chebbi 			if (!rc && pps->pins[pin].event)
3719e518f25SPavan Chebbi 				rc = bnxt_ptp_cfg_event(bp,
3729e518f25SPavan Chebbi 							pps->pins[pin].event);
3739e518f25SPavan Chebbi 			if (rc)
3749e518f25SPavan Chebbi 				netdev_err(bp->dev, "1PPS: Failed to configure pin%d\n",
3759e518f25SPavan Chebbi 					   pin);
3769e518f25SPavan Chebbi 		}
3779e518f25SPavan Chebbi 	}
3789e518f25SPavan Chebbi }
3799e518f25SPavan Chebbi 
bnxt_get_target_cycles(struct bnxt_ptp_cfg * ptp,u64 target_ns,u64 * cycles_delta)3809e518f25SPavan Chebbi static int bnxt_get_target_cycles(struct bnxt_ptp_cfg *ptp, u64 target_ns,
3819e518f25SPavan Chebbi 				  u64 *cycles_delta)
3829e518f25SPavan Chebbi {
3839e518f25SPavan Chebbi 	u64 cycles_now;
3849e518f25SPavan Chebbi 	u64 nsec_now, nsec_delta;
3859e518f25SPavan Chebbi 	int rc;
3869e518f25SPavan Chebbi 
3879e518f25SPavan Chebbi 	spin_lock_bh(&ptp->ptp_lock);
3889e518f25SPavan Chebbi 	rc = bnxt_refclk_read(ptp->bp, NULL, &cycles_now);
3899e518f25SPavan Chebbi 	if (rc) {
3909e518f25SPavan Chebbi 		spin_unlock_bh(&ptp->ptp_lock);
3919e518f25SPavan Chebbi 		return rc;
3929e518f25SPavan Chebbi 	}
3939e518f25SPavan Chebbi 	nsec_now = timecounter_cyc2time(&ptp->tc, cycles_now);
3949e518f25SPavan Chebbi 	spin_unlock_bh(&ptp->ptp_lock);
3959e518f25SPavan Chebbi 
3969e518f25SPavan Chebbi 	nsec_delta = target_ns - nsec_now;
3979e518f25SPavan Chebbi 	*cycles_delta = div64_u64(nsec_delta << ptp->cc.shift, ptp->cc.mult);
3989e518f25SPavan Chebbi 	return 0;
3999e518f25SPavan Chebbi }
4009e518f25SPavan Chebbi 
bnxt_ptp_perout_cfg(struct bnxt_ptp_cfg * ptp,struct ptp_clock_request * rq)4019e518f25SPavan Chebbi static int bnxt_ptp_perout_cfg(struct bnxt_ptp_cfg *ptp,
4029e518f25SPavan Chebbi 			       struct ptp_clock_request *rq)
4039e518f25SPavan Chebbi {
404bbf33d1dSEdwin Peer 	struct hwrm_func_ptp_cfg_input *req;
4059e518f25SPavan Chebbi 	struct bnxt *bp = ptp->bp;
4069e518f25SPavan Chebbi 	struct timespec64 ts;
4079e518f25SPavan Chebbi 	u64 target_ns, delta;
4089e518f25SPavan Chebbi 	u16 enables;
4099e518f25SPavan Chebbi 	int rc;
4109e518f25SPavan Chebbi 
4119e518f25SPavan Chebbi 	ts.tv_sec = rq->perout.start.sec;
4129e518f25SPavan Chebbi 	ts.tv_nsec = rq->perout.start.nsec;
4139e518f25SPavan Chebbi 	target_ns = timespec64_to_ns(&ts);
4149e518f25SPavan Chebbi 
4159e518f25SPavan Chebbi 	rc = bnxt_get_target_cycles(ptp, target_ns, &delta);
4169e518f25SPavan Chebbi 	if (rc)
4179e518f25SPavan Chebbi 		return rc;
4189e518f25SPavan Chebbi 
419bbf33d1dSEdwin Peer 	rc = hwrm_req_init(bp, req, HWRM_FUNC_PTP_CFG);
420bbf33d1dSEdwin Peer 	if (rc)
421bbf33d1dSEdwin Peer 		return rc;
4229e518f25SPavan Chebbi 
4239e518f25SPavan Chebbi 	enables = FUNC_PTP_CFG_REQ_ENABLES_PTP_FREQ_ADJ_EXT_PERIOD |
4249e518f25SPavan Chebbi 		  FUNC_PTP_CFG_REQ_ENABLES_PTP_FREQ_ADJ_EXT_UP |
4259e518f25SPavan Chebbi 		  FUNC_PTP_CFG_REQ_ENABLES_PTP_FREQ_ADJ_EXT_PHASE;
426bbf33d1dSEdwin Peer 	req->enables = cpu_to_le16(enables);
427bbf33d1dSEdwin Peer 	req->ptp_pps_event = 0;
428bbf33d1dSEdwin Peer 	req->ptp_freq_adj_dll_source = 0;
429bbf33d1dSEdwin Peer 	req->ptp_freq_adj_dll_phase = 0;
430bbf33d1dSEdwin Peer 	req->ptp_freq_adj_ext_period = cpu_to_le32(NSEC_PER_SEC);
431bbf33d1dSEdwin Peer 	req->ptp_freq_adj_ext_up = 0;
432bbf33d1dSEdwin Peer 	req->ptp_freq_adj_ext_phase_lower = cpu_to_le32(delta);
4339e518f25SPavan Chebbi 
434bbf33d1dSEdwin Peer 	return hwrm_req_send(bp, req);
4359e518f25SPavan Chebbi }
4369e518f25SPavan Chebbi 
bnxt_ptp_enable(struct ptp_clock_info * ptp_info,struct ptp_clock_request * rq,int on)4379e518f25SPavan Chebbi static int bnxt_ptp_enable(struct ptp_clock_info *ptp_info,
438118612d5SMichael Chan 			   struct ptp_clock_request *rq, int on)
439118612d5SMichael Chan {
4409e518f25SPavan Chebbi 	struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
4419e518f25SPavan Chebbi 						ptp_info);
4429e518f25SPavan Chebbi 	struct bnxt *bp = ptp->bp;
443dcf50006SDamien Le Moal 	int pin_id;
4449e518f25SPavan Chebbi 	int rc;
4459e518f25SPavan Chebbi 
4469e518f25SPavan Chebbi 	switch (rq->type) {
4479e518f25SPavan Chebbi 	case PTP_CLK_REQ_EXTTS:
4489e518f25SPavan Chebbi 		/* Configure an External PPS IN */
4499e518f25SPavan Chebbi 		pin_id = ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS,
4509e518f25SPavan Chebbi 				      rq->extts.index);
451dcf50006SDamien Le Moal 		if (!TSIO_PIN_VALID(pin_id))
452dcf50006SDamien Le Moal 			return -EOPNOTSUPP;
4539e518f25SPavan Chebbi 		if (!on)
4549e518f25SPavan Chebbi 			break;
4559e518f25SPavan Chebbi 		rc = bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_PPS_IN);
4569e518f25SPavan Chebbi 		if (rc)
4579e518f25SPavan Chebbi 			return rc;
4589e518f25SPavan Chebbi 		rc = bnxt_ptp_cfg_event(bp, BNXT_PPS_EVENT_EXTERNAL);
4599e518f25SPavan Chebbi 		if (!rc)
4609e518f25SPavan Chebbi 			ptp->pps_info.pins[pin_id].event = BNXT_PPS_EVENT_EXTERNAL;
4619e518f25SPavan Chebbi 		return rc;
4629e518f25SPavan Chebbi 	case PTP_CLK_REQ_PEROUT:
4639e518f25SPavan Chebbi 		/* Configure a Periodic PPS OUT */
4649e518f25SPavan Chebbi 		pin_id = ptp_find_pin(ptp->ptp_clock, PTP_PF_PEROUT,
4659e518f25SPavan Chebbi 				      rq->perout.index);
466dcf50006SDamien Le Moal 		if (!TSIO_PIN_VALID(pin_id))
467dcf50006SDamien Le Moal 			return -EOPNOTSUPP;
4689e518f25SPavan Chebbi 		if (!on)
4699e518f25SPavan Chebbi 			break;
4709e518f25SPavan Chebbi 
4719e518f25SPavan Chebbi 		rc = bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_PPS_OUT);
4729e518f25SPavan Chebbi 		if (!rc)
4739e518f25SPavan Chebbi 			rc = bnxt_ptp_perout_cfg(ptp, rq);
4749e518f25SPavan Chebbi 
4759e518f25SPavan Chebbi 		return rc;
4769e518f25SPavan Chebbi 	case PTP_CLK_REQ_PPS:
4779e518f25SPavan Chebbi 		/* Configure PHC PPS IN */
4789e518f25SPavan Chebbi 		rc = bnxt_ptp_cfg_pin(bp, 0, BNXT_PPS_PIN_PPS_IN);
4799e518f25SPavan Chebbi 		if (rc)
4809e518f25SPavan Chebbi 			return rc;
4819e518f25SPavan Chebbi 		rc = bnxt_ptp_cfg_event(bp, BNXT_PPS_EVENT_INTERNAL);
4829e518f25SPavan Chebbi 		if (!rc)
4839e518f25SPavan Chebbi 			ptp->pps_info.pins[0].event = BNXT_PPS_EVENT_INTERNAL;
4849e518f25SPavan Chebbi 		return rc;
4859e518f25SPavan Chebbi 	default:
4869e518f25SPavan Chebbi 		netdev_err(ptp->bp->dev, "Unrecognized PIN function\n");
487118612d5SMichael Chan 		return -EOPNOTSUPP;
488118612d5SMichael Chan 	}
489118612d5SMichael Chan 
4909e518f25SPavan Chebbi 	return bnxt_ptp_cfg_pin(bp, pin_id, BNXT_PPS_PIN_NONE);
4919e518f25SPavan Chebbi }
4929e518f25SPavan Chebbi 
bnxt_hwrm_ptp_cfg(struct bnxt * bp)493118612d5SMichael Chan static int bnxt_hwrm_ptp_cfg(struct bnxt *bp)
494118612d5SMichael Chan {
495118612d5SMichael Chan 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
496118612d5SMichael Chan 	u32 flags = 0;
49711862689SPavan Chebbi 	int rc = 0;
498118612d5SMichael Chan 
49911862689SPavan Chebbi 	switch (ptp->rx_filter) {
50066ed81dcSPavan Chebbi 	case HWTSTAMP_FILTER_ALL:
50166ed81dcSPavan Chebbi 		flags = PORT_MAC_CFG_REQ_FLAGS_ALL_RX_TS_CAPTURE_ENABLE;
50266ed81dcSPavan Chebbi 		break;
50311862689SPavan Chebbi 	case HWTSTAMP_FILTER_NONE:
50411862689SPavan Chebbi 		flags = PORT_MAC_CFG_REQ_FLAGS_PTP_RX_TS_CAPTURE_DISABLE;
50566ed81dcSPavan Chebbi 		if (bp->fw_cap & BNXT_FW_CAP_RX_ALL_PKT_TS)
50666ed81dcSPavan Chebbi 			flags |= PORT_MAC_CFG_REQ_FLAGS_ALL_RX_TS_CAPTURE_DISABLE;
50711862689SPavan Chebbi 		break;
50811862689SPavan Chebbi 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
50911862689SPavan Chebbi 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
51011862689SPavan Chebbi 	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
51111862689SPavan Chebbi 		flags = PORT_MAC_CFG_REQ_FLAGS_PTP_RX_TS_CAPTURE_ENABLE;
51211862689SPavan Chebbi 		break;
51311862689SPavan Chebbi 	}
514bbf33d1dSEdwin Peer 
515118612d5SMichael Chan 	if (ptp->tx_tstamp_en)
516118612d5SMichael Chan 		flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_TX_TS_CAPTURE_ENABLE;
517118612d5SMichael Chan 	else
518118612d5SMichael Chan 		flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_TX_TS_CAPTURE_DISABLE;
519118612d5SMichael Chan 
52011862689SPavan Chebbi 	ptp->tstamp_filters = flags;
52111862689SPavan Chebbi 
52211862689SPavan Chebbi 	if (netif_running(bp->dev)) {
5238db3d514SVadim Fedorenko 		if (ptp->rx_filter == HWTSTAMP_FILTER_ALL) {
524*909f5a48SKalesh AP 			bnxt_close_nic(bp, false, false);
52511862689SPavan Chebbi 			rc = bnxt_open_nic(bp, false, false);
5268db3d514SVadim Fedorenko 		} else {
5278db3d514SVadim Fedorenko 			bnxt_ptp_cfg_tstamp_filters(bp);
5288db3d514SVadim Fedorenko 		}
52911862689SPavan Chebbi 		if (!rc && !ptp->tstamp_filters)
53011862689SPavan Chebbi 			rc = -EIO;
53111862689SPavan Chebbi 	}
53211862689SPavan Chebbi 
53311862689SPavan Chebbi 	return rc;
534118612d5SMichael Chan }
535118612d5SMichael Chan 
bnxt_hwtstamp_set(struct net_device * dev,struct ifreq * ifr)536118612d5SMichael Chan int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
537118612d5SMichael Chan {
538118612d5SMichael Chan 	struct bnxt *bp = netdev_priv(dev);
539118612d5SMichael Chan 	struct hwtstamp_config stmpconf;
540118612d5SMichael Chan 	struct bnxt_ptp_cfg *ptp;
541118612d5SMichael Chan 	u16 old_rxctl;
542118612d5SMichael Chan 	int old_rx_filter, rc;
543118612d5SMichael Chan 	u8 old_tx_tstamp_en;
544118612d5SMichael Chan 
545118612d5SMichael Chan 	ptp = bp->ptp_cfg;
546118612d5SMichael Chan 	if (!ptp)
547118612d5SMichael Chan 		return -EOPNOTSUPP;
548118612d5SMichael Chan 
549118612d5SMichael Chan 	if (copy_from_user(&stmpconf, ifr->ifr_data, sizeof(stmpconf)))
550118612d5SMichael Chan 		return -EFAULT;
551118612d5SMichael Chan 
552118612d5SMichael Chan 	if (stmpconf.tx_type != HWTSTAMP_TX_ON &&
553118612d5SMichael Chan 	    stmpconf.tx_type != HWTSTAMP_TX_OFF)
554118612d5SMichael Chan 		return -ERANGE;
555118612d5SMichael Chan 
556118612d5SMichael Chan 	old_rx_filter = ptp->rx_filter;
557118612d5SMichael Chan 	old_rxctl = ptp->rxctl;
558118612d5SMichael Chan 	old_tx_tstamp_en = ptp->tx_tstamp_en;
559118612d5SMichael Chan 	switch (stmpconf.rx_filter) {
560118612d5SMichael Chan 	case HWTSTAMP_FILTER_NONE:
561118612d5SMichael Chan 		ptp->rxctl = 0;
562118612d5SMichael Chan 		ptp->rx_filter = HWTSTAMP_FILTER_NONE;
563118612d5SMichael Chan 		break;
56466ed81dcSPavan Chebbi 	case HWTSTAMP_FILTER_ALL:
56566ed81dcSPavan Chebbi 		if (bp->fw_cap & BNXT_FW_CAP_RX_ALL_PKT_TS) {
56666ed81dcSPavan Chebbi 			ptp->rx_filter = HWTSTAMP_FILTER_ALL;
56766ed81dcSPavan Chebbi 			break;
56866ed81dcSPavan Chebbi 		}
56966ed81dcSPavan Chebbi 		return -EOPNOTSUPP;
570118612d5SMichael Chan 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
571118612d5SMichael Chan 	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
572118612d5SMichael Chan 	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
573118612d5SMichael Chan 		ptp->rxctl = BNXT_PTP_MSG_EVENTS;
574118612d5SMichael Chan 		ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
575118612d5SMichael Chan 		break;
576118612d5SMichael Chan 	case HWTSTAMP_FILTER_PTP_V2_SYNC:
577118612d5SMichael Chan 	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
578118612d5SMichael Chan 	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
579118612d5SMichael Chan 		ptp->rxctl = BNXT_PTP_MSG_SYNC;
580118612d5SMichael Chan 		ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC;
581118612d5SMichael Chan 		break;
582118612d5SMichael Chan 	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
583118612d5SMichael Chan 	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
584118612d5SMichael Chan 	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
585118612d5SMichael Chan 		ptp->rxctl = BNXT_PTP_MSG_DELAY_REQ;
586118612d5SMichael Chan 		ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ;
587118612d5SMichael Chan 		break;
588118612d5SMichael Chan 	default:
589118612d5SMichael Chan 		return -ERANGE;
590118612d5SMichael Chan 	}
591118612d5SMichael Chan 
592118612d5SMichael Chan 	if (stmpconf.tx_type == HWTSTAMP_TX_ON)
593118612d5SMichael Chan 		ptp->tx_tstamp_en = 1;
594118612d5SMichael Chan 	else
595118612d5SMichael Chan 		ptp->tx_tstamp_en = 0;
596118612d5SMichael Chan 
597118612d5SMichael Chan 	rc = bnxt_hwrm_ptp_cfg(bp);
598118612d5SMichael Chan 	if (rc)
599118612d5SMichael Chan 		goto ts_set_err;
600118612d5SMichael Chan 
601118612d5SMichael Chan 	stmpconf.rx_filter = ptp->rx_filter;
602118612d5SMichael Chan 	return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ?
603118612d5SMichael Chan 		-EFAULT : 0;
604118612d5SMichael Chan 
605118612d5SMichael Chan ts_set_err:
606118612d5SMichael Chan 	ptp->rx_filter = old_rx_filter;
607118612d5SMichael Chan 	ptp->rxctl = old_rxctl;
608118612d5SMichael Chan 	ptp->tx_tstamp_en = old_tx_tstamp_en;
609118612d5SMichael Chan 	return rc;
610118612d5SMichael Chan }
611118612d5SMichael Chan 
bnxt_hwtstamp_get(struct net_device * dev,struct ifreq * ifr)612118612d5SMichael Chan int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
613118612d5SMichael Chan {
614118612d5SMichael Chan 	struct bnxt *bp = netdev_priv(dev);
615118612d5SMichael Chan 	struct hwtstamp_config stmpconf;
616118612d5SMichael Chan 	struct bnxt_ptp_cfg *ptp;
617118612d5SMichael Chan 
618118612d5SMichael Chan 	ptp = bp->ptp_cfg;
619118612d5SMichael Chan 	if (!ptp)
620118612d5SMichael Chan 		return -EOPNOTSUPP;
621118612d5SMichael Chan 
622118612d5SMichael Chan 	stmpconf.flags = 0;
623118612d5SMichael Chan 	stmpconf.tx_type = ptp->tx_tstamp_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
624118612d5SMichael Chan 
625118612d5SMichael Chan 	stmpconf.rx_filter = ptp->rx_filter;
626118612d5SMichael Chan 	return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ?
627118612d5SMichael Chan 		-EFAULT : 0;
628118612d5SMichael Chan }
629118612d5SMichael Chan 
bnxt_map_regs(struct bnxt * bp,u32 * reg_arr,int count,int reg_win)630118612d5SMichael Chan static int bnxt_map_regs(struct bnxt *bp, u32 *reg_arr, int count, int reg_win)
631118612d5SMichael Chan {
632118612d5SMichael Chan 	u32 reg_base = *reg_arr & BNXT_GRC_BASE_MASK;
633118612d5SMichael Chan 	u32 win_off;
634118612d5SMichael Chan 	int i;
635118612d5SMichael Chan 
636118612d5SMichael Chan 	for (i = 0; i < count; i++) {
637118612d5SMichael Chan 		if ((reg_arr[i] & BNXT_GRC_BASE_MASK) != reg_base)
638118612d5SMichael Chan 			return -ERANGE;
639118612d5SMichael Chan 	}
640118612d5SMichael Chan 	win_off = BNXT_GRCPF_REG_WINDOW_BASE_OUT + (reg_win - 1) * 4;
641118612d5SMichael Chan 	writel(reg_base, bp->bar0 + win_off);
642118612d5SMichael Chan 	return 0;
643118612d5SMichael Chan }
644118612d5SMichael Chan 
bnxt_map_ptp_regs(struct bnxt * bp)645118612d5SMichael Chan static int bnxt_map_ptp_regs(struct bnxt *bp)
646118612d5SMichael Chan {
647118612d5SMichael Chan 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
648118612d5SMichael Chan 	u32 *reg_arr;
649118612d5SMichael Chan 	int rc, i;
650118612d5SMichael Chan 
651118612d5SMichael Chan 	reg_arr = ptp->refclk_regs;
652118612d5SMichael Chan 	if (bp->flags & BNXT_FLAG_CHIP_P5) {
653118612d5SMichael Chan 		rc = bnxt_map_regs(bp, reg_arr, 2, BNXT_PTP_GRC_WIN);
654118612d5SMichael Chan 		if (rc)
655118612d5SMichael Chan 			return rc;
656118612d5SMichael Chan 		for (i = 0; i < 2; i++)
657118612d5SMichael Chan 			ptp->refclk_mapped_regs[i] = BNXT_PTP_GRC_WIN_BASE +
658118612d5SMichael Chan 				(ptp->refclk_regs[i] & BNXT_GRC_OFFSET_MASK);
659118612d5SMichael Chan 		return 0;
660118612d5SMichael Chan 	}
661118612d5SMichael Chan 	return -ENODEV;
662118612d5SMichael Chan }
663118612d5SMichael Chan 
bnxt_unmap_ptp_regs(struct bnxt * bp)664118612d5SMichael Chan static void bnxt_unmap_ptp_regs(struct bnxt *bp)
665118612d5SMichael Chan {
666118612d5SMichael Chan 	writel(0, bp->bar0 + BNXT_GRCPF_REG_WINDOW_BASE_OUT +
667118612d5SMichael Chan 		  (BNXT_PTP_GRC_WIN - 1) * 4);
668118612d5SMichael Chan }
669118612d5SMichael Chan 
bnxt_cc_read(const struct cyclecounter * cc)670118612d5SMichael Chan static u64 bnxt_cc_read(const struct cyclecounter *cc)
671118612d5SMichael Chan {
672118612d5SMichael Chan 	struct bnxt_ptp_cfg *ptp = container_of(cc, struct bnxt_ptp_cfg, cc);
67330e96f48SMichael Chan 	u64 ns = 0;
674118612d5SMichael Chan 
67530e96f48SMichael Chan 	bnxt_refclk_read(ptp->bp, NULL, &ns);
67630e96f48SMichael Chan 	return ns;
677118612d5SMichael Chan }
678118612d5SMichael Chan 
bnxt_stamp_tx_skb(struct bnxt * bp,struct sk_buff * skb)67983bb623cSPavan Chebbi static void bnxt_stamp_tx_skb(struct bnxt *bp, struct sk_buff *skb)
68083bb623cSPavan Chebbi {
68183bb623cSPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
68283bb623cSPavan Chebbi 	struct skb_shared_hwtstamps timestamp;
68383bb623cSPavan Chebbi 	u64 ts = 0, ns = 0;
68483bb623cSPavan Chebbi 	int rc;
68583bb623cSPavan Chebbi 
68683bb623cSPavan Chebbi 	rc = bnxt_hwrm_port_ts_query(bp, PORT_TS_QUERY_REQ_FLAGS_PATH_TX, &ts);
68783bb623cSPavan Chebbi 	if (!rc) {
68883bb623cSPavan Chebbi 		memset(&timestamp, 0, sizeof(timestamp));
68983bb623cSPavan Chebbi 		spin_lock_bh(&ptp->ptp_lock);
69083bb623cSPavan Chebbi 		ns = timecounter_cyc2time(&ptp->tc, ts);
69183bb623cSPavan Chebbi 		spin_unlock_bh(&ptp->ptp_lock);
69283bb623cSPavan Chebbi 		timestamp.hwtstamp = ns_to_ktime(ns);
69383bb623cSPavan Chebbi 		skb_tstamp_tx(ptp->tx_skb, &timestamp);
69483bb623cSPavan Chebbi 	} else {
69583bb623cSPavan Chebbi 		netdev_err(bp->dev, "TS query for TX timer failed rc = %x\n",
69683bb623cSPavan Chebbi 			   rc);
69783bb623cSPavan Chebbi 	}
69883bb623cSPavan Chebbi 
69983bb623cSPavan Chebbi 	dev_kfree_skb_any(ptp->tx_skb);
70083bb623cSPavan Chebbi 	ptp->tx_skb = NULL;
70183bb623cSPavan Chebbi 	atomic_inc(&ptp->tx_avail);
70283bb623cSPavan Chebbi }
70383bb623cSPavan Chebbi 
bnxt_ptp_ts_aux_work(struct ptp_clock_info * ptp_info)704390862f4SPavan Chebbi static long bnxt_ptp_ts_aux_work(struct ptp_clock_info *ptp_info)
705390862f4SPavan Chebbi {
706390862f4SPavan Chebbi 	struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
707390862f4SPavan Chebbi 						ptp_info);
70883bb623cSPavan Chebbi 	unsigned long now = jiffies;
709390862f4SPavan Chebbi 	struct bnxt *bp = ptp->bp;
710390862f4SPavan Chebbi 
71183bb623cSPavan Chebbi 	if (ptp->tx_skb)
71283bb623cSPavan Chebbi 		bnxt_stamp_tx_skb(bp, ptp->tx_skb);
71383bb623cSPavan Chebbi 
71483bb623cSPavan Chebbi 	if (!time_after_eq(now, ptp->next_period))
71583bb623cSPavan Chebbi 		return ptp->next_period - now;
71683bb623cSPavan Chebbi 
717390862f4SPavan Chebbi 	bnxt_ptp_get_current_time(bp);
71883bb623cSPavan Chebbi 	ptp->next_period = now + HZ;
71989bc7f45SMichael Chan 	if (time_after_eq(now, ptp->next_overflow_check)) {
72089bc7f45SMichael Chan 		spin_lock_bh(&ptp->ptp_lock);
72189bc7f45SMichael Chan 		timecounter_read(&ptp->tc);
72289bc7f45SMichael Chan 		spin_unlock_bh(&ptp->ptp_lock);
72389bc7f45SMichael Chan 		ptp->next_overflow_check = now + BNXT_PHC_OVERFLOW_PERIOD;
72489bc7f45SMichael Chan 	}
725390862f4SPavan Chebbi 	return HZ;
726390862f4SPavan Chebbi }
727390862f4SPavan Chebbi 
bnxt_get_tx_ts_p5(struct bnxt * bp,struct sk_buff * skb)72883bb623cSPavan Chebbi int bnxt_get_tx_ts_p5(struct bnxt *bp, struct sk_buff *skb)
72983bb623cSPavan Chebbi {
73083bb623cSPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
73183bb623cSPavan Chebbi 
73283bb623cSPavan Chebbi 	if (ptp->tx_skb) {
73383bb623cSPavan Chebbi 		netdev_err(bp->dev, "deferring skb:one SKB is still outstanding\n");
73483bb623cSPavan Chebbi 		return -EBUSY;
73583bb623cSPavan Chebbi 	}
73683bb623cSPavan Chebbi 	ptp->tx_skb = skb;
73783bb623cSPavan Chebbi 	ptp_schedule_worker(ptp->ptp_clock, 0);
73883bb623cSPavan Chebbi 	return 0;
73983bb623cSPavan Chebbi }
74083bb623cSPavan Chebbi 
bnxt_get_rx_ts_p5(struct bnxt * bp,u64 * ts,u32 pkt_ts)7417f5515d1SPavan Chebbi int bnxt_get_rx_ts_p5(struct bnxt *bp, u64 *ts, u32 pkt_ts)
7427f5515d1SPavan Chebbi {
7437f5515d1SPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
7447f5515d1SPavan Chebbi 	u64 time;
7457f5515d1SPavan Chebbi 
7467f5515d1SPavan Chebbi 	if (!ptp)
7477f5515d1SPavan Chebbi 		return -ENODEV;
7487f5515d1SPavan Chebbi 
7497f5515d1SPavan Chebbi 	BNXT_READ_TIME64(ptp, time, ptp->old_time);
7507f5515d1SPavan Chebbi 	*ts = (time & BNXT_HI_TIMER_MASK) | pkt_ts;
7517f5515d1SPavan Chebbi 	if (pkt_ts < (time & BNXT_LO_TIMER_MASK))
7527f5515d1SPavan Chebbi 		*ts += BNXT_LO_TIMER_MASK + 1;
7537f5515d1SPavan Chebbi 
7547f5515d1SPavan Chebbi 	return 0;
7557f5515d1SPavan Chebbi }
7567f5515d1SPavan Chebbi 
757118612d5SMichael Chan static const struct ptp_clock_info bnxt_ptp_caps = {
758118612d5SMichael Chan 	.owner		= THIS_MODULE,
759118612d5SMichael Chan 	.name		= "bnxt clock",
760118612d5SMichael Chan 	.max_adj	= BNXT_MAX_PHC_DRIFT,
761118612d5SMichael Chan 	.n_alarm	= 0,
762118612d5SMichael Chan 	.n_ext_ts	= 0,
763118612d5SMichael Chan 	.n_per_out	= 0,
764118612d5SMichael Chan 	.n_pins		= 0,
765118612d5SMichael Chan 	.pps		= 0,
766a29c132fSJacob Keller 	.adjfine	= bnxt_ptp_adjfine,
767118612d5SMichael Chan 	.adjtime	= bnxt_ptp_adjtime,
768390862f4SPavan Chebbi 	.do_aux_work	= bnxt_ptp_ts_aux_work,
769118612d5SMichael Chan 	.gettimex64	= bnxt_ptp_gettimex,
770118612d5SMichael Chan 	.settime64	= bnxt_ptp_settime,
771118612d5SMichael Chan 	.enable		= bnxt_ptp_enable,
772118612d5SMichael Chan };
773118612d5SMichael Chan 
bnxt_ptp_verify(struct ptp_clock_info * ptp_info,unsigned int pin,enum ptp_pin_function func,unsigned int chan)774caf3eedbSPavan Chebbi static int bnxt_ptp_verify(struct ptp_clock_info *ptp_info, unsigned int pin,
775caf3eedbSPavan Chebbi 			   enum ptp_pin_function func, unsigned int chan)
776caf3eedbSPavan Chebbi {
777caf3eedbSPavan Chebbi 	struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
778caf3eedbSPavan Chebbi 						ptp_info);
779caf3eedbSPavan Chebbi 	/* Allow only PPS pin function configuration */
780caf3eedbSPavan Chebbi 	if (ptp->pps_info.pins[pin].usage <= BNXT_PPS_PIN_PPS_OUT &&
781caf3eedbSPavan Chebbi 	    func != PTP_PF_PHYSYNC)
782caf3eedbSPavan Chebbi 		return 0;
783caf3eedbSPavan Chebbi 	else
784caf3eedbSPavan Chebbi 		return -EOPNOTSUPP;
785caf3eedbSPavan Chebbi }
786caf3eedbSPavan Chebbi 
bnxt_ptp_pps_init(struct bnxt * bp)787caf3eedbSPavan Chebbi static int bnxt_ptp_pps_init(struct bnxt *bp)
788caf3eedbSPavan Chebbi {
789bbf33d1dSEdwin Peer 	struct hwrm_func_ptp_pin_qcfg_output *resp;
790bbf33d1dSEdwin Peer 	struct hwrm_func_ptp_pin_qcfg_input *req;
791caf3eedbSPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
792caf3eedbSPavan Chebbi 	struct ptp_clock_info *ptp_info;
793caf3eedbSPavan Chebbi 	struct bnxt_pps *pps_info;
794caf3eedbSPavan Chebbi 	u8 *pin_usg;
795caf3eedbSPavan Chebbi 	u32 i, rc;
796caf3eedbSPavan Chebbi 
797caf3eedbSPavan Chebbi 	/* Query current/default PIN CFG */
798bbf33d1dSEdwin Peer 	rc = hwrm_req_init(bp, req, HWRM_FUNC_PTP_PIN_QCFG);
799bbf33d1dSEdwin Peer 	if (rc)
800bbf33d1dSEdwin Peer 		return rc;
801caf3eedbSPavan Chebbi 
802bbf33d1dSEdwin Peer 	resp = hwrm_req_hold(bp, req);
803bbf33d1dSEdwin Peer 	rc = hwrm_req_send(bp, req);
804bbf33d1dSEdwin Peer 	if (rc || !resp->num_pins) {
805bbf33d1dSEdwin Peer 		hwrm_req_drop(bp, req);
806caf3eedbSPavan Chebbi 		return -EOPNOTSUPP;
807bbf33d1dSEdwin Peer 	}
808caf3eedbSPavan Chebbi 
809caf3eedbSPavan Chebbi 	ptp_info = &ptp->ptp_info;
810caf3eedbSPavan Chebbi 	pps_info = &ptp->pps_info;
811caf3eedbSPavan Chebbi 	pps_info->num_pins = resp->num_pins;
812caf3eedbSPavan Chebbi 	ptp_info->n_pins = pps_info->num_pins;
813caf3eedbSPavan Chebbi 	ptp_info->pin_config = kcalloc(ptp_info->n_pins,
814caf3eedbSPavan Chebbi 				       sizeof(*ptp_info->pin_config),
815caf3eedbSPavan Chebbi 				       GFP_KERNEL);
816bbf33d1dSEdwin Peer 	if (!ptp_info->pin_config) {
817bbf33d1dSEdwin Peer 		hwrm_req_drop(bp, req);
818caf3eedbSPavan Chebbi 		return -ENOMEM;
819bbf33d1dSEdwin Peer 	}
820caf3eedbSPavan Chebbi 
821caf3eedbSPavan Chebbi 	/* Report the TSIO capability to kernel */
822caf3eedbSPavan Chebbi 	pin_usg = &resp->pin0_usage;
823caf3eedbSPavan Chebbi 	for (i = 0; i < pps_info->num_pins; i++, pin_usg++) {
824caf3eedbSPavan Chebbi 		snprintf(ptp_info->pin_config[i].name,
825caf3eedbSPavan Chebbi 			 sizeof(ptp_info->pin_config[i].name), "bnxt_pps%d", i);
826caf3eedbSPavan Chebbi 		ptp_info->pin_config[i].index = i;
827caf3eedbSPavan Chebbi 		ptp_info->pin_config[i].chan = i;
828caf3eedbSPavan Chebbi 		if (*pin_usg == BNXT_PPS_PIN_PPS_IN)
829caf3eedbSPavan Chebbi 			ptp_info->pin_config[i].func = PTP_PF_EXTTS;
830caf3eedbSPavan Chebbi 		else if (*pin_usg == BNXT_PPS_PIN_PPS_OUT)
831caf3eedbSPavan Chebbi 			ptp_info->pin_config[i].func = PTP_PF_PEROUT;
832caf3eedbSPavan Chebbi 		else
833caf3eedbSPavan Chebbi 			ptp_info->pin_config[i].func = PTP_PF_NONE;
834caf3eedbSPavan Chebbi 
835caf3eedbSPavan Chebbi 		pps_info->pins[i].usage = *pin_usg;
836caf3eedbSPavan Chebbi 	}
837bbf33d1dSEdwin Peer 	hwrm_req_drop(bp, req);
838caf3eedbSPavan Chebbi 
839caf3eedbSPavan Chebbi 	/* Only 1 each of ext_ts and per_out pins is available in HW */
840caf3eedbSPavan Chebbi 	ptp_info->n_ext_ts = 1;
841caf3eedbSPavan Chebbi 	ptp_info->n_per_out = 1;
842caf3eedbSPavan Chebbi 	ptp_info->pps = 1;
843caf3eedbSPavan Chebbi 	ptp_info->verify = bnxt_ptp_verify;
844caf3eedbSPavan Chebbi 
845caf3eedbSPavan Chebbi 	return 0;
846caf3eedbSPavan Chebbi }
847caf3eedbSPavan Chebbi 
bnxt_pps_config_ok(struct bnxt * bp)848caf3eedbSPavan Chebbi static bool bnxt_pps_config_ok(struct bnxt *bp)
849caf3eedbSPavan Chebbi {
850caf3eedbSPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
851caf3eedbSPavan Chebbi 
852caf3eedbSPavan Chebbi 	return !(bp->fw_cap & BNXT_FW_CAP_PTP_PPS) == !ptp->ptp_info.pin_config;
853caf3eedbSPavan Chebbi }
854caf3eedbSPavan Chebbi 
bnxt_ptp_timecounter_init(struct bnxt * bp,bool init_tc)855740c342eSPavan Chebbi static void bnxt_ptp_timecounter_init(struct bnxt *bp, bool init_tc)
856740c342eSPavan Chebbi {
857740c342eSPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
858740c342eSPavan Chebbi 
859740c342eSPavan Chebbi 	if (!ptp->ptp_clock) {
860740c342eSPavan Chebbi 		memset(&ptp->cc, 0, sizeof(ptp->cc));
861740c342eSPavan Chebbi 		ptp->cc.read = bnxt_cc_read;
862740c342eSPavan Chebbi 		ptp->cc.mask = CYCLECOUNTER_MASK(48);
863a02c3313SPavan Chebbi 		if (BNXT_MH(bp)) {
864a02c3313SPavan Chebbi 			/* Use timecounter based non-real time mode */
86585036aeeSPavan Chebbi 			ptp->cc.shift = BNXT_CYCLES_SHIFT;
86685036aeeSPavan Chebbi 			ptp->cc.mult = clocksource_khz2mult(BNXT_DEVCLK_FREQ, ptp->cc.shift);
86785036aeeSPavan Chebbi 			ptp->cmult = ptp->cc.mult;
868a02c3313SPavan Chebbi 		} else {
869a02c3313SPavan Chebbi 			ptp->cc.shift = 0;
870a02c3313SPavan Chebbi 			ptp->cc.mult = 1;
871a02c3313SPavan Chebbi 		}
872740c342eSPavan Chebbi 		ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD;
873740c342eSPavan Chebbi 	}
874740c342eSPavan Chebbi 	if (init_tc)
875740c342eSPavan Chebbi 		timecounter_init(&ptp->tc, &ptp->cc, ktime_to_ns(ktime_get_real()));
876740c342eSPavan Chebbi }
877740c342eSPavan Chebbi 
87824ac1ecdSPavan Chebbi /* Caller holds ptp_lock */
bnxt_ptp_rtc_timecounter_init(struct bnxt_ptp_cfg * ptp,u64 ns)87924ac1ecdSPavan Chebbi void bnxt_ptp_rtc_timecounter_init(struct bnxt_ptp_cfg *ptp, u64 ns)
88024ac1ecdSPavan Chebbi {
88124ac1ecdSPavan Chebbi 	timecounter_init(&ptp->tc, &ptp->cc, ns);
88224ac1ecdSPavan Chebbi 	/* For RTC, cycle_last must be in sync with the timecounter value. */
88324ac1ecdSPavan Chebbi 	ptp->tc.cycle_last = ns & ptp->cc.mask;
88424ac1ecdSPavan Chebbi }
88524ac1ecdSPavan Chebbi 
bnxt_ptp_init_rtc(struct bnxt * bp,bool phc_cfg)88624ac1ecdSPavan Chebbi int bnxt_ptp_init_rtc(struct bnxt *bp, bool phc_cfg)
88724ac1ecdSPavan Chebbi {
88824ac1ecdSPavan Chebbi 	struct timespec64 tsp;
88924ac1ecdSPavan Chebbi 	u64 ns;
89024ac1ecdSPavan Chebbi 	int rc;
89124ac1ecdSPavan Chebbi 
892131db499SVadim Fedorenko 	if (!bp->ptp_cfg || !BNXT_PTP_USE_RTC(bp))
89324ac1ecdSPavan Chebbi 		return -ENODEV;
89424ac1ecdSPavan Chebbi 
89524ac1ecdSPavan Chebbi 	if (!phc_cfg) {
89624ac1ecdSPavan Chebbi 		ktime_get_real_ts64(&tsp);
89724ac1ecdSPavan Chebbi 		ns = timespec64_to_ns(&tsp);
89824ac1ecdSPavan Chebbi 		rc = bnxt_ptp_cfg_settime(bp, ns);
89924ac1ecdSPavan Chebbi 		if (rc)
90024ac1ecdSPavan Chebbi 			return rc;
90124ac1ecdSPavan Chebbi 	} else {
90224ac1ecdSPavan Chebbi 		rc = bnxt_hwrm_port_ts_query(bp, PORT_TS_QUERY_REQ_FLAGS_CURRENT_TIME, &ns);
90324ac1ecdSPavan Chebbi 		if (rc)
90424ac1ecdSPavan Chebbi 			return rc;
90524ac1ecdSPavan Chebbi 	}
90624ac1ecdSPavan Chebbi 	spin_lock_bh(&bp->ptp_cfg->ptp_lock);
90724ac1ecdSPavan Chebbi 	bnxt_ptp_rtc_timecounter_init(bp->ptp_cfg, ns);
90824ac1ecdSPavan Chebbi 	spin_unlock_bh(&bp->ptp_cfg->ptp_lock);
90924ac1ecdSPavan Chebbi 
91024ac1ecdSPavan Chebbi 	return 0;
91124ac1ecdSPavan Chebbi }
91224ac1ecdSPavan Chebbi 
bnxt_ptp_free(struct bnxt * bp)913740c342eSPavan Chebbi static void bnxt_ptp_free(struct bnxt *bp)
914740c342eSPavan Chebbi {
915740c342eSPavan Chebbi 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
916740c342eSPavan Chebbi 
917740c342eSPavan Chebbi 	if (ptp->ptp_clock) {
918740c342eSPavan Chebbi 		ptp_clock_unregister(ptp->ptp_clock);
919740c342eSPavan Chebbi 		ptp->ptp_clock = NULL;
920740c342eSPavan Chebbi 		kfree(ptp->ptp_info.pin_config);
921740c342eSPavan Chebbi 		ptp->ptp_info.pin_config = NULL;
922740c342eSPavan Chebbi 	}
923740c342eSPavan Chebbi }
924740c342eSPavan Chebbi 
bnxt_ptp_init(struct bnxt * bp,bool phc_cfg)92524ac1ecdSPavan Chebbi int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg)
926118612d5SMichael Chan {
927118612d5SMichael Chan 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
928118612d5SMichael Chan 	int rc;
929118612d5SMichael Chan 
930118612d5SMichael Chan 	if (!ptp)
931118612d5SMichael Chan 		return 0;
932118612d5SMichael Chan 
933118612d5SMichael Chan 	rc = bnxt_map_ptp_regs(bp);
934118612d5SMichael Chan 	if (rc)
935118612d5SMichael Chan 		return rc;
936118612d5SMichael Chan 
937caf3eedbSPavan Chebbi 	if (ptp->ptp_clock && bnxt_pps_config_ok(bp))
938a521c8a0SMichael Chan 		return 0;
939a521c8a0SMichael Chan 
940740c342eSPavan Chebbi 	bnxt_ptp_free(bp);
941740c342eSPavan Chebbi 
942118612d5SMichael Chan 	atomic_set(&ptp->tx_avail, BNXT_MAX_TX_TS);
943118612d5SMichael Chan 	spin_lock_init(&ptp->ptp_lock);
944118612d5SMichael Chan 
945131db499SVadim Fedorenko 	if (BNXT_PTP_USE_RTC(bp)) {
9462b156fb5SMichael Chan 		bnxt_ptp_timecounter_init(bp, false);
9472b156fb5SMichael Chan 		rc = bnxt_ptp_init_rtc(bp, phc_cfg);
9482b156fb5SMichael Chan 		if (rc)
9492b156fb5SMichael Chan 			goto out;
9502b156fb5SMichael Chan 	} else {
951740c342eSPavan Chebbi 		bnxt_ptp_timecounter_init(bp, true);
952131db499SVadim Fedorenko 		bnxt_ptp_adjfine_rtc(bp, 0);
9532b156fb5SMichael Chan 	}
954319a7827SPavan Chebbi 	bnxt_hwrm_func_drv_rgtr(bp, NULL, 0, true);
955118612d5SMichael Chan 
956118612d5SMichael Chan 	ptp->ptp_info = bnxt_ptp_caps;
957caf3eedbSPavan Chebbi 	if ((bp->fw_cap & BNXT_FW_CAP_PTP_PPS)) {
958caf3eedbSPavan Chebbi 		if (bnxt_ptp_pps_init(bp))
959caf3eedbSPavan Chebbi 			netdev_err(bp->dev, "1pps not initialized, continuing without 1pps support\n");
960caf3eedbSPavan Chebbi 	}
961118612d5SMichael Chan 	ptp->ptp_clock = ptp_clock_register(&ptp->ptp_info, &bp->pdev->dev);
962118612d5SMichael Chan 	if (IS_ERR(ptp->ptp_clock)) {
963118612d5SMichael Chan 		int err = PTR_ERR(ptp->ptp_clock);
964118612d5SMichael Chan 
965118612d5SMichael Chan 		ptp->ptp_clock = NULL;
96624ac1ecdSPavan Chebbi 		rc = err;
96724ac1ecdSPavan Chebbi 		goto out;
968118612d5SMichael Chan 	}
969d7859afbSMichael Chan 	if (bp->flags & BNXT_FLAG_CHIP_P5) {
970d7859afbSMichael Chan 		spin_lock_bh(&ptp->ptp_lock);
97130e96f48SMichael Chan 		bnxt_refclk_read(bp, NULL, &ptp->current_time);
972d7859afbSMichael Chan 		WRITE_ONCE(ptp->old_time, ptp->current_time);
973d7859afbSMichael Chan 		spin_unlock_bh(&ptp->ptp_lock);
974d7859afbSMichael Chan 		ptp_schedule_worker(ptp->ptp_clock, 0);
975d7859afbSMichael Chan 	}
976118612d5SMichael Chan 	return 0;
97724ac1ecdSPavan Chebbi 
97824ac1ecdSPavan Chebbi out:
97924ac1ecdSPavan Chebbi 	bnxt_ptp_free(bp);
98024ac1ecdSPavan Chebbi 	bnxt_unmap_ptp_regs(bp);
98124ac1ecdSPavan Chebbi 	return rc;
982118612d5SMichael Chan }
983118612d5SMichael Chan 
bnxt_ptp_clear(struct bnxt * bp)984118612d5SMichael Chan void bnxt_ptp_clear(struct bnxt *bp)
985118612d5SMichael Chan {
986118612d5SMichael Chan 	struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
987118612d5SMichael Chan 
988118612d5SMichael Chan 	if (!ptp)
989118612d5SMichael Chan 		return;
990118612d5SMichael Chan 
991118612d5SMichael Chan 	if (ptp->ptp_clock)
992118612d5SMichael Chan 		ptp_clock_unregister(ptp->ptp_clock);
993118612d5SMichael Chan 
994118612d5SMichael Chan 	ptp->ptp_clock = NULL;
995caf3eedbSPavan Chebbi 	kfree(ptp->ptp_info.pin_config);
996caf3eedbSPavan Chebbi 	ptp->ptp_info.pin_config = NULL;
997caf3eedbSPavan Chebbi 
99883bb623cSPavan Chebbi 	if (ptp->tx_skb) {
99983bb623cSPavan Chebbi 		dev_kfree_skb_any(ptp->tx_skb);
100083bb623cSPavan Chebbi 		ptp->tx_skb = NULL;
100183bb623cSPavan Chebbi 	}
1002118612d5SMichael Chan 	bnxt_unmap_ptp_regs(bp);
1003118612d5SMichael Chan }
1004