hwtimer.c revision 256281
11573Srgrimes/******************************************************************************
21573Srgrimes *
31573Srgrimes * Name: hwtimer.c - ACPI Power Management Timer Interface
41573Srgrimes *
51573Srgrimes *****************************************************************************/
61573Srgrimes
71573Srgrimes/*
8227753Stheraven * Copyright (C) 2000 - 2013, Intel Corp.
9227753Stheraven * All rights reserved.
10227753Stheraven *
11227753Stheraven * Redistribution and use in source and binary forms, with or without
12227753Stheraven * modification, are permitted provided that the following conditions
131573Srgrimes * are met:
141573Srgrimes * 1. Redistributions of source code must retain the above copyright
151573Srgrimes *    notice, this list of conditions, and the following disclaimer,
161573Srgrimes *    without modification.
171573Srgrimes * 2. Redistributions in binary form must reproduce at minimum a disclaimer
181573Srgrimes *    substantially similar to the "NO WARRANTY" disclaimer below
191573Srgrimes *    ("Disclaimer") and any redistribution must be conditioned upon
201573Srgrimes *    including a substantially similar Disclaimer requirement for further
211573Srgrimes *    binary redistribution.
221573Srgrimes * 3. Neither the names of the above-listed copyright holders nor the names
231573Srgrimes *    of any contributors may be used to endorse or promote products derived
241573Srgrimes *    from this software without specific prior written permission.
251573Srgrimes *
261573Srgrimes * Alternatively, this software may be distributed under the terms of the
271573Srgrimes * GNU General Public License ("GPL") version 2 as published by the Free
281573Srgrimes * Software Foundation.
291573Srgrimes *
301573Srgrimes * NO WARRANTY
311573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
321573Srgrimes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
331573Srgrimes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
341573Srgrimes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
351573Srgrimes * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
361573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
371573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
381573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
391573Srgrimes * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
401573Srgrimes * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4192986Sobrien * POSSIBILITY OF SUCH DAMAGES.
4292986Sobrien */
431573Srgrimes
441573Srgrimes#include <contrib/dev/acpica/include/acpi.h>
45132820Stjr#include <contrib/dev/acpica/include/accommon.h>
46121845Stjr
47129153Stjr#define _COMPONENT          ACPI_HARDWARE
481573Srgrimes        ACPI_MODULE_NAME    ("hwtimer")
49227753Stheraven
501573Srgrimes
5161218Sache#if (!ACPI_REDUCED_HARDWARE) /* Entire module */
52136609Stjr/******************************************************************************
53136609Stjr *
541573Srgrimes * FUNCTION:    AcpiGetTimerResolution
551573Srgrimes *
5657035Sobrien * PARAMETERS:  Resolution          - Where the resolution is returned
5757035Sobrien *
5857035Sobrien * RETURN:      Status and timer resolution
5957035Sobrien *
6057035Sobrien * DESCRIPTION: Obtains resolution of the ACPI PM Timer (24 or 32 bits).
6157035Sobrien *
6257035Sobrien ******************************************************************************/
6357035Sobrien
6457035SobrienACPI_STATUS
6557035SobrienAcpiGetTimerResolution (
6657035Sobrien    UINT32                  *Resolution)
6757035Sobrien{
6857035Sobrien    ACPI_FUNCTION_TRACE (AcpiGetTimerResolution);
6957035Sobrien
7057035Sobrien
7157035Sobrien    if (!Resolution)
7257035Sobrien    {
7357035Sobrien        return_ACPI_STATUS (AE_BAD_PARAMETER);
7457035Sobrien    }
7557035Sobrien
7657035Sobrien    if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0)
7757035Sobrien    {
7857035Sobrien        *Resolution = 24;
7957035Sobrien    }
8057035Sobrien    else
8157035Sobrien    {
8257035Sobrien        *Resolution = 32;
8357035Sobrien    }
8457035Sobrien
8557035Sobrien    return_ACPI_STATUS (AE_OK);
8657035Sobrien}
8757035Sobrien
8857035SobrienACPI_EXPORT_SYMBOL (AcpiGetTimerResolution)
8957035Sobrien
9057035Sobrien
9157035Sobrien/******************************************************************************
9257035Sobrien *
9357035Sobrien * FUNCTION:    AcpiGetTimer
9457035Sobrien *
9557035Sobrien * PARAMETERS:  Ticks               - Where the timer value is returned
9657035Sobrien *
9757035Sobrien * RETURN:      Status and current timer value (ticks)
9857035Sobrien *
9957035Sobrien * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks).
10057035Sobrien *
10157035Sobrien ******************************************************************************/
10257035Sobrien
10357035SobrienACPI_STATUS
10457035SobrienAcpiGetTimer (
10557035Sobrien    UINT32                  *Ticks)
10657035Sobrien{
10757035Sobrien    ACPI_STATUS             Status;
10857035Sobrien
10957035Sobrien
11057035Sobrien    ACPI_FUNCTION_TRACE (AcpiGetTimer);
11157035Sobrien
11257035Sobrien
11357035Sobrien    if (!Ticks)
11457035Sobrien    {
11557035Sobrien        return_ACPI_STATUS (AE_BAD_PARAMETER);
11657035Sobrien    }
11757035Sobrien
11857035Sobrien    /* ACPI 5.0A: PM Timer is optional */
11957035Sobrien
12057035Sobrien    if (!AcpiGbl_FADT.XPmTimerBlock.Address)
12157035Sobrien    {
12257035Sobrien        return_ACPI_STATUS (AE_SUPPORT);
12357035Sobrien    }
12457035Sobrien
12557035Sobrien    Status = AcpiHwRead (Ticks, &AcpiGbl_FADT.XPmTimerBlock);
12657035Sobrien    return_ACPI_STATUS (Status);
12757035Sobrien}
12857035Sobrien
12957035SobrienACPI_EXPORT_SYMBOL (AcpiGetTimer)
13057035Sobrien
13157035Sobrien
13257035Sobrien/******************************************************************************
13357035Sobrien *
13457035Sobrien * FUNCTION:    AcpiGetTimerDuration
13557035Sobrien *
13657035Sobrien * PARAMETERS:  StartTicks          - Starting timestamp
13757035Sobrien *              EndTicks            - End timestamp
13857035Sobrien *              TimeElapsed         - Where the elapsed time is returned
13957035Sobrien *
14057035Sobrien * RETURN:      Status and TimeElapsed
14157035Sobrien *
14257035Sobrien * DESCRIPTION: Computes the time elapsed (in microseconds) between two
14357035Sobrien *              PM Timer time stamps, taking into account the possibility of
14457035Sobrien *              rollovers, the timer resolution, and timer frequency.
14557035Sobrien *
14657035Sobrien *              The PM Timer's clock ticks at roughly 3.6 times per
14757035Sobrien *              _microsecond_, and its clock continues through Cx state
14857035Sobrien *              transitions (unlike many CPU timestamp counters) -- making it
14957035Sobrien *              a versatile and accurate timer.
15057035Sobrien *
15157035Sobrien *              Note that this function accommodates only a single timer
15257035Sobrien *              rollover. Thus for 24-bit timers, this function should only
15357035Sobrien *              be used for calculating durations less than ~4.6 seconds
15457035Sobrien *              (~20 minutes for 32-bit timers) -- calculations below:
15557035Sobrien *
15657035Sobrien *              2**24 Ticks / 3,600,000 Ticks/Sec = 4.66 sec
15757035Sobrien *              2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes
15857035Sobrien *
15957035Sobrien ******************************************************************************/
16057035Sobrien
16157035SobrienACPI_STATUS
16257035SobrienAcpiGetTimerDuration (
16357035Sobrien    UINT32                  StartTicks,
16457035Sobrien    UINT32                  EndTicks,
16557035Sobrien    UINT32                  *TimeElapsed)
16657035Sobrien{
16757035Sobrien    ACPI_STATUS             Status;
16857035Sobrien    UINT32                  DeltaTicks;
16957035Sobrien    UINT64                  Quotient;
17057035Sobrien
17157035Sobrien
17257035Sobrien    ACPI_FUNCTION_TRACE (AcpiGetTimerDuration);
17357035Sobrien
17457035Sobrien
17557035Sobrien    if (!TimeElapsed)
17657035Sobrien    {
17757035Sobrien        return_ACPI_STATUS (AE_BAD_PARAMETER);
17857035Sobrien    }
17957035Sobrien
18057035Sobrien    /* ACPI 5.0A: PM Timer is optional */
18157035Sobrien
18257035Sobrien    if (!AcpiGbl_FADT.XPmTimerBlock.Address)
18357035Sobrien    {
1841573Srgrimes        return_ACPI_STATUS (AE_SUPPORT);
1851573Srgrimes    }
1861573Srgrimes
1871573Srgrimes    /*
1881573Srgrimes     * Compute Tick Delta:
1891573Srgrimes     * Handle (max one) timer rollovers on 24-bit versus 32-bit timers.
1901573Srgrimes     */
1911573Srgrimes    if (StartTicks < EndTicks)
1921573Srgrimes    {
1931573Srgrimes        DeltaTicks = EndTicks - StartTicks;
1941573Srgrimes    }
1951573Srgrimes    else if (StartTicks > EndTicks)
1961573Srgrimes    {
1971573Srgrimes        if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0)
1981573Srgrimes        {
1991573Srgrimes            /* 24-bit Timer */
2001573Srgrimes
2011573Srgrimes            DeltaTicks = (((0x00FFFFFF - StartTicks) + EndTicks) & 0x00FFFFFF);
2021573Srgrimes        }
2031573Srgrimes        else
2041573Srgrimes        {
2051573Srgrimes            /* 32-bit Timer */
2061573Srgrimes
2071573Srgrimes            DeltaTicks = (0xFFFFFFFF - StartTicks) + EndTicks;
2081573Srgrimes        }
2091573Srgrimes    }
2101573Srgrimes    else /* StartTicks == EndTicks */
2111573Srgrimes    {
2121573Srgrimes        *TimeElapsed = 0;
2131573Srgrimes        return_ACPI_STATUS (AE_OK);
2141573Srgrimes    }
2151573Srgrimes
2161573Srgrimes    /*
2171573Srgrimes     * Compute Duration (Requires a 64-bit multiply and divide):
2181573Srgrimes     *
2191573Srgrimes     * TimeElapsed (microseconds) =
2201573Srgrimes     *  (DeltaTicks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY;
2211573Srgrimes     */
2221573Srgrimes    Status = AcpiUtShortDivide (((UINT64) DeltaTicks) * ACPI_USEC_PER_SEC,
2231573Srgrimes                ACPI_PM_TIMER_FREQUENCY, &Quotient, NULL);
2241573Srgrimes
2251573Srgrimes    *TimeElapsed = (UINT32) Quotient;
2261573Srgrimes    return_ACPI_STATUS (Status);
2271573Srgrimes}
2281573Srgrimes
2291573SrgrimesACPI_EXPORT_SYMBOL (AcpiGetTimerDuration)
2301573Srgrimes
2311573Srgrimes#endif /* !ACPI_REDUCED_HARDWARE */
2321573Srgrimes