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 /* 124 * acpica module is never unloaded at run-time; there's always 125 * a PSM depending on it, at the very least 126 */ 127 return (EBUSY); 128 } 129 130 /* 131 * Install acpica-provided address-space handlers 132 */ 133 static int 134 acpica_install_handlers() 135 { 136 ACPI_STATUS rv = AE_OK; 137 138 /* 139 * Install ACPI CA default handlers 140 */ 141 if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 142 ACPI_ADR_SPACE_SYSTEM_MEMORY, 143 ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 144 cmn_err(CE_WARN, "!acpica: no default handler for" 145 " system memory"); 146 rv = AE_ERROR; 147 } 148 149 if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 150 ACPI_ADR_SPACE_SYSTEM_IO, 151 ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 152 cmn_err(CE_WARN, "!acpica: no default handler for" 153 " system I/O"); 154 rv = AE_ERROR; 155 } 156 157 if (AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 158 ACPI_ADR_SPACE_PCI_CONFIG, 159 ACPI_DEFAULT_HANDLER, NULL, NULL) != AE_OK) { 160 cmn_err(CE_WARN, "!acpica: no default handler for" 161 " PCI Config"); 162 rv = AE_ERROR; 163 } 164 165 166 return (rv); 167 } 168 169 /* 170 * Find the BIOS date, and return TRUE if supplied 171 * date is same or later than the BIOS date, or FALSE 172 * if the BIOS date can't be fetched for any reason 173 */ 174 static int 175 acpica_check_bios_date(int yy, int mm, int dd) 176 { 177 178 char *datep; 179 int bios_year, bios_month, bios_day; 180 181 /* 182 * PC BIOSes contain a string in the form of 183 * "mm/dd/yy" at absolute address 0xffff5, 184 * where mm, dd and yy are all ASCII digits. 185 * We map the string, pluck out the values, 186 * and accept all BIOSes from 1 Jan 1999 on 187 * as valid. 188 */ 189 190 if ((int)AcpiOsMapMemory(0xffff5, 8, (void **) &datep) != AE_OK) 191 return (FALSE); 192 193 /* year */ 194 bios_year = ((int)(*(datep + 6) - '0') * 10) + (*(datep + 7) - '0'); 195 /* month */ 196 bios_month = ((int)(*datep - '0') * 10) + (*(datep + 1) - '0'); 197 /* day */ 198 bios_day = ((int)(*(datep + 3) - '0') * 10) + (*(datep + 4) - '0'); 199 200 AcpiOsUnmapMemory((void *) datep, 8); 201 202 if (bios_year < 0 || bios_year > 99 || bios_month < 0 || 203 bios_month > 99 || bios_day < 0 || bios_day > 99) { 204 /* non-digit chars in BIOS date */ 205 return (FALSE); 206 } 207 208 /* 209 * Adjust for 2-digit year; note to grand-children: 210 * need a new scheme before 2080 rolls around 211 */ 212 bios_year += (bios_year >= 80 && bios_year <= 99) ? 213 1900 : 2000; 214 215 if (bios_year < yy) 216 return (FALSE); 217 else if (bios_year > yy) 218 return (TRUE); 219 220 if (bios_month < mm) 221 return (FALSE); 222 else if (bios_month > mm) 223 return (TRUE); 224 225 if (bios_day < dd) 226 return (FALSE); 227 228 return (TRUE); 229 } 230 231 /* 232 * Check for Metropolis systems with BIOSes older than 10/12/04 233 * return TRUE if BIOS requires legacy mode, FALSE otherwise 234 */ 235 static int 236 acpica_metro_old_bios() 237 { 238 ACPI_TABLE_HEADER *fadt; 239 240 /* get the FADT */ 241 if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING, 242 (ACPI_TABLE_HEADER **)&fadt) != AE_OK) 243 return (FALSE); 244 245 /* compare OEM Table ID to "SUNmetro" - no match, return false */ 246 if (strncmp("SUNmetro", fadt->OemTableId, 8)) 247 return (FALSE); 248 249 /* On a Metro - return FALSE if later than 10/12/04 */ 250 return (!acpica_check_bios_date(2004, 10, 12)); 251 } 252 253 254 /* 255 * Process acpi-user-options property if present 256 */ 257 static void 258 acpica_process_user_options() 259 { 260 static int processed = 0; 261 int acpi_user_options; 262 char *acpi_prop; 263 264 /* 265 * return if acpi-user-options has already been processed 266 */ 267 if (processed) 268 return; 269 else 270 processed = 1; 271 272 /* converts acpi-user-options from type string to int, if any */ 273 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 274 DDI_PROP_DONTPASS, "acpi-user-options", &acpi_prop) == 275 DDI_PROP_SUCCESS) { 276 long data; 277 int ret; 278 ret = ddi_strtol(acpi_prop, NULL, 0, &data); 279 if (ret == 0) { 280 e_ddi_prop_remove(DDI_DEV_T_NONE, ddi_root_node(), 281 "acpi-user-options"); 282 e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), 283 "acpi-user-options", data); 284 } 285 ddi_prop_free(acpi_prop); 286 } 287 288 /* 289 * fetch the optional options property 290 */ 291 acpi_user_options = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(), 0, 292 "acpi-user-options", 0); 293 294 /* 295 * Note that 'off' has precedence over 'on' 296 * Also note - all cases of ACPI_OUSER_MASK 297 * provided here, no default: case is present 298 */ 299 switch (acpi_user_options & ACPI_OUSER_MASK) { 300 case ACPI_OUSER_DFLT: 301 acpica_enable = acpica_check_bios_date(1999, 1, 1); 302 break; 303 case ACPI_OUSER_ON: 304 acpica_enable = TRUE; 305 break; 306 case ACPI_OUSER_OFF: 307 case ACPI_OUSER_OFF | ACPI_OUSER_ON: 308 acpica_enable = FALSE; 309 break; 310 } 311 312 acpi_init_level = ACPI_FULL_INITIALIZATION; 313 314 /* 315 * special test here; may be generalized in the 316 * future - test for a machines that are known to 317 * work only in legacy mode, and set OUSER_LEGACY if 318 * we're on one 319 */ 320 if (acpica_metro_old_bios()) 321 acpi_user_options |= ACPI_OUSER_LEGACY; 322 323 /* 324 * If legacy mode is specified, set initialization 325 * options to avoid entering ACPI mode and hooking SCI 326 * - basically try to act like legacy acpi_intp 327 */ 328 if ((acpi_user_options & ACPI_OUSER_LEGACY) != 0) 329 acpi_init_level |= (ACPI_NO_ACPI_ENABLE | ACPI_NO_HANDLER_INIT); 330 } 331 332 /* 333 * Initialize the CA subsystem if it hasn't been done already 334 */ 335 int 336 acpica_init() 337 { 338 ACPI_STATUS status; 339 340 /* 341 * Make sure user options are processed, 342 * then fail to initialize if ACPI CA has been 343 * disabled 344 */ 345 acpica_process_user_options(); 346 if (!acpica_enable) 347 return (AE_ERROR); 348 349 mutex_enter(&acpica_module_lock); 350 351 if (acpica_init_state == ACPICA_NOT_INITIALIZED) { 352 if ((status = AcpiLoadTables()) != AE_OK) { 353 goto error; 354 } 355 if ((status = acpica_install_handlers()) != AE_OK) { 356 goto error; 357 } 358 if ((status = AcpiEnableSubsystem(acpi_init_level)) != AE_OK) { 359 goto error; 360 } 361 if ((status = AcpiInitializeObjects(0)) != AE_OK) { 362 goto error; 363 } 364 /* 365 * Initialize EC 366 */ 367 acpica_ec_init(); 368 369 acpica_init_state = ACPICA_INITIALIZED; 370 error: 371 if (acpica_init_state != ACPICA_INITIALIZED) { 372 cmn_err(CE_NOTE, "!failed to initialize" 373 " ACPI services"); 374 } 375 } else 376 status = AE_OK; 377 378 /* 379 * Set acpi-status to 13 if acpica has been initialized successfully. 380 * This indicates that acpica is up and running. This variable name 381 * and value were chosen in order to remain compatible with acpi_intp. 382 */ 383 e_ddi_prop_update_int(DDI_DEV_T_NONE, ddi_root_node(), "acpi-status", 384 (status == AE_OK) ? (ACPI_BOOT_INIT | ACPI_BOOT_ENABLE | 385 ACPI_BOOT_BOOTCONF) : 0); 386 387 mutex_exit(&acpica_module_lock); 388 return (status); 389 } 390 391 /* 392 * SCI handling 393 */ 394 395 ACPI_STATUS 396 acpica_get_sci(int *sci_irq, iflag_t *sci_flags) 397 { 398 APIC_HEADER *ap; 399 MULTIPLE_APIC_TABLE *mat; 400 MADT_INTERRUPT_OVERRIDE *mio; 401 FADT_DESCRIPTOR *fadt; 402 int madt_seen, madt_size; 403 404 405 /* 406 * Make sure user options are processed, 407 * then return error if ACPI CA has been 408 * disabled or system is not running in ACPI 409 * and won't need/understand SCI 410 */ 411 acpica_process_user_options(); 412 if ((!acpica_enable) || (acpi_init_level & ACPI_NO_ACPI_ENABLE)) 413 return (AE_ERROR); 414 415 /* 416 * according to Intel ACPI developers, SCI 417 * conforms to PCI bus conventions; level/low 418 * unless otherwise directed by overrides. 419 */ 420 sci_flags->intr_el = INTR_EL_LEVEL; 421 sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 422 sci_flags->bustype = BUS_PCI; /* we *do* conform to PCI */ 423 424 /* get the SCI from the FADT */ 425 if (AcpiGetFirmwareTable(FADT_SIG, 1, ACPI_LOGICAL_ADDRESSING, 426 (ACPI_TABLE_HEADER **)&fadt) != AE_OK) 427 return (AE_ERROR); 428 429 *sci_irq = fadt->SciInt; 430 431 /* search for ISOs that modify it */ 432 /* if we don't find a MADT, that's OK; no ISOs then */ 433 if (AcpiGetFirmwareTable(APIC_SIG, 1, ACPI_LOGICAL_ADDRESSING, 434 (ACPI_TABLE_HEADER **) &mat) != AE_OK) { 435 return (AE_OK); 436 } 437 438 ap = (APIC_HEADER *) (mat + 1); 439 madt_size = mat->Length; 440 madt_seen = sizeof (*mat); 441 442 while (madt_seen < madt_size) { 443 switch (ap->Type) { 444 case APIC_XRUPT_OVERRIDE: 445 mio = (MADT_INTERRUPT_OVERRIDE *) ap; 446 if (mio->Source == *sci_irq) { 447 *sci_irq = mio->Interrupt; 448 sci_flags->intr_el = mio->TriggerMode; 449 sci_flags->intr_po = mio->Polarity; 450 } 451 break; 452 } 453 454 /* advance to next entry */ 455 madt_seen += ap->Length; 456 ap = (APIC_HEADER *)(((char *)ap) + ap->Length); 457 } 458 459 /* 460 * One more check; if ISO said "conform", revert to default 461 */ 462 if (sci_flags->intr_el == INTR_EL_CONFORM) 463 sci_flags->intr_el = INTR_EL_LEVEL; 464 if (sci_flags->intr_po == INTR_PO_CONFORM) 465 sci_flags->intr_po = INTR_PO_ACTIVE_LOW; 466 467 return (AE_OK); 468 } 469