From 1595ecce1cf32688760281f40b58b7a1d4a69aa9 Mon Sep 17 00:00:00 2001 From: Krishnanand Prabhu Date: Mon, 20 Mar 2023 12:33:02 +0200 Subject: wifi: iwlwifi: mvm: add support for PTP HW clock (PHC) Add support to enable/disable PHC clock. The PHC clock includes support for fetching the cross timestamp i.e. a non-atomic snapshot of the current time from the hardware (WiFi device) clock and system clock (wall-clock) simultaneously. Signed-off-by: Krishnanand Prabhu Signed-off-by: Luca Coelho Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230320122330.ae1d64f513b9.Ib3b6ad61c9fa2fc5908f1e0d6f59f4af6eec1a77@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 131 +++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 drivers/net/wireless/intel/iwlwifi/mvm/ptp.c (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ptp.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c new file mode 100644 index 000000000000..f786f5efb497 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2021 - 2023 Intel Corporation + */ + +#include "mvm.h" +#include "iwl-debug.h" +#include + +#define IWL_PTP_GP2_WRAP 0x100000000ULL +#define IWL_PTP_WRAP_TIME (3600 * HZ) + +static void iwl_mvm_ptp_update_new_read(struct iwl_mvm *mvm, u32 gp2) +{ + if (gp2 < mvm->ptp_data.last_gp2) { + mvm->ptp_data.wrap_counter++; + IWL_DEBUG_INFO(mvm, + "PTP: wraparound detected (new counter=%u)\n", + mvm->ptp_data.wrap_counter); + } + + mvm->ptp_data.last_gp2 = gp2; + schedule_delayed_work(&mvm->ptp_data.dwork, IWL_PTP_WRAP_TIME); +} + +static int +iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp, + struct system_device_crosststamp *xtstamp) +{ + struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm, + ptp_data.ptp_clock_info); + /* Raw value read from GP2 register in usec */ + u32 gp2; + /* GP2 value in ns*/ + s64 gp2_ns; + /* System (wall) time */ + ktime_t sys_time; + + memset(xtstamp, 0, sizeof(struct system_device_crosststamp)); + + if (!mvm->ptp_data.ptp_clock) { + IWL_ERR(mvm, "No PHC clock registered\n"); + return -ENODEV; + } + + iwl_mvm_get_sync_time(mvm, CLOCK_REALTIME, &gp2, NULL, &sys_time); + + iwl_mvm_ptp_update_new_read(mvm, gp2); + + gp2_ns = (gp2 + (mvm->ptp_data.wrap_counter * IWL_PTP_GP2_WRAP)) * + NSEC_PER_USEC; + + IWL_INFO(mvm, "Got Sync Time: GP2:%u, last_GP2: %u, GP2_ns: %lld, sys_time: %lld\n", + gp2, mvm->ptp_data.last_gp2, gp2_ns, (s64)sys_time); + + /* System monotonic raw time is not used */ + xtstamp->device = (ktime_t)gp2_ns; + xtstamp->sys_realtime = sys_time; + + return 0; +} + +static void iwl_mvm_ptp_work(struct work_struct *wk) +{ + struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, + ptp_data.dwork.work); + u32 gp2; + + mutex_lock(&mvm->mutex); + gp2 = iwl_mvm_get_systime(mvm); + iwl_mvm_ptp_update_new_read(mvm, gp2); + mutex_unlock(&mvm->mutex); +} + +/* iwl_mvm_ptp_init - initialize PTP for devices which support it. + * @mvm: internal mvm structure, see &struct iwl_mvm. + * + * Performs the required steps for enabling PTP support. + */ +void iwl_mvm_ptp_init(struct iwl_mvm *mvm) +{ + /* Warn if the interface already has a ptp_clock defined */ + if (WARN_ON(mvm->ptp_data.ptp_clock)) + return; + + mvm->ptp_data.ptp_clock_info.owner = THIS_MODULE; + mvm->ptp_data.ptp_clock_info.max_adj = 0x7fffffff; + mvm->ptp_data.ptp_clock_info.getcrosststamp = + iwl_mvm_phc_get_crosstimestamp; + + /* Give a short 'friendly name' to identify the PHC clock */ + snprintf(mvm->ptp_data.ptp_clock_info.name, + sizeof(mvm->ptp_data.ptp_clock_info.name), + "%s", "iwlwifi-PTP"); + + INIT_DELAYED_WORK(&mvm->ptp_data.dwork, iwl_mvm_ptp_work); + + mvm->ptp_data.ptp_clock = + ptp_clock_register(&mvm->ptp_data.ptp_clock_info, mvm->dev); + + if (IS_ERR(mvm->ptp_data.ptp_clock)) { + IWL_ERR(mvm, "Failed to register PHC clock (%ld)\n", + PTR_ERR(mvm->ptp_data.ptp_clock)); + mvm->ptp_data.ptp_clock = NULL; + } else if (mvm->ptp_data.ptp_clock) { + IWL_INFO(mvm, "Registered PHC clock: %s, with index: %d\n", + mvm->ptp_data.ptp_clock_info.name, + ptp_clock_index(mvm->ptp_data.ptp_clock)); + } +} + +/* iwl_mvm_ptp_remove - disable PTP device. + * @mvm: internal mvm structure, see &struct iwl_mvm. + * + * Disable PTP support. + */ +void iwl_mvm_ptp_remove(struct iwl_mvm *mvm) +{ + if (mvm->ptp_data.ptp_clock) { + IWL_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n", + mvm->ptp_data.ptp_clock_info.name, + ptp_clock_index(mvm->ptp_data.ptp_clock)); + + ptp_clock_unregister(mvm->ptp_data.ptp_clock); + mvm->ptp_data.ptp_clock = NULL; + memset(&mvm->ptp_data.ptp_clock_info, 0, + sizeof(mvm->ptp_data.ptp_clock_info)); + mvm->ptp_data.last_gp2 = 0; + cancel_delayed_work_sync(&mvm->ptp_data.dwork); + } +} -- cgit From 21fb8da6ebe40ce83468d6198143b4b583b967f9 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Mon, 20 Mar 2023 12:33:03 +0200 Subject: wifi: iwlwifi: mvm: read synced time from firmware if supported If the firmware supports reading synced GP2/ATRB timestamps, read the synced timestamps from firmware instead of reading the GP2 register and the system time separately. Reading the synced time from firmware should be more accurate. Signed-off-by: Avraham Stern Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230320122330.a6be5f0b5580.Idedb496a5943fa496143066ffbed08185a8c4582@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 57 +++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ptp.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c index f786f5efb497..10f23c8b1dd4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -23,12 +23,54 @@ static void iwl_mvm_ptp_update_new_read(struct iwl_mvm *mvm, u32 gp2) schedule_delayed_work(&mvm->ptp_data.dwork, IWL_PTP_WRAP_TIME); } +static int +iwl_mvm_get_crosstimestamp_fw(struct iwl_mvm *mvm, u32 *gp2, u64 *sys_time) +{ + struct iwl_synced_time_cmd synced_time_cmd = { + .operation = cpu_to_le32(IWL_SYNCED_TIME_OPERATION_READ_BOTH) + }; + struct iwl_host_cmd cmd = { + .id = WIDE_ID(DATA_PATH_GROUP, WNM_PLATFORM_PTM_REQUEST_CMD), + .flags = CMD_WANT_SKB, + .data[0] = &synced_time_cmd, + .len[0] = sizeof(synced_time_cmd), + }; + struct iwl_synced_time_rsp *resp; + struct iwl_rx_packet *pkt; + int ret; + u64 gp2_10ns; + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret) + return ret; + + pkt = cmd.resp_pkt; + + if (iwl_rx_packet_payload_len(pkt) != sizeof(*resp)) { + IWL_ERR(mvm, "PTP: Invalid command response\n"); + iwl_free_resp(&cmd); + return -EIO; + } + + resp = (void *)pkt->data; + + gp2_10ns = (u64)le32_to_cpu(resp->gp2_timestamp_hi) << 32 | + le32_to_cpu(resp->gp2_timestamp_lo); + *gp2 = gp2_10ns / 100; + + *sys_time = (u64)le32_to_cpu(resp->platform_timestamp_hi) << 32 | + le32_to_cpu(resp->platform_timestamp_lo); + + return ret; +} + static int iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp, struct system_device_crosststamp *xtstamp) { struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm, ptp_data.ptp_clock_info); + int ret = 0; /* Raw value read from GP2 register in usec */ u32 gp2; /* GP2 value in ns*/ @@ -43,7 +85,16 @@ iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp, return -ENODEV; } - iwl_mvm_get_sync_time(mvm, CLOCK_REALTIME, &gp2, NULL, &sys_time); + mutex_lock(&mvm->mutex); + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SYNCED_TIME)) { + ret = iwl_mvm_get_crosstimestamp_fw(mvm, &gp2, &sys_time); + + if (ret) + goto out; + } else { + iwl_mvm_get_sync_time(mvm, CLOCK_REALTIME, &gp2, NULL, + &sys_time); + } iwl_mvm_ptp_update_new_read(mvm, gp2); @@ -57,7 +108,9 @@ iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp, xtstamp->device = (ktime_t)gp2_ns; xtstamp->sys_realtime = sys_time; - return 0; +out: + mutex_unlock(&mvm->mutex); + return ret; } static void iwl_mvm_ptp_work(struct work_struct *wk) -- cgit From a2f49f7d52a9e7d0dce8f090541a28192b7abd59 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Mon, 20 Mar 2023 12:33:07 +0200 Subject: wifi: iwlwifi: mvm: implement PHC clock adjustments Implement the following PHC operations: 1. adjtime - for adding an offset to the PHC clock time. 2. adjfine - for adjusting the PHC clock frequency. 3. gettime64 - for getting the PHC clock time. This function returns the time as adjusted by adjtime and adjfine. The adjusted time will also be used for time sync frames timestamping. Signed-off-by: Avraham Stern Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230320122330.f59750deeee4.I110a7e3ac3c6d39d9dbe1fe77001e3f5bc3814eb@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 127 ++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 4 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ptp.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c index 10f23c8b1dd4..1eafaaed415d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -6,12 +6,31 @@ #include "mvm.h" #include "iwl-debug.h" #include +#include #define IWL_PTP_GP2_WRAP 0x100000000ULL #define IWL_PTP_WRAP_TIME (3600 * HZ) +/* The scaled_ppm parameter is ppm (parts per million) with a 16-bit fractional + * part, which means that a value of 1 in one of those fields actually means + * 2^-16 ppm, and 2^16=65536 is 1 ppm. + */ +#define SCALE_FACTOR 65536000000ULL +#define IWL_PTP_WRAP_THRESHOLD_USEC (5000) + static void iwl_mvm_ptp_update_new_read(struct iwl_mvm *mvm, u32 gp2) { + /* If the difference is above the threshold, assume it's a wraparound. + * Otherwise assume it's an old read and ignore it. + */ + if (gp2 < mvm->ptp_data.last_gp2 && + mvm->ptp_data.last_gp2 - gp2 < IWL_PTP_WRAP_THRESHOLD_USEC) { + IWL_DEBUG_INFO(mvm, + "PTP: ignore old read (gp2=%u, last_gp2=%u)\n", + gp2, mvm->ptp_data.last_gp2); + return; + } + if (gp2 < mvm->ptp_data.last_gp2) { mvm->ptp_data.wrap_counter++; IWL_DEBUG_INFO(mvm, @@ -23,6 +42,45 @@ static void iwl_mvm_ptp_update_new_read(struct iwl_mvm *mvm, u32 gp2) schedule_delayed_work(&mvm->ptp_data.dwork, IWL_PTP_WRAP_TIME); } +u64 iwl_mvm_ptp_get_adj_time(struct iwl_mvm *mvm, u64 base_time_ns) +{ + struct ptp_data *data = &mvm->ptp_data; + u64 last_gp2_ns = mvm->ptp_data.scale_update_gp2 * NSEC_PER_USEC; + u64 res; + u64 diff; + + iwl_mvm_ptp_update_new_read(mvm, + div64_u64(base_time_ns, NSEC_PER_USEC)); + + IWL_DEBUG_INFO(mvm, "base_time_ns=%llu, wrap_counter=%u\n", + (unsigned long long)base_time_ns, data->wrap_counter); + + base_time_ns = base_time_ns + + (data->wrap_counter * IWL_PTP_GP2_WRAP * NSEC_PER_USEC); + + /* It is possible that a GP2 timestamp was received from fw before the + * last scale update. Since we don't know how to scale - ignore it. + */ + if (base_time_ns < last_gp2_ns) { + IWL_DEBUG_INFO(mvm, "Time before scale update - ignore\n"); + return 0; + } + + diff = base_time_ns - last_gp2_ns; + IWL_DEBUG_INFO(mvm, "diff ns=%llu\n", (unsigned long long)diff); + + diff = mul_u64_u64_div_u64(diff, data->scaled_freq, + SCALE_FACTOR); + IWL_DEBUG_INFO(mvm, "scaled diff ns=%llu\n", (unsigned long long)diff); + + res = data->scale_update_adj_time_ns + data->delta + diff; + + IWL_DEBUG_INFO(mvm, "base=%llu delta=%lld adj=%llu\n", + (unsigned long long)base_time_ns, (long long)data->delta, + (unsigned long long)res); + return res; +} + static int iwl_mvm_get_crosstimestamp_fw(struct iwl_mvm *mvm, u32 *gp2, u64 *sys_time) { @@ -96,10 +154,7 @@ iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp, &sys_time); } - iwl_mvm_ptp_update_new_read(mvm, gp2); - - gp2_ns = (gp2 + (mvm->ptp_data.wrap_counter * IWL_PTP_GP2_WRAP)) * - NSEC_PER_USEC; + gp2_ns = iwl_mvm_ptp_get_adj_time(mvm, (u64)gp2 * NSEC_PER_USEC); IWL_INFO(mvm, "Got Sync Time: GP2:%u, last_GP2: %u, GP2_ns: %lld, sys_time: %lld\n", gp2, mvm->ptp_data.last_gp2, gp2_ns, (s64)sys_time); @@ -125,6 +180,66 @@ static void iwl_mvm_ptp_work(struct work_struct *wk) mutex_unlock(&mvm->mutex); } +static int iwl_mvm_ptp_gettime(struct ptp_clock_info *ptp, + struct timespec64 *ts) +{ + struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm, + ptp_data.ptp_clock_info); + u64 gp2; + u64 ns; + + mutex_lock(&mvm->mutex); + gp2 = iwl_mvm_get_systime(mvm); + ns = iwl_mvm_ptp_get_adj_time(mvm, gp2 * NSEC_PER_USEC); + mutex_unlock(&mvm->mutex); + + *ts = ns_to_timespec64(ns); + return 0; +} + +static int iwl_mvm_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm, + ptp_data.ptp_clock_info); + struct ptp_data *data = container_of(ptp, struct ptp_data, + ptp_clock_info); + + mutex_lock(&mvm->mutex); + data->delta += delta; + IWL_DEBUG_INFO(mvm, "delta=%lld, new delta=%lld\n", (long long)delta, + (long long)data->delta); + mutex_unlock(&mvm->mutex); + return 0; +} + +static int iwl_mvm_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm, + ptp_data.ptp_clock_info); + struct ptp_data *data = &mvm->ptp_data; + u32 gp2; + + mutex_lock(&mvm->mutex); + + /* Must call _iwl_mvm_ptp_get_adj_time() before updating + * data->scale_update_gp2 or data->scaled_freq since + * scale_update_adj_time_ns should reflect the previous scaled_freq. + */ + gp2 = iwl_mvm_get_systime(mvm); + data->scale_update_adj_time_ns = + iwl_mvm_ptp_get_adj_time(mvm, gp2 * NSEC_PER_USEC); + data->scale_update_gp2 = gp2; + data->wrap_counter = 0; + data->delta = 0; + + data->scaled_freq = SCALE_FACTOR + scaled_ppm; + IWL_DEBUG_INFO(mvm, "adjfine: scaled_ppm=%ld new=%llu\n", + scaled_ppm, (unsigned long long)data->scaled_freq); + + mutex_unlock(&mvm->mutex); + return 0; +} + /* iwl_mvm_ptp_init - initialize PTP for devices which support it. * @mvm: internal mvm structure, see &struct iwl_mvm. * @@ -140,6 +255,10 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm) mvm->ptp_data.ptp_clock_info.max_adj = 0x7fffffff; mvm->ptp_data.ptp_clock_info.getcrosststamp = iwl_mvm_phc_get_crosstimestamp; + mvm->ptp_data.ptp_clock_info.adjfine = iwl_mvm_ptp_adjfine; + mvm->ptp_data.ptp_clock_info.adjtime = iwl_mvm_ptp_adjtime; + mvm->ptp_data.ptp_clock_info.gettime64 = iwl_mvm_ptp_gettime; + mvm->ptp_data.scaled_freq = SCALE_FACTOR; /* Give a short 'friendly name' to identify the PHC clock */ snprintf(mvm->ptp_data.ptp_clock_info.name, -- cgit From e86103394474b0c15eca4bb9ed678f6e9ab5d004 Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Mon, 20 Mar 2023 12:33:08 +0200 Subject: wifi: iwlwifi: mvm: select ptp cross timestamp from multiple reads iwl_mvm_get_sync_time() reads the gp2 from the device and then reads the system clock. Since the two reads are not done atomically, unexpected delays may happen between the two reads (e.g. context switch) which make it inaccurate. In order to improve the accuracy of the cross timestamp, call iwl_mvm_get_sync_time() multiple times in a loop and take the result in which the difference between the two clock is the smallest. Signed-off-by: Avraham Stern Signed-off-by: Gregory Greenman Link: https://lore.kernel.org/r/20230320122330.d9e6f8f8998a.I569939ec4ddf0c6c64c112e7d0c30583f5509d9a@changeid Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ptp.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c index 1eafaaed415d..5c2bfc8ed88d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -18,6 +18,8 @@ #define SCALE_FACTOR 65536000000ULL #define IWL_PTP_WRAP_THRESHOLD_USEC (5000) +#define IWL_PTP_GET_CROSS_TS_NUM 5 + static void iwl_mvm_ptp_update_new_read(struct iwl_mvm *mvm, u32 gp2) { /* If the difference is above the threshold, assume it's a wraparound. @@ -122,6 +124,28 @@ iwl_mvm_get_crosstimestamp_fw(struct iwl_mvm *mvm, u32 *gp2, u64 *sys_time) return ret; } +static void iwl_mvm_phc_get_crosstimestamp_loop(struct iwl_mvm *mvm, + ktime_t *sys_time, u32 *gp2) +{ + u64 diff = 0, new_diff; + u64 tmp_sys_time; + u32 tmp_gp2; + int i; + + for (i = 0; i < IWL_PTP_GET_CROSS_TS_NUM; i++) { + iwl_mvm_get_sync_time(mvm, CLOCK_REALTIME, &tmp_gp2, NULL, + &tmp_sys_time); + new_diff = tmp_sys_time - ((u64)tmp_gp2 * NSEC_PER_USEC); + if (!diff || new_diff < diff) { + *sys_time = tmp_sys_time; + *gp2 = tmp_gp2; + diff = new_diff; + IWL_DEBUG_INFO(mvm, "PTP: new times: gp2=%u sys=%lld\n", + *gp2, *sys_time); + } + } +} + static int iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp, struct system_device_crosststamp *xtstamp) @@ -150,8 +174,7 @@ iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp, if (ret) goto out; } else { - iwl_mvm_get_sync_time(mvm, CLOCK_REALTIME, &gp2, NULL, - &sys_time); + iwl_mvm_phc_get_crosstimestamp_loop(mvm, &sys_time, &gp2); } gp2_ns = iwl_mvm_ptp_get_adj_time(mvm, (u64)gp2 * NSEC_PER_USEC); -- cgit From 6cf882d9aa9e8f1f2d63182e179ac4b2e59c00db Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 29 Mar 2023 10:32:46 -0700 Subject: wifi: iwlwifi: mvm: Use 64-bit division helper in iwl_mvm_get_crosstimestamp_fw() There is a 64-bit division in iwl_mvm_get_crosstimestamp_fw(), which results in a link failure when building 32-bit architectures with clang: ld.lld: error: undefined symbol: __udivdi3 >>> referenced by ptp.c >>> drivers/net/wireless/intel/iwlwifi/mvm/ptp.o:(iwl_mvm_phc_get_crosstimestamp) in archive vmlinux.a GCC has optimizations for division by a constant that clang does not implement, so this issue is not visible when building with GCC. Use the 64-bit division helper div_u64(), which takes a u64 dividend and u32 divisor, which matches this situation and prevents the emission of a libcall for the division. Fixes: 21fb8da6ebe4 ("wifi: iwlwifi: mvm: read synced time from firmware if supported") Reported-by: Arnd Bergmann Link: https://github.com/ClangBuiltLinux/linux/issues/1826 Reported-by: "kernelci.org bot" Link: https://lore.kernel.org/6423173a.620a0220.3d5cc.6358@mx.google.com/ Signed-off-by: Nathan Chancellor Signed-off-by: Johannes Berg --- drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/ptp.c') diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c index 5c2bfc8ed88d..e89259de6f4c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -116,7 +116,7 @@ iwl_mvm_get_crosstimestamp_fw(struct iwl_mvm *mvm, u32 *gp2, u64 *sys_time) gp2_10ns = (u64)le32_to_cpu(resp->gp2_timestamp_hi) << 32 | le32_to_cpu(resp->gp2_timestamp_lo); - *gp2 = gp2_10ns / 100; + *gp2 = div_u64(gp2_10ns, 100); *sys_time = (u64)le32_to_cpu(resp->platform_timestamp_hi) << 32 | le32_to_cpu(resp->platform_timestamp_lo); -- cgit