xref: /illumos-gate/usr/src/uts/intel/io/acpica/acpica.c (revision f7534bc1423f9f2536244f445e8ffb24c86d5a46)
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