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