| .. | .. |
|---|
| 11 | 11 | * operate with the nanosecond field directly without fear of overflow. |
|---|
| 12 | 12 | * |
|---|
| 13 | 13 | * Much like the 82599, the update period is dependent upon the link speed: |
|---|
| 14 | | - * At 40Gb link or no link, the period is 1.6ns. |
|---|
| 15 | | - * At 10Gb link, the period is multiplied by 2. (3.2ns) |
|---|
| 14 | + * At 40Gb, 25Gb, or no link, the period is 1.6ns. |
|---|
| 15 | + * At 10Gb or 5Gb link, the period is multiplied by 2. (3.2ns) |
|---|
| 16 | 16 | * At 1Gb link, the period is multiplied by 20. (32ns) |
|---|
| 17 | 17 | * 1588 functionality is not supported at 100Mbps. |
|---|
| 18 | 18 | */ |
|---|
| 19 | 19 | #define I40E_PTP_40GB_INCVAL 0x0199999999ULL |
|---|
| 20 | 20 | #define I40E_PTP_10GB_INCVAL_MULT 2 |
|---|
| 21 | +#define I40E_PTP_5GB_INCVAL_MULT 2 |
|---|
| 21 | 22 | #define I40E_PTP_1GB_INCVAL_MULT 20 |
|---|
| 22 | 23 | |
|---|
| 23 | 24 | #define I40E_PRTTSYN_CTL1_TSYNTYPE_V1 BIT(I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) |
|---|
| .. | .. |
|---|
| 28 | 29 | * i40e_ptp_read - Read the PHC time from the device |
|---|
| 29 | 30 | * @pf: Board private structure |
|---|
| 30 | 31 | * @ts: timespec structure to hold the current time value |
|---|
| 32 | + * @sts: structure to hold the system time before and after reading the PHC |
|---|
| 31 | 33 | * |
|---|
| 32 | 34 | * This function reads the PRTTSYN_TIME registers and stores them in a |
|---|
| 33 | 35 | * timespec. However, since the registers are 64 bits of nanoseconds, we must |
|---|
| 34 | 36 | * convert the result to a timespec before we can return. |
|---|
| 35 | 37 | **/ |
|---|
| 36 | | -static void i40e_ptp_read(struct i40e_pf *pf, struct timespec64 *ts) |
|---|
| 38 | +static void i40e_ptp_read(struct i40e_pf *pf, struct timespec64 *ts, |
|---|
| 39 | + struct ptp_system_timestamp *sts) |
|---|
| 37 | 40 | { |
|---|
| 38 | 41 | struct i40e_hw *hw = &pf->hw; |
|---|
| 39 | 42 | u32 hi, lo; |
|---|
| 40 | 43 | u64 ns; |
|---|
| 41 | 44 | |
|---|
| 42 | 45 | /* The timer latches on the lowest register read. */ |
|---|
| 46 | + ptp_read_system_prets(sts); |
|---|
| 43 | 47 | lo = rd32(hw, I40E_PRTTSYN_TIME_L); |
|---|
| 48 | + ptp_read_system_postts(sts); |
|---|
| 44 | 49 | hi = rd32(hw, I40E_PRTTSYN_TIME_H); |
|---|
| 45 | 50 | |
|---|
| 46 | 51 | ns = (((u64)hi) << 32) | lo; |
|---|
| .. | .. |
|---|
| 136 | 141 | * @ptp: The PTP clock structure |
|---|
| 137 | 142 | * @delta: Offset in nanoseconds to adjust the PHC time by |
|---|
| 138 | 143 | * |
|---|
| 139 | | - * Adjust the frequency of the PHC by the indicated parts per billion from the |
|---|
| 140 | | - * base frequency. |
|---|
| 144 | + * Adjust the current clock time by a delta specified in nanoseconds. |
|---|
| 141 | 145 | **/ |
|---|
| 142 | 146 | static int i40e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) |
|---|
| 143 | 147 | { |
|---|
| 144 | 148 | struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps); |
|---|
| 145 | | - struct timespec64 now; |
|---|
| 149 | + struct timespec64 now, then; |
|---|
| 146 | 150 | |
|---|
| 151 | + then = ns_to_timespec64(delta); |
|---|
| 147 | 152 | mutex_lock(&pf->tmreg_lock); |
|---|
| 148 | 153 | |
|---|
| 149 | | - i40e_ptp_read(pf, &now); |
|---|
| 150 | | - timespec64_add_ns(&now, delta); |
|---|
| 154 | + i40e_ptp_read(pf, &now, NULL); |
|---|
| 155 | + now = timespec64_add(now, then); |
|---|
| 151 | 156 | i40e_ptp_write(pf, (const struct timespec64 *)&now); |
|---|
| 152 | 157 | |
|---|
| 153 | 158 | mutex_unlock(&pf->tmreg_lock); |
|---|
| .. | .. |
|---|
| 156 | 161 | } |
|---|
| 157 | 162 | |
|---|
| 158 | 163 | /** |
|---|
| 159 | | - * i40e_ptp_gettime - Get the time of the PHC |
|---|
| 164 | + * i40e_ptp_gettimex - Get the time of the PHC |
|---|
| 160 | 165 | * @ptp: The PTP clock structure |
|---|
| 161 | 166 | * @ts: timespec structure to hold the current time value |
|---|
| 167 | + * @sts: structure to hold the system time before and after reading the PHC |
|---|
| 162 | 168 | * |
|---|
| 163 | 169 | * Read the device clock and return the correct value on ns, after converting it |
|---|
| 164 | 170 | * into a timespec struct. |
|---|
| 165 | 171 | **/ |
|---|
| 166 | | -static int i40e_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) |
|---|
| 172 | +static int i40e_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts, |
|---|
| 173 | + struct ptp_system_timestamp *sts) |
|---|
| 167 | 174 | { |
|---|
| 168 | 175 | struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps); |
|---|
| 169 | 176 | |
|---|
| 170 | 177 | mutex_lock(&pf->tmreg_lock); |
|---|
| 171 | | - i40e_ptp_read(pf, ts); |
|---|
| 178 | + i40e_ptp_read(pf, ts, sts); |
|---|
| 172 | 179 | mutex_unlock(&pf->tmreg_lock); |
|---|
| 173 | 180 | |
|---|
| 174 | 181 | return 0; |
|---|
| .. | .. |
|---|
| 253 | 260 | /** |
|---|
| 254 | 261 | * i40e_ptp_rx_hang - Detect error case when Rx timestamp registers are hung |
|---|
| 255 | 262 | * @pf: The PF private data structure |
|---|
| 256 | | - * @vsi: The VSI with the rings relevant to 1588 |
|---|
| 257 | 263 | * |
|---|
| 258 | 264 | * This watchdog task is scheduled to detect error case where hardware has |
|---|
| 259 | 265 | * dropped an Rx packet that was timestamped when the ring is full. The |
|---|
| .. | .. |
|---|
| 460 | 466 | case I40E_LINK_SPEED_10GB: |
|---|
| 461 | 467 | mult = I40E_PTP_10GB_INCVAL_MULT; |
|---|
| 462 | 468 | break; |
|---|
| 469 | + case I40E_LINK_SPEED_5GB: |
|---|
| 470 | + mult = I40E_PTP_5GB_INCVAL_MULT; |
|---|
| 471 | + break; |
|---|
| 463 | 472 | case I40E_LINK_SPEED_1GB: |
|---|
| 464 | 473 | mult = I40E_PTP_1GB_INCVAL_MULT; |
|---|
| 465 | 474 | break; |
|---|
| .. | .. |
|---|
| 580 | 589 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: |
|---|
| 581 | 590 | if (!(pf->hw_features & I40E_HW_PTP_L4_CAPABLE)) |
|---|
| 582 | 591 | return -ERANGE; |
|---|
| 583 | | - /* fall through */ |
|---|
| 592 | + fallthrough; |
|---|
| 584 | 593 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: |
|---|
| 585 | 594 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: |
|---|
| 586 | 595 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: |
|---|
| .. | .. |
|---|
| 694 | 703 | if (!IS_ERR_OR_NULL(pf->ptp_clock)) |
|---|
| 695 | 704 | return 0; |
|---|
| 696 | 705 | |
|---|
| 697 | | - strncpy(pf->ptp_caps.name, i40e_driver_name, |
|---|
| 706 | + strlcpy(pf->ptp_caps.name, i40e_driver_name, |
|---|
| 698 | 707 | sizeof(pf->ptp_caps.name) - 1); |
|---|
| 699 | 708 | pf->ptp_caps.owner = THIS_MODULE; |
|---|
| 700 | 709 | pf->ptp_caps.max_adj = 999999999; |
|---|
| .. | .. |
|---|
| 702 | 711 | pf->ptp_caps.pps = 0; |
|---|
| 703 | 712 | pf->ptp_caps.adjfreq = i40e_ptp_adjfreq; |
|---|
| 704 | 713 | pf->ptp_caps.adjtime = i40e_ptp_adjtime; |
|---|
| 705 | | - pf->ptp_caps.gettime64 = i40e_ptp_gettime; |
|---|
| 714 | + pf->ptp_caps.gettimex64 = i40e_ptp_gettimex; |
|---|
| 706 | 715 | pf->ptp_caps.settime64 = i40e_ptp_settime; |
|---|
| 707 | 716 | pf->ptp_caps.enable = i40e_ptp_feature_enable; |
|---|
| 708 | 717 | |
|---|
| .. | .. |
|---|
| 718 | 727 | pf->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; |
|---|
| 719 | 728 | pf->tstamp_config.tx_type = HWTSTAMP_TX_OFF; |
|---|
| 720 | 729 | |
|---|
| 730 | + /* Set the previous "reset" time to the current Kernel clock time */ |
|---|
| 731 | + ktime_get_real_ts64(&pf->ptp_prev_hw_time); |
|---|
| 732 | + pf->ptp_reset_start = ktime_get(); |
|---|
| 733 | + |
|---|
| 721 | 734 | return 0; |
|---|
| 735 | +} |
|---|
| 736 | + |
|---|
| 737 | +/** |
|---|
| 738 | + * i40e_ptp_save_hw_time - Save the current PTP time as ptp_prev_hw_time |
|---|
| 739 | + * @pf: Board private structure |
|---|
| 740 | + * |
|---|
| 741 | + * Read the current PTP time and save it into pf->ptp_prev_hw_time. This should |
|---|
| 742 | + * be called at the end of preparing to reset, just before hardware reset |
|---|
| 743 | + * occurs, in order to preserve the PTP time as close as possible across |
|---|
| 744 | + * resets. |
|---|
| 745 | + */ |
|---|
| 746 | +void i40e_ptp_save_hw_time(struct i40e_pf *pf) |
|---|
| 747 | +{ |
|---|
| 748 | + /* don't try to access the PTP clock if it's not enabled */ |
|---|
| 749 | + if (!(pf->flags & I40E_FLAG_PTP)) |
|---|
| 750 | + return; |
|---|
| 751 | + |
|---|
| 752 | + i40e_ptp_gettimex(&pf->ptp_caps, &pf->ptp_prev_hw_time, NULL); |
|---|
| 753 | + /* Get a monotonic starting time for this reset */ |
|---|
| 754 | + pf->ptp_reset_start = ktime_get(); |
|---|
| 755 | +} |
|---|
| 756 | + |
|---|
| 757 | +/** |
|---|
| 758 | + * i40e_ptp_restore_hw_time - Restore the ptp_prev_hw_time + delta to PTP regs |
|---|
| 759 | + * @pf: Board private structure |
|---|
| 760 | + * |
|---|
| 761 | + * Restore the PTP hardware clock registers. We previously cached the PTP |
|---|
| 762 | + * hardware time as pf->ptp_prev_hw_time. To be as accurate as possible, |
|---|
| 763 | + * update this value based on the time delta since the time was saved, using |
|---|
| 764 | + * CLOCK_MONOTONIC (via ktime_get()) to calculate the time difference. |
|---|
| 765 | + * |
|---|
| 766 | + * This ensures that the hardware clock is restored to nearly what it should |
|---|
| 767 | + * have been if a reset had not occurred. |
|---|
| 768 | + */ |
|---|
| 769 | +void i40e_ptp_restore_hw_time(struct i40e_pf *pf) |
|---|
| 770 | +{ |
|---|
| 771 | + ktime_t delta = ktime_sub(ktime_get(), pf->ptp_reset_start); |
|---|
| 772 | + |
|---|
| 773 | + /* Update the previous HW time with the ktime delta */ |
|---|
| 774 | + timespec64_add_ns(&pf->ptp_prev_hw_time, ktime_to_ns(delta)); |
|---|
| 775 | + |
|---|
| 776 | + /* Restore the hardware clock registers */ |
|---|
| 777 | + i40e_ptp_settime(&pf->ptp_caps, &pf->ptp_prev_hw_time); |
|---|
| 722 | 778 | } |
|---|
| 723 | 779 | |
|---|
| 724 | 780 | /** |
|---|
| .. | .. |
|---|
| 728 | 784 | * This function sets device up for 1588 support. The first time it is run, it |
|---|
| 729 | 785 | * will create a PHC clock device. It does not create a clock device if one |
|---|
| 730 | 786 | * already exists. It also reconfigures the device after a reset. |
|---|
| 787 | + * |
|---|
| 788 | + * The first time a clock is created, i40e_ptp_create_clock will set |
|---|
| 789 | + * pf->ptp_prev_hw_time to the current system time. During resets, it is |
|---|
| 790 | + * expected that this timespec will be set to the last known PTP clock time, |
|---|
| 791 | + * in order to preserve the clock time as close as possible across a reset. |
|---|
| 731 | 792 | **/ |
|---|
| 732 | 793 | void i40e_ptp_init(struct i40e_pf *pf) |
|---|
| 733 | 794 | { |
|---|
| .. | .. |
|---|
| 759 | 820 | dev_err(&pf->pdev->dev, "%s: ptp_clock_register failed\n", |
|---|
| 760 | 821 | __func__); |
|---|
| 761 | 822 | } else if (pf->ptp_clock) { |
|---|
| 762 | | - struct timespec64 ts; |
|---|
| 763 | 823 | u32 regval; |
|---|
| 764 | 824 | |
|---|
| 765 | 825 | if (pf->hw.debug_mask & I40E_DEBUG_LAN) |
|---|
| .. | .. |
|---|
| 780 | 840 | /* reset timestamping mode */ |
|---|
| 781 | 841 | i40e_ptp_set_timestamp_mode(pf, &pf->tstamp_config); |
|---|
| 782 | 842 | |
|---|
| 783 | | - /* Set the clock value. */ |
|---|
| 784 | | - ts = ktime_to_timespec64(ktime_get_real()); |
|---|
| 785 | | - i40e_ptp_settime(&pf->ptp_caps, &ts); |
|---|
| 843 | + /* Restore the clock time based on last known value */ |
|---|
| 844 | + i40e_ptp_restore_hw_time(pf); |
|---|
| 786 | 845 | } |
|---|
| 787 | 846 | } |
|---|
| 788 | 847 | |
|---|