2 /******************************************************************************
4 * Name: hwtimer.c - ACPI Power Management Timer Interface
7 *****************************************************************************/
10 * Copyright (C) 2000, 2001 R. Byron Moore
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #define _COMPONENT ACPI_HARDWARE
31 MODULE_NAME ("hwtimer")
34 /******************************************************************************
36 * FUNCTION: Acpi_get_timer_resolution
40 * RETURN: Number of bits of resolution in the PM Timer (24 or 32).
42 * DESCRIPTION: Obtains resolution of the ACPI PM Timer.
44 ******************************************************************************/
47 acpi_get_timer_resolution (
50 FUNCTION_TRACE ("Acpi_get_timer_resolution");
54 return_ACPI_STATUS (AE_BAD_PARAMETER);
57 if (0 == acpi_gbl_FADT->tmr_val_ext) {
65 return_ACPI_STATUS (AE_OK);
69 /******************************************************************************
71 * FUNCTION: Acpi_get_timer
75 * RETURN: Current value of the ACPI PM Timer (in ticks).
77 * DESCRIPTION: Obtains current value of ACPI PM Timer.
79 ******************************************************************************/
85 FUNCTION_TRACE ("Acpi_get_timer");
89 return_ACPI_STATUS (AE_BAD_PARAMETER);
92 acpi_os_read_port ((ACPI_IO_ADDRESS)
93 ACPI_GET_ADDRESS (acpi_gbl_FADT->Xpm_tmr_blk.address), ticks, 32);
95 return_ACPI_STATUS (AE_OK);
99 /******************************************************************************
101 * FUNCTION: Acpi_get_timer_duration
103 * PARAMETERS: Start_ticks
107 * RETURN: Time_elapsed
109 * DESCRIPTION: Computes the time elapsed (in microseconds) between two
110 * PM Timer time stamps, taking into account the possibility of
111 * rollovers, the timer resolution, and timer frequency.
113 * The PM Timer's clock ticks at roughly 3.6 times per
114 * _microsecond_, and its clock continues through Cx state
115 * transitions (unlike many CPU timestamp counters) -- making it
116 * a versatile and accurate timer.
118 * Note that this function accomodates only a single timer
119 * rollover. Thus for 24-bit timers, this function should only
120 * be used for calculating durations less than ~4.6 seconds
121 * (~20 hours for 32-bit timers).
123 ******************************************************************************/
126 acpi_get_timer_duration (
133 u32 milliseconds = 0;
134 u32 microseconds = 0;
138 FUNCTION_TRACE ("Acpi_get_timer_duration");
142 return_ACPI_STATUS (AE_BAD_PARAMETER);
146 * Compute Tick Delta:
147 * -------------------
148 * Handle (max one) timer rollovers on 24- versus 32-bit timers.
150 if (start_ticks < end_ticks) {
151 delta_ticks = end_ticks - start_ticks;
154 else if (start_ticks > end_ticks) {
157 if (0 == acpi_gbl_FADT->tmr_val_ext) {
158 delta_ticks = (((0x00FFFFFF - start_ticks) + end_ticks) & 0x00FFFFFF);
164 delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks;
170 return_ACPI_STATUS (AE_OK);
176 * Since certain compilers (gcc/Linux, argh!) don't support 64-bit
177 * divides in kernel-space we have to do some trickery to preserve
178 * accuracy while using 32-bit math.
180 * TBD: Change to use 64-bit math when supported.
182 * The process is as follows:
183 * 1. Compute the number of seconds by dividing Delta Ticks by
184 * the timer frequency.
185 * 2. Compute the number of milliseconds in the remainder from step #1
186 * by multiplying by 1000 and then dividing by the timer frequency.
187 * 3. Compute the number of microseconds in the remainder from step #2
188 * by multiplying by 1000 and then dividing by the timer frequency.
189 * 4. Add the results from steps 1, 2, and 3 to get the total duration.
191 * Example: The time elapsed for Delta_ticks = 0xFFFFFFFF should be
192 * 1199864031 microseconds. This is computed as follows:
193 * Step #1: Seconds = 1199; Remainder = 3092840
194 * Step #2: Milliseconds = 864; Remainder = 113120
195 * Step #3: Microseconds = 31; Remainder = <don't care!>
200 seconds = delta_ticks / PM_TIMER_FREQUENCY;
201 remainder = delta_ticks % PM_TIMER_FREQUENCY;
205 milliseconds = (remainder * 1000) / PM_TIMER_FREQUENCY;
206 remainder = (remainder * 1000) % PM_TIMER_FREQUENCY;
210 microseconds = (remainder * 1000) / PM_TIMER_FREQUENCY;
214 *time_elapsed = seconds * 1000000;
215 *time_elapsed += milliseconds * 1000;
216 *time_elapsed += microseconds;
218 return_ACPI_STATUS (AE_OK);