Use the direct __int128 calculation on 64-bit builds to keep the frequency adjustment path short and readable, while preserving the portable split-and-scale calculation on 32-bit builds where __int128 may be unavailable.
Both paths avoid the INT64_MIN negation issue in the original code. Coverity issue: 501832 Signed-off-by: Soumyadeep Hore <[email protected]> --- v3: - Fixed build failure for 32 bit systems --- v2: - Addressed Bruce's comments --- drivers/net/intel/idpf/idpf_ethdev.c | 78 ++++++++++++++++++---------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/drivers/net/intel/idpf/idpf_ethdev.c b/drivers/net/intel/idpf/idpf_ethdev.c index 5e57a45775..31291379d3 100644 --- a/drivers/net/intel/idpf/idpf_ethdev.c +++ b/drivers/net/intel/idpf/idpf_ethdev.c @@ -1005,42 +1005,64 @@ idpf_timesync_adjust_freq(struct rte_eth_dev *dev, int64_t ppm) struct idpf_vport *vport = dev->data->dev_private; struct idpf_adapter *adapter = vport->adapter; struct idpf_ptp *ptp = adapter->ptp; - int64_t incval, diff = 0; - bool negative = false; - uint64_t div, rem; - uint64_t divisor = 1000000ULL << 16; - int shift; + uint64_t incval; int ret; incval = ptp->base_incval; - if (ppm < 0) { - negative = true; - ppm = -ppm; - } - - /* can incval * ppm overflow ? */ - if (rte_log2_u64(incval) + rte_log2_u64(ppm) > 62) { - rem = ppm % divisor; - div = ppm / divisor; - diff = div * incval; - ppm = rem; +#ifdef RTE_ARCH_64 + /* ppm is scaled by 2^16 to match Linux adjfine. */ + { + __int128 diff; + + diff = ((__int128)incval * ppm) / (1000000LL << 16); + incval += (int64_t)diff; + } +#else + { + int64_t diff = 0; + bool negative = false; + uint64_t abs_ppm, div, rem; + uint64_t divisor = 1000000ULL << 16; + int shift; + + if (ppm < 0) { + negative = true; + abs_ppm = ppm == INT64_MIN ? (uint64_t)INT64_MAX + 1 : + (uint64_t)(-ppm); + } else { + abs_ppm = (uint64_t)ppm; + } - shift = rte_log2_u64(incval) + rte_log2_u64(ppm) - 62; - if (shift > 0) { - /* drop precision */ - ppm >>= shift; - divisor >>= shift; + /* can incval * ppm overflow ? */ + if (rte_log2_u64(incval) + rte_log2_u64(abs_ppm) > 62) { + rem = abs_ppm % divisor; + div = abs_ppm / divisor; + diff = div * incval; + abs_ppm = rem; + + if (abs_ppm != 0) { + uint32_t log_sum; + + log_sum = rte_log2_u64(incval) + rte_log2_u64(abs_ppm); + if (log_sum > 62) { + shift = log_sum - 62; + /* drop precision */ + abs_ppm >>= shift; + divisor >>= shift; + } + } } - } - if (divisor) - diff = diff + incval * ppm / divisor; + if (divisor) + diff += incval * abs_ppm / divisor; - if (negative) - incval -= diff; - else - incval += diff; + if (negative) + incval -= diff; + else + incval += diff; + } +#endif ret = idpf_ptp_adj_dev_clk_fine(adapter, incval); if (ret) { -- 2.47.1

