| From 85fa9116d39817791f3da4dd642549db8916cb8e Mon Sep 17 00:00:00 2001 |
| From: Bo-Cun Chen <bc-bocun.chen@mediatek.com> |
| Date: Tue, 30 Jan 2024 12:29:37 +0800 |
| Subject: [PATCH] 999-1715-v6.2-net-ptp-introduce-adjust-by-scaled-ppm.patch |
| |
| --- |
| drivers/ptp/ptp_clock.c | 21 ------ |
| include/linux/math64.h | 12 ++++ |
| include/linux/ptp_clock_kernel.h | 72 +++++++++++++++++++ |
| lib/math/div64.c | 42 +++++++++++ |
| 4 files changed, 126 insertions(+), 21 deletions(-) |
| |
| diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c |
| index eedf067..5cca99f 100644 |
| --- a/drivers/ptp/ptp_clock.c |
| +++ b/drivers/ptp/ptp_clock.c |
| @@ -63,27 +63,6 @@ static void enqueue_external_timestamp(struct timestamp_event_queue *queue, |
| spin_unlock_irqrestore(&queue->lock, flags); |
| } |
| |
| -long scaled_ppm_to_ppb(long ppm) |
| -{ |
| - /* |
| - * The 'freq' field in the 'struct timex' is in parts per |
| - * million, but with a 16 bit binary fractional field. |
| - * |
| - * We want to calculate |
| - * |
| - * ppb = scaled_ppm * 1000 / 2^16 |
| - * |
| - * which simplifies to |
| - * |
| - * ppb = scaled_ppm * 125 / 2^13 |
| - */ |
| - s64 ppb = 1 + ppm; |
| - ppb *= 125; |
| - ppb >>= 13; |
| - return (long) ppb; |
| -} |
| -EXPORT_SYMBOL(scaled_ppm_to_ppb); |
| - |
| /* posix clock implementation */ |
| |
| static int ptp_clock_getres(struct posix_clock *pc, struct timespec64 *tp) |
| diff --git a/include/linux/math64.h b/include/linux/math64.h |
| index 65bef21..a593096 100644 |
| --- a/include/linux/math64.h |
| +++ b/include/linux/math64.h |
| @@ -281,6 +281,18 @@ static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor) |
| } |
| #endif /* mul_u64_u32_div */ |
| |
| +u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div); |
| + |
| +/** |
| + * DIV64_U64_ROUND_UP - unsigned 64bit divide with 64bit divisor rounded up |
| + * @ll: unsigned 64bit dividend |
| + * @d: unsigned 64bit divisor |
| + * |
| + * Divide unsigned 64bit dividend by unsigned 64bit divisor |
| + * and round up. |
| + * |
| + * Return: dividend / divisor rounded up |
| + */ |
| #define DIV64_U64_ROUND_UP(ll, d) \ |
| ({ u64 _tmp = (d); div64_u64((ll) + _tmp - 1, _tmp); }) |
| |
| diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h |
| index 874f7e7..2ff9afe 100644 |
| --- a/include/linux/ptp_clock_kernel.h |
| +++ b/include/linux/ptp_clock_kernel.h |
| @@ -169,6 +169,78 @@ struct ptp_clock_event { |
| }; |
| }; |
| |
| +/** |
| + * scaled_ppm_to_ppb() - convert scaled ppm to ppb |
| + * |
| + * @ppm: Parts per million, but with a 16 bit binary fractional field |
| + */ |
| +static inline long scaled_ppm_to_ppb(long ppm) |
| +{ |
| + /* |
| + * The 'freq' field in the 'struct timex' is in parts per |
| + * million, but with a 16 bit binary fractional field. |
| + * |
| + * We want to calculate |
| + * |
| + * ppb = scaled_ppm * 1000 / 2^16 |
| + * |
| + * which simplifies to |
| + * |
| + * ppb = scaled_ppm * 125 / 2^13 |
| + */ |
| + s64 ppb = 1 + ppm; |
| + |
| + ppb *= 125; |
| + ppb >>= 13; |
| + return (long)ppb; |
| +} |
| + |
| +/** |
| + * diff_by_scaled_ppm - Calculate difference using scaled ppm |
| + * @base: the base increment value to adjust |
| + * @scaled_ppm: scaled parts per million to adjust by |
| + * @diff: on return, the absolute value of calculated diff |
| + * |
| + * Calculate the difference to adjust the base increment using scaled parts |
| + * per million. |
| + * |
| + * Use mul_u64_u64_div_u64 to perform the difference calculation in avoid |
| + * possible overflow. |
| + * |
| + * Returns: true if scaled_ppm is negative, false otherwise |
| + */ |
| +static inline bool diff_by_scaled_ppm(u64 base, long scaled_ppm, u64 *diff) |
| +{ |
| + bool negative = false; |
| + |
| + if (scaled_ppm < 0) { |
| + negative = true; |
| + scaled_ppm = -scaled_ppm; |
| + } |
| + |
| + *diff = mul_u64_u64_div_u64(base, (u64)scaled_ppm, 1000000ULL << 16); |
| + |
| + return negative; |
| +} |
| + |
| +/** |
| + * adjust_by_scaled_ppm - Adjust a base increment by scaled parts per million |
| + * @base: the base increment value to adjust |
| + * @scaled_ppm: scaled parts per million frequency adjustment |
| + * |
| + * Helper function which calculates a new increment value based on the |
| + * requested scaled parts per million adjustment. |
| + */ |
| +static inline u64 adjust_by_scaled_ppm(u64 base, long scaled_ppm) |
| +{ |
| + u64 diff; |
| + |
| + if (diff_by_scaled_ppm(base, scaled_ppm, &diff)) |
| + return base - diff; |
| + |
| + return base + diff; |
| +} |
| + |
| #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK) |
| |
| /** |
| diff --git a/lib/math/div64.c b/lib/math/div64.c |
| index 368ca7f..edd1090 100644 |
| --- a/lib/math/div64.c |
| +++ b/lib/math/div64.c |
| @@ -190,3 +190,45 @@ u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder) |
| return __iter_div_u64_rem(dividend, divisor, remainder); |
| } |
| EXPORT_SYMBOL(iter_div_u64_rem); |
| + |
| +#ifndef mul_u64_u64_div_u64 |
| +u64 mul_u64_u64_div_u64(u64 a, u64 b, u64 c) |
| +{ |
| + u64 res = 0, div, rem; |
| + int shift; |
| + |
| + /* can a * b overflow ? */ |
| + if (ilog2(a) + ilog2(b) > 62) { |
| + /* |
| + * (b * a) / c is equal to |
| + * |
| + * (b / c) * a + |
| + * (b % c) * a / c |
| + * |
| + * if nothing overflows. Can the 1st multiplication |
| + * overflow? Yes, but we do not care: this can only |
| + * happen if the end result can't fit in u64 anyway. |
| + * |
| + * So the code below does |
| + * |
| + * res = (b / c) * a; |
| + * b = b % c; |
| + */ |
| + div = div64_u64_rem(b, c, &rem); |
| + res = div * a; |
| + b = rem; |
| + |
| + shift = ilog2(a) + ilog2(b) - 62; |
| + if (shift > 0) { |
| + /* drop precision */ |
| + b >>= shift; |
| + c >>= shift; |
| + if (!c) |
| + return res; |
| + } |
| + } |
| + |
| + return res + div64_u64(a * b, c); |
| +} |
| +EXPORT_SYMBOL(mul_u64_u64_div_u64); |
| +#endif |
| -- |
| 2.18.0 |