52f6eb1442e5f36f4e1f54c22e156bf256143dcd
[dpdk.git] / drivers / net / cnxk / cnxk_ptp.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4
5 #include "cnxk_ethdev.h"
6
7 /* This function calculates two parameters "clk_freq_mult" and
8  * "clk_delta" which is useful in deriving PTP HI clock from
9  * timestamp counter (tsc) value.
10  */
11 int
12 cnxk_nix_tsc_convert(struct cnxk_eth_dev *dev)
13 {
14         uint64_t ticks_base = 0, ticks = 0, tsc = 0, t_freq;
15         struct roc_nix *nix = &dev->nix;
16         int rc, val;
17
18         /* Calculating the frequency at which PTP HI clock is running */
19         rc = roc_nix_ptp_clock_read(nix, &ticks_base, &tsc, false);
20         if (rc) {
21                 plt_err("Failed to read the raw clock value: %d", rc);
22                 goto fail;
23         }
24
25         rte_delay_ms(100);
26
27         rc = roc_nix_ptp_clock_read(nix, &ticks, &tsc, false);
28         if (rc) {
29                 plt_err("Failed to read the raw clock value: %d", rc);
30                 goto fail;
31         }
32
33         t_freq = (ticks - ticks_base) * 10;
34
35         /* Calculating the freq multiplier viz the ratio between the
36          * frequency at which PTP HI clock works and tsc clock runs
37          */
38         dev->clk_freq_mult =
39                 (double)pow(10, floor(log10(t_freq))) / rte_get_timer_hz();
40
41         val = false;
42 #ifdef RTE_ARM_EAL_RDTSC_USE_PMU
43         val = true;
44 #endif
45         rc = roc_nix_ptp_clock_read(nix, &ticks, &tsc, val);
46         if (rc) {
47                 plt_err("Failed to read the raw clock value: %d", rc);
48                 goto fail;
49         }
50
51         /* Calculating delta between PTP HI clock and tsc */
52         dev->clk_delta = ((uint64_t)(ticks / dev->clk_freq_mult) - tsc);
53
54 fail:
55         return rc;
56 }
57
58 int
59 cnxk_nix_timesync_read_time(struct rte_eth_dev *eth_dev, struct timespec *ts)
60 {
61         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
62         struct roc_nix *nix = &dev->nix;
63         uint64_t clock, ns;
64         int rc;
65
66         rc = roc_nix_ptp_clock_read(nix, &clock, NULL, false);
67         if (rc)
68                 return rc;
69
70         ns = rte_timecounter_update(&dev->systime_tc, clock);
71         *ts = rte_ns_to_timespec(ns);
72         return 0;
73 }
74
75 int
76 cnxk_nix_timesync_write_time(struct rte_eth_dev *eth_dev,
77                              const struct timespec *ts)
78 {
79         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
80         uint64_t ns;
81
82         ns = rte_timespec_to_ns(ts);
83         /* Set the time counters to a new value. */
84         dev->systime_tc.nsec = ns;
85         dev->rx_tstamp_tc.nsec = ns;
86         dev->tx_tstamp_tc.nsec = ns;
87
88         return 0;
89 }
90
91 int
92 cnxk_nix_timesync_adjust_time(struct rte_eth_dev *eth_dev, int64_t delta)
93 {
94         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
95         struct roc_nix *nix = &dev->nix;
96         int rc;
97
98         /* Adjust the frequent to make tics increments in 10^9 tics per sec */
99         if (delta < ROC_NIX_PTP_FREQ_ADJUST &&
100             delta > -ROC_NIX_PTP_FREQ_ADJUST) {
101                 rc = roc_nix_ptp_sync_time_adjust(nix, delta);
102                 if (rc)
103                         return rc;
104
105                 /* Since the frequency of PTP comp register is tuned, delta and
106                  * freq mult calculation for deriving PTP_HI from timestamp
107                  * counter should be done again.
108                  */
109                 rc = cnxk_nix_tsc_convert(dev);
110                 if (rc)
111                         plt_err("Failed to calculate delta and freq mult");
112         }
113
114         dev->systime_tc.nsec += delta;
115         dev->rx_tstamp_tc.nsec += delta;
116         dev->tx_tstamp_tc.nsec += delta;
117
118         return 0;
119 }
120
121 int
122 cnxk_nix_timesync_read_rx_timestamp(struct rte_eth_dev *eth_dev,
123                                     struct timespec *timestamp, uint32_t flags)
124 {
125         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
126         struct cnxk_timesync_info *tstamp = &dev->tstamp;
127         uint64_t ns;
128
129         PLT_SET_USED(flags);
130
131         if (!tstamp->rx_ready)
132                 return -EINVAL;
133
134         ns = rte_timecounter_update(&dev->rx_tstamp_tc, tstamp->rx_tstamp);
135         *timestamp = rte_ns_to_timespec(ns);
136         tstamp->rx_ready = 0;
137         return 0;
138 }
139
140 int
141 cnxk_nix_timesync_read_tx_timestamp(struct rte_eth_dev *eth_dev,
142                                     struct timespec *timestamp)
143 {
144         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
145         struct cnxk_timesync_info *tstamp = &dev->tstamp;
146         uint64_t ns;
147
148         if (*tstamp->tx_tstamp == 0)
149                 return -EINVAL;
150
151         ns = rte_timecounter_update(&dev->tx_tstamp_tc, *tstamp->tx_tstamp);
152         *timestamp = rte_ns_to_timespec(ns);
153         *tstamp->tx_tstamp = 0;
154         rte_wmb();
155
156         return 0;
157 }
158
159 int
160 cnxk_nix_timesync_enable(struct rte_eth_dev *eth_dev)
161 {
162         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
163         struct cnxk_timesync_info *tstamp = &dev->tstamp;
164         struct roc_nix *nix = &dev->nix;
165         const struct rte_memzone *ts;
166         int rc = 0;
167
168         /* If we are VF/SDP/LBK, ptp cannot not be enabled */
169         if (roc_nix_is_vf_or_sdp(nix) || roc_nix_is_lbk(nix)) {
170                 plt_err("PTP cannot be enabled for VF/SDP/LBK");
171                 return -EINVAL;
172         }
173
174         if (dev->ptp_en)
175                 return rc;
176
177         if (dev->ptype_disable) {
178                 plt_err("Ptype offload is disabled, it should be enabled");
179                 return -EINVAL;
180         }
181
182         if (dev->npc.switch_header_type == ROC_PRIV_FLAGS_HIGIG) {
183                 plt_err("Both PTP and switch header cannot be enabled");
184                 return -EINVAL;
185         }
186
187         /* Allocating a iova address for tx tstamp */
188         ts = rte_eth_dma_zone_reserve(eth_dev, "cnxk_ts", 0, 128, 128, 0);
189         if (ts == NULL) {
190                 plt_err("Failed to allocate mem for tx tstamp addr");
191                 return -ENOMEM;
192         }
193
194         tstamp->tx_tstamp_iova = ts->iova;
195         tstamp->tx_tstamp = ts->addr;
196
197         rc = rte_mbuf_dyn_rx_timestamp_register(&tstamp->tstamp_dynfield_offset,
198                                                 &tstamp->rx_tstamp_dynflag);
199         if (rc) {
200                 plt_err("Failed to register Rx timestamp field/flag");
201                 goto error;
202         }
203
204         /* System time should be already on by default */
205         memset(&dev->systime_tc, 0, sizeof(struct rte_timecounter));
206         memset(&dev->rx_tstamp_tc, 0, sizeof(struct rte_timecounter));
207         memset(&dev->tx_tstamp_tc, 0, sizeof(struct rte_timecounter));
208
209         dev->systime_tc.cc_mask = CNXK_CYCLECOUNTER_MASK;
210         dev->rx_tstamp_tc.cc_mask = CNXK_CYCLECOUNTER_MASK;
211         dev->tx_tstamp_tc.cc_mask = CNXK_CYCLECOUNTER_MASK;
212
213         dev->rx_offloads |= DEV_RX_OFFLOAD_TIMESTAMP;
214
215         rc = roc_nix_ptp_rx_ena_dis(nix, true);
216         if (!rc) {
217                 rc = roc_nix_ptp_tx_ena_dis(nix, true);
218                 if (rc) {
219                         roc_nix_ptp_rx_ena_dis(nix, false);
220                         goto error;
221                 }
222         }
223
224         rc = nix_recalc_mtu(eth_dev);
225         if (rc) {
226                 plt_err("Failed to set MTU size for ptp");
227                 goto error;
228         }
229
230         return rc;
231
232 error:
233         rte_eth_dma_zone_free(eth_dev, "cnxk_ts", 0);
234         dev->tstamp.tx_tstamp_iova = 0;
235         dev->tstamp.tx_tstamp = NULL;
236         return rc;
237 }
238
239 int
240 cnxk_nix_timesync_disable(struct rte_eth_dev *eth_dev)
241 {
242         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
243         uint64_t rx_offloads = DEV_RX_OFFLOAD_TIMESTAMP;
244         struct roc_nix *nix = &dev->nix;
245         int rc = 0;
246
247         /* If we are VF/SDP/LBK, ptp cannot not be disabled */
248         if (roc_nix_is_vf_or_sdp(nix) || roc_nix_is_lbk(nix))
249                 return -EINVAL;
250
251         if (!dev->ptp_en)
252                 return rc;
253
254         dev->rx_offloads &= ~rx_offloads;
255
256         rc = roc_nix_ptp_rx_ena_dis(nix, false);
257         if (!rc) {
258                 rc = roc_nix_ptp_tx_ena_dis(nix, false);
259                 if (rc) {
260                         roc_nix_ptp_rx_ena_dis(nix, true);
261                         return rc;
262                 }
263         }
264
265         rc = nix_recalc_mtu(eth_dev);
266         if (rc)
267                 plt_err("Failed to set MTU size for ptp");
268
269         return rc;
270 }