1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (C) 2024 Intel Corporation */
3
4 #include "idpf.h"
5 #include "idpf_ptp.h"
6 #include "idpf_virtchnl.h"
7
8 /**
9 * idpf_ptp_get_caps - Send virtchnl get ptp capabilities message
10 * @adapter: Driver specific private structure
11 *
12 * Send virtchnl get PTP capabilities message.
13 *
14 * Return: 0 on success, -errno on failure.
15 */
idpf_ptp_get_caps(struct idpf_adapter * adapter)16 int idpf_ptp_get_caps(struct idpf_adapter *adapter)
17 {
18 struct virtchnl2_ptp_get_caps send_ptp_caps_msg = {
19 .caps = cpu_to_le32(VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME |
20 VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME_MB |
21 VIRTCHNL2_CAP_PTP_GET_CROSS_TIME |
22 VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME_MB |
23 VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK_MB |
24 VIRTCHNL2_CAP_PTP_TX_TSTAMPS_MB)
25 };
26 struct libie_ctlq_xn_send_params xn_params = {
27 .chnl_opcode = VIRTCHNL2_OP_PTP_GET_CAPS,
28 .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
29 };
30 struct virtchnl2_ptp_cross_time_reg_offsets cross_tstamp_offsets;
31 struct libie_mmio_info *mmio = &adapter->ctlq_ctx.mmio_info;
32 struct virtchnl2_ptp_clk_adj_reg_offsets clk_adj_offsets;
33 struct virtchnl2_ptp_clk_reg_offsets clock_offsets;
34 struct virtchnl2_ptp_get_caps *recv_ptp_caps_msg;
35 struct idpf_ptp_secondary_mbx *scnd_mbx;
36 struct idpf_ptp *ptp = adapter->ptp;
37 enum idpf_ptp_access access_type;
38 u32 temp_offset;
39 size_t reply_sz;
40 int err;
41
42 err = idpf_send_mb_msg_stack(adapter, &xn_params, &send_ptp_caps_msg);
43 if (err)
44 return err;
45
46 reply_sz = xn_params.recv_mem.iov_len;
47 if (reply_sz != sizeof(*recv_ptp_caps_msg)) {
48 err = -EIO;
49 goto free_resp;
50 }
51
52 recv_ptp_caps_msg = xn_params.recv_mem.iov_base;
53
54 ptp->caps = le32_to_cpu(recv_ptp_caps_msg->caps);
55 ptp->base_incval = le64_to_cpu(recv_ptp_caps_msg->base_incval);
56 ptp->max_adj = le32_to_cpu(recv_ptp_caps_msg->max_adj);
57
58 scnd_mbx = &ptp->secondary_mbx;
59 scnd_mbx->peer_mbx_q_id = le16_to_cpu(recv_ptp_caps_msg->peer_mbx_q_id);
60
61 /* if the ptp_mb_q_id holds invalid value (0xffff), the secondary
62 * mailbox is not supported.
63 */
64 scnd_mbx->valid = scnd_mbx->peer_mbx_q_id != 0xffff;
65 if (scnd_mbx->valid)
66 scnd_mbx->peer_id = recv_ptp_caps_msg->peer_id;
67
68 /* Determine the access type for the PTP features */
69 idpf_ptp_get_features_access(adapter);
70
71 access_type = ptp->get_dev_clk_time_access;
72 if (access_type != IDPF_PTP_DIRECT)
73 goto cross_tstamp;
74
75 clock_offsets = recv_ptp_caps_msg->clk_offsets;
76
77 temp_offset = le32_to_cpu(clock_offsets.dev_clk_ns_l);
78 ptp->dev_clk_regs.dev_clk_ns_l =
79 libie_pci_get_mmio_addr(mmio, temp_offset);
80 temp_offset = le32_to_cpu(clock_offsets.dev_clk_ns_h);
81 ptp->dev_clk_regs.dev_clk_ns_h =
82 libie_pci_get_mmio_addr(mmio, temp_offset);
83 temp_offset = le32_to_cpu(clock_offsets.phy_clk_ns_l);
84 ptp->dev_clk_regs.phy_clk_ns_l =
85 libie_pci_get_mmio_addr(mmio, temp_offset);
86 temp_offset = le32_to_cpu(clock_offsets.phy_clk_ns_h);
87 ptp->dev_clk_regs.phy_clk_ns_h =
88 libie_pci_get_mmio_addr(mmio, temp_offset);
89 temp_offset = le32_to_cpu(clock_offsets.cmd_sync_trigger);
90 ptp->dev_clk_regs.cmd_sync =
91 libie_pci_get_mmio_addr(mmio, temp_offset);
92
93 cross_tstamp:
94 access_type = ptp->get_cross_tstamp_access;
95 if (access_type != IDPF_PTP_DIRECT)
96 goto discipline_clock;
97
98 cross_tstamp_offsets = recv_ptp_caps_msg->cross_time_offsets;
99
100 temp_offset = le32_to_cpu(cross_tstamp_offsets.sys_time_ns_l);
101 ptp->dev_clk_regs.sys_time_ns_l =
102 libie_pci_get_mmio_addr(mmio, temp_offset);
103 temp_offset = le32_to_cpu(cross_tstamp_offsets.sys_time_ns_h);
104 ptp->dev_clk_regs.sys_time_ns_h =
105 libie_pci_get_mmio_addr(mmio, temp_offset);
106 temp_offset = le32_to_cpu(cross_tstamp_offsets.cmd_sync_trigger);
107 ptp->dev_clk_regs.cmd_sync =
108 libie_pci_get_mmio_addr(mmio, temp_offset);
109
110 discipline_clock:
111 access_type = ptp->adj_dev_clk_time_access;
112 if (access_type != IDPF_PTP_DIRECT)
113 goto free_resp;
114
115 clk_adj_offsets = recv_ptp_caps_msg->clk_adj_offsets;
116
117 /* Device clock offsets */
118 temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_cmd_type);
119 ptp->dev_clk_regs.cmd = libie_pci_get_mmio_addr(mmio, temp_offset);
120 temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_incval_l);
121 ptp->dev_clk_regs.incval_l = libie_pci_get_mmio_addr(mmio, temp_offset);
122 temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_incval_h);
123 ptp->dev_clk_regs.incval_h = libie_pci_get_mmio_addr(mmio, temp_offset);
124 temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_shadj_l);
125 ptp->dev_clk_regs.shadj_l = libie_pci_get_mmio_addr(mmio, temp_offset);
126 temp_offset = le32_to_cpu(clk_adj_offsets.dev_clk_shadj_h);
127 ptp->dev_clk_regs.shadj_h = libie_pci_get_mmio_addr(mmio, temp_offset);
128
129 /* PHY clock offsets */
130 temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_cmd_type);
131 ptp->dev_clk_regs.phy_cmd =
132 libie_pci_get_mmio_addr(mmio, temp_offset);
133 temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_incval_l);
134 ptp->dev_clk_regs.phy_incval_l =
135 libie_pci_get_mmio_addr(mmio, temp_offset);
136 temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_incval_h);
137 ptp->dev_clk_regs.phy_incval_h =
138 libie_pci_get_mmio_addr(mmio, temp_offset);
139 temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_shadj_l);
140 ptp->dev_clk_regs.phy_shadj_l =
141 libie_pci_get_mmio_addr(mmio, temp_offset);
142 temp_offset = le32_to_cpu(clk_adj_offsets.phy_clk_shadj_h);
143 ptp->dev_clk_regs.phy_shadj_h =
144 libie_pci_get_mmio_addr(mmio, temp_offset);
145
146 free_resp:
147 libie_ctlq_release_rx_buf(&xn_params.recv_mem);
148 return err;
149 }
150
151 /**
152 * idpf_ptp_get_dev_clk_time - Send virtchnl get device clk time message
153 * @adapter: Driver specific private structure
154 * @dev_clk_time: Pointer to the device clock structure where the value is set
155 *
156 * Send virtchnl get time message to get the time of the clock.
157 *
158 * Return: 0 on success, -errno otherwise.
159 */
idpf_ptp_get_dev_clk_time(struct idpf_adapter * adapter,struct idpf_ptp_dev_timers * dev_clk_time)160 int idpf_ptp_get_dev_clk_time(struct idpf_adapter *adapter,
161 struct idpf_ptp_dev_timers *dev_clk_time)
162 {
163 struct virtchnl2_ptp_get_dev_clk_time *get_dev_clk_time_resp;
164 struct virtchnl2_ptp_get_dev_clk_time get_dev_clk_time_msg;
165 struct libie_ctlq_xn_send_params xn_params = {
166 .chnl_opcode = VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME,
167 .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
168 };
169 size_t reply_sz;
170 u64 dev_time;
171 int err;
172
173 err = idpf_send_mb_msg_stack(adapter, &xn_params,
174 &get_dev_clk_time_msg);
175 if (err)
176 return err;
177
178 reply_sz = xn_params.recv_mem.iov_len;
179 if (reply_sz != sizeof(*get_dev_clk_time_resp)) {
180 err = -EIO;
181 goto free_resp;
182 }
183
184 get_dev_clk_time_resp = xn_params.recv_mem.iov_base;
185 dev_time = le64_to_cpu(get_dev_clk_time_resp->dev_time_ns);
186 dev_clk_time->dev_clk_time_ns = dev_time;
187
188 free_resp:
189 libie_ctlq_release_rx_buf(&xn_params.recv_mem);
190 return err;
191 }
192
193 /**
194 * idpf_ptp_get_cross_time - Send virtchnl get cross time message
195 * @adapter: Driver specific private structure
196 * @cross_time: Pointer to the device clock structure where the value is set
197 *
198 * Send virtchnl get cross time message to get the time of the clock and the
199 * system time.
200 *
201 * Return: 0 on success, -errno otherwise.
202 */
idpf_ptp_get_cross_time(struct idpf_adapter * adapter,struct idpf_ptp_dev_timers * cross_time)203 int idpf_ptp_get_cross_time(struct idpf_adapter *adapter,
204 struct idpf_ptp_dev_timers *cross_time)
205 {
206 struct virtchnl2_ptp_get_cross_time cross_time_send, *cross_time_recv;
207 struct libie_ctlq_xn_send_params xn_params = {
208 .chnl_opcode = VIRTCHNL2_OP_PTP_GET_CROSS_TIME,
209 .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
210 };
211 int err = 0;
212
213 err = idpf_send_mb_msg_stack(adapter, &xn_params, &cross_time_send);
214 if (err)
215 return err;
216
217 if (xn_params.recv_mem.iov_len != sizeof(*cross_time_recv)) {
218 err = -EIO;
219 goto free_resp;
220 }
221
222 cross_time_recv = xn_params.recv_mem.iov_base;
223 cross_time->dev_clk_time_ns = le64_to_cpu(cross_time_recv->dev_time_ns);
224 cross_time->sys_time_ns = le64_to_cpu(cross_time_recv->sys_time_ns);
225
226 free_resp:
227 libie_ctlq_release_rx_buf(&xn_params.recv_mem);
228 return err;
229 }
230
231 /**
232 * idpf_ptp_set_dev_clk_time - Send virtchnl set device time message
233 * @adapter: Driver specific private structure
234 * @time: New time value
235 *
236 * Send virtchnl set time message to set the time of the clock.
237 *
238 * Return: 0 on success, -errno otherwise.
239 */
idpf_ptp_set_dev_clk_time(struct idpf_adapter * adapter,u64 time)240 int idpf_ptp_set_dev_clk_time(struct idpf_adapter *adapter, u64 time)
241 {
242 struct virtchnl2_ptp_set_dev_clk_time set_dev_clk_time_msg = {
243 .dev_time_ns = cpu_to_le64(time),
244 };
245 struct libie_ctlq_xn_send_params xn_params = {
246 .chnl_opcode = VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME,
247 .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
248 };
249 int err;
250
251 err = idpf_send_mb_msg_stack(adapter, &xn_params,
252 &set_dev_clk_time_msg);
253 if (!err)
254 libie_ctlq_release_rx_buf(&xn_params.recv_mem);
255
256 return err;
257 }
258
259 /**
260 * idpf_ptp_adj_dev_clk_time - Send virtchnl adj device clock time message
261 * @adapter: Driver specific private structure
262 * @delta: Offset in nanoseconds to adjust the time by
263 *
264 * Send virtchnl adj time message to adjust the clock by the indicated delta.
265 *
266 * Return: 0 on success, -errno otherwise.
267 */
idpf_ptp_adj_dev_clk_time(struct idpf_adapter * adapter,s64 delta)268 int idpf_ptp_adj_dev_clk_time(struct idpf_adapter *adapter, s64 delta)
269 {
270 struct virtchnl2_ptp_adj_dev_clk_time adj_dev_clk_time_msg = {
271 .delta = cpu_to_le64(delta),
272 };
273 struct libie_ctlq_xn_send_params xn_params = {
274 .chnl_opcode = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_TIME,
275 .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
276 };
277 int err;
278
279 err = idpf_send_mb_msg_stack(adapter, &xn_params,
280 &adj_dev_clk_time_msg);
281 if (!err)
282 libie_ctlq_release_rx_buf(&xn_params.recv_mem);
283
284 return err;
285 }
286
287 /**
288 * idpf_ptp_adj_dev_clk_fine - Send virtchnl adj time message
289 * @adapter: Driver specific private structure
290 * @incval: Source timer increment value per clock cycle
291 *
292 * Send virtchnl adj fine message to adjust the frequency of the clock by
293 * incval.
294 *
295 * Return: 0 on success, -errno otherwise.
296 */
idpf_ptp_adj_dev_clk_fine(struct idpf_adapter * adapter,u64 incval)297 int idpf_ptp_adj_dev_clk_fine(struct idpf_adapter *adapter, u64 incval)
298 {
299 struct virtchnl2_ptp_adj_dev_clk_fine adj_dev_clk_fine_msg = {
300 .incval = cpu_to_le64(incval),
301 };
302 struct libie_ctlq_xn_send_params xn_params = {
303 .chnl_opcode = VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_FINE,
304 .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
305 };
306 int err;
307
308 err = idpf_send_mb_msg_stack(adapter, &xn_params,
309 &adj_dev_clk_fine_msg);
310 if (!err)
311 libie_ctlq_release_rx_buf(&xn_params.recv_mem);
312
313 return err;
314 }
315
316 /**
317 * idpf_ptp_get_vport_tstamps_caps - Send virtchnl to get tstamps caps for vport
318 * @vport: Virtual port structure
319 *
320 * Send virtchnl get vport tstamps caps message to receive the set of tstamp
321 * capabilities per vport.
322 *
323 * Return: 0 on success, -errno otherwise.
324 */
idpf_ptp_get_vport_tstamps_caps(struct idpf_vport * vport)325 int idpf_ptp_get_vport_tstamps_caps(struct idpf_vport *vport)
326 {
327 struct virtchnl2_ptp_get_vport_tx_tstamp_caps send_tx_tstamp_caps;
328 struct virtchnl2_ptp_get_vport_tx_tstamp_caps *rcv_tx_tstamp_caps;
329 struct virtchnl2_ptp_tx_tstamp_latch_caps tx_tstamp_latch_caps;
330 struct idpf_ptp_vport_tx_tstamp_caps *tstamp_caps;
331 struct idpf_ptp_tx_tstamp *ptp_tx_tstamp, *tmp;
332 struct libie_ctlq_xn_send_params xn_params = {
333 .chnl_opcode = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP_CAPS,
334 .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
335 };
336 enum idpf_ptp_access tstamp_access, get_dev_clk_access;
337 struct idpf_ptp *ptp = vport->adapter->ptp;
338 struct list_head *head;
339 size_t reply_sz;
340 u16 num_latches;
341 int err = 0;
342 u32 size;
343
344 if (!ptp)
345 return -EOPNOTSUPP;
346
347 tstamp_access = ptp->tx_tstamp_access;
348 get_dev_clk_access = ptp->get_dev_clk_time_access;
349 if (tstamp_access == IDPF_PTP_NONE ||
350 get_dev_clk_access == IDPF_PTP_NONE)
351 return -EOPNOTSUPP;
352
353 send_tx_tstamp_caps.vport_id = cpu_to_le32(vport->vport_id);
354
355 err = idpf_send_mb_msg_stack(vport->adapter, &xn_params,
356 &send_tx_tstamp_caps);
357 if (err)
358 return err;
359
360 rcv_tx_tstamp_caps = xn_params.recv_mem.iov_base;
361 reply_sz = xn_params.recv_mem.iov_len;
362 if (reply_sz < sizeof(*rcv_tx_tstamp_caps)) {
363 err = -EIO;
364 goto get_tstamp_caps_out;
365 }
366 num_latches = le16_to_cpu(rcv_tx_tstamp_caps->num_latches);
367 size = struct_size(rcv_tx_tstamp_caps, tstamp_latches, num_latches);
368 if (reply_sz != size) {
369 err = -EIO;
370 goto get_tstamp_caps_out;
371 }
372
373 size = struct_size(tstamp_caps, tx_tstamp_status, num_latches);
374 tstamp_caps = kzalloc(size, GFP_KERNEL);
375 if (!tstamp_caps) {
376 err = -ENOMEM;
377 goto get_tstamp_caps_out;
378 }
379
380 tstamp_caps->access = true;
381 tstamp_caps->num_entries = num_latches;
382
383 INIT_LIST_HEAD(&tstamp_caps->latches_in_use);
384 INIT_LIST_HEAD(&tstamp_caps->latches_free);
385
386 spin_lock_init(&tstamp_caps->latches_lock);
387 spin_lock_init(&tstamp_caps->status_lock);
388
389 tstamp_caps->tstamp_ns_lo_bit = rcv_tx_tstamp_caps->tstamp_ns_lo_bit;
390
391 for (u16 i = 0; i < tstamp_caps->num_entries; i++) {
392 __le32 offset_l, offset_h;
393
394 ptp_tx_tstamp = kzalloc_obj(*ptp_tx_tstamp);
395 if (!ptp_tx_tstamp) {
396 err = -ENOMEM;
397 goto err_free_ptp_tx_stamp_list;
398 }
399
400 tx_tstamp_latch_caps = rcv_tx_tstamp_caps->tstamp_latches[i];
401
402 if (tstamp_access != IDPF_PTP_DIRECT)
403 goto skip_offsets;
404
405 offset_l = tx_tstamp_latch_caps.tx_latch_reg_offset_l;
406 offset_h = tx_tstamp_latch_caps.tx_latch_reg_offset_h;
407 ptp_tx_tstamp->tx_latch_reg_offset_l = le32_to_cpu(offset_l);
408 ptp_tx_tstamp->tx_latch_reg_offset_h = le32_to_cpu(offset_h);
409
410 skip_offsets:
411 ptp_tx_tstamp->idx = tx_tstamp_latch_caps.index;
412
413 list_add(&ptp_tx_tstamp->list_member,
414 &tstamp_caps->latches_free);
415
416 tstamp_caps->tx_tstamp_status[i].state = IDPF_PTP_FREE;
417 }
418
419 vport->tx_tstamp_caps = tstamp_caps;
420 libie_ctlq_release_rx_buf(&xn_params.recv_mem);
421
422 return 0;
423
424 err_free_ptp_tx_stamp_list:
425 head = &tstamp_caps->latches_free;
426 list_for_each_entry_safe(ptp_tx_tstamp, tmp, head, list_member) {
427 list_del(&ptp_tx_tstamp->list_member);
428 kfree(ptp_tx_tstamp);
429 }
430
431 kfree(tstamp_caps);
432 get_tstamp_caps_out:
433 libie_ctlq_release_rx_buf(&xn_params.recv_mem);
434
435 return err;
436 }
437
438 /**
439 * idpf_ptp_update_tstamp_tracker - Update the Tx timestamp tracker based on
440 * the skb compatibility.
441 * @caps: Tx timestamp capabilities that monitor the latch status
442 * @skb: skb for which the tstamp value is returned through virtchnl message
443 * @current_state: Current state of the Tx timestamp latch
444 * @expected_state: Expected state of the Tx timestamp latch
445 *
446 * Find a proper skb tracker for which the Tx timestamp is received and change
447 * the state to expected value.
448 *
449 * Return: true if the tracker has been found and updated, false otherwise.
450 */
451 static bool
idpf_ptp_update_tstamp_tracker(struct idpf_ptp_vport_tx_tstamp_caps * caps,struct sk_buff * skb,enum idpf_ptp_tx_tstamp_state current_state,enum idpf_ptp_tx_tstamp_state expected_state)452 idpf_ptp_update_tstamp_tracker(struct idpf_ptp_vport_tx_tstamp_caps *caps,
453 struct sk_buff *skb,
454 enum idpf_ptp_tx_tstamp_state current_state,
455 enum idpf_ptp_tx_tstamp_state expected_state)
456 {
457 bool updated = false;
458
459 spin_lock(&caps->status_lock);
460 for (u16 i = 0; i < caps->num_entries; i++) {
461 struct idpf_ptp_tx_tstamp_status *status;
462
463 status = &caps->tx_tstamp_status[i];
464
465 if (skb == status->skb && status->state == current_state) {
466 status->state = expected_state;
467 updated = true;
468 break;
469 }
470 }
471 spin_unlock(&caps->status_lock);
472
473 return updated;
474 }
475
476 /**
477 * idpf_ptp_get_tstamp_value - Get the Tx timestamp value and provide it
478 * back to the skb.
479 * @vport: Virtual port structure
480 * @tstamp_latch: Tx timestamp latch structure fulfilled by the Control Plane
481 * @ptp_tx_tstamp: Tx timestamp latch to add to the free list
482 *
483 * Read the value of the Tx timestamp for a given latch received from the
484 * Control Plane, extend it to 64 bit and provide back to the skb.
485 *
486 * Return: 0 on success, -errno otherwise.
487 */
488 static int
idpf_ptp_get_tstamp_value(struct idpf_vport * vport,struct virtchnl2_ptp_tx_tstamp_latch * tstamp_latch,struct idpf_ptp_tx_tstamp * ptp_tx_tstamp)489 idpf_ptp_get_tstamp_value(struct idpf_vport *vport,
490 struct virtchnl2_ptp_tx_tstamp_latch *tstamp_latch,
491 struct idpf_ptp_tx_tstamp *ptp_tx_tstamp)
492 {
493 struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;
494 struct skb_shared_hwtstamps shhwtstamps;
495 bool state_upd = false;
496 u8 tstamp_ns_lo_bit;
497 u64 tstamp;
498
499 tx_tstamp_caps = vport->tx_tstamp_caps;
500 tstamp_ns_lo_bit = tx_tstamp_caps->tstamp_ns_lo_bit;
501
502 ptp_tx_tstamp->tstamp = le64_to_cpu(tstamp_latch->tstamp);
503 ptp_tx_tstamp->tstamp >>= tstamp_ns_lo_bit;
504
505 state_upd = idpf_ptp_update_tstamp_tracker(tx_tstamp_caps,
506 ptp_tx_tstamp->skb,
507 IDPF_PTP_READ_VALUE,
508 IDPF_PTP_FREE);
509 if (!state_upd)
510 return -EINVAL;
511
512 tstamp = idpf_ptp_extend_ts(vport, ptp_tx_tstamp->tstamp);
513 shhwtstamps.hwtstamp = ns_to_ktime(tstamp);
514 skb_tstamp_tx(ptp_tx_tstamp->skb, &shhwtstamps);
515 consume_skb(ptp_tx_tstamp->skb);
516 ptp_tx_tstamp->skb = NULL;
517
518 list_add(&ptp_tx_tstamp->list_member,
519 &tx_tstamp_caps->latches_free);
520
521 u64_stats_update_begin(&vport->tstamp_stats.stats_sync);
522 u64_stats_inc(&vport->tstamp_stats.packets);
523 u64_stats_update_end(&vport->tstamp_stats.stats_sync);
524
525 return 0;
526 }
527
528 /**
529 * idpf_ptp_get_tx_tstamp_async_handler - Async callback for getting Tx tstamps
530 * @ctx: adapter pointer
531 * @mem: address and size of the response
532 * @status: return value of the request
533 *
534 * Read the tstamps Tx tstamp values from a received message and put them
535 * directly to the skb. The number of timestamps to read is specified by
536 * the virtchnl message.
537 *
538 * Return: 0 on success, -errno otherwise.
539 */
540 static void
idpf_ptp_get_tx_tstamp_async_handler(void * ctx,struct kvec * mem,int status)541 idpf_ptp_get_tx_tstamp_async_handler(void *ctx, struct kvec *mem, int status)
542 {
543 struct virtchnl2_ptp_get_vport_tx_tstamp_latches *recv_tx_tstamp_msg;
544 struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;
545 struct virtchnl2_ptp_tx_tstamp_latch tstamp_latch;
546 struct idpf_ptp_tx_tstamp *tx_tstamp, *tmp;
547 struct idpf_vport *tstamp_vport = NULL;
548 struct idpf_adapter *adapter = ctx;
549 struct list_head *head;
550 u16 num_latches;
551 u32 vport_id;
552
553 if (status)
554 return;
555
556 recv_tx_tstamp_msg = mem->iov_base;
557 if (mem->iov_len < sizeof(*recv_tx_tstamp_msg))
558 return;
559
560 vport_id = le32_to_cpu(recv_tx_tstamp_msg->vport_id);
561
562 idpf_for_each_vport(adapter, vport) {
563 if (!vport)
564 continue;
565
566 if (vport->vport_id == vport_id) {
567 tstamp_vport = vport;
568 break;
569 }
570 }
571
572 if (!tstamp_vport || !tstamp_vport->tx_tstamp_caps)
573 return;
574
575 tx_tstamp_caps = tstamp_vport->tx_tstamp_caps;
576 num_latches = le16_to_cpu(recv_tx_tstamp_msg->num_latches);
577 if (mem->iov_len < struct_size(recv_tx_tstamp_msg, tstamp_latches,
578 num_latches))
579 return;
580
581 spin_lock_bh(&tx_tstamp_caps->latches_lock);
582 head = &tx_tstamp_caps->latches_in_use;
583
584 for (u16 i = 0; i < num_latches; i++) {
585 tstamp_latch = recv_tx_tstamp_msg->tstamp_latches[i];
586
587 if (!tstamp_latch.valid)
588 continue;
589
590 if (list_empty(head))
591 goto unlock;
592
593 list_for_each_entry_safe(tx_tstamp, tmp, head, list_member) {
594 if (tstamp_latch.index == tx_tstamp->idx) {
595 int err;
596
597 list_del(&tx_tstamp->list_member);
598 err = idpf_ptp_get_tstamp_value(tstamp_vport,
599 &tstamp_latch,
600 tx_tstamp);
601 if (err)
602 goto unlock;
603
604 break;
605 }
606 }
607 }
608
609 unlock:
610 spin_unlock_bh(&tx_tstamp_caps->latches_lock);
611 }
612
613 /**
614 * idpf_ptp_get_tx_tstamp - Send virtchnl get Tx timestamp latches message
615 * @vport: Virtual port structure
616 *
617 * Send virtchnl get Tx tstamp message to read the value of the HW timestamp.
618 * The message contains a list of indexes set in the Tx descriptors.
619 *
620 * Return: 0 on success, -errno otherwise.
621 */
idpf_ptp_get_tx_tstamp(struct idpf_vport * vport)622 int idpf_ptp_get_tx_tstamp(struct idpf_vport *vport)
623 {
624 struct virtchnl2_ptp_get_vport_tx_tstamp_latches *send_tx_tstamp_msg;
625 struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps;
626 struct libie_ctlq_xn_send_params xn_params = {
627 .chnl_opcode = VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP,
628 .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC,
629 .resp_cb = idpf_ptp_get_tx_tstamp_async_handler,
630 .send_ctx = vport->adapter,
631 };
632 struct idpf_ptp_tx_tstamp *ptp_tx_tstamp;
633 struct list_head *head;
634 int size, msg_size;
635 bool state_upd;
636 u16 id = 0;
637
638 tx_tstamp_caps = vport->tx_tstamp_caps;
639 head = &tx_tstamp_caps->latches_in_use;
640
641 size = struct_size(send_tx_tstamp_msg, tstamp_latches,
642 tx_tstamp_caps->num_entries);
643 send_tx_tstamp_msg = kzalloc(size, GFP_KERNEL);
644 if (!send_tx_tstamp_msg)
645 return -ENOMEM;
646
647 spin_lock_bh(&tx_tstamp_caps->latches_lock);
648 list_for_each_entry(ptp_tx_tstamp, head, list_member) {
649 u8 idx;
650
651 state_upd = idpf_ptp_update_tstamp_tracker(tx_tstamp_caps,
652 ptp_tx_tstamp->skb,
653 IDPF_PTP_REQUEST,
654 IDPF_PTP_READ_VALUE);
655 if (!state_upd)
656 continue;
657
658 idx = ptp_tx_tstamp->idx;
659 send_tx_tstamp_msg->tstamp_latches[id].index = idx;
660 id++;
661 }
662 spin_unlock_bh(&tx_tstamp_caps->latches_lock);
663
664 msg_size = struct_size(send_tx_tstamp_msg, tstamp_latches, id);
665 send_tx_tstamp_msg->vport_id = cpu_to_le32(vport->vport_id);
666 send_tx_tstamp_msg->num_latches = cpu_to_le16(id);
667
668 return idpf_send_mb_msg_kfree(vport->adapter, &xn_params,
669 send_tx_tstamp_msg, msg_size);
670 }
671