diff options
Diffstat (limited to 'drivers/net/ethernet/intel/idpf/idpf_ptp.c')
-rw-r--r-- | drivers/net/ethernet/intel/idpf/idpf_ptp.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c index 4f8725c85332..ee21f2ff0cad 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c @@ -42,6 +42,13 @@ void idpf_ptp_get_features_access(const struct idpf_adapter *adapter) direct, mailbox); + /* Get the cross timestamp */ + direct = VIRTCHNL2_CAP_PTP_GET_CROSS_TIME; + mailbox = VIRTCHNL2_CAP_PTP_GET_CROSS_TIME_MB; + ptp->get_cross_tstamp_access = idpf_ptp_get_access(adapter, + direct, + mailbox); + /* Set the device clock time */ direct = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME; mailbox = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME; @@ -171,6 +178,127 @@ static int idpf_ptp_read_src_clk_reg(struct idpf_adapter *adapter, u64 *src_clk, return 0; } +#if IS_ENABLED(CONFIG_ARM_ARCH_TIMER) || IS_ENABLED(CONFIG_X86) +/** + * idpf_ptp_get_sync_device_time_direct - Get the cross time stamp values + * directly + * @adapter: Driver specific private structure + * @dev_time: 64bit main timer value + * @sys_time: 64bit system time value + */ +static void idpf_ptp_get_sync_device_time_direct(struct idpf_adapter *adapter, + u64 *dev_time, u64 *sys_time) +{ + u32 dev_time_lo, dev_time_hi, sys_time_lo, sys_time_hi; + struct idpf_ptp *ptp = adapter->ptp; + + spin_lock(&ptp->read_dev_clk_lock); + + idpf_ptp_enable_shtime(adapter); + + dev_time_lo = readl(ptp->dev_clk_regs.dev_clk_ns_l); + dev_time_hi = readl(ptp->dev_clk_regs.dev_clk_ns_h); + + sys_time_lo = readl(ptp->dev_clk_regs.sys_time_ns_l); + sys_time_hi = readl(ptp->dev_clk_regs.sys_time_ns_h); + + spin_unlock(&ptp->read_dev_clk_lock); + + *dev_time = (u64)dev_time_hi << 32 | dev_time_lo; + *sys_time = (u64)sys_time_hi << 32 | sys_time_lo; +} + +/** + * idpf_ptp_get_sync_device_time_mailbox - Get the cross time stamp values + * through mailbox + * @adapter: Driver specific private structure + * @dev_time: 64bit main timer value expressed in nanoseconds + * @sys_time: 64bit system time value expressed in nanoseconds + * + * Return: 0 on success, -errno otherwise. + */ +static int idpf_ptp_get_sync_device_time_mailbox(struct idpf_adapter *adapter, + u64 *dev_time, u64 *sys_time) +{ + struct idpf_ptp_dev_timers cross_time; + int err; + + err = idpf_ptp_get_cross_time(adapter, &cross_time); + if (err) + return err; + + *dev_time = cross_time.dev_clk_time_ns; + *sys_time = cross_time.sys_time_ns; + + return err; +} + +/** + * idpf_ptp_get_sync_device_time - Get the cross time stamp info + * @device: Current device time + * @system: System counter value read synchronously with device time + * @ctx: Context provided by timekeeping code + * + * The device and the system clocks time read simultaneously. + * + * Return: 0 on success, -errno otherwise. + */ +static int idpf_ptp_get_sync_device_time(ktime_t *device, + struct system_counterval_t *system, + void *ctx) +{ + struct idpf_adapter *adapter = ctx; + u64 ns_time_dev, ns_time_sys; + int err; + + switch (adapter->ptp->get_cross_tstamp_access) { + case IDPF_PTP_NONE: + return -EOPNOTSUPP; + case IDPF_PTP_DIRECT: + idpf_ptp_get_sync_device_time_direct(adapter, &ns_time_dev, + &ns_time_sys); + break; + case IDPF_PTP_MAILBOX: + err = idpf_ptp_get_sync_device_time_mailbox(adapter, + &ns_time_dev, + &ns_time_sys); + if (err) + return err; + break; + default: + return -EOPNOTSUPP; + } + + *device = ns_to_ktime(ns_time_dev); + + system->cs_id = IS_ENABLED(CONFIG_X86) ? CSID_X86_ART + : CSID_ARM_ARCH_COUNTER; + system->cycles = ns_time_sys; + system->use_nsecs = true; + + return 0; +} + +/** + * idpf_ptp_get_crosststamp - Capture a device cross timestamp + * @info: the driver's PTP info structure + * @cts: The memory to fill the cross timestamp info + * + * Capture a cross timestamp between the system time and the device PTP hardware + * clock. + * + * Return: cross timestamp value on success, -errno on failure. + */ +static int idpf_ptp_get_crosststamp(struct ptp_clock_info *info, + struct system_device_crosststamp *cts) +{ + struct idpf_adapter *adapter = idpf_ptp_info_to_adapter(info); + + return get_device_system_crosststamp(idpf_ptp_get_sync_device_time, + adapter, NULL, cts); +} +#endif /* CONFIG_ARM_ARCH_TIMER || CONFIG_X86 */ + /** * idpf_ptp_gettimex64 - Get the time of the clock * @info: the driver's PTP info structure @@ -661,6 +789,14 @@ static void idpf_ptp_set_caps(const struct idpf_adapter *adapter) info->verify = idpf_ptp_verify_pin; info->enable = idpf_ptp_gpio_enable; info->do_aux_work = idpf_ptp_do_aux_work; +#if IS_ENABLED(CONFIG_ARM_ARCH_TIMER) + info->getcrosststamp = idpf_ptp_get_crosststamp; +#elif IS_ENABLED(CONFIG_X86) + if (pcie_ptm_enabled(adapter->pdev) && + boot_cpu_has(X86_FEATURE_ART) && + boot_cpu_has(X86_FEATURE_TSC_KNOWN_FREQ)) + info->getcrosststamp = idpf_ptp_get_crosststamp; +#endif /* CONFIG_ARM_ARCH_TIMER */ } /** |