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