| From: Xiaoming Gao <gxm.linux.kernel@gmail.com> |
| Date: Fri, 13 Apr 2018 17:48:08 +0800 |
| Subject: x86/tsc: Prevent 32bit truncation in calc_hpet_ref() |
| |
| commit d3878e164dcd3925a237a20e879432400e369172 upstream. |
| |
| The TSC calibration code uses HPET as reference. The conversion normalizes |
| the delta of two HPET timestamps: |
| |
| hpetref = ((tshpet1 - tshpet2) * HPET_PERIOD) / 1e6 |
| |
| and then divides the normalized delta of the corresponding TSC timestamps |
| by the result to calulate the TSC frequency. |
| |
| tscfreq = ((tstsc1 - tstsc2 ) * 1e6) / hpetref |
| |
| This uses do_div() which takes an u32 as the divisor, which worked so far |
| because the HPET frequency was low enough that 'hpetref' never exceeded |
| 32bit. |
| |
| On Skylake machines the HPET frequency increased so 'hpetref' can exceed |
| 32bit. do_div() truncates the divisor, which causes the calibration to |
| fail. |
| |
| Use div64_u64() to avoid the problem. |
| |
| [ tglx: Fixes whitespace mangled patch and rewrote changelog ] |
| |
| Signed-off-by: Xiaoming Gao <newtongao@tencent.com> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Cc: peterz@infradead.org |
| Cc: hpa@zytor.com |
| Link: https://lkml.kernel.org/r/38894564-4fc9-b8ec-353f-de702839e44e@gmail.com |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| arch/x86/kernel/tsc.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/arch/x86/kernel/tsc.c |
| +++ b/arch/x86/kernel/tsc.c |
| @@ -398,7 +398,7 @@ static unsigned long calc_hpet_ref(u64 d |
| hpet2 -= hpet1; |
| tmp = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); |
| do_div(tmp, 1000000); |
| - do_div(deltatsc, tmp); |
| + deltatsc = div64_u64(deltatsc, tmp); |
| |
| return (unsigned long) deltatsc; |
| } |