176 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Name: hwtimer.c - ACPI Power Management Timer Interface5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#define EXPORT_ACPI_INTERFACES11 12#include <acpi/acpi.h>13#include "accommon.h"14 15#define _COMPONENT ACPI_HARDWARE16ACPI_MODULE_NAME("hwtimer")17 18#if (!ACPI_REDUCED_HARDWARE) /* Entire module */19/******************************************************************************20 *21 * FUNCTION: acpi_get_timer_resolution22 *23 * PARAMETERS: resolution - Where the resolution is returned24 *25 * RETURN: Status and timer resolution26 *27 * DESCRIPTION: Obtains resolution of the ACPI PM Timer (24 or 32 bits).28 *29 ******************************************************************************/30acpi_status acpi_get_timer_resolution(u32 * resolution)31{32 ACPI_FUNCTION_TRACE(acpi_get_timer_resolution);33 34 if (!resolution) {35 return_ACPI_STATUS(AE_BAD_PARAMETER);36 }37 38 if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {39 *resolution = 24;40 } else {41 *resolution = 32;42 }43 44 return_ACPI_STATUS(AE_OK);45}46 47ACPI_EXPORT_SYMBOL(acpi_get_timer_resolution)48 49/******************************************************************************50 *51 * FUNCTION: acpi_get_timer52 *53 * PARAMETERS: ticks - Where the timer value is returned54 *55 * RETURN: Status and current timer value (ticks)56 *57 * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks).58 *59 ******************************************************************************/60acpi_status acpi_get_timer(u32 * ticks)61{62 acpi_status status;63 u64 timer_value;64 65 ACPI_FUNCTION_TRACE(acpi_get_timer);66 67 if (!ticks) {68 return_ACPI_STATUS(AE_BAD_PARAMETER);69 }70 71 /* ACPI 5.0A: PM Timer is optional */72 73 if (!acpi_gbl_FADT.xpm_timer_block.address) {74 return_ACPI_STATUS(AE_SUPPORT);75 }76 77 status = acpi_hw_read(&timer_value, &acpi_gbl_FADT.xpm_timer_block);78 if (ACPI_SUCCESS(status)) {79 80 /* ACPI PM Timer is defined to be 32 bits (PM_TMR_LEN) */81 82 *ticks = (u32)timer_value;83 }84 85 return_ACPI_STATUS(status);86}87 88ACPI_EXPORT_SYMBOL(acpi_get_timer)89 90/******************************************************************************91 *92 * FUNCTION: acpi_get_timer_duration93 *94 * PARAMETERS: start_ticks - Starting timestamp95 * end_ticks - End timestamp96 * time_elapsed - Where the elapsed time is returned97 *98 * RETURN: Status and time_elapsed99 *100 * DESCRIPTION: Computes the time elapsed (in microseconds) between two101 * PM Timer time stamps, taking into account the possibility of102 * rollovers, the timer resolution, and timer frequency.103 *104 * The PM Timer's clock ticks at roughly 3.6 times per105 * _microsecond_, and its clock continues through Cx state106 * transitions (unlike many CPU timestamp counters) -- making it107 * a versatile and accurate timer.108 *109 * Note that this function accommodates only a single timer110 * rollover. Thus for 24-bit timers, this function should only111 * be used for calculating durations less than ~4.6 seconds112 * (~20 minutes for 32-bit timers) -- calculations below:113 *114 * 2**24 Ticks / 3,600,000 Ticks/Sec = 4.66 sec115 * 2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes116 *117 ******************************************************************************/118acpi_status119acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 *time_elapsed)120{121 acpi_status status;122 u64 delta_ticks;123 u64 quotient;124 125 ACPI_FUNCTION_TRACE(acpi_get_timer_duration);126 127 if (!time_elapsed) {128 return_ACPI_STATUS(AE_BAD_PARAMETER);129 }130 131 /* ACPI 5.0A: PM Timer is optional */132 133 if (!acpi_gbl_FADT.xpm_timer_block.address) {134 return_ACPI_STATUS(AE_SUPPORT);135 }136 137 if (start_ticks == end_ticks) {138 *time_elapsed = 0;139 return_ACPI_STATUS(AE_OK);140 }141 142 /*143 * Compute Tick Delta:144 * Handle (max one) timer rollovers on 24-bit versus 32-bit timers.145 */146 delta_ticks = end_ticks;147 if (start_ticks > end_ticks) {148 if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {149 150 /* 24-bit Timer */151 152 delta_ticks |= (u64)1 << 24;153 } else {154 /* 32-bit Timer */155 156 delta_ticks |= (u64)1 << 32;157 }158 }159 delta_ticks -= start_ticks;160 161 /*162 * Compute Duration (Requires a 64-bit multiply and divide):163 *164 * time_elapsed (microseconds) =165 * (delta_ticks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY;166 */167 status = acpi_ut_short_divide(delta_ticks * ACPI_USEC_PER_SEC,168 ACPI_PM_TIMER_FREQUENCY, "ient, NULL);169 170 *time_elapsed = (u32)quotient;171 return_ACPI_STATUS(status);172}173 174ACPI_EXPORT_SYMBOL(acpi_get_timer_duration)175#endif /* !ACPI_REDUCED_HARDWARE */176