diff options
author | Laurence Evans <levans@solarflare.com> | 2013-12-04 18:47:56 -0500 |
---|---|---|
committer | Ben Hutchings <bhutchings@solarflare.com> | 2013-12-12 17:07:09 -0500 |
commit | a6f73460b592404cca4ceafa69a835a61cdc20d8 (patch) | |
tree | e078025a329894bfc741c4a585597975ae5db87c /drivers/net/ethernet | |
parent | dfd8d581fbdce9f3b4777a7c59d28ca35ed194be (diff) |
sfc: Add support for SFC9100 timestamp format
The clock minor tick on the SFC9100 family is 2^-27 s, not 1 ns.
There are also various pipeline delays which we need to correct for
when interpreting timestamps.
We query the firmware for the clock format and corrections at run-time.
[bwh: Combined and rebased several changes]
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r-- | drivers/net/ethernet/sfc/ptp.c | 256 |
1 files changed, 231 insertions, 25 deletions
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index 361d7cedd897..cf2ae11b13f1 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c | |||
@@ -62,7 +62,7 @@ | |||
62 | #define SYNCHRONISATION_GRANULARITY_NS 200 | 62 | #define SYNCHRONISATION_GRANULARITY_NS 200 |
63 | 63 | ||
64 | /* Minimum permitted length of a (corrected) synchronisation time */ | 64 | /* Minimum permitted length of a (corrected) synchronisation time */ |
65 | #define MIN_SYNCHRONISATION_NS 120 | 65 | #define DEFAULT_MIN_SYNCHRONISATION_NS 120 |
66 | 66 | ||
67 | /* Maximum permitted length of a (corrected) synchronisation time */ | 67 | /* Maximum permitted length of a (corrected) synchronisation time */ |
68 | #define MAX_SYNCHRONISATION_NS 1000 | 68 | #define MAX_SYNCHRONISATION_NS 1000 |
@@ -195,20 +195,20 @@ struct efx_ptp_event_rx { | |||
195 | /** | 195 | /** |
196 | * struct efx_ptp_timeset - Synchronisation between host and MC | 196 | * struct efx_ptp_timeset - Synchronisation between host and MC |
197 | * @host_start: Host time immediately before hardware timestamp taken | 197 | * @host_start: Host time immediately before hardware timestamp taken |
198 | * @seconds: Hardware timestamp, seconds | 198 | * @major: Hardware timestamp, major |
199 | * @nanoseconds: Hardware timestamp, nanoseconds | 199 | * @minor: Hardware timestamp, minor |
200 | * @host_end: Host time immediately after hardware timestamp taken | 200 | * @host_end: Host time immediately after hardware timestamp taken |
201 | * @waitns: Number of nanoseconds between hardware timestamp being read and | 201 | * @wait: Number of NIC clock ticks between hardware timestamp being read and |
202 | * host end time being seen | 202 | * host end time being seen |
203 | * @window: Difference of host_end and host_start | 203 | * @window: Difference of host_end and host_start |
204 | * @valid: Whether this timeset is valid | 204 | * @valid: Whether this timeset is valid |
205 | */ | 205 | */ |
206 | struct efx_ptp_timeset { | 206 | struct efx_ptp_timeset { |
207 | u32 host_start; | 207 | u32 host_start; |
208 | u32 seconds; | 208 | u32 major; |
209 | u32 nanoseconds; | 209 | u32 minor; |
210 | u32 host_end; | 210 | u32 host_end; |
211 | u32 waitns; | 211 | u32 wait; |
212 | u32 window; /* Derived: end - start, allowing for wrap */ | 212 | u32 window; /* Derived: end - start, allowing for wrap */ |
213 | }; | 213 | }; |
214 | 214 | ||
@@ -232,6 +232,14 @@ struct efx_ptp_timeset { | |||
232 | * @config: Current timestamp configuration | 232 | * @config: Current timestamp configuration |
233 | * @enabled: PTP operation enabled | 233 | * @enabled: PTP operation enabled |
234 | * @mode: Mode in which PTP operating (PTP version) | 234 | * @mode: Mode in which PTP operating (PTP version) |
235 | * @time_format: Time format supported by this NIC | ||
236 | * @ns_to_nic_time: Function to convert from scalar nanoseconds to NIC time | ||
237 | * @nic_to_kernel_time: Function to convert from NIC to kernel time | ||
238 | * @min_synchronisation_ns: Minimum acceptable corrected sync window | ||
239 | * @ts_corrections.tx: Required driver correction of transmit timestamps | ||
240 | * @ts_corrections.rx: Required driver correction of receive timestamps | ||
241 | * @ts_corrections.pps_out: PPS output error (information only) | ||
242 | * @ts_corrections.pps_in: Required driver correction of PPS input timestamps | ||
235 | * @evt_frags: Partly assembled PTP events | 243 | * @evt_frags: Partly assembled PTP events |
236 | * @evt_frag_idx: Current fragment number | 244 | * @evt_frag_idx: Current fragment number |
237 | * @evt_code: Last event code | 245 | * @evt_code: Last event code |
@@ -266,6 +274,17 @@ struct efx_ptp_data { | |||
266 | struct hwtstamp_config config; | 274 | struct hwtstamp_config config; |
267 | bool enabled; | 275 | bool enabled; |
268 | unsigned int mode; | 276 | unsigned int mode; |
277 | unsigned int time_format; | ||
278 | void (*ns_to_nic_time)(s64 ns, u32 *nic_major, u32 *nic_minor); | ||
279 | ktime_t (*nic_to_kernel_time)(u32 nic_major, u32 nic_minor, | ||
280 | s32 correction); | ||
281 | unsigned int min_synchronisation_ns; | ||
282 | struct { | ||
283 | s32 tx; | ||
284 | s32 rx; | ||
285 | s32 pps_out; | ||
286 | s32 pps_in; | ||
287 | } ts_corrections; | ||
269 | efx_qword_t evt_frags[MAX_EVENT_FRAGS]; | 288 | efx_qword_t evt_frags[MAX_EVENT_FRAGS]; |
270 | int evt_frag_idx; | 289 | int evt_frag_idx; |
271 | int evt_code; | 290 | int evt_code; |
@@ -290,6 +309,167 @@ static int efx_phc_settime(struct ptp_clock_info *ptp, | |||
290 | static int efx_phc_enable(struct ptp_clock_info *ptp, | 309 | static int efx_phc_enable(struct ptp_clock_info *ptp, |
291 | struct ptp_clock_request *request, int on); | 310 | struct ptp_clock_request *request, int on); |
292 | 311 | ||
312 | /* For Siena platforms NIC time is s and ns */ | ||
313 | static void efx_ptp_ns_to_s_ns(s64 ns, u32 *nic_major, u32 *nic_minor) | ||
314 | { | ||
315 | struct timespec ts = ns_to_timespec(ns); | ||
316 | *nic_major = ts.tv_sec; | ||
317 | *nic_minor = ts.tv_nsec; | ||
318 | } | ||
319 | |||
320 | static ktime_t efx_ptp_s_ns_to_ktime(u32 nic_major, u32 nic_minor, | ||
321 | s32 correction) | ||
322 | { | ||
323 | ktime_t kt = ktime_set(nic_major, nic_minor); | ||
324 | if (correction >= 0) | ||
325 | kt = ktime_add_ns(kt, (u64)correction); | ||
326 | else | ||
327 | kt = ktime_sub_ns(kt, (u64)-correction); | ||
328 | return kt; | ||
329 | } | ||
330 | |||
331 | /* To convert from s27 format to ns we multiply then divide by a power of 2. | ||
332 | * For the conversion from ns to s27, the operation is also converted to a | ||
333 | * multiply and shift. | ||
334 | */ | ||
335 | #define S27_TO_NS_SHIFT (27) | ||
336 | #define NS_TO_S27_MULT (((1ULL << 63) + NSEC_PER_SEC / 2) / NSEC_PER_SEC) | ||
337 | #define NS_TO_S27_SHIFT (63 - S27_TO_NS_SHIFT) | ||
338 | #define S27_MINOR_MAX (1 << S27_TO_NS_SHIFT) | ||
339 | |||
340 | /* For Huntington platforms NIC time is in seconds and fractions of a second | ||
341 | * where the minor register only uses 27 bits in units of 2^-27s. | ||
342 | */ | ||
343 | static void efx_ptp_ns_to_s27(s64 ns, u32 *nic_major, u32 *nic_minor) | ||
344 | { | ||
345 | struct timespec ts = ns_to_timespec(ns); | ||
346 | u32 maj = ts.tv_sec; | ||
347 | u32 min = (u32)(((u64)ts.tv_nsec * NS_TO_S27_MULT + | ||
348 | (1ULL << (NS_TO_S27_SHIFT - 1))) >> NS_TO_S27_SHIFT); | ||
349 | |||
350 | /* The conversion can result in the minor value exceeding the maximum. | ||
351 | * In this case, round up to the next second. | ||
352 | */ | ||
353 | if (min >= S27_MINOR_MAX) { | ||
354 | min -= S27_MINOR_MAX; | ||
355 | maj++; | ||
356 | } | ||
357 | |||
358 | *nic_major = maj; | ||
359 | *nic_minor = min; | ||
360 | } | ||
361 | |||
362 | static ktime_t efx_ptp_s27_to_ktime(u32 nic_major, u32 nic_minor, | ||
363 | s32 correction) | ||
364 | { | ||
365 | u32 ns; | ||
366 | |||
367 | /* Apply the correction and deal with carry */ | ||
368 | nic_minor += correction; | ||
369 | if ((s32)nic_minor < 0) { | ||
370 | nic_minor += S27_MINOR_MAX; | ||
371 | nic_major--; | ||
372 | } else if (nic_minor >= S27_MINOR_MAX) { | ||
373 | nic_minor -= S27_MINOR_MAX; | ||
374 | nic_major++; | ||
375 | } | ||
376 | |||
377 | ns = (u32)(((u64)nic_minor * NSEC_PER_SEC + | ||
378 | (1ULL << (S27_TO_NS_SHIFT - 1))) >> S27_TO_NS_SHIFT); | ||
379 | |||
380 | return ktime_set(nic_major, ns); | ||
381 | } | ||
382 | |||
383 | /* Get PTP attributes and set up time conversions */ | ||
384 | static int efx_ptp_get_attributes(struct efx_nic *efx) | ||
385 | { | ||
386 | MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_GET_ATTRIBUTES_LEN); | ||
387 | MCDI_DECLARE_BUF(outbuf, MC_CMD_PTP_OUT_GET_ATTRIBUTES_LEN); | ||
388 | struct efx_ptp_data *ptp = efx->ptp_data; | ||
389 | int rc; | ||
390 | u32 fmt; | ||
391 | size_t out_len; | ||
392 | |||
393 | /* Get the PTP attributes. If the NIC doesn't support the operation we | ||
394 | * use the default format for compatibility with older NICs i.e. | ||
395 | * seconds and nanoseconds. | ||
396 | */ | ||
397 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_GET_ATTRIBUTES); | ||
398 | MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0); | ||
399 | rc = efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf), | ||
400 | outbuf, sizeof(outbuf), &out_len); | ||
401 | if (rc == 0) | ||
402 | fmt = MCDI_DWORD(outbuf, PTP_OUT_GET_ATTRIBUTES_TIME_FORMAT); | ||
403 | else if (rc == -EINVAL) | ||
404 | fmt = MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_NANOSECONDS; | ||
405 | else | ||
406 | return rc; | ||
407 | |||
408 | if (fmt == MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_27FRACTION) { | ||
409 | ptp->ns_to_nic_time = efx_ptp_ns_to_s27; | ||
410 | ptp->nic_to_kernel_time = efx_ptp_s27_to_ktime; | ||
411 | } else if (fmt == MC_CMD_PTP_OUT_GET_ATTRIBUTES_SECONDS_NANOSECONDS) { | ||
412 | ptp->ns_to_nic_time = efx_ptp_ns_to_s_ns; | ||
413 | ptp->nic_to_kernel_time = efx_ptp_s_ns_to_ktime; | ||
414 | } else { | ||
415 | return -ERANGE; | ||
416 | } | ||
417 | |||
418 | ptp->time_format = fmt; | ||
419 | |||
420 | /* MC_CMD_PTP_OP_GET_ATTRIBUTES is an extended version of an older | ||
421 | * operation MC_CMD_PTP_OP_GET_TIME_FORMAT that also returns a value | ||
422 | * to use for the minimum acceptable corrected synchronization window. | ||
423 | * If we have the extra information store it. For older firmware that | ||
424 | * does not implement the extended command use the default value. | ||
425 | */ | ||
426 | if (rc == 0 && out_len >= MC_CMD_PTP_OUT_GET_ATTRIBUTES_LEN) | ||
427 | ptp->min_synchronisation_ns = | ||
428 | MCDI_DWORD(outbuf, | ||
429 | PTP_OUT_GET_ATTRIBUTES_SYNC_WINDOW_MIN); | ||
430 | else | ||
431 | ptp->min_synchronisation_ns = DEFAULT_MIN_SYNCHRONISATION_NS; | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | /* Get PTP timestamp corrections */ | ||
437 | static int efx_ptp_get_timestamp_corrections(struct efx_nic *efx) | ||
438 | { | ||
439 | MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_GET_TIMESTAMP_CORRECTIONS_LEN); | ||
440 | MCDI_DECLARE_BUF(outbuf, MC_CMD_PTP_OUT_GET_TIMESTAMP_CORRECTIONS_LEN); | ||
441 | int rc; | ||
442 | |||
443 | /* Get the timestamp corrections from the NIC. If this operation is | ||
444 | * not supported (older NICs) then no correction is required. | ||
445 | */ | ||
446 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, | ||
447 | MC_CMD_PTP_OP_GET_TIMESTAMP_CORRECTIONS); | ||
448 | MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0); | ||
449 | |||
450 | rc = efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf), | ||
451 | outbuf, sizeof(outbuf), NULL); | ||
452 | if (rc == 0) { | ||
453 | efx->ptp_data->ts_corrections.tx = MCDI_DWORD(outbuf, | ||
454 | PTP_OUT_GET_TIMESTAMP_CORRECTIONS_TRANSMIT); | ||
455 | efx->ptp_data->ts_corrections.rx = MCDI_DWORD(outbuf, | ||
456 | PTP_OUT_GET_TIMESTAMP_CORRECTIONS_RECEIVE); | ||
457 | efx->ptp_data->ts_corrections.pps_out = MCDI_DWORD(outbuf, | ||
458 | PTP_OUT_GET_TIMESTAMP_CORRECTIONS_PPS_OUT); | ||
459 | efx->ptp_data->ts_corrections.pps_in = MCDI_DWORD(outbuf, | ||
460 | PTP_OUT_GET_TIMESTAMP_CORRECTIONS_PPS_IN); | ||
461 | } else if (rc == -EINVAL) { | ||
462 | efx->ptp_data->ts_corrections.tx = 0; | ||
463 | efx->ptp_data->ts_corrections.rx = 0; | ||
464 | efx->ptp_data->ts_corrections.pps_out = 0; | ||
465 | efx->ptp_data->ts_corrections.pps_in = 0; | ||
466 | } else { | ||
467 | return rc; | ||
468 | } | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
293 | /* Enable MCDI PTP support. */ | 473 | /* Enable MCDI PTP support. */ |
294 | static int efx_ptp_enable(struct efx_nic *efx) | 474 | static int efx_ptp_enable(struct efx_nic *efx) |
295 | { | 475 | { |
@@ -402,11 +582,10 @@ static void efx_ptp_read_timeset(MCDI_DECLARE_STRUCT_PTR(data), | |||
402 | unsigned start_ns, end_ns; | 582 | unsigned start_ns, end_ns; |
403 | 583 | ||
404 | timeset->host_start = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_HOSTSTART); | 584 | timeset->host_start = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_HOSTSTART); |
405 | timeset->seconds = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_SECONDS); | 585 | timeset->major = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_MAJOR); |
406 | timeset->nanoseconds = MCDI_DWORD(data, | 586 | timeset->minor = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_MINOR); |
407 | PTP_OUT_SYNCHRONIZE_NANOSECONDS); | ||
408 | timeset->host_end = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_HOSTEND), | 587 | timeset->host_end = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_HOSTEND), |
409 | timeset->waitns = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_WAITNS); | 588 | timeset->wait = MCDI_DWORD(data, PTP_OUT_SYNCHRONIZE_WAITNS); |
410 | 589 | ||
411 | /* Ignore seconds */ | 590 | /* Ignore seconds */ |
412 | start_ns = timeset->host_start & MC_NANOSECOND_MASK; | 591 | start_ns = timeset->host_start & MC_NANOSECOND_MASK; |
@@ -441,6 +620,7 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf), | |||
441 | u32 last_sec; | 620 | u32 last_sec; |
442 | u32 start_sec; | 621 | u32 start_sec; |
443 | struct timespec delta; | 622 | struct timespec delta; |
623 | ktime_t mc_time; | ||
444 | 624 | ||
445 | if (number_readings == 0) | 625 | if (number_readings == 0) |
446 | return -EAGAIN; | 626 | return -EAGAIN; |
@@ -452,14 +632,17 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf), | |||
452 | */ | 632 | */ |
453 | for (i = 0; i < number_readings; i++) { | 633 | for (i = 0; i < number_readings; i++) { |
454 | s32 window, corrected; | 634 | s32 window, corrected; |
635 | struct timespec wait; | ||
455 | 636 | ||
456 | efx_ptp_read_timeset( | 637 | efx_ptp_read_timeset( |
457 | MCDI_ARRAY_STRUCT_PTR(synch_buf, | 638 | MCDI_ARRAY_STRUCT_PTR(synch_buf, |
458 | PTP_OUT_SYNCHRONIZE_TIMESET, i), | 639 | PTP_OUT_SYNCHRONIZE_TIMESET, i), |
459 | &ptp->timeset[i]); | 640 | &ptp->timeset[i]); |
460 | 641 | ||
642 | wait = ktime_to_timespec( | ||
643 | ptp->nic_to_kernel_time(0, ptp->timeset[i].wait, 0)); | ||
461 | window = ptp->timeset[i].window; | 644 | window = ptp->timeset[i].window; |
462 | corrected = window - ptp->timeset[i].waitns; | 645 | corrected = window - wait.tv_nsec; |
463 | 646 | ||
464 | /* We expect the uncorrected synchronization window to be at | 647 | /* We expect the uncorrected synchronization window to be at |
465 | * least as large as the interval between host start and end | 648 | * least as large as the interval between host start and end |
@@ -472,7 +655,7 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf), | |||
472 | */ | 655 | */ |
473 | if (window >= SYNCHRONISATION_GRANULARITY_NS && | 656 | if (window >= SYNCHRONISATION_GRANULARITY_NS && |
474 | corrected < MAX_SYNCHRONISATION_NS && | 657 | corrected < MAX_SYNCHRONISATION_NS && |
475 | corrected >= MIN_SYNCHRONISATION_NS) { | 658 | corrected >= ptp->min_synchronisation_ns) { |
476 | ngood++; | 659 | ngood++; |
477 | last_good = i; | 660 | last_good = i; |
478 | } | 661 | } |
@@ -484,9 +667,15 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf), | |||
484 | return -EAGAIN; | 667 | return -EAGAIN; |
485 | } | 668 | } |
486 | 669 | ||
670 | /* Convert the NIC time into kernel time. No correction is required- | ||
671 | * this time is the output of a firmware process. | ||
672 | */ | ||
673 | mc_time = ptp->nic_to_kernel_time(ptp->timeset[last_good].major, | ||
674 | ptp->timeset[last_good].minor, 0); | ||
675 | |||
487 | /* Calculate delay from actual PPS to last_time */ | 676 | /* Calculate delay from actual PPS to last_time */ |
488 | delta.tv_nsec = | 677 | delta = ktime_to_timespec(mc_time); |
489 | ptp->timeset[last_good].nanoseconds + | 678 | delta.tv_nsec += |
490 | last_time->ts_real.tv_nsec - | 679 | last_time->ts_real.tv_nsec - |
491 | (ptp->timeset[last_good].host_start & MC_NANOSECOND_MASK); | 680 | (ptp->timeset[last_good].host_start & MC_NANOSECOND_MASK); |
492 | 681 | ||
@@ -596,9 +785,10 @@ static int efx_ptp_xmit_skb(struct efx_nic *efx, struct sk_buff *skb) | |||
596 | goto fail; | 785 | goto fail; |
597 | 786 | ||
598 | memset(×tamps, 0, sizeof(timestamps)); | 787 | memset(×tamps, 0, sizeof(timestamps)); |
599 | timestamps.hwtstamp = ktime_set( | 788 | timestamps.hwtstamp = ptp_data->nic_to_kernel_time( |
600 | MCDI_DWORD(txtime, PTP_OUT_TRANSMIT_SECONDS), | 789 | MCDI_DWORD(txtime, PTP_OUT_TRANSMIT_MAJOR), |
601 | MCDI_DWORD(txtime, PTP_OUT_TRANSMIT_NANOSECONDS)); | 790 | MCDI_DWORD(txtime, PTP_OUT_TRANSMIT_MINOR), |
791 | ptp_data->ts_corrections.tx); | ||
602 | 792 | ||
603 | skb_tstamp_tx(skb, ×tamps); | 793 | skb_tstamp_tx(skb, ×tamps); |
604 | 794 | ||
@@ -954,6 +1144,16 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel) | |||
954 | list_add(&ptp->rx_evts[pos].link, &ptp->evt_free_list); | 1144 | list_add(&ptp->rx_evts[pos].link, &ptp->evt_free_list); |
955 | ptp->evt_overflow = false; | 1145 | ptp->evt_overflow = false; |
956 | 1146 | ||
1147 | /* Get the NIC PTP attributes and set up time conversions */ | ||
1148 | rc = efx_ptp_get_attributes(efx); | ||
1149 | if (rc < 0) | ||
1150 | goto fail3; | ||
1151 | |||
1152 | /* Get the timestamp corrections */ | ||
1153 | rc = efx_ptp_get_timestamp_corrections(efx); | ||
1154 | if (rc < 0) | ||
1155 | goto fail3; | ||
1156 | |||
957 | ptp->phc_clock_info = efx_phc_clock_info; | 1157 | ptp->phc_clock_info = efx_phc_clock_info; |
958 | ptp->phc_clock = ptp_clock_register(&ptp->phc_clock_info, | 1158 | ptp->phc_clock = ptp_clock_register(&ptp->phc_clock_info, |
959 | &efx->pci_dev->dev); | 1159 | &efx->pci_dev->dev); |
@@ -1358,9 +1558,10 @@ static void ptp_event_rx(struct efx_nic *efx, struct efx_ptp_data *ptp) | |||
1358 | MCDI_EVENT_SRC) << 8) | | 1558 | MCDI_EVENT_SRC) << 8) | |
1359 | (EFX_QWORD_FIELD(ptp->evt_frags[0], | 1559 | (EFX_QWORD_FIELD(ptp->evt_frags[0], |
1360 | MCDI_EVENT_SRC) << 16)); | 1560 | MCDI_EVENT_SRC) << 16)); |
1361 | evt->hwtimestamp = ktime_set( | 1561 | evt->hwtimestamp = efx->ptp_data->nic_to_kernel_time( |
1362 | EFX_QWORD_FIELD(ptp->evt_frags[0], MCDI_EVENT_DATA), | 1562 | EFX_QWORD_FIELD(ptp->evt_frags[0], MCDI_EVENT_DATA), |
1363 | EFX_QWORD_FIELD(ptp->evt_frags[1], MCDI_EVENT_DATA)); | 1563 | EFX_QWORD_FIELD(ptp->evt_frags[1], MCDI_EVENT_DATA), |
1564 | ptp->ts_corrections.rx); | ||
1364 | evt->expiry = jiffies + msecs_to_jiffies(PKT_EVENT_LIFETIME_MS); | 1565 | evt->expiry = jiffies + msecs_to_jiffies(PKT_EVENT_LIFETIME_MS); |
1365 | list_add_tail(&evt->link, &ptp->evt_list); | 1566 | list_add_tail(&evt->link, &ptp->evt_list); |
1366 | 1567 | ||
@@ -1470,18 +1671,20 @@ static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) | |||
1470 | 1671 | ||
1471 | static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) | 1672 | static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) |
1472 | { | 1673 | { |
1674 | u32 nic_major, nic_minor; | ||
1473 | struct efx_ptp_data *ptp_data = container_of(ptp, | 1675 | struct efx_ptp_data *ptp_data = container_of(ptp, |
1474 | struct efx_ptp_data, | 1676 | struct efx_ptp_data, |
1475 | phc_clock_info); | 1677 | phc_clock_info); |
1476 | struct efx_nic *efx = ptp_data->efx; | 1678 | struct efx_nic *efx = ptp_data->efx; |
1477 | struct timespec delta_ts = ns_to_timespec(delta); | ||
1478 | MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_ADJUST_LEN); | 1679 | MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_ADJUST_LEN); |
1479 | 1680 | ||
1681 | efx->ptp_data->ns_to_nic_time(delta, &nic_major, &nic_minor); | ||
1682 | |||
1480 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_ADJUST); | 1683 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_ADJUST); |
1481 | MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0); | 1684 | MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0); |
1482 | MCDI_SET_QWORD(inbuf, PTP_IN_ADJUST_FREQ, ptp_data->current_adjfreq); | 1685 | MCDI_SET_QWORD(inbuf, PTP_IN_ADJUST_FREQ, ptp_data->current_adjfreq); |
1483 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_SECONDS, (u32)delta_ts.tv_sec); | 1686 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_MAJOR, nic_major); |
1484 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_NANOSECONDS, (u32)delta_ts.tv_nsec); | 1687 | MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_MINOR, nic_minor); |
1485 | return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf), | 1688 | return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf), |
1486 | NULL, 0, NULL); | 1689 | NULL, 0, NULL); |
1487 | } | 1690 | } |
@@ -1495,6 +1698,7 @@ static int efx_phc_gettime(struct ptp_clock_info *ptp, struct timespec *ts) | |||
1495 | MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_READ_NIC_TIME_LEN); | 1698 | MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_READ_NIC_TIME_LEN); |
1496 | MCDI_DECLARE_BUF(outbuf, MC_CMD_PTP_OUT_READ_NIC_TIME_LEN); | 1699 | MCDI_DECLARE_BUF(outbuf, MC_CMD_PTP_OUT_READ_NIC_TIME_LEN); |
1497 | int rc; | 1700 | int rc; |
1701 | ktime_t kt; | ||
1498 | 1702 | ||
1499 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_READ_NIC_TIME); | 1703 | MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_READ_NIC_TIME); |
1500 | MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0); | 1704 | MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0); |
@@ -1504,8 +1708,10 @@ static int efx_phc_gettime(struct ptp_clock_info *ptp, struct timespec *ts) | |||
1504 | if (rc != 0) | 1708 | if (rc != 0) |
1505 | return rc; | 1709 | return rc; |
1506 | 1710 | ||
1507 | ts->tv_sec = MCDI_DWORD(outbuf, PTP_OUT_READ_NIC_TIME_SECONDS); | 1711 | kt = ptp_data->nic_to_kernel_time( |
1508 | ts->tv_nsec = MCDI_DWORD(outbuf, PTP_OUT_READ_NIC_TIME_NANOSECONDS); | 1712 | MCDI_DWORD(outbuf, PTP_OUT_READ_NIC_TIME_MAJOR), |
1713 | MCDI_DWORD(outbuf, PTP_OUT_READ_NIC_TIME_MINOR), 0); | ||
1714 | *ts = ktime_to_timespec(kt); | ||
1509 | return 0; | 1715 | return 0; |
1510 | } | 1716 | } |
1511 | 1717 | ||