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) {
524909f5a48SKalesh 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(×tamp, 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, ×tamp);
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)925*85c37802SMichael Chan int bnxt_ptp_init(struct bnxt *bp)
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);
947*85c37802SMichael Chan rc = bnxt_ptp_init_rtc(bp, ptp->rtc_configured);
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