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