diff --git a/Makefile b/Makefile index 87c305a..2ced4e5 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ obj-y += os/linux/ip_utils.o obj-y += os/linux/ioctl.o obj-y += os/linux/kmem.o obj-y += os/linux/log.o +obj-y += os/linux/timers.o obj-y += os/linux/mem_mgmt_utils.o obj-y += os/linux/regops_utils.o diff --git a/hal/t234/t234_aperture.c b/hal/t234/t234_aperture.c index 84d000c..e794524 100644 --- a/hal/t234/t234_aperture.c +++ b/hal/t234/t234_aperture.c @@ -11,6 +11,7 @@ * more details. */ +#include #include #include #include @@ -25,8 +26,8 @@ int t234_hwpm_disable_triggers(struct tegra_soc_hwpm *hwpm) u32 reg_val = 0U; u32 field_mask = 0U; u32 field_val = 0U; - s32 timeout_msecs = 1000; u32 sleep_msecs = 100; + struct tegra_hwpm_timeout timeout; struct tegra_soc_hwpm_chip *active_chip = hwpm->active_chip; struct hwpm_ip *chip_ip = active_chip->chip_ips[ active_chip->get_rtr_int_idx(hwpm)]; @@ -84,7 +85,13 @@ int t234_hwpm_disable_triggers(struct tegra_soc_hwpm *hwpm) return err; } - /* Wait for PERFMONs, ROUTER, and PMA to idle */ + /* Wait for PERFMONs to idle */ + err = tegra_hwpm_timeout_init(hwpm, &timeout, 10U); + if (err != 0) { + tegra_hwpm_err(hwpm, "hwpm timeout init failed"); + return err; + } + do { err = tegra_hwpm_readl(hwpm, rtr_perfmux, pmmsys_sys0router_perfmonstatus_r(), ®_val); @@ -92,18 +99,22 @@ int t234_hwpm_disable_triggers(struct tegra_soc_hwpm *hwpm) tegra_hwpm_err(hwpm, "hwpm read failed"); return err; } - msleep(sleep_msecs); - timeout_msecs -= sleep_msecs; + tegra_hwpm_msleep(sleep_msecs); } while ((pmmsys_sys0router_perfmonstatus_merged_v(reg_val) != 0U) && - (timeout_msecs > 0)); + (tegra_hwpm_timeout_expired(hwpm, &timeout) == 0)); - if (timeout_msecs <= 0) { + if (pmmsys_sys0router_perfmonstatus_merged_v(reg_val) != 0U) { tegra_hwpm_err(hwpm, "Timeout expired for " "NV_PERF_PMMSYS_SYS0ROUTER_PERFMONSTATUS_MERGED_EMPTY"); return -ETIMEDOUT; } - timeout_msecs = 1000; + /* Wait for ROUTER to idle */ + err = tegra_hwpm_timeout_init(hwpm, &timeout, 10U); + if (err != 0) { + tegra_hwpm_err(hwpm, "hwpm timeout init failed"); + return err; + } do { err = tegra_hwpm_readl(hwpm, rtr_perfmux, @@ -112,18 +123,23 @@ int t234_hwpm_disable_triggers(struct tegra_soc_hwpm *hwpm) tegra_hwpm_err(hwpm, "hwpm read failed"); return err; } - msleep(sleep_msecs); - timeout_msecs -= sleep_msecs; + tegra_hwpm_msleep(sleep_msecs); } while ((pmmsys_sys0router_enginestatus_status_v(reg_val) != pmmsys_sys0router_enginestatus_status_empty_v()) && - (timeout_msecs > 0)); - if (timeout_msecs <= 0) { + (tegra_hwpm_timeout_expired(hwpm, &timeout) == 0)); + if (pmmsys_sys0router_enginestatus_status_v(reg_val) != + pmmsys_sys0router_enginestatus_status_empty_v()) { tegra_hwpm_err(hwpm, "Timeout expired for " "NV_PERF_PMMSYS_SYS0ROUTER_ENGINESTATUS_STATUS_EMPTY"); return -ETIMEDOUT; } - timeout_msecs = 1000; + /* Wait for PMA to idle */ + err = tegra_hwpm_timeout_init(hwpm, &timeout, 10U); + if (err != 0) { + tegra_hwpm_err(hwpm, "hwpm timeout init failed"); + return err; + } field_mask = pmasys_enginestatus_status_m() | pmasys_enginestatus_rbufempty_m(); @@ -136,11 +152,11 @@ int t234_hwpm_disable_triggers(struct tegra_soc_hwpm *hwpm) tegra_hwpm_err(hwpm, "hwpm read failed"); return err; } - msleep(sleep_msecs); - timeout_msecs -= sleep_msecs; - } while (((reg_val & field_mask) != field_val) && (timeout_msecs > 0)); + tegra_hwpm_msleep(sleep_msecs); + } while (((reg_val & field_mask) != field_val) && + (tegra_hwpm_timeout_expired(hwpm, &timeout) == 0)); - if (timeout_msecs <= 0) { + if ((reg_val & field_mask) != field_val) { tegra_hwpm_err(hwpm, "Timeout expired for " "NV_PERF_PMASYS_ENGINESTATUS"); return -ETIMEDOUT; diff --git a/include/tegra_hwpm_timers.h b/include/tegra_hwpm_timers.h new file mode 100644 index 0000000..4fda009 --- /dev/null +++ b/include/tegra_hwpm_timers.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef TEGRA_HWPM_TIMERS_H +#define TEGRA_HWPM_TIMERS_H + +#include + +#ifdef __KERNEL__ +#include +#else +int tegra_hwpm_timeout_init_impl(struct tegra_hwpm *hwpm, + struct tegra_hwpm_timeout *timeout, u32 retries) +{ + return -EINVAL; +} + +int tegra_hwpm_timeout_expired_impl(struct tegra_hwpm *hwpm, + struct tegra_hwpm_timeout *timeout) +{ + return -EINVAL; +} + +void tegra_hwpm_msleep_impl(unsigned int msecs) +{ + return -EINVAL; +} +#endif + +#define tegra_hwpm_timeout_init(hwpm, timeout, retries) \ + tegra_hwpm_timeout_init_impl(hwpm, timeout, retries) +#define tegra_hwpm_timeout_expired(hwpm, timeout) \ + tegra_hwpm_timeout_expired_impl(hwpm, timeout) +#define tegra_hwpm_msleep(msecs) \ + tegra_hwpm_msleep_impl(msecs) + +#endif /* TEGRA_HWPM_TIMERS_H */ diff --git a/os/linux/mem_mgmt_utils.c b/os/linux/mem_mgmt_utils.c index 1cb2492..cb11300 100644 --- a/os/linux/mem_mgmt_utils.c +++ b/os/linux/mem_mgmt_utils.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -243,10 +244,10 @@ int tegra_hwpm_clear_mem_pipeline(struct tegra_soc_hwpm *hwpm) /* Stream MEM_BYTES to clear pipeline */ if (hwpm->mem_mgmt->mem_bytes_kernel) { - s32 timeout_msecs = 1000; - u32 sleep_msecs = 100; u32 *mem_bytes_kernel_u32 = (u32 *)(hwpm->mem_mgmt->mem_bytes_kernel); + u32 sleep_msecs = 100; + struct tegra_hwpm_timeout timeout; do { ret = hwpm->active_chip->stream_mem_bytes(hwpm); @@ -255,13 +256,12 @@ int tegra_hwpm_clear_mem_pipeline(struct tegra_soc_hwpm *hwpm) "Trigger mem_bytes streaming failed"); goto fail; } - msleep(sleep_msecs); - timeout_msecs -= sleep_msecs; + tegra_hwpm_msleep(sleep_msecs); } while ((*mem_bytes_kernel_u32 == TEGRA_SOC_HWPM_MEM_BYTES_INVALID) && - (timeout_msecs > 0)); + (tegra_hwpm_timeout_expired(hwpm, &timeout) == 0)); - if (timeout_msecs <= 0) { + if (*mem_bytes_kernel_u32 == TEGRA_SOC_HWPM_MEM_BYTES_INVALID) { tegra_hwpm_err(hwpm, "Timeout expired for MEM_BYTES streaming"); return -ETIMEDOUT; diff --git a/os/linux/timers.c b/os/linux/timers.c new file mode 100644 index 0000000..fab9142 --- /dev/null +++ b/os/linux/timers.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include + +#include +#include + +int tegra_hwpm_timeout_init_impl(struct tegra_soc_hwpm *hwpm, + struct tegra_hwpm_timeout *timeout, u32 retries) +{ + timeout->max_attempts = retries; + timeout->attempted = 0; + + return 0; +} + +int tegra_hwpm_timeout_expired_impl(struct tegra_soc_hwpm *hwpm, + struct tegra_hwpm_timeout *timeout) +{ + if (timeout->attempted >= timeout->max_attempts) { + return -ETIMEDOUT; + } + + timeout->attempted++; + return 0; +} + +void tegra_hwpm_msleep_impl(unsigned int msecs) +{ + msleep(msecs); +} diff --git a/os/linux/timers.h b/os/linux/timers.h new file mode 100644 index 0000000..d97fa07 --- /dev/null +++ b/os/linux/timers.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef TEGRA_HWPM_OS_LINUX_TIMERS_H +#define TEGRA_HWPM_OS_LINUX_TIMERS_H + +struct tegra_hwpm_timeout { + u32 max_attempts; + u32 attempted; +}; + +struct tegra_soc_hwpm; + +int tegra_hwpm_timeout_init_impl(struct tegra_soc_hwpm *hwpm, + struct tegra_hwpm_timeout *timeout, u32 retries); +int tegra_hwpm_timeout_expired_impl(struct tegra_soc_hwpm *hwpm, + struct tegra_hwpm_timeout *timeout); + +void tegra_hwpm_msleep_impl(unsigned int msecs); + +#endif /* TEGRA_HWPM_OS_LINUX_TIMERS_H */