acpi_timer.c (cace7a2a4d49e2588f5fb0b5ebd56b59c47e1b31) | acpi_timer.c (be2b179704218e240b66f023545f8e97d4c29a08) |
---|---|
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: --- 28 unchanged lines hidden (view full) --- 37#include <sys/time.h> 38#endif 39 40#include <machine/bus.h> 41#include <machine/resource.h> 42#include <sys/rman.h> 43 44#include "acpi.h" | 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: --- 28 unchanged lines hidden (view full) --- 37#include <sys/time.h> 38#endif 39 40#include <machine/bus.h> 41#include <machine/resource.h> 42#include <sys/rman.h> 43 44#include "acpi.h" |
45 | |
46#include <dev/acpica/acpivar.h> 47#include <dev/pci/pcivar.h> 48 49/* 50 * A timecounter based on the free-running ACPI timer. 51 * 52 * Based on the i386-only mp_clock.c by <phk@FreeBSD.ORG>. 53 */ 54 | 45#include <dev/acpica/acpivar.h> 46#include <dev/pci/pcivar.h> 47 48/* 49 * A timecounter based on the free-running ACPI timer. 50 * 51 * Based on the i386-only mp_clock.c by <phk@FreeBSD.ORG>. 52 */ 53 |
55/* 56 * Hooks for the ACPI CA debugging infrastructure 57 */ | 54/* Hooks for the ACPI CA debugging infrastructure */ |
58#define _COMPONENT ACPI_SYSTEM 59ACPI_MODULE_NAME("TIMER") 60 61static device_t acpi_timer_dev; 62struct resource *acpi_timer_reg; 63 | 55#define _COMPONENT ACPI_SYSTEM 56ACPI_MODULE_NAME("TIMER") 57 58static device_t acpi_timer_dev; 59struct resource *acpi_timer_reg; 60 |
64static u_int acpi_timer_frequency = 14318182/4; | 61static 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); 71static int acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS); 72static void acpi_timer_test(void); 73 | 62 63static void acpi_timer_identify(driver_t *driver, device_t parent); 64static int acpi_timer_probe(device_t dev); 65static int acpi_timer_attach(device_t dev); 66static unsigned acpi_timer_get_timecount(struct timecounter *tc); 67static unsigned acpi_timer_get_timecount_safe(struct timecounter *tc); 68static int acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS); 69static void acpi_timer_test(void); 70 |
74static u_int32_t read_counter(void); 75static int test_counter(void); | 71static uint32_t read_counter(void); 72static int test_counter(void); |
76 | 73 |
77/* 78 * Driver hung off ACPI. 79 */ | |
80static device_method_t acpi_timer_methods[] = { 81 DEVMETHOD(device_identify, acpi_timer_identify), 82 DEVMETHOD(device_probe, acpi_timer_probe), 83 DEVMETHOD(device_attach, acpi_timer_attach), 84 85 {0, 0} 86}; 87 88static driver_t acpi_timer_driver = { 89 "acpi_timer", 90 acpi_timer_methods, 91 0, 92}; 93 94static devclass_t acpi_timer_devclass; 95DRIVER_MODULE(acpi_timer, acpi, acpi_timer_driver, acpi_timer_devclass, 0, 0); 96 | 74static device_method_t acpi_timer_methods[] = { 75 DEVMETHOD(device_identify, acpi_timer_identify), 76 DEVMETHOD(device_probe, acpi_timer_probe), 77 DEVMETHOD(device_attach, acpi_timer_attach), 78 79 {0, 0} 80}; 81 82static driver_t acpi_timer_driver = { 83 "acpi_timer", 84 acpi_timer_methods, 85 0, 86}; 87 88static devclass_t acpi_timer_devclass; 89DRIVER_MODULE(acpi_timer, acpi, acpi_timer_driver, acpi_timer_devclass, 0, 0); 90 |
97/* 98 * Timecounter. 99 */ | |
100static struct timecounter acpi_timer_timecounter = { 101 acpi_timer_get_timecount_safe, 102 0, 103 0xffffff, 104 0, 105 "ACPI", 106 1000 107}; 108 | 91static struct timecounter acpi_timer_timecounter = { 92 acpi_timer_get_timecount_safe, 93 0, 94 0xffffff, 95 0, 96 "ACPI", 97 1000 98}; 99 |
109 110static u_int32_t | 100static uint32_t |
111read_counter() 112{ | 101read_counter() 102{ |
113 bus_space_handle_t bsh; 114 bus_space_tag_t bst; 115 u_int32_t tv; | 103 bus_space_handle_t bsh; 104 bus_space_tag_t bst; 105 u_int32_t tv; |
116 | 106 |
117 bsh = rman_get_bushandle(acpi_timer_reg); 118 bst = rman_get_bustag(acpi_timer_reg); 119 tv = bus_space_read_4(bst, bsh, 0); 120 bus_space_barrier(bst, bsh, 0, 4, BUS_SPACE_BARRIER_READ); 121 return (tv); | 107 bsh = rman_get_bushandle(acpi_timer_reg); 108 bst = rman_get_bustag(acpi_timer_reg); 109 tv = bus_space_read_4(bst, bsh, 0); 110 bus_space_barrier(bst, bsh, 0, 4, BUS_SPACE_BARRIER_READ); 111 112 return (tv); |
122} 123 124#define N 2000 125static int 126test_counter() 127{ | 113} 114 115#define N 2000 116static int 117test_counter() 118{ |
128 int min, max, n, delta; 129 unsigned last, this; | 119 u_int last, this; 120 int min, max, n, delta; |
130 | 121 |
131 min = 10000000; 132 max = 0; 133 last = read_counter(); 134 for (n = 0; n < N; n++) { 135 this = read_counter(); 136 delta = (this - last) & 0xffffff; 137 if (delta > max) 138 max = delta; 139 else if (delta < min) 140 min = delta; 141 last = this; 142 } 143 if (max - min > 2) 144 n = 0; 145 else if (min < 0 || max == 0) 146 n = 0; 147 else 148 n = 1; 149 if (bootverbose) 150 printf("ACPI timer looks %s min = %d, max = %d, width = %d\n", 151 n ? "GOOD" : "BAD ", 152 min, max, max - min); 153 return (n); | 122 min = 10000000; 123 max = 0; 124 last = read_counter(); 125 for (n = 0; n < N; n++) { 126 this = read_counter(); 127 delta = (this - last) & 0xffffff; 128 if (delta > max) 129 max = delta; 130 else if (delta < min) 131 min = delta; 132 last = this; 133 } 134 if (max - min > 2) 135 n = 0; 136 else if (min < 0 || max == 0) 137 n = 0; 138 else 139 n = 1; 140 if (bootverbose) { 141 printf("ACPI timer looks %s min = %d, max = %d, width = %d\n", 142 n ? "GOOD" : "BAD ", 143 min, max, max - min); 144 } 145 146 return (n); |
154} | 147} |
148#undef N |
|
155 156/* 157 * Locate the ACPI timer using the FADT, set up and allocate the I/O resources 158 * we will be using. 159 */ 160static void 161acpi_timer_identify(driver_t *driver, device_t parent) 162{ 163 device_t dev; 164 char desc[40]; 165 u_long rlen, rstart; 166 int i, j, rid, rtype; 167 168 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 169 | 149 150/* 151 * Locate the ACPI timer using the FADT, set up and allocate the I/O resources 152 * we will be using. 153 */ 154static void 155acpi_timer_identify(driver_t *driver, device_t parent) 156{ 157 device_t dev; 158 char desc[40]; 159 u_long rlen, rstart; 160 int i, j, rid, rtype; 161 162 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 163 |
170 if (acpi_disabled("timer")) | 164 if (acpi_disabled("timer") || AcpiGbl_FADT == NULL) |
171 return_VOID; | 165 return_VOID; |
172 173 if (AcpiGbl_FADT == NULL) 174 return_VOID; | |
175 176 if ((dev = BUS_ADD_CHILD(parent, 0, "acpi_timer", 0)) == NULL) { 177 device_printf(parent, "could not add acpi_timer0\n"); 178 return_VOID; 179 } 180 acpi_timer_dev = dev; 181 182 rid = 0; 183 rlen = AcpiGbl_FADT->PmTmLen; 184 rtype = (AcpiGbl_FADT->XPmTmrBlk.AddressSpaceId) 185 ? SYS_RES_IOPORT : SYS_RES_MEMORY; 186 rstart = AcpiGbl_FADT->XPmTmrBlk.Address; 187 bus_set_resource(dev, rtype, rid, rstart, rlen); 188 acpi_timer_reg = bus_alloc_resource(dev, rtype, &rid, 0, ~0, 1, RF_ACTIVE); 189 if (acpi_timer_reg == NULL) { 190 device_printf(dev, "couldn't allocate I/O resource (%s 0x%lx)\n", | 166 167 if ((dev = BUS_ADD_CHILD(parent, 0, "acpi_timer", 0)) == NULL) { 168 device_printf(parent, "could not add acpi_timer0\n"); 169 return_VOID; 170 } 171 acpi_timer_dev = dev; 172 173 rid = 0; 174 rlen = AcpiGbl_FADT->PmTmLen; 175 rtype = (AcpiGbl_FADT->XPmTmrBlk.AddressSpaceId) 176 ? SYS_RES_IOPORT : SYS_RES_MEMORY; 177 rstart = AcpiGbl_FADT->XPmTmrBlk.Address; 178 bus_set_resource(dev, rtype, rid, rstart, rlen); 179 acpi_timer_reg = bus_alloc_resource(dev, rtype, &rid, 0, ~0, 1, RF_ACTIVE); 180 if (acpi_timer_reg == NULL) { 181 device_printf(dev, "couldn't allocate I/O resource (%s 0x%lx)\n", |
191 (rtype == SYS_RES_IOPORT) ? "port" : "mem", rstart); | 182 rtype == SYS_RES_IOPORT ? "port" : "mem", rstart); |
192 return_VOID; 193 } 194 if (testenv("debug.acpi.timer_test")) 195 acpi_timer_test(); 196 197 acpi_timer_timecounter.tc_frequency = acpi_timer_frequency; 198 j = 0; 199 for(i = 0; i < 10; i++) 200 j += test_counter(); 201 if (j == 10) { 202 acpi_timer_timecounter.tc_name = "ACPI-fast"; 203 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount; 204 } else { 205 acpi_timer_timecounter.tc_name = "ACPI-safe"; 206 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount_safe; 207 } 208 tc_init(&acpi_timer_timecounter); 209 | 183 return_VOID; 184 } 185 if (testenv("debug.acpi.timer_test")) 186 acpi_timer_test(); 187 188 acpi_timer_timecounter.tc_frequency = acpi_timer_frequency; 189 j = 0; 190 for(i = 0; i < 10; i++) 191 j += test_counter(); 192 if (j == 10) { 193 acpi_timer_timecounter.tc_name = "ACPI-fast"; 194 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount; 195 } else { 196 acpi_timer_timecounter.tc_name = "ACPI-safe"; 197 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount_safe; 198 } 199 tc_init(&acpi_timer_timecounter); 200 |
210 sprintf(desc, "%d-bit timer at 3.579545MHz", (AcpiGbl_FADT->TmrValExt) 211 ? 32 : 24); | 201 sprintf(desc, "%d-bit timer at 3.579545MHz", 202 AcpiGbl_FADT->TmrValExt ? 32 : 24); |
212 device_set_desc_copy(dev, desc); 213 214 return_VOID; 215} 216 217static int 218acpi_timer_probe(device_t dev) 219{ 220 if (dev == acpi_timer_dev) | 203 device_set_desc_copy(dev, desc); 204 205 return_VOID; 206} 207 208static int 209acpi_timer_probe(device_t dev) 210{ 211 if (dev == acpi_timer_dev) |
221 return(0); 222 return(ENXIO); | 212 return (0); 213 214 return (ENXIO); |
223} 224 225static int 226acpi_timer_attach(device_t dev) 227{ | 215} 216 217static int 218acpi_timer_attach(device_t dev) 219{ |
228 return(0); | 220 return (0); |
229} 230 231/* 232 * Fetch current time value from reliable hardware. 233 */ 234static unsigned 235acpi_timer_get_timecount(struct timecounter *tc) 236{ --- 10 unchanged lines hidden (view full) --- 247 unsigned u1, u2, u3; 248 249 u2 = read_counter(); 250 u3 = read_counter(); 251 do { 252 u1 = u2; 253 u2 = u3; 254 u3 = read_counter(); | 221} 222 223/* 224 * Fetch current time value from reliable hardware. 225 */ 226static unsigned 227acpi_timer_get_timecount(struct timecounter *tc) 228{ --- 10 unchanged lines hidden (view full) --- 239 unsigned u1, u2, u3; 240 241 u2 = read_counter(); 242 u3 = read_counter(); 243 do { 244 u1 = u2; 245 u2 = u3; 246 u3 = read_counter(); |
255 } while (u1 > u2 || u2 > u3 || (u3 - u1) > 15); | 247 } while (u1 > u2 || u2 > u3 || u3 - u1 > 15); 248 |
256 return (u2); 257} 258 259/* 260 * Timecounter freqency adjustment interface. 261 */ 262static int 263acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS) --- 4 unchanged lines hidden (view full) --- 268 if (acpi_timer_timecounter.tc_frequency == 0) 269 return (EOPNOTSUPP); 270 freq = acpi_timer_frequency; 271 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 272 if (error == 0 && req->newptr != NULL) { 273 acpi_timer_frequency = freq; 274 acpi_timer_timecounter.tc_frequency = acpi_timer_frequency; 275 } | 249 return (u2); 250} 251 252/* 253 * Timecounter freqency adjustment interface. 254 */ 255static int 256acpi_timer_sysctl_freq(SYSCTL_HANDLER_ARGS) --- 4 unchanged lines hidden (view full) --- 261 if (acpi_timer_timecounter.tc_frequency == 0) 262 return (EOPNOTSUPP); 263 freq = acpi_timer_frequency; 264 error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); 265 if (error == 0 && req->newptr != NULL) { 266 acpi_timer_frequency = freq; 267 acpi_timer_timecounter.tc_frequency = acpi_timer_frequency; 268 } |
269 |
|
276 return (error); 277} 278 279SYSCTL_PROC(_machdep, OID_AUTO, acpi_timer_freq, CTLTYPE_INT | CTLFLAG_RW, 280 0, sizeof(u_int), acpi_timer_sysctl_freq, "I", ""); 281 282/* 283 * Test harness for verifying ACPI timer behaviour. --- 6 unchanged lines hidden (view full) --- 290 291 u1 = read_counter(); 292 u2 = read_counter(); 293 u3 = read_counter(); 294 295 device_printf(acpi_timer_dev, "timer test in progress, reboot to quit.\n"); 296 for (;;) { 297 /* | 270 return (error); 271} 272 273SYSCTL_PROC(_machdep, OID_AUTO, acpi_timer_freq, CTLTYPE_INT | CTLFLAG_RW, 274 0, sizeof(u_int), acpi_timer_sysctl_freq, "I", ""); 275 276/* 277 * Test harness for verifying ACPI timer behaviour. --- 6 unchanged lines hidden (view full) --- 284 285 u1 = read_counter(); 286 u2 = read_counter(); 287 u3 = read_counter(); 288 289 device_printf(acpi_timer_dev, "timer test in progress, reboot to quit.\n"); 290 for (;;) { 291 /* |
298 * The failure case is where u3 > u1, but u2 does not fall between the two, 299 * ie. it contains garbage. | 292 * The failure case is where u3 > u1, but u2 does not fall between 293 * the two, ie. it contains garbage. |
300 */ 301 if (u3 > u1) { | 294 */ 295 if (u3 > u1) { |
302 if ((u2 < u1) || (u2 > u3)) 303 device_printf(acpi_timer_dev, "timer is not monotonic: 0x%08x,0x%08x,0x%08x\n", | 296 if (u2 < u1 || u2 > u3) 297 device_printf(acpi_timer_dev, 298 "timer is not monotonic: 0x%08x,0x%08x,0x%08x\n", |
304 u1, u2, u3); 305 } 306 u1 = u2; 307 u2 = u3; 308 u3 = read_counter(); 309 } 310} 311 --- 42 unchanged lines hidden (view full) --- 354 355static driver_t acpi_timer_pci_driver = { 356 "acpi_timer_pci", 357 acpi_timer_pci_methods, 358 0, 359}; 360 361devclass_t acpi_timer_pci_devclass; | 299 u1, u2, u3); 300 } 301 u1 = u2; 302 u2 = u3; 303 u3 = read_counter(); 304 } 305} 306 --- 42 unchanged lines hidden (view full) --- 349 350static driver_t acpi_timer_pci_driver = { 351 "acpi_timer_pci", 352 acpi_timer_pci_methods, 353 0, 354}; 355 356devclass_t acpi_timer_pci_devclass; |
362DRIVER_MODULE(acpi_timer_pci, pci, acpi_timer_pci_driver, acpi_timer_pci_devclass, 0, 0); | 357DRIVER_MODULE(acpi_timer_pci, pci, acpi_timer_pci_driver, 358 acpi_timer_pci_devclass, 0, 0); |
363 364/* 365 * Look at PCI devices going past; if we detect one we know contains 366 * a functional ACPI timer device, enable the faster timecounter read 367 * routine. 368 */ 369static int 370acpi_timer_pci_probe(device_t dev) 371{ 372 int vendor, device, revid; 373 374 vendor = pci_get_vendor(dev); 375 device = pci_get_device(dev); 376 revid = pci_get_revid(dev); 377 | 359 360/* 361 * Look at PCI devices going past; if we detect one we know contains 362 * a functional ACPI timer device, enable the faster timecounter read 363 * routine. 364 */ 365static int 366acpi_timer_pci_probe(device_t dev) 367{ 368 int vendor, device, revid; 369 370 vendor = pci_get_vendor(dev); 371 device = pci_get_device(dev); 372 revid = pci_get_revid(dev); 373 |
378 if (((vendor == 0x8086) && (device == 0x7113) && (revid >= 0x03)) || /* PIIX4M */ 379 ((vendor == 0x8086) && (device == 0x719b)) || /* i440MX */ 380 0) { | 374 /* Detect the PIIX4M and i440MX, respectively */ 375 if ((vendor == 0x8086 && device == 0x7113 && revid >= 0x03) || 376 (vendor == 0x8086 && device == 0x719b)) { |
381 382 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount; 383 acpi_timer_timecounter.tc_name = "ACPI-fast"; | 377 378 acpi_timer_timecounter.tc_get_timecount = acpi_timer_get_timecount; 379 acpi_timer_timecounter.tc_name = "ACPI-fast"; |
384 if (bootverbose) 385 device_printf(acpi_timer_dev, "functional ACPI timer detected, enabling fast timecount interface\n"); | 380 if (bootverbose) { 381 device_printf(acpi_timer_dev,"functional ACPI timer detected, " 382 "enabling fast timecount interface\n"); 383 } |
386 } 387 | 384 } 385 |
388 return(ENXIO); /* we never match anything */ | 386 /* We never match anything */ 387 return (ENXIO); |
389} 390#endif | 388} 389#endif |