acpi_timer.c (80602) | acpi_timer.c (81096) |
---|---|
1/*- 2 * Copyright (c) 2000, 2001 Michael Smith 3 * Copyright (c) 2000 BSDi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 10 unchanged lines hidden (view full) --- 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * | 1/*- 2 * Copyright (c) 2000, 2001 Michael Smith 3 * Copyright (c) 2000 BSDi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 10 unchanged lines hidden (view full) --- 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * |
27 * $FreeBSD: head/sys/dev/acpica/acpi_timer.c 80602 2001-07-30 08:57:55Z msmith $ | 27 * $FreeBSD: head/sys/dev/acpica/acpi_timer.c 81096 2001-08-03 09:52:53Z msmith $ |
28 */ 29#include "opt_acpi.h" 30#include <sys/param.h> 31#include <sys/bus.h> 32#include <sys/kernel.h> 33#include <sys/sysctl.h> 34#include <sys/timetc.h> 35 --- 26 unchanged lines hidden (view full) --- 62 0) 63 64static u_int acpi_timer_frequency = 14318182/4; 65 66static void acpi_timer_identify(driver_t *driver, device_t parent); 67static int acpi_timer_probe(device_t dev); 68static int acpi_timer_attach(device_t dev); 69static unsigned acpi_timer_get_timecount(struct timecounter *tc); | 28 */ 29#include "opt_acpi.h" 30#include <sys/param.h> 31#include <sys/bus.h> 32#include <sys/kernel.h> 33#include <sys/sysctl.h> 34#include <sys/timetc.h> 35 --- 26 unchanged lines hidden (view full) --- 62 0) 63 64static u_int acpi_timer_frequency = 14318182/4; 65 66static void acpi_timer_identify(driver_t *driver, device_t parent); 67static int acpi_timer_probe(device_t dev); 68static int acpi_timer_attach(device_t dev); 69static unsigned acpi_timer_get_timecount(struct timecounter *tc); |
70static unsigned acpi_timer_get_timecount_safe(struct timecounter *tc); |
|
70static int acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS); 71static void acpi_timer_test(void); 72 73/* 74 * Driver hung off ACPI. 75 */ 76static device_method_t acpi_timer_methods[] = { 77 DEVMETHOD(device_identify, acpi_timer_identify), --- 11 unchanged lines hidden (view full) --- 89 90devclass_t acpi_timer_devclass; 91DRIVER_MODULE(acpi_timer, acpi, acpi_timer_driver, acpi_timer_devclass, 0, 0); 92 93/* 94 * Timecounter. 95 */ 96static struct timecounter acpi_timer_timecounter = { | 71static int acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS); 72static void acpi_timer_test(void); 73 74/* 75 * Driver hung off ACPI. 76 */ 77static device_method_t acpi_timer_methods[] = { 78 DEVMETHOD(device_identify, acpi_timer_identify), --- 11 unchanged lines hidden (view full) --- 90 91devclass_t acpi_timer_devclass; 92DRIVER_MODULE(acpi_timer, acpi, acpi_timer_driver, acpi_timer_devclass, 0, 0); 93 94/* 95 * Timecounter. 96 */ 97static struct timecounter acpi_timer_timecounter = { |
97 acpi_timer_get_timecount, | 98 acpi_timer_get_timecount_safe, |
98 0, 99 0xffffff, 100 0, 101 "ACPI" 102}; 103 104SYSCTL_OPAQUE(_debug, OID_AUTO, acpi_timecounter, CTLFLAG_RD, 105 &acpi_timer_timecounter, sizeof(acpi_timer_timecounter), "S,timecounter", ""); --- 33 unchanged lines hidden (view full) --- 139 140 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount; 141 acpi_timer_timecounter.tc_frequency = acpi_timer_frequency; 142 tc_init(&acpi_timer_timecounter); 143 144 sprintf(desc, "%d-bit timer at 3.579545MHz", AcpiGbl_FADT->TmrValExt ? 32 : 24); 145 device_set_desc_copy(dev, desc); 146 | 99 0, 100 0xffffff, 101 0, 102 "ACPI" 103}; 104 105SYSCTL_OPAQUE(_debug, OID_AUTO, acpi_timecounter, CTLFLAG_RD, 106 &acpi_timer_timecounter, sizeof(acpi_timer_timecounter), "S,timecounter", ""); --- 33 unchanged lines hidden (view full) --- 140 141 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount; 142 acpi_timer_timecounter.tc_frequency = acpi_timer_frequency; 143 tc_init(&acpi_timer_timecounter); 144 145 sprintf(desc, "%d-bit timer at 3.579545MHz", AcpiGbl_FADT->TmrValExt ? 32 : 24); 146 device_set_desc_copy(dev, desc); 147 |
148#if 0 149 { 150 u_int64_t first; 151 152 first = rdtsc(); 153 acpi_timer_get_timecount(NULL); 154 printf("acpi_timer_get_timecount %lld cycles\n", rdtsc() - first); 155 156 first = rdtsc(); 157 acpi_timer_get_timecount_safe(NULL); 158 printf("acpi_timer_get_timecount_safe %lld cycles\n", rdtsc() - first); 159 } 160#endif 161 |
|
147 return_VOID; 148} 149 150static int 151acpi_timer_probe(device_t dev) 152{ 153 if (dev == acpi_timer_dev) 154 return(0); 155 return(ENXIO); 156} 157 158static int 159acpi_timer_attach(device_t dev) 160{ 161 return(0); 162} 163 164/* | 162 return_VOID; 163} 164 165static int 166acpi_timer_probe(device_t dev) 167{ 168 if (dev == acpi_timer_dev) 169 return(0); 170 return(ENXIO); 171} 172 173static int 174acpi_timer_attach(device_t dev) 175{ 176 return(0); 177} 178 179/* |
165 * Fetch current time value from hardware. | 180 * Fetch current time value from reliable hardware. |
166 */ 167static unsigned 168acpi_timer_get_timecount(struct timecounter *tc) 169{ 170 return(TIMER_READ); 171} 172 173/* | 181 */ 182static unsigned 183acpi_timer_get_timecount(struct timecounter *tc) 184{ 185 return(TIMER_READ); 186} 187 188/* |
189 * Fetch current time value from hardware that may not correctly 190 * latch the counter. 191 */ 192static unsigned 193acpi_timer_get_timecount_safe(struct timecounter *tc) 194{ 195 unsigned u1, u2, u3; 196 197 u2 = TIMER_READ; 198 u3 = TIMER_READ; 199 do { 200 u1 = u2; 201 u2 = u3; 202 u3 = TIMER_READ; 203 } while (u1 > u2 || u2 > u3); 204 return (u2); 205} 206 207/* |
|
174 * Timecounter freqency adjustment interface. 175 */ 176static int 177acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS) 178{ 179 int error; 180 u_int freq; 181 --- 40 unchanged lines hidden (view full) --- 222 u2 = u3; 223 u3 = TIMER_READ; 224 } 225} 226 227/* 228 * Chipset workaround driver hung off PCI. 229 * | 208 * Timecounter freqency adjustment interface. 209 */ 210static int 211acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS) 212{ 213 int error; 214 u_int freq; 215 --- 40 unchanged lines hidden (view full) --- 256 u2 = u3; 257 u3 = TIMER_READ; 258 } 259} 260 261/* 262 * Chipset workaround driver hung off PCI. 263 * |
264 * Some ACPI timers are known or believed to suffer from implementation 265 * problems which can lead to erroneous values being read from the timer. 266 * 267 * Since we can't trust unknown chipsets, we default to a timer-read 268 * routine which compensates for the most common problem (as detailed 269 * in the excerpt from the Intel PIIX4 datasheet below). 270 * 271 * When we detect a known-functional chipset, we disable the workaround 272 * to improve speed. 273 * |
|
230 * ] 20. ACPI Timer Errata 231 * ] 232 * ] Problem: The power management timer may return improper result when 233 * ] read. Although the timer value settles properly after incrementing, 234 * ] while incrementing there is a 3nS window every 69.8nS where the 235 * ] timer value is indeterminate (a 4.2% chance that the data will be 236 * ] incorrect when read). As a result, the ACPI free running count up 237 * ] timer specification is violated due to erroneous reads. Implication: --- 7 unchanged lines hidden (view full) --- 245 * The counter is in other words not latched to the PCI bus clock when 246 * read. Notice the workaround isn't: We need to read until we have 247 * three monotonic samples and then use the middle one, otherwise we are 248 * not protected against the fact that the bits can be wrong in two 249 * directions. If we only cared about monosity two reads would be enough. 250 */ 251 252static int acpi_timer_pci_probe(device_t dev); | 274 * ] 20. ACPI Timer Errata 275 * ] 276 * ] Problem: The power management timer may return improper result when 277 * ] read. Although the timer value settles properly after incrementing, 278 * ] while incrementing there is a 3nS window every 69.8nS where the 279 * ] timer value is indeterminate (a 4.2% chance that the data will be 280 * ] incorrect when read). As a result, the ACPI free running count up 281 * ] timer specification is violated due to erroneous reads. Implication: --- 7 unchanged lines hidden (view full) --- 289 * The counter is in other words not latched to the PCI bus clock when 290 * read. Notice the workaround isn't: We need to read until we have 291 * three monotonic samples and then use the middle one, otherwise we are 292 * not protected against the fact that the bits can be wrong in two 293 * directions. If we only cared about monosity two reads would be enough. 294 */ 295 296static int acpi_timer_pci_probe(device_t dev); |
253static unsigned acpi_timer_get_timecount_piix(struct timecounter *tc); | |
254 255static device_method_t acpi_timer_pci_methods[] = { 256 DEVMETHOD(device_probe, acpi_timer_pci_probe), 257 {0, 0} 258}; 259 260static driver_t acpi_timer_pci_driver = { 261 "acpi_timer_pci", 262 acpi_timer_pci_methods, 263 0, 264}; 265 266devclass_t acpi_timer_pci_devclass; 267DRIVER_MODULE(acpi_timer_pci, pci, acpi_timer_pci_driver, acpi_timer_pci_devclass, 0, 0); 268 269/* | 297 298static device_method_t acpi_timer_pci_methods[] = { 299 DEVMETHOD(device_probe, acpi_timer_pci_probe), 300 {0, 0} 301}; 302 303static driver_t acpi_timer_pci_driver = { 304 "acpi_timer_pci", 305 acpi_timer_pci_methods, 306 0, 307}; 308 309devclass_t acpi_timer_pci_devclass; 310DRIVER_MODULE(acpi_timer_pci, pci, acpi_timer_pci_driver, acpi_timer_pci_devclass, 0, 0); 311 312/* |
270 * Look at PCI devices as they go past, and if we detect a PIIX4 older than 271 * the PIIX4M, use an alternate get_timecount routine. 272 * 273 * XXX do we know that other timecounters work? Perhaps we should test them? | 313 * Look at PCI devices going past; if we detect one we know contains 314 * a functional ACPI timer device, enable the faster timecounter read 315 * routine. |
274 */ 275static int 276acpi_timer_pci_probe(device_t dev) 277{ 278 if ((pci_get_vendor(dev) == 0x8086) && 279 (pci_get_device(dev) == 0x7113) && | 316 */ 317static int 318acpi_timer_pci_probe(device_t dev) 319{ 320 if ((pci_get_vendor(dev) == 0x8086) && 321 (pci_get_device(dev) == 0x7113) && |
280 (pci_get_revid(dev) < 0x03)) { 281 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount_piix; 282 acpi_timer_timecounter.tc_name = "ACPI-PIIX"; 283 device_printf(acpi_timer_dev, "enabling PIIX4 timer workaround\n"); | 322 (pci_get_revid(dev) >= 0x03)) { 323 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount; 324 acpi_timer_timecounter.tc_name = "ACPI-PIIX4M"; 325 if (bootverbose) 326 device_printf(acpi_timer_dev, "PIIX4M or later detected, enabling ACPI timer optimisation\n"); |
284 } 285 286 return(ENXIO); /* we never match anything */ 287} | 327 } 328 329 return(ENXIO); /* we never match anything */ 330} |
288 289/* 290 * Read the buggy PIIX4 ACPI timer and compensate for its behaviour. 291 */ 292static unsigned 293acpi_timer_get_timecount_piix(struct timecounter *tc) 294{ 295 unsigned u1, u2, u3; 296 297 u2 = TIMER_READ; 298 u3 = TIMER_READ; 299 do { 300 u1 = u2; 301 u2 = u3; 302 u3 = TIMER_READ; 303 } while (u1 > u2 || u2 > u3); 304 return (u2); 305} 306 | |