iPXE
acpi_timer.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2018 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26#include <unistd.h>
27#include <errno.h>
28#include <assert.h>
29#include <byteswap.h>
30#include <ipxe/io.h>
31#include <ipxe/acpi.h>
32
33/** @file
34 *
35 * ACPI power management timer
36 *
37 */
38
39/** ACPI timer frequency (fixed 3.579545MHz) */
40#define ACPI_TIMER_HZ 3579545
41
42/** ACPI timer mask
43 *
44 * Timers may be implemented as either 24-bit or 32-bit counters. We
45 * simplify the code by pessimistically assuming that the timer has
46 * only 24 bits.
47 */
48#define ACPI_TIMER_MASK 0x00ffffffUL
49
50/** Power management timer register address */
51static unsigned int pm_tmr;
52
53struct timer acpi_timer __timer ( TIMER_PREFERRED );
54
55/**
56 * Get current system time in ticks
57 *
58 * @ret ticks Current time, in ticks
59 */
60static unsigned long acpi_currticks ( void ) {
61 static unsigned long offset;
62 static uint32_t prev;
63 uint32_t now;
64
65 /* Read timer and account for wraparound */
66 now = ( inl ( pm_tmr ) & ACPI_TIMER_MASK );
67 if ( now < prev ) {
68 offset += ( ( ACPI_TIMER_MASK + 1 ) /
70 }
71 prev = now;
72
73 /* Convert to timer ticks */
74 return ( offset + ( now / ( ACPI_TIMER_HZ / TICKS_PER_SEC ) ) );
75}
76
77/**
78 * Delay for a fixed number of microseconds
79 *
80 * @v usecs Number of microseconds for which to delay
81 */
82static void acpi_udelay ( unsigned long usecs ) {
84 uint32_t elapsed;
85 uint32_t threshold;
86
87 /* Delay until a suitable number of ticks have elapsed. We do
88 * not need to allow for multiple wraparound, since the
89 * wraparound period for a 24-bit timer at 3.579545MHz is
90 * around 4700000us.
91 */
92 start = inl ( pm_tmr );
93 threshold = ( ( usecs * ACPI_TIMER_HZ ) / 1000000 );
94 do {
95 elapsed = ( ( inl ( pm_tmr ) - start ) & ACPI_TIMER_MASK );
96 } while ( elapsed < threshold );
97}
98
99/**
100 * Probe ACPI power management timer
101 *
102 * @ret rc Return status code
103 */
104static int acpi_timer_probe ( void ) {
105 const struct acpi_fadt *fadt;
106 unsigned int pm_tmr_blk;
107
108 /* Locate FADT */
109 fadt = container_of ( acpi_table ( FADT_SIGNATURE, 0 ),
110 struct acpi_fadt, acpi );
111 if ( ! fadt ) {
112 DBGC ( &acpi_timer, "ACPI could not find FADT\n" );
113 return -ENOENT;
114 }
115
116 /* Read FADT */
118 if ( ! pm_tmr_blk ) {
119 DBGC ( &acpi_timer, "ACPI has no timer\n" );
120 return -ENOENT;
121 }
122
123 /* Record power management timer register address */
125
126 return 0;
127}
128
129/** ACPI timer */
130struct timer acpi_timer __timer ( TIMER_PREFERRED ) = {
131 .name = "acpi",
132 .probe = acpi_timer_probe,
133 .currticks = acpi_currticks,
134 .udelay = acpi_udelay,
135};
const struct acpi_header * acpi_table(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition acpi.c:93
static void acpi_udelay(unsigned long usecs)
Delay for a fixed number of microseconds.
Definition acpi_timer.c:82
#define ACPI_TIMER_MASK
ACPI timer mask.
Definition acpi_timer.c:48
#define ACPI_TIMER_HZ
ACPI timer frequency (fixed 3.579545MHz)
Definition acpi_timer.c:40
static unsigned long acpi_currticks(void)
Get current system time in ticks.
Definition acpi_timer.c:60
static int acpi_timer_probe(void)
Probe ACPI power management timer.
Definition acpi_timer.c:104
static unsigned int pm_tmr
Power management timer register address.
Definition acpi_timer.c:51
unsigned int uint32_t
Definition stdint.h:12
Assertions.
uint16_t offset
Offset to command line.
Definition bzimage.h:3
static EFI_ACPI_TABLE_PROTOCOL * acpi
ACPI table protocol protocol.
Definition efi_block.c:67
Error codes.
#define DBGC(...)
Definition compiler.h:505
uint32_t start
Starting offset.
Definition netvsc.h:1
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOENT
No such file or directory.
Definition errno.h:515
#define TIMER_PREFERRED
Preferred timer.
Definition timer.h:63
#define le32_to_cpu(value)
Definition byteswap.h:114
ACPI data structures.
#define ACPI_PM_TMR
ACPI PM Timer Register (within PM_TMR_BLK)
Definition acpi.h:286
#define FADT_SIGNATURE
Fixed ACPI Description Table (FADT) signature.
Definition acpi.h:258
iPXE I/O API
#define inl(io_addr)
Definition io.h:301
#define TICKS_PER_SEC
Number of ticks per second.
Definition timer.h:16
#define __timer(order)
Declare a timer.
Definition timer.h:56
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
Fixed ACPI Description Table (FADT)
Definition acpi.h:261
uint32_t pm_tmr_blk
PM Timer Control Register Block.
Definition acpi.h:277
A timer.
Definition timer.h:29