1 /******************************************************************************
2  *
3  * Name: hwtimer.c - ACPI Power Management Timer Interface
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2022, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #define EXPORT_ACPI_INTERFACES
45 
46 #include "acpi.h"
47 #include "accommon.h"
48 
49 #define _COMPONENT          ACPI_HARDWARE
50         ACPI_MODULE_NAME    ("hwtimer")
51 
52 
53 #if (!ACPI_REDUCED_HARDWARE) /* Entire module */
54 /******************************************************************************
55  *
56  * FUNCTION:    AcpiGetTimerResolution
57  *
58  * PARAMETERS:  Resolution          - Where the resolution is returned
59  *
60  * RETURN:      Status and timer resolution
61  *
62  * DESCRIPTION: Obtains resolution of the ACPI PM Timer (24 or 32 bits).
63  *
64  ******************************************************************************/
65 
66 ACPI_STATUS
67 AcpiGetTimerResolution (
68     UINT32                  *Resolution)
69 {
70     ACPI_FUNCTION_TRACE (AcpiGetTimerResolution);
71 
72 
73     if (!Resolution)
74     {
75         return_ACPI_STATUS (AE_BAD_PARAMETER);
76     }
77 
78     if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0)
79     {
80         *Resolution = 24;
81     }
82     else
83     {
84         *Resolution = 32;
85     }
86 
87     return_ACPI_STATUS (AE_OK);
88 }
89 
90 ACPI_EXPORT_SYMBOL (AcpiGetTimerResolution)
91 
92 
93 /******************************************************************************
94  *
95  * FUNCTION:    AcpiGetTimer
96  *
97  * PARAMETERS:  Ticks               - Where the timer value is returned
98  *
99  * RETURN:      Status and current timer value (ticks)
100  *
101  * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks).
102  *
103  ******************************************************************************/
104 
105 ACPI_STATUS
106 AcpiGetTimer (
107     UINT32                  *Ticks)
108 {
109     ACPI_STATUS             Status;
110     UINT64                  TimerValue;
111 
112 
113     ACPI_FUNCTION_TRACE (AcpiGetTimer);
114 
115 
116     if (!Ticks)
117     {
118         return_ACPI_STATUS (AE_BAD_PARAMETER);
119     }
120 
121     /* ACPI 5.0A: PM Timer is optional */
122 
123     if (!AcpiGbl_FADT.XPmTimerBlock.Address)
124     {
125         return_ACPI_STATUS (AE_SUPPORT);
126     }
127 
128     Status = AcpiHwRead (&TimerValue, &AcpiGbl_FADT.XPmTimerBlock);
129     if (ACPI_SUCCESS (Status))
130     {
131         /* ACPI PM Timer is defined to be 32 bits (PM_TMR_LEN) */
132 
133         *Ticks = (UINT32) TimerValue;
134     }
135 
136     return_ACPI_STATUS (Status);
137 }
138 
139 ACPI_EXPORT_SYMBOL (AcpiGetTimer)
140 
141 
142 /******************************************************************************
143  *
144  * FUNCTION:    AcpiGetTimerDuration
145  *
146  * PARAMETERS:  StartTicks          - Starting timestamp
147  *              EndTicks            - End timestamp
148  *              TimeElapsed         - Where the elapsed time is returned
149  *
150  * RETURN:      Status and TimeElapsed
151  *
152  * DESCRIPTION: Computes the time elapsed (in microseconds) between two
153  *              PM Timer time stamps, taking into account the possibility of
154  *              rollovers, the timer resolution, and timer frequency.
155  *
156  *              The PM Timer's clock ticks at roughly 3.6 times per
157  *              _microsecond_, and its clock continues through Cx state
158  *              transitions (unlike many CPU timestamp counters) -- making it
159  *              a versatile and accurate timer.
160  *
161  *              Note that this function accommodates only a single timer
162  *              rollover. Thus for 24-bit timers, this function should only
163  *              be used for calculating durations less than ~4.6 seconds
164  *              (~20 minutes for 32-bit timers) -- calculations below:
165  *
166  *              2**24 Ticks / 3,600,000 Ticks/Sec = 4.66 sec
167  *              2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes
168  *
169  ******************************************************************************/
170 
171 ACPI_STATUS
172 AcpiGetTimerDuration (
173     UINT32                  StartTicks,
174     UINT32                  EndTicks,
175     UINT32                  *TimeElapsed)
176 {
177     ACPI_STATUS             Status;
178     UINT64                  DeltaTicks;
179     UINT64                  Quotient;
180 
181 
182     ACPI_FUNCTION_TRACE (AcpiGetTimerDuration);
183 
184 
185     if (!TimeElapsed)
186     {
187         return_ACPI_STATUS (AE_BAD_PARAMETER);
188     }
189 
190     /* ACPI 5.0A: PM Timer is optional */
191 
192     if (!AcpiGbl_FADT.XPmTimerBlock.Address)
193     {
194         return_ACPI_STATUS (AE_SUPPORT);
195     }
196 
197     if (StartTicks == EndTicks)
198     {
199         *TimeElapsed = 0;
200         return_ACPI_STATUS (AE_OK);
201     }
202 
203     /*
204      * Compute Tick Delta:
205      * Handle (max one) timer rollovers on 24-bit versus 32-bit timers.
206      */
207     DeltaTicks = EndTicks;
208     if (StartTicks > EndTicks)
209     {
210         if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0)
211         {
212             /* 24-bit Timer */
213 
214             DeltaTicks |= (UINT64) 1 << 24;
215         }
216         else
217         {
218             /* 32-bit Timer */
219 
220             DeltaTicks |= (UINT64) 1 << 32;
221         }
222     }
223     DeltaTicks -= StartTicks;
224 
225     /*
226      * Compute Duration (Requires a 64-bit multiply and divide):
227      *
228      * TimeElapsed (microseconds) =
229      *  (DeltaTicks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY;
230      */
231     Status = AcpiUtShortDivide (DeltaTicks * ACPI_USEC_PER_SEC,
232                 ACPI_PM_TIMER_FREQUENCY, &Quotient, NULL);
233 
234     *TimeElapsed = (UINT32) Quotient;
235     return_ACPI_STATUS (Status);
236 }
237 
238 ACPI_EXPORT_SYMBOL (AcpiGetTimerDuration)
239 
240 #endif /* !ACPI_REDUCED_HARDWARE */
241