From: Christopher Hall <christopher.s.hall@xxxxxxxxx> The PWM 'apply' interface uses units of nominal nanoseconds for period and the Intel(R) PMC Timed I/O hardware requires a period in terms of ART cycles. Add a function using ART conversion coefficients determined at boot time by the TSC initialization code to convert from ART in nominal nanoseconds to ART cycles. Signed-off-by: Christopher Hall <christopher.s.hall@xxxxxxxxx> Signed-off-by: Tamal Saha <tamal.saha@xxxxxxxxx> Signed-off-by: Lakshmi Sowjanya D <lakshmi.sowjanya.d@xxxxxxxxx> Reviewed-by: Mark Gross <mgross@xxxxxxxxxxxxxxx> --- arch/x86/include/asm/tsc.h | 1 + arch/x86/kernel/tsc.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h index f1de7ede3ec9..e53507df92e1 100644 --- a/arch/x86/include/asm/tsc.h +++ b/arch/x86/include/asm/tsc.h @@ -34,6 +34,7 @@ extern u64 read_art_time(void); extern int convert_tsc_to_art(const struct system_counterval_t *tsc, u64 *art); extern struct system_counterval_t convert_art_to_tsc(u64 art); extern struct system_counterval_t convert_art_ns_to_tsc(u64 art_ns); +extern u64 convert_art_ns_to_art(u64 art_ns); extern void tsc_early_init(void); extern void tsc_init(void); diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 040109228100..381d15894dd2 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -1329,6 +1329,38 @@ struct system_counterval_t convert_art_ns_to_tsc(u64 art_ns) } EXPORT_SYMBOL(convert_art_ns_to_tsc); +/* + * convert_art_ns_to_art() - Convert ART in nanoseconds to ART + * @art_ns: ART (Always Running Timer) in nominal nanoseconds + * + * Computes the ART cycles given the duration in nominal nanoseconds + * + * This is valid when CPU feature flag X86_FEATURE_TSC_KNOWN_FREQ is set + * indicating the tsc_khz is derived from CPUID[15H]. Drivers should check + * that this flag is set before conversion to ART is attempted. + * + * Return: + * u64 ART value rounded to nearest cycle corresponding to nanosecond + * duration input + */ +u64 convert_art_ns_to_art(u64 art_ns) +{ + u64 tmp, res, rem; + u32 crystal_khz; + + crystal_khz = (tsc_khz * art_to_tsc_denominator) / + art_to_tsc_numerator; + + rem = do_div(art_ns, USEC_PER_SEC); + res = art_ns * crystal_khz; + tmp = rem * crystal_khz; + + rem = do_div(tmp, USEC_PER_SEC); + res += rem < USEC_PER_SEC / 2 ? tmp : tmp + 1; + + return res; +} +EXPORT_SYMBOL(convert_art_ns_to_art); static void tsc_refine_calibration_work(struct work_struct *work); static DECLARE_DELAYED_WORK(tsc_irqwork, tsc_refine_calibration_work); -- 2.17.1