1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Solaris x86 ACPI CA services 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 32 #include <sys/file.h> 33 #include <sys/errno.h> 34 #include <sys/conf.h> 35 #include <sys/modctl.h> 36 #include <sys/open.h> 37 #include <sys/stat.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 #include <sys/esunddi.h> 41 42 #include <sys/acpi/acpi.h> 43 #include <sys/acpica.h> 44 45 /* 46 * 47 */ 48 static struct modlmisc modlmisc = { 49 &mod_miscops, 50 "ACPI interpreter %I%", 51 }; 52 53 static struct modlinkage modlinkage = { 54 MODREV_1, /* MODREV_1 manual */ 55 (void *)&modlmisc, /* module linkage */ 56 NULL, /* list terminator */ 57 }; 58 59 /* 60 * Local data 61 */ 62 63 static kmutex_t acpica_module_lock; 64 65 /* 66 * State of acpica subsystem 67 * After successful initialization, will be ACPICA_INITIALIZED 68 */ 69 int acpica_init_state = ACPICA_NOT_INITIALIZED; 70 71 /* 72 * Following are set by acpica_process_user_options() 73 * 74 * acpica_enable = FALSE prevents initialization of ACPI CA 75 * completely 76 * 77 * acpi_init_level determines level of ACPI CA functionality 78 * enabled in acpica_init() 79 */ 80 int acpica_enable; 81 UINT32 acpi_init_level; 82 83 /* 84 * Non-zero enables lax behavior with respect to some 85 * common ACPI BIOS issues; see ACPI CA documentation 86 * Setting this to zero causes ACPI CA to enforce strict 87 * compliance with ACPI specification 88 */ 89 int acpica_enable_interpreter_slack = 1; 90 91 /* 92 * For non-DEBUG builds, set the ACPI CA debug level to 0 93 * to quiet chatty BIOS output into /var/adm/messages 94 * Field-patchable for diagnostic use. 95 */ 96 #ifdef DEBUG 97 int acpica_muzzle_debug_output = 0; 98 #else 99 int acpica_muzzle_debug_output = 1; 100 #endif 101 102 103 int 104 _init(void) 105 { 106 int error = EBUSY; 107 int status; 108 109 mutex_init(&acpica_module_lock, NULL, MUTEX_DRIVER, NULL); 110 111 if ((error = mod_install(&modlinkage)) != 0) { 112 mutex_destroy(&acpica_module_lock); 113 } 114 115 AcpiGbl_EnableInterpreterSlack = (acpica_enable_interpreter_slack != 0); 116 117 if ((status = AcpiInitializeSubsystem()) != AE_OK) { 118 cmn_err(CE_WARN, "!acpica: error pre-init:1:%d", status); 119 } 120 121 return (error); 122 } 123 124 int 125 _info(struct modinfo *modinfop) 126 { 127 return (mod_info(&modlinkage, modinfop)); 128 } 129 130 int 131 _fini(void) 132 { 133 /* 134 * acpica module is never unloaded at run-time; there's always 135 * a PSM depending on it, at the very least 136 */ 137 return (EBUSY); 138 } 139 140 /* 141 * Install acpica-provided address-space handlers 142 */ 143 static int 144 acpica_install_handlers() 145 { 146 ACPI_STATUS rv = AE_OK; 147 148 /* 149 * Install ACPI CA default handlers 150 */ 151 if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 152 ACPI_ADR_SPACE_SYSTEM_MEMORY, 153 ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 154 cmn_err(CE_WARN, "!acpica: no default handler for" 155 " system memory"); 156 rv = AE_ERROR; 157 } 158 159 if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 160 ACPI_ADR_SPACE_SYSTEM_IO, 161 ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 162 cmn_err(CE_WARN, "!acpica: no default handler for" 163 " system I/O"); 164 rv = AE_ERROR; 165 } 166 167 if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 168 ACPI_ADR_SPACE_PCI_CONFIG, 169 ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 170 cmn_err(CE_WARN, "!acpica: no default handler for" 171 " PCI Config"); 172 rv = AE_ERROR; 173 } 174 175 176 return (rv); 177 } 178 179 /* 180 * Find the BIOS date, and return TRUE if supplied 181 * date is same or later than the BIOS date, or FALSE 182 * if the BIOS date can't be fetched for any reason 183 */ 184 static int 185 acpica_check_bios_date(int yy, int mm, int dd) 186 { 187 188 char *datep; 189 int bios_year, bios_month, bios_day; 190 191 /* If firmware has no bios, skip the check */ 192 if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), 0, "bios-free")) 193 return (TRUE); 194 195 /* 196 * PC BIOSes contain a string in the form of 197 * "mm/dd/yy" at absolute address 0xffff5, 198 * where mm, dd and yy are all ASCII digits. 199 * We map the string, pluck out the values, 200 * and accept all BIOSes from 1 Jan 1999 on 201 * as valid. 202 */ 203 204 if ((int)AcpiOsMapMemory(0xffff5, 8, (void **) &datep) != AE_OK) 205 return (FALSE); 206 207 /* year */ 208 bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0'); 209 /* month */ 210 bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0'); 211 /* day */ 212 bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0'); 213 214 AcpiOsUnmapMemory((void *) datep, 8); 215 216 if (bios_year < 0 || bios_year > 99 || bios_month < 0 || 217 bios_month > 99 || bios_day < 0 || bios_day > 99) { 218 /* non-digit chars in BIOS date */ 219 return (FALSE); 220 } 221 222 /* 223 * Adjust for 2-digit year; note to grand-children: 224 * need a new scheme before 2080 rolls around 225 */ 226 bios_year += (bios_year >= 80 && bios_year <= 99) ? 227 1900 : 2000; 228 229 if (bios_year < yy) 230 return (FALSE); 231 else if (bios_year > yy) 232 return (TRUE); 233 234 if (bios_month < mm) 235 return (FALSE); 236 else if (bios_month > mm) 237 return (TRUE); 238 239 if (bios_day < dd) 240 return (FALSE); 241 242 return (TRUE); 243 } 244 245 /* 246 * Check for Metropolis systems with BIOSes older than 10/12/04 247 * return TRUE if BIOS requires legacy mode, FALSE otherwise 248 */ 249 static int 250 acpica_metro_old_bios() 251 { 252 ACPI_TABLE_HEADER *fadt; 253 254 /* get the FADT */ 255 if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING, 256 (ACPI_TABLE_HEADER **)&fadt) != AE_OK) 257 return (FALSE); 258 259 /* compare OEM Table ID to "SUNmetro" - no match, return false */ 260 if (strncmp("SUNmetro", fadt->OemTableId, 8)) 261 return (FALSE); 262 263 /* On a Metro - return FALSE if later than 10/12/04 */ 264 return (!acpica_check_bios_date(2004, 10, 12)); 265 } 266 267 268 /* 269 * Process acpi-user-options property if present 270 */ 271 static void 272 acpica_process_user_options() 273 { 274 static int processed = 0; 275 int acpi_user_options; 276 char *acpi_prop; 277 278 /* 279 * return if acpi-user-options has already been processed 280 */ 281 if (processed) 282 return; 283 else 284 processed = 1; 285 286 /* converts acpi-user-options from type string to int, if any */ 287 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 288 DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) == 289 DDI_PROP_SUCCESS) { 290 long data; 291 int ret; 292 ret = ddi_strtol(acpi_prop, NULL, 0, &data); 293 if (ret == 0) { 294 e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(), 295 "acpi-user-options"); 296 e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), 297 "acpi-user-options", data); 298 } 299 ddi_prop_free(acpi_prop); 300 } 301 302 /* 303 * fetch the optional options property 304 */ 305 acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(), 0, 306 "acpi-user-options", 0); 307 308 /* 309 * Note that 'off' has precedence over 'on' 310 * Also note - all cases of ACPI_OUSER_MASK 311 * provided here, no default: case is present 312 */ 313 switch (acpi_user_options & ACPI_OUSER_MASK) { 314 case ACPI_OUSER_DFLT: 315 acpica_enable = acpica_check_bios_date(1999, 1, 1); 316 break; 317 case ACPI_OUSER_ON: 318 acpica_enable = TRUE; 319 break; 320 case ACPI_OUSER_OFF: 321 case ACPI_OUSER_OFF | ACPI_OUSER_ON: 322 acpica_enable = FALSE; 323 break; 324 } 325 326 acpi_init_level = ACPI_FULL_INITIALIZATION; 327 328 /* 329 * special test here; may be generalized in the 330 * future - test for a machines that are known to 331 * work only in legacy mode, and set OUSER_LEGACY if 332 * we're on one 333 */ 334 if (acpica_metro_old_bios()) 335 acpi_user_options |= ACPI_OUSER_LEGACY; 336 337 /* 338 * If legacy mode is specified, set initialization 339 * options to avoid entering ACPI mode and hooking SCI 340 * - basically try to act like legacy acpi_intp 341 */ 342 if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0) 343 acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT); 344 345 /* 346 * modify default ACPI CA debug output level for non-DEBUG builds 347 * (to avoid BIOS debug chatter in /var/adm/messages) 348 */ 349 if (acpica_muzzle_debug_output) 350 AcpiDbgLevel = 0; 351 } 352 353 /* 354 * Initialize the CA subsystem if it hasn't been done already 355 */ 356 int 357 acpica_init() 358 { 359 ACPI_STATUS status; 360 361 /* 362 * Make sure user options are processed, 363 * then fail to initialize if ACPI CA has been 364 * disabled 365 */ 366 acpica_process_user_options(); 367 if (!acpica_enable) 368 return (AE_ERROR); 369 370 mutex_enter(&acpica_module_lock); 371 372 if (acpica_init_state == ACPICA_NOT_INITIALIZED) { 373 if ((status = AcpiLoadTables()) != AE_OK) { 374 goto error; 375 } 376 if ((status = acpica_install_handlers()) != AE_OK) { 377 goto error; 378 } 379 if ((status = AcpiEnableSubsystem(acpi_init_level)) != AE_OK) { 380 goto error; 381 } 382 if ((status = AcpiInitializeObjects(0)) != AE_OK) { 383 goto error; 384 } 385 /* 386 * Initialize EC 387 */ 388 acpica_ec_init(); 389 390 acpica_init_state = ACPICA_INITIALIZED; 391 error: 392 if (acpica_init_state != ACPICA_INITIALIZED) { 393 cmn_err(CE_NOTE, "!failed to initialize" 394 " ACPI services"); 395 } 396 } else 397 status = AE_OK; 398 399 /* 400 * Set acpi-status to 13 if acpica has been initialized successfully. 401 * This indicates that acpica is up and running. This variable name 402 * and value were chosen in order to remain compatible with acpi_intp. 403 */ 404 e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), "acpi-status", 405 (status == AE_OK) ? (ACPI_BOOT_INIT | ACPI_BOOT_ENABLE | 406 ACPI_BOOT_BOOTCONF) : 0); 407 408 mutex_exit(&acpica_module_lock); 409 return (status); 410 } 411 412 /* 413 * SCI handling 414 */ 415 416 ACPI_STATUS 417 acpica_get_sci(int *sci_irq, iflag_t *sci_flags) 418 { 419 APIC_HEADER *ap; 420 MULTIPLE_APIC_TABLE *mat; 421 MADT_INTERRUPT_OVERRIDE *mio; 422 FADT_DESCRIPTOR *fadt; 423 int madt_seen, madt_size; 424 425 426 /* 427 * Make sure user options are processed, 428 * then return error if ACPI CA has been 429 * disabled or system is not running in ACPI 430 * and won't need/understand SCI 431 */ 432 acpica_process_user_options(); 433 if ((!acpica_enable) || (acpi_init_level & ACPI_NO_ACPI_ENABLE)) 434 return (AE_ERROR); 435 436 /* 437 * according to Intel ACPI developers, SCI 438 * conforms to PCI bus conventions; level/low 439 * unless otherwise directed by overrides. 440 */ 441 sci_flags->intr_el = INTR_EL_LEVEL; 442 sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 443 sci_flags->bustype = BUS_PCI; /* we *do* conform to PCI */ 444 445 /* get the SCI from the FADT */ 446 if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING, 447 (ACPI_TABLE_HEADER **)&fadt) != AE_OK) 448 return (AE_ERROR); 449 450 *sci_irq = fadt->SciInt; 451 452 /* search for ISOs that modify it */ 453 /* if we don't find a MADT, that's OK; no ISOs then */ 454 if (AcpiGetFirmwareTable(APIC_SIG, 1, ACPI_LOGICAL_ADDRESSING, 455 (ACPI_TABLE_HEADER **) &mat) != AE_OK) { 456 return (AE_OK); 457 } 458 459 ap = (APIC_HEADER *) (mat + 1); 460 madt_size = mat->Length; 461 madt_seen = sizeof (*mat); 462 463 while (madt_seen < madt_size) { 464 switch (ap->Type) { 465 case APIC_XRUPT_OVERRIDE: 466 mio = (MADT_INTERRUPT_OVERRIDE *) ap; 467 if (mio->Source == *sci_irq) { 468 *sci_irq = mio->Interrupt; 469 sci_flags->intr_el = mio->TriggerMode; 470 sci_flags->intr_po = mio->Polarity; 471 } 472 break; 473 } 474 475 /* advance to next entry */ 476 madt_seen += ap->Length; 477 ap = (APIC_HEADER *)(((char *)ap) + ap->Length); 478 } 479 480 /* 481 * One more check; if ISO said "conform", revert to default 482 */ 483 if (sci_flags->intr_el == INTR_EL_CONFORM) 484 sci_flags->intr_el = INTR_EL_LEVEL; 485 if (sci_flags->intr_po == INTR_PO_CONFORM) 486 sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 487 488 return (AE_OK); 489 } 490