xref: /linux/drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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