diff options
| -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 | ||
