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 
24 FILE_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 */
51 static unsigned int pm_tmr;
52 
53 struct timer acpi_timer __timer ( TIMER_PREFERRED );
54 
55 /**
56  * Get current system time in ticks
57  *
58  * @ret ticks Current time, in ticks
59  */
60 static 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  */
82 static 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  */
104 static int acpi_timer_probe ( void ) {
105  struct acpi_fadt fadtab;
106  userptr_t fadt;
107  unsigned int pm_tmr_blk;
108 
109  /* Locate FADT */
110  fadt = acpi_find ( FADT_SIGNATURE, 0 );
111  if ( ! fadt ) {
112  DBGC ( &acpi_timer, "ACPI could not find FADT\n" );
113  return -ENOENT;
114  }
115 
116  /* Read FADT */
117  copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) );
118  pm_tmr_blk = le32_to_cpu ( fadtab.pm_tmr_blk );
119  if ( ! pm_tmr_blk ) {
120  DBGC ( &acpi_timer, "ACPI has no timer\n" );
121  return -ENOENT;
122  }
123 
124  /* Record power management timer register address */
125  pm_tmr = ( pm_tmr_blk + ACPI_PM_TMR );
126 
127  return 0;
128 }
129 
130 /** ACPI timer */
131 struct timer acpi_timer __timer ( TIMER_PREFERRED ) = {
132  .name = "acpi",
133  .probe = acpi_timer_probe,
134  .currticks = acpi_currticks,
135  .udelay = acpi_udelay,
136 };
struct timer acpi_timer __timer(TIMER_PREFERRED)
ACPI timer.
iPXE I/O API
#define TICKS_PER_SEC
Number of ticks per second.
Definition: timer.h:15
#define le32_to_cpu(value)
Definition: byteswap.h:113
Error codes.
static int acpi_timer_probe(void)
Probe ACPI power management timer.
Definition: acpi_timer.c:104
static __always_inline void copy_from_user(void *dest, userptr_t src, off_t src_off, size_t len)
Copy data from user buffer.
Definition: uaccess.h:337
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define DBGC(...)
Definition: compiler.h:505
#define ENOENT
No such file or directory.
Definition: errno.h:514
#define ACPI_PM_TMR
ACPI PM Timer Register (within PM_TMR_BLK)
Definition: acpi.h:134
A timer.
Definition: timer.h:28
#define ACPI_TIMER_HZ
ACPI timer frequency (fixed 3.579545MHz)
Definition: acpi_timer.c:40
uint32_t start
Starting offset.
Definition: netvsc.h:12
static unsigned long acpi_currticks(void)
Get current system time in ticks.
Definition: acpi_timer.c:60
uint32_t pm_tmr_blk
PM Timer Control Register Block.
Definition: acpi.h:125
Assertions.
Fixed ACPI Description Table (FADT)
Definition: acpi.h:109
#define TIMER_PREFERRED
Preferred timer.
Definition: timer.h:62
static unsigned int pm_tmr
Power management timer register address.
Definition: acpi_timer.c:51
static userptr_t size_t offset
Offset of the first segment within the content.
Definition: deflate.h:259
#define FADT_SIGNATURE
Fixed ACPI Description Table (FADT) signature.
Definition: acpi.h:106
#define ACPI_TIMER_MASK
ACPI timer mask.
Definition: acpi_timer.c:48
ACPI data structures.
static void acpi_udelay(unsigned long usecs)
Delay for a fixed number of microseconds.
Definition: acpi_timer.c:82
unsigned int uint32_t
Definition: stdint.h:12
const char * name
Name.
Definition: timer.h:30
uint32_t inl(volatile uint32_t *io_addr)
Read 32-bit dword from I/O-mapped device.
userptr_t acpi_find(uint32_t signature, unsigned int index)
Locate ACPI table.
Definition: acpi.c:89
unsigned long userptr_t
A pointer to a user buffer.
Definition: uaccess.h:33