xref: /onnv-gate/usr/src/uts/intel/io/acpica/osl.c (revision 12004:93f274d4a367)
13446Smrj /*
23446Smrj  * CDDL HEADER START
33446Smrj  *
43446Smrj  * The contents of this file are subject to the terms of the
53446Smrj  * Common Development and Distribution License (the "License").
63446Smrj  * You may not use this file except in compliance with the License.
73446Smrj  *
83446Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93446Smrj  * or http://www.opensolaris.org/os/licensing.
103446Smrj  * See the License for the specific language governing permissions
113446Smrj  * and limitations under the License.
123446Smrj  *
133446Smrj  * When distributing Covered Code, include this CDDL HEADER in each
143446Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153446Smrj  * If applicable, add the following below this CDDL HEADER, with the
163446Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
173446Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
183446Smrj  *
193446Smrj  * CDDL HEADER END
203446Smrj  */
213446Smrj 
223446Smrj /*
238906SEric.Saxe@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
243446Smrj  * Use is subject to license terms.
253446Smrj  */
263446Smrj /*
27*12004Sjiang.liu@intel.com  * Copyright (c) 2009-2010, Intel Corporation.
289652SMichael.Corcoran@Sun.COM  * All rights reserved.
299652SMichael.Corcoran@Sun.COM  */
309652SMichael.Corcoran@Sun.COM /*
313446Smrj  * ACPI CA OSL for Solaris x86
323446Smrj  */
333446Smrj 
343446Smrj #include <sys/types.h>
353446Smrj #include <sys/kmem.h>
363446Smrj #include <sys/psm.h>
373446Smrj #include <sys/pci_cfgspace.h>
389000SStuart.Maybee@Sun.COM #include <sys/apic.h>
393446Smrj #include <sys/ddi.h>
408973SDana.Myers@Sun.COM #include <sys/sunddi.h>
414667Smh27603 #include <sys/sunndi.h>
423446Smrj #include <sys/pci.h>
433446Smrj #include <sys/kobj.h>
443446Smrj #include <sys/taskq.h>
453446Smrj #include <sys/strlog.h>
4610394SMichael.Corcoran@Sun.COM #include <sys/x86_archext.h>
473446Smrj #include <sys/note.h>
4810235SDana.Myers@Sun.COM #include <sys/promif.h>
493446Smrj 
5010147SMark.Haywood@Sun.COM #include <sys/acpi/accommon.h>
513446Smrj #include <sys/acpica.h>
523446Smrj 
533446Smrj #define	MAX_DAT_FILE_SIZE	(64*1024)
543446Smrj 
553446Smrj /* local functions */
563446Smrj static int CompressEisaID(char *np);
573446Smrj 
584667Smh27603 static void scan_d2a_subtree(dev_info_t *dip, ACPI_HANDLE acpiobj, int bus);
593446Smrj static int acpica_query_bbn_problem(void);
603446Smrj static int acpica_find_pcibus(int busno, ACPI_HANDLE *rh);
613446Smrj static int acpica_eval_hid(ACPI_HANDLE dev, char *method, int *rint);
624667Smh27603 static ACPI_STATUS acpica_set_devinfo(ACPI_HANDLE, dev_info_t *);
639652SMichael.Corcoran@Sun.COM static ACPI_STATUS acpica_unset_devinfo(ACPI_HANDLE);
6411225SDana.Myers@Sun.COM static void acpica_devinfo_handler(ACPI_HANDLE, void *);
653446Smrj 
663446Smrj /*
673446Smrj  * Event queue vars
683446Smrj  */
693446Smrj int acpica_eventq_init = 0;
703446Smrj ddi_taskq_t *osl_eventq[OSL_EC_BURST_HANDLER+1];
713446Smrj 
723446Smrj /*
737851SDana.Myers@Sun.COM  * Priorities relative to minclsyspri that each taskq
747851SDana.Myers@Sun.COM  * run at; OSL_NOTIFY_HANDLER needs to run at a higher
757851SDana.Myers@Sun.COM  * priority than OSL_GPE_HANDLER.  There's an implicit
767851SDana.Myers@Sun.COM  * assumption that no priority here results in exceeding
777851SDana.Myers@Sun.COM  * maxclsyspri.
787851SDana.Myers@Sun.COM  * Note: these initializations need to match the order of
797851SDana.Myers@Sun.COM  * ACPI_EXECUTE_TYPE.
807851SDana.Myers@Sun.COM  */
817851SDana.Myers@Sun.COM int osl_eventq_pri_delta[OSL_EC_BURST_HANDLER+1] = {
827851SDana.Myers@Sun.COM 	0,	/* OSL_GLOBAL_LOCK_HANDLER */
837851SDana.Myers@Sun.COM 	2,	/* OSL_NOTIFY_HANDLER */
847851SDana.Myers@Sun.COM 	0,	/* OSL_GPE_HANDLER */
857851SDana.Myers@Sun.COM 	0,	/* OSL_DEBUGGER_THREAD */
867851SDana.Myers@Sun.COM 	0,	/* OSL_EC_POLL_HANDLER */
877851SDana.Myers@Sun.COM 	0	/* OSL_EC_BURST_HANDLER */
887851SDana.Myers@Sun.COM };
897851SDana.Myers@Sun.COM 
907851SDana.Myers@Sun.COM /*
913446Smrj  * Note, if you change this path, you need to update
923446Smrj  * /boot/grub/filelist.ramdisk and pkg SUNWckr/prototype_i386
933446Smrj  */
943446Smrj static char *acpi_table_path = "/boot/acpi/tables/";
953446Smrj 
964667Smh27603 /* non-zero while scan_d2a_map() is working */
974667Smh27603 static int scanning_d2a_map = 0;
984667Smh27603 static int d2a_done = 0;
993446Smrj 
1009652SMichael.Corcoran@Sun.COM /* features supported by ACPICA and ACPI device configuration. */
101*12004Sjiang.liu@intel.com uint64_t acpica_core_features = ACPI_FEATURE_OSI_MODULE;
1029652SMichael.Corcoran@Sun.COM static uint64_t acpica_devcfg_features = 0;
1039652SMichael.Corcoran@Sun.COM 
1048122SKerry.Shu@Sun.COM /* set by acpi_poweroff() in PSMs and appm_ioctl() in acpippm for S3 */
1058122SKerry.Shu@Sun.COM int acpica_use_safe_delay = 0;
1063446Smrj 
1074667Smh27603 /* CPU mapping data */
1084667Smh27603 struct cpu_map_item {
1099652SMichael.Corcoran@Sun.COM 	processorid_t	cpu_id;
1107282Smishra 	UINT32		proc_id;
1119652SMichael.Corcoran@Sun.COM 	UINT32		apic_id;
1124667Smh27603 	ACPI_HANDLE	obj;
1134667Smh27603 };
1144667Smh27603 
115*12004Sjiang.liu@intel.com kmutex_t cpu_map_lock;
1164667Smh27603 static struct cpu_map_item **cpu_map = NULL;
1179652SMichael.Corcoran@Sun.COM static int cpu_map_count_max = 0;
1184667Smh27603 static int cpu_map_count = 0;
1194667Smh27603 static int cpu_map_built = 0;
1204667Smh27603 
12110394SMichael.Corcoran@Sun.COM /*
12210394SMichael.Corcoran@Sun.COM  * On systems with the uppc PSM only, acpica_map_cpu() won't be called at all.
12310394SMichael.Corcoran@Sun.COM  * This flag is used to check for uppc-only systems by detecting whether
12410394SMichael.Corcoran@Sun.COM  * acpica_map_cpu() has been called or not.
12510394SMichael.Corcoran@Sun.COM  */
12610394SMichael.Corcoran@Sun.COM static int cpu_map_called = 0;
12710394SMichael.Corcoran@Sun.COM 
1284667Smh27603 static int acpi_has_broken_bbn = -1;
1294667Smh27603 
1305155Smyers /* buffer for AcpiOsVprintf() */
1315155Smyers #define	ACPI_OSL_PR_BUFLEN	1024
1325155Smyers static char *acpi_osl_pr_buffer = NULL;
1335155Smyers static int acpi_osl_pr_buflen;
1345155Smyers 
1354667Smh27603 #define	D2A_DEBUG
1364667Smh27603 
1373446Smrj /*
1383446Smrj  *
1393446Smrj  */
1403446Smrj static void
discard_event_queues()1413446Smrj discard_event_queues()
1423446Smrj {
1433446Smrj 	int	i;
1443446Smrj 
1453446Smrj 	/*
1463446Smrj 	 * destroy event queues
1473446Smrj 	 */
1483446Smrj 	for (i = OSL_GLOBAL_LOCK_HANDLER; i <= OSL_EC_BURST_HANDLER; i++) {
1493446Smrj 		if (osl_eventq[i])
1503446Smrj 			ddi_taskq_destroy(osl_eventq[i]);
1513446Smrj 	}
1523446Smrj }
1533446Smrj 
1543446Smrj 
1553446Smrj /*
1563446Smrj  *
1573446Smrj  */
1583446Smrj static ACPI_STATUS
init_event_queues()1593446Smrj init_event_queues()
1603446Smrj {
1613446Smrj 	char	namebuf[32];
1623446Smrj 	int	i, error = 0;
1633446Smrj 
1643446Smrj 	/*
1653446Smrj 	 * Initialize event queues
1663446Smrj 	 */
1673446Smrj 
1687851SDana.Myers@Sun.COM 	/* Always allocate only 1 thread per queue to force FIFO execution */
1693446Smrj 	for (i = OSL_GLOBAL_LOCK_HANDLER; i <= OSL_EC_BURST_HANDLER; i++) {
1703446Smrj 		snprintf(namebuf, 32, "ACPI%d", i);
1717851SDana.Myers@Sun.COM 		osl_eventq[i] = ddi_taskq_create(NULL, namebuf, 1,
1727851SDana.Myers@Sun.COM 		    osl_eventq_pri_delta[i] + minclsyspri, 0);
1733446Smrj 		if (osl_eventq[i] == NULL)
1743446Smrj 			error++;
1753446Smrj 	}
1763446Smrj 
1773446Smrj 	if (error != 0) {
1783446Smrj 		discard_event_queues();
1793446Smrj #ifdef	DEBUG
1803446Smrj 		cmn_err(CE_WARN, "!acpica: could not initialize event queues");
1813446Smrj #endif
1823446Smrj 		return (AE_ERROR);
1833446Smrj 	}
1843446Smrj 
1853446Smrj 	acpica_eventq_init = 1;
1863446Smrj 	return (AE_OK);
1873446Smrj }
1883446Smrj 
1893446Smrj /*
1905155Smyers  * One-time initialization of OSL layer
1913446Smrj  */
1923446Smrj ACPI_STATUS
AcpiOsInitialize(void)1933446Smrj AcpiOsInitialize(void)
1943446Smrj {
1955155Smyers 	/*
1965155Smyers 	 * Allocate buffer for AcpiOsVprintf() here to avoid
1975155Smyers 	 * kmem_alloc()/kmem_free() at high PIL
1985155Smyers 	 */
1995155Smyers 	acpi_osl_pr_buffer = kmem_alloc(ACPI_OSL_PR_BUFLEN, KM_SLEEP);
2005155Smyers 	if (acpi_osl_pr_buffer != NULL)
2015155Smyers 		acpi_osl_pr_buflen = ACPI_OSL_PR_BUFLEN;
2025155Smyers 
2033446Smrj 	return (AE_OK);
2043446Smrj }
2053446Smrj 
2063446Smrj /*
2075155Smyers  * One-time shut-down of OSL layer
2083446Smrj  */
2093446Smrj ACPI_STATUS
AcpiOsTerminate(void)2103446Smrj AcpiOsTerminate(void)
2113446Smrj {
2123446Smrj 
2135155Smyers 	if (acpi_osl_pr_buffer != NULL)
2145155Smyers 		kmem_free(acpi_osl_pr_buffer, acpi_osl_pr_buflen);
2155155Smyers 
2163446Smrj 	discard_event_queues();
2173446Smrj 	return (AE_OK);
2183446Smrj }
2193446Smrj 
2203446Smrj 
2217851SDana.Myers@Sun.COM ACPI_PHYSICAL_ADDRESS
AcpiOsGetRootPointer()2227851SDana.Myers@Sun.COM AcpiOsGetRootPointer()
2233446Smrj {
2247851SDana.Myers@Sun.COM 	ACPI_PHYSICAL_ADDRESS Address;
2253446Smrj 
2263446Smrj 	/*
2273446Smrj 	 * For EFI firmware, the root pointer is defined in EFI systab.
2283446Smrj 	 * The boot code process the table and put the physical address
2293446Smrj 	 * in the acpi-root-tab property.
2303446Smrj 	 */
2319388SDana.Myers@Sun.COM 	Address = ddi_prop_get_int(DDI_DEV_T_ANY, ddi_root_node(),
2329388SDana.Myers@Sun.COM 	    DDI_PROP_DONTPASS, "acpi-root-tab", NULL);
2337851SDana.Myers@Sun.COM 
2347851SDana.Myers@Sun.COM 	if ((Address == NULL) && ACPI_FAILURE(AcpiFindRootPointer(&Address)))
2357851SDana.Myers@Sun.COM 		Address = NULL;
2367851SDana.Myers@Sun.COM 
2377851SDana.Myers@Sun.COM 	return (Address);
2383446Smrj }
2393446Smrj 
2403446Smrj /*ARGSUSED*/
2413446Smrj ACPI_STATUS
AcpiOsPredefinedOverride(const ACPI_PREDEFINED_NAMES * InitVal,ACPI_STRING * NewVal)2423446Smrj AcpiOsPredefinedOverride(const ACPI_PREDEFINED_NAMES *InitVal,
2433446Smrj 				ACPI_STRING *NewVal)
2443446Smrj {
2453446Smrj 
2463446Smrj 	*NewVal = 0;
2473446Smrj 	return (AE_OK);
2483446Smrj }
2493446Smrj 
2503446Smrj static void
acpica_strncpy(char * dest,const char * src,int len)2513446Smrj acpica_strncpy(char *dest, const char *src, int len)
2523446Smrj {
2533446Smrj 
2543446Smrj 	/*LINTED*/
2553446Smrj 	while ((*dest++ = *src++) && (--len > 0))
2563446Smrj 		/* copy the string */;
2573446Smrj 	*dest = '\0';
2583446Smrj }
2593446Smrj 
2603446Smrj ACPI_STATUS
AcpiOsTableOverride(ACPI_TABLE_HEADER * ExistingTable,ACPI_TABLE_HEADER ** NewTable)2613446Smrj AcpiOsTableOverride(ACPI_TABLE_HEADER *ExistingTable,
2623446Smrj 			ACPI_TABLE_HEADER **NewTable)
2633446Smrj {
2643446Smrj 	char signature[5];
2653446Smrj 	char oemid[7];
2663446Smrj 	char oemtableid[9];
2673446Smrj 	struct _buf *file;
2683446Smrj 	char *buf1, *buf2;
2693446Smrj 	int count;
2703446Smrj 	char acpi_table_loc[128];
2713446Smrj 
2723446Smrj 	acpica_strncpy(signature, ExistingTable->Signature, 4);
2733446Smrj 	acpica_strncpy(oemid, ExistingTable->OemId, 6);
2743446Smrj 	acpica_strncpy(oemtableid, ExistingTable->OemTableId, 8);
2753446Smrj 
2763446Smrj #ifdef	DEBUG
2773446Smrj 	cmn_err(CE_NOTE, "!acpica: table [%s] v%d OEM ID [%s]"
2784476Smyers 	    " OEM TABLE ID [%s] OEM rev %x",
2794476Smyers 	    signature, ExistingTable->Revision, oemid, oemtableid,
2804476Smyers 	    ExistingTable->OemRevision);
2813446Smrj #endif
2823446Smrj 
2833446Smrj 	/* File name format is "signature_oemid_oemtableid.dat" */
2843446Smrj 	(void) strcpy(acpi_table_loc, acpi_table_path);
2853446Smrj 	(void) strcat(acpi_table_loc, signature); /* for example, DSDT */
2863446Smrj 	(void) strcat(acpi_table_loc, "_");
2873446Smrj 	(void) strcat(acpi_table_loc, oemid); /* for example, IntelR */
2883446Smrj 	(void) strcat(acpi_table_loc, "_");
2893446Smrj 	(void) strcat(acpi_table_loc, oemtableid); /* for example, AWRDACPI */
2903446Smrj 	(void) strcat(acpi_table_loc, ".dat");
2913446Smrj 
2923446Smrj 	file = kobj_open_file(acpi_table_loc);
2933446Smrj 	if (file == (struct _buf *)-1) {
2943446Smrj 		*NewTable = 0;
2953446Smrj 		return (AE_OK);
2963446Smrj 	} else {
2973446Smrj 		buf1 = (char *)kmem_alloc(MAX_DAT_FILE_SIZE, KM_SLEEP);
2983446Smrj 		count = kobj_read_file(file, buf1, MAX_DAT_FILE_SIZE-1, 0);
2993446Smrj 		if (count >= MAX_DAT_FILE_SIZE) {
3003446Smrj 			cmn_err(CE_WARN, "!acpica: table %s file size too big",
3013446Smrj 			    acpi_table_loc);
3023446Smrj 			*NewTable = 0;
3033446Smrj 		} else {
3043446Smrj 			buf2 = (char *)kmem_alloc(count, KM_SLEEP);
3053446Smrj 			(void) memcpy(buf2, buf1, count);
3063446Smrj 			*NewTable = (ACPI_TABLE_HEADER *)buf2;
3073446Smrj 			cmn_err(CE_NOTE, "!acpica: replacing table: %s",
3083446Smrj 			    acpi_table_loc);
3093446Smrj 		}
3103446Smrj 	}
3113446Smrj 	kobj_close_file(file);
3123446Smrj 	kmem_free(buf1, MAX_DAT_FILE_SIZE);
3133446Smrj 
3143446Smrj 	return (AE_OK);
3153446Smrj }
3163446Smrj 
3173446Smrj 
3183446Smrj /*
3193446Smrj  * ACPI semaphore implementation
3203446Smrj  */
3213446Smrj typedef struct {
3223446Smrj 	kmutex_t	mutex;
3233446Smrj 	kcondvar_t	cv;
3243446Smrj 	uint32_t	available;
3253446Smrj 	uint32_t	initial;
3263446Smrj 	uint32_t	maximum;
3273446Smrj } acpi_sema_t;
3283446Smrj 
3293446Smrj /*
3303446Smrj  *
3313446Smrj  */
3323446Smrj void
acpi_sema_init(acpi_sema_t * sp,unsigned max,unsigned count)3333446Smrj acpi_sema_init(acpi_sema_t *sp, unsigned max, unsigned count)
3343446Smrj {
3353446Smrj 	mutex_init(&sp->mutex, NULL, MUTEX_DRIVER, NULL);
3363446Smrj 	cv_init(&sp->cv, NULL, CV_DRIVER, NULL);
3373446Smrj 	/* no need to enter mutex here at creation */
3383446Smrj 	sp->available = count;
3393446Smrj 	sp->initial = count;
3403446Smrj 	sp->maximum = max;
3413446Smrj }
3423446Smrj 
3433446Smrj /*
3443446Smrj  *
3453446Smrj  */
3463446Smrj void
acpi_sema_destroy(acpi_sema_t * sp)3473446Smrj acpi_sema_destroy(acpi_sema_t *sp)
3483446Smrj {
3493446Smrj 
3503446Smrj 	cv_destroy(&sp->cv);
3513446Smrj 	mutex_destroy(&sp->mutex);
3523446Smrj }
3533446Smrj 
3543446Smrj /*
3553446Smrj  *
3563446Smrj  */
3573446Smrj ACPI_STATUS
acpi_sema_p(acpi_sema_t * sp,unsigned count,uint16_t wait_time)3583446Smrj acpi_sema_p(acpi_sema_t *sp, unsigned count, uint16_t wait_time)
3593446Smrj {
3603446Smrj 	ACPI_STATUS rv = AE_OK;
3613446Smrj 	clock_t deadline;
3623446Smrj 
3633446Smrj 	mutex_enter(&sp->mutex);
3643446Smrj 
3653446Smrj 	if (sp->available >= count) {
3663446Smrj 		/*
3673446Smrj 		 * Enough units available, no blocking
3683446Smrj 		 */
3693446Smrj 		sp->available -= count;
3703446Smrj 		mutex_exit(&sp->mutex);
3713446Smrj 		return (rv);
3723446Smrj 	} else if (wait_time == 0) {
3733446Smrj 		/*
3743446Smrj 		 * Not enough units available and timeout
3753446Smrj 		 * specifies no blocking
3763446Smrj 		 */
3773446Smrj 		rv = AE_TIME;
3783446Smrj 		mutex_exit(&sp->mutex);
3793446Smrj 		return (rv);
3803446Smrj 	}
3813446Smrj 
3823446Smrj 	/*
3833446Smrj 	 * Not enough units available and timeout specifies waiting
3843446Smrj 	 */
3853446Smrj 	if (wait_time != ACPI_WAIT_FOREVER)
3863446Smrj 		deadline = ddi_get_lbolt() +
3873446Smrj 		    (clock_t)drv_usectohz(wait_time * 1000);
3883446Smrj 
3893446Smrj 	do {
3903446Smrj 		if (wait_time == ACPI_WAIT_FOREVER)
3913446Smrj 			cv_wait(&sp->cv, &sp->mutex);
3923446Smrj 		else if (cv_timedwait(&sp->cv, &sp->mutex, deadline) < 0) {
3933446Smrj 			rv = AE_TIME;
3943446Smrj 			break;
3953446Smrj 		}
3963446Smrj 	} while (sp->available < count);
3973446Smrj 
3983446Smrj 	/* if we dropped out of the wait with AE_OK, we got the units */
3993446Smrj 	if (rv == AE_OK)
4003446Smrj 		sp->available -= count;
4013446Smrj 
4023446Smrj 	mutex_exit(&sp->mutex);
4033446Smrj 	return (rv);
4043446Smrj }
4053446Smrj 
4063446Smrj /*
4073446Smrj  *
4083446Smrj  */
4093446Smrj void
acpi_sema_v(acpi_sema_t * sp,unsigned count)4103446Smrj acpi_sema_v(acpi_sema_t *sp, unsigned count)
4113446Smrj {
4123446Smrj 	mutex_enter(&sp->mutex);
4133446Smrj 	sp->available += count;
4143446Smrj 	cv_broadcast(&sp->cv);
4153446Smrj 	mutex_exit(&sp->mutex);
4163446Smrj }
4173446Smrj 
4183446Smrj 
4193446Smrj ACPI_STATUS
AcpiOsCreateSemaphore(UINT32 MaxUnits,UINT32 InitialUnits,ACPI_HANDLE * OutHandle)4203446Smrj AcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits,
4213446Smrj ACPI_HANDLE *OutHandle)
4223446Smrj {
4233446Smrj 	acpi_sema_t *sp;
4243446Smrj 
4253446Smrj 	if ((OutHandle == NULL) || (InitialUnits > MaxUnits))
4263446Smrj 		return (AE_BAD_PARAMETER);
4273446Smrj 
4283446Smrj 	sp = (acpi_sema_t *)kmem_alloc(sizeof (acpi_sema_t), KM_SLEEP);
4293446Smrj 	acpi_sema_init(sp, MaxUnits, InitialUnits);
4303446Smrj 	*OutHandle = (ACPI_HANDLE)sp;
4313446Smrj 	return (AE_OK);
4323446Smrj }
4333446Smrj 
4343446Smrj 
4353446Smrj ACPI_STATUS
AcpiOsDeleteSemaphore(ACPI_HANDLE Handle)4363446Smrj AcpiOsDeleteSemaphore(ACPI_HANDLE Handle)
4373446Smrj {
4383446Smrj 
4393446Smrj 	if (Handle == NULL)
4403446Smrj 		return (AE_BAD_PARAMETER);
4413446Smrj 
4423446Smrj 	acpi_sema_destroy((acpi_sema_t *)Handle);
4433446Smrj 	kmem_free((void *)Handle, sizeof (acpi_sema_t));
4443446Smrj 	return (AE_OK);
4453446Smrj }
4463446Smrj 
4473446Smrj ACPI_STATUS
AcpiOsWaitSemaphore(ACPI_HANDLE Handle,UINT32 Units,UINT16 Timeout)4483446Smrj AcpiOsWaitSemaphore(ACPI_HANDLE Handle, UINT32 Units, UINT16 Timeout)
4493446Smrj {
4503446Smrj 
4513446Smrj 	if ((Handle == NULL) || (Units < 1))
4523446Smrj 		return (AE_BAD_PARAMETER);
4533446Smrj 
4543446Smrj 	return (acpi_sema_p((acpi_sema_t *)Handle, Units, Timeout));
4553446Smrj }
4563446Smrj 
4573446Smrj ACPI_STATUS
AcpiOsSignalSemaphore(ACPI_HANDLE Handle,UINT32 Units)4583446Smrj AcpiOsSignalSemaphore(ACPI_HANDLE Handle, UINT32 Units)
4593446Smrj {
4603446Smrj 
4613446Smrj 	if ((Handle == NULL) || (Units < 1))
4623446Smrj 		return (AE_BAD_PARAMETER);
4633446Smrj 
4643446Smrj 	acpi_sema_v((acpi_sema_t *)Handle, Units);
4653446Smrj 	return (AE_OK);
4663446Smrj }
4673446Smrj 
4683446Smrj ACPI_STATUS
AcpiOsCreateLock(ACPI_HANDLE * OutHandle)4693446Smrj AcpiOsCreateLock(ACPI_HANDLE *OutHandle)
4703446Smrj {
4713446Smrj 	kmutex_t *mp;
4723446Smrj 
4733446Smrj 	if (OutHandle == NULL)
4743446Smrj 		return (AE_BAD_PARAMETER);
4753446Smrj 
4763446Smrj 	mp = (kmutex_t *)kmem_alloc(sizeof (kmutex_t), KM_SLEEP);
4773446Smrj 	mutex_init(mp, NULL, MUTEX_DRIVER, NULL);
4783446Smrj 	*OutHandle = (ACPI_HANDLE)mp;
4793446Smrj 	return (AE_OK);
4803446Smrj }
4813446Smrj 
4823446Smrj void
AcpiOsDeleteLock(ACPI_HANDLE Handle)4833446Smrj AcpiOsDeleteLock(ACPI_HANDLE Handle)
4843446Smrj {
4853446Smrj 
4863446Smrj 	if (Handle == NULL)
4873446Smrj 		return;
4883446Smrj 
4893446Smrj 	mutex_destroy((kmutex_t *)Handle);
4903446Smrj 	kmem_free((void *)Handle, sizeof (kmutex_t));
4913446Smrj }
4923446Smrj 
4937851SDana.Myers@Sun.COM ACPI_CPU_FLAGS
AcpiOsAcquireLock(ACPI_HANDLE Handle)4943446Smrj AcpiOsAcquireLock(ACPI_HANDLE Handle)
4953446Smrj {
4963446Smrj 
4978906SEric.Saxe@Sun.COM 
4988906SEric.Saxe@Sun.COM 	if (Handle == NULL)
4998906SEric.Saxe@Sun.COM 		return (AE_BAD_PARAMETER);
5008906SEric.Saxe@Sun.COM 
5018906SEric.Saxe@Sun.COM 	if (curthread == CPU->cpu_idle_thread) {
5028906SEric.Saxe@Sun.COM 		while (!mutex_tryenter((kmutex_t *)Handle))
5038906SEric.Saxe@Sun.COM 			/* spin */;
5048906SEric.Saxe@Sun.COM 	} else
5058906SEric.Saxe@Sun.COM 		mutex_enter((kmutex_t *)Handle);
5068906SEric.Saxe@Sun.COM 	return (AE_OK);
5073446Smrj }
5083446Smrj 
5093446Smrj void
AcpiOsReleaseLock(ACPI_HANDLE Handle,ACPI_CPU_FLAGS Flags)5107851SDana.Myers@Sun.COM AcpiOsReleaseLock(ACPI_HANDLE Handle, ACPI_CPU_FLAGS Flags)
5113446Smrj {
5123446Smrj 	_NOTE(ARGUNUSED(Flags))
5133446Smrj 
5143446Smrj 	mutex_exit((kmutex_t *)Handle);
5153446Smrj }
5163446Smrj 
5173446Smrj 
5183446Smrj void *
AcpiOsAllocate(ACPI_SIZE Size)5193446Smrj AcpiOsAllocate(ACPI_SIZE Size)
5203446Smrj {
5213446Smrj 	ACPI_SIZE *tmp_ptr;
5223446Smrj 
5233446Smrj 	Size += sizeof (Size);
5243446Smrj 	tmp_ptr = (ACPI_SIZE *)kmem_zalloc(Size, KM_SLEEP);
5253446Smrj 	*tmp_ptr++ = Size;
5263446Smrj 	return (tmp_ptr);
5273446Smrj }
5283446Smrj 
5293446Smrj void
AcpiOsFree(void * Memory)5303446Smrj AcpiOsFree(void *Memory)
5313446Smrj {
5323446Smrj 	ACPI_SIZE	size, *tmp_ptr;
5333446Smrj 
5343446Smrj 	tmp_ptr = (ACPI_SIZE *)Memory;
5353446Smrj 	tmp_ptr -= 1;
5363446Smrj 	size = *tmp_ptr;
5373446Smrj 	kmem_free(tmp_ptr, size);
5383446Smrj }
5393446Smrj 
5409000SStuart.Maybee@Sun.COM static int napics_found;	/* number of ioapic addresses in array */
5419000SStuart.Maybee@Sun.COM static ACPI_PHYSICAL_ADDRESS ioapic_paddr[MAX_IO_APIC];
5429000SStuart.Maybee@Sun.COM static ACPI_TABLE_MADT *acpi_mapic_dtp = NULL;
5439000SStuart.Maybee@Sun.COM static void *dummy_ioapicadr;
5449000SStuart.Maybee@Sun.COM 
5459000SStuart.Maybee@Sun.COM void
acpica_find_ioapics(void)5469000SStuart.Maybee@Sun.COM acpica_find_ioapics(void)
5479000SStuart.Maybee@Sun.COM {
5489000SStuart.Maybee@Sun.COM 	int			madt_seen, madt_size;
5499000SStuart.Maybee@Sun.COM 	ACPI_SUBTABLE_HEADER		*ap;
5509000SStuart.Maybee@Sun.COM 	ACPI_MADT_IO_APIC		*mia;
5519000SStuart.Maybee@Sun.COM 
5529000SStuart.Maybee@Sun.COM 	if (acpi_mapic_dtp != NULL)
5539000SStuart.Maybee@Sun.COM 		return;	/* already parsed table */
5549000SStuart.Maybee@Sun.COM 	if (AcpiGetTable(ACPI_SIG_MADT, 1,
5559000SStuart.Maybee@Sun.COM 	    (ACPI_TABLE_HEADER **) &acpi_mapic_dtp) != AE_OK)
5569000SStuart.Maybee@Sun.COM 		return;
5579000SStuart.Maybee@Sun.COM 
5589000SStuart.Maybee@Sun.COM 	napics_found = 0;
5599000SStuart.Maybee@Sun.COM 
5609000SStuart.Maybee@Sun.COM 	/*
5619000SStuart.Maybee@Sun.COM 	 * Search the MADT for ioapics
5629000SStuart.Maybee@Sun.COM 	 */
5639000SStuart.Maybee@Sun.COM 	ap = (ACPI_SUBTABLE_HEADER *) (acpi_mapic_dtp + 1);
5649000SStuart.Maybee@Sun.COM 	madt_size = acpi_mapic_dtp->Header.Length;
5659000SStuart.Maybee@Sun.COM 	madt_seen = sizeof (*acpi_mapic_dtp);
5669000SStuart.Maybee@Sun.COM 
5679000SStuart.Maybee@Sun.COM 	while (madt_seen < madt_size) {
5689000SStuart.Maybee@Sun.COM 
5699000SStuart.Maybee@Sun.COM 		switch (ap->Type) {
5709000SStuart.Maybee@Sun.COM 		case ACPI_MADT_TYPE_IO_APIC:
5719000SStuart.Maybee@Sun.COM 			mia = (ACPI_MADT_IO_APIC *) ap;
5729000SStuart.Maybee@Sun.COM 			if (napics_found < MAX_IO_APIC) {
5739000SStuart.Maybee@Sun.COM 				ioapic_paddr[napics_found++] =
5749000SStuart.Maybee@Sun.COM 				    (ACPI_PHYSICAL_ADDRESS)
5759000SStuart.Maybee@Sun.COM 				    (mia->Address & PAGEMASK);
5769000SStuart.Maybee@Sun.COM 			}
5779000SStuart.Maybee@Sun.COM 			break;
5789000SStuart.Maybee@Sun.COM 
5799000SStuart.Maybee@Sun.COM 		default:
5809000SStuart.Maybee@Sun.COM 			break;
5819000SStuart.Maybee@Sun.COM 		}
5829000SStuart.Maybee@Sun.COM 
5839000SStuart.Maybee@Sun.COM 		/* advance to next entry */
5849000SStuart.Maybee@Sun.COM 		madt_seen += ap->Length;
5859000SStuart.Maybee@Sun.COM 		ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length);
5869000SStuart.Maybee@Sun.COM 	}
5879000SStuart.Maybee@Sun.COM 	if (dummy_ioapicadr == NULL)
5889000SStuart.Maybee@Sun.COM 		dummy_ioapicadr = kmem_zalloc(PAGESIZE, KM_SLEEP);
5899000SStuart.Maybee@Sun.COM }
5909000SStuart.Maybee@Sun.COM 
5919000SStuart.Maybee@Sun.COM 
5927851SDana.Myers@Sun.COM void *
AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress,ACPI_SIZE Size)5937851SDana.Myers@Sun.COM AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS PhysicalAddress, ACPI_SIZE Size)
5943446Smrj {
5959000SStuart.Maybee@Sun.COM 	int	i;
5969000SStuart.Maybee@Sun.COM 
5979000SStuart.Maybee@Sun.COM 	/*
5989000SStuart.Maybee@Sun.COM 	 * If the iopaic address table is populated, check if trying
5999000SStuart.Maybee@Sun.COM 	 * to access an ioapic.  Instead, return a pointer to a dummy ioapic.
6009000SStuart.Maybee@Sun.COM 	 */
6019000SStuart.Maybee@Sun.COM 	for (i = 0; i < napics_found; i++) {
6029000SStuart.Maybee@Sun.COM 		if ((PhysicalAddress & PAGEMASK) == ioapic_paddr[i])
6039000SStuart.Maybee@Sun.COM 			return (dummy_ioapicadr);
6049000SStuart.Maybee@Sun.COM 	}
6053446Smrj 	/* FUTUREWORK: test PhysicalAddress for > 32 bits */
6067851SDana.Myers@Sun.COM 	return (psm_map_new((paddr_t)PhysicalAddress,
6077851SDana.Myers@Sun.COM 	    (size_t)Size, PSM_PROT_WRITE | PSM_PROT_READ));
6083446Smrj }
6093446Smrj 
6103446Smrj void
AcpiOsUnmapMemory(void * LogicalAddress,ACPI_SIZE Size)6113446Smrj AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Size)
6123446Smrj {
6139000SStuart.Maybee@Sun.COM 	/*
6149000SStuart.Maybee@Sun.COM 	 * Check if trying to unmap dummy ioapic address.
6159000SStuart.Maybee@Sun.COM 	 */
6169000SStuart.Maybee@Sun.COM 	if (LogicalAddress == dummy_ioapicadr)
6179000SStuart.Maybee@Sun.COM 		return;
6183446Smrj 
6193446Smrj 	psm_unmap((caddr_t)LogicalAddress, (size_t)Size);
6203446Smrj }
6213446Smrj 
6223446Smrj /*ARGSUSED*/
6233446Smrj ACPI_STATUS
AcpiOsGetPhysicalAddress(void * LogicalAddress,ACPI_PHYSICAL_ADDRESS * PhysicalAddress)6243446Smrj AcpiOsGetPhysicalAddress(void *LogicalAddress,
6253446Smrj 			ACPI_PHYSICAL_ADDRESS *PhysicalAddress)
6263446Smrj {
6273446Smrj 
6283446Smrj 	/* UNIMPLEMENTED: not invoked by ACPI CA code */
6293446Smrj 	return (AE_NOT_IMPLEMENTED);
6303446Smrj }
6313446Smrj 
6323446Smrj 
6333446Smrj ACPI_OSD_HANDLER acpi_isr;
6343446Smrj void *acpi_isr_context;
6353446Smrj 
6363446Smrj uint_t
acpi_wrapper_isr(char * arg)6373446Smrj acpi_wrapper_isr(char *arg)
6383446Smrj {
6393446Smrj 	_NOTE(ARGUNUSED(arg))
6403446Smrj 
6413446Smrj 	int	status;
6423446Smrj 
6433446Smrj 	status = (*acpi_isr)(acpi_isr_context);
6443446Smrj 
6453446Smrj 	if (status == ACPI_INTERRUPT_HANDLED) {
6463446Smrj 		return (DDI_INTR_CLAIMED);
6473446Smrj 	} else {
6483446Smrj 		return (DDI_INTR_UNCLAIMED);
6493446Smrj 	}
6503446Smrj }
6513446Smrj 
6523446Smrj static int acpi_intr_hooked = 0;
6533446Smrj 
6543446Smrj ACPI_STATUS
AcpiOsInstallInterruptHandler(UINT32 InterruptNumber,ACPI_OSD_HANDLER ServiceRoutine,void * Context)6553446Smrj AcpiOsInstallInterruptHandler(UINT32 InterruptNumber,
6563446Smrj 		ACPI_OSD_HANDLER ServiceRoutine,
6573446Smrj 		void *Context)
6583446Smrj {
6593446Smrj 	_NOTE(ARGUNUSED(InterruptNumber))
6603446Smrj 
6613446Smrj 	int retval;
6623446Smrj 	int sci_vect;
6633446Smrj 	iflag_t sci_flags;
6643446Smrj 
6653446Smrj 	acpi_isr = ServiceRoutine;
6663446Smrj 	acpi_isr_context = Context;
6673446Smrj 
6683446Smrj 	/*
6693446Smrj 	 * Get SCI (adjusted for PIC/APIC mode if necessary)
6703446Smrj 	 */
6713446Smrj 	if (acpica_get_sci(&sci_vect, &sci_flags) != AE_OK) {
6723446Smrj 		return (AE_ERROR);
6733446Smrj 	}
6743446Smrj 
6753446Smrj #ifdef	DEBUG
6763446Smrj 	cmn_err(CE_NOTE, "!acpica: attaching SCI %d", sci_vect);
6773446Smrj #endif
6783446Smrj 
6793446Smrj 	retval = add_avintr(NULL, SCI_IPL, (avfunc)acpi_wrapper_isr,
6804476Smyers 	    "ACPI SCI", sci_vect, NULL, NULL, NULL, NULL);
6813446Smrj 	if (retval) {
6823446Smrj 		acpi_intr_hooked = 1;
6833446Smrj 		return (AE_OK);
6843446Smrj 	} else
6853446Smrj 		return (AE_BAD_PARAMETER);
6863446Smrj }
6873446Smrj 
6883446Smrj ACPI_STATUS
AcpiOsRemoveInterruptHandler(UINT32 InterruptNumber,ACPI_OSD_HANDLER ServiceRoutine)6893446Smrj AcpiOsRemoveInterruptHandler(UINT32 InterruptNumber,
6903446Smrj 			ACPI_OSD_HANDLER ServiceRoutine)
6913446Smrj {
6923446Smrj 	_NOTE(ARGUNUSED(ServiceRoutine))
6933446Smrj 
6943446Smrj #ifdef	DEBUG
6953446Smrj 	cmn_err(CE_NOTE, "!acpica: detaching SCI %d", InterruptNumber);
6963446Smrj #endif
6973446Smrj 	if (acpi_intr_hooked) {
6983446Smrj 		rem_avintr(NULL, LOCK_LEVEL - 1, (avfunc)acpi_wrapper_isr,
6994476Smyers 		    InterruptNumber);
7003446Smrj 		acpi_intr_hooked = 0;
7013446Smrj 	}
7023446Smrj 	return (AE_OK);
7033446Smrj }
7043446Smrj 
7053446Smrj 
7063446Smrj ACPI_THREAD_ID
AcpiOsGetThreadId(void)7073446Smrj AcpiOsGetThreadId(void)
7083446Smrj {
7093446Smrj 	/*
7109980SDana.Myers@Sun.COM 	 * ACPI CA doesn't care what actual value is returned as long
7119980SDana.Myers@Sun.COM 	 * as it is non-zero and unique to each existing thread.
7129980SDana.Myers@Sun.COM 	 * ACPI CA assumes that thread ID is castable to a pointer,
7139980SDana.Myers@Sun.COM 	 * so we use the current thread pointer.
7143446Smrj 	 */
7159980SDana.Myers@Sun.COM 	return (curthread);
7163446Smrj }
7173446Smrj 
7183446Smrj /*
7193446Smrj  *
7203446Smrj  */
7213446Smrj ACPI_STATUS
AcpiOsExecute(ACPI_EXECUTE_TYPE Type,ACPI_OSD_EXEC_CALLBACK Function,void * Context)7223446Smrj AcpiOsExecute(ACPI_EXECUTE_TYPE Type, ACPI_OSD_EXEC_CALLBACK  Function,
7233446Smrj     void *Context)
7243446Smrj {
7253446Smrj 
7263446Smrj 	if (!acpica_eventq_init) {
7273446Smrj 		/*
7283446Smrj 		 * Create taskqs for event handling
7293446Smrj 		 */
7303446Smrj 		if (init_event_queues() != AE_OK)
7314476Smyers 			return (AE_ERROR);
7323446Smrj 	}
7333446Smrj 
7343446Smrj 	if (ddi_taskq_dispatch(osl_eventq[Type], Function, Context,
7353446Smrj 	    DDI_NOSLEEP) == DDI_FAILURE) {
7363446Smrj #ifdef	DEBUG
7373446Smrj 		cmn_err(CE_WARN, "!acpica: unable to dispatch event");
7383446Smrj #endif
7393446Smrj 		return (AE_ERROR);
7403446Smrj 	}
7413446Smrj 	return (AE_OK);
7423446Smrj 
7433446Smrj }
7443446Smrj 
7453446Smrj void
AcpiOsSleep(ACPI_INTEGER Milliseconds)7463446Smrj AcpiOsSleep(ACPI_INTEGER Milliseconds)
7473446Smrj {
7483446Smrj 	/*
7498122SKerry.Shu@Sun.COM 	 * During kernel startup, before the first tick interrupt
7508122SKerry.Shu@Sun.COM 	 * has taken place, we can't call delay; very late in
7518122SKerry.Shu@Sun.COM 	 * kernel shutdown or suspend/resume, clock interrupts
7523446Smrj 	 * are blocked, so delay doesn't work then either.
7533446Smrj 	 * So we busy wait if lbolt == 0 (kernel startup)
7548122SKerry.Shu@Sun.COM 	 * or if acpica_use_safe_delay has been set to a
7558122SKerry.Shu@Sun.COM 	 * non-zero value.
7563446Smrj 	 */
7578122SKerry.Shu@Sun.COM 	if ((ddi_get_lbolt() == 0) || acpica_use_safe_delay)
7583446Smrj 		drv_usecwait(Milliseconds * 1000);
7593446Smrj 	else
7603446Smrj 		delay(drv_usectohz(Milliseconds * 1000));
7613446Smrj }
7623446Smrj 
7633446Smrj void
AcpiOsStall(UINT32 Microseconds)7643446Smrj AcpiOsStall(UINT32 Microseconds)
7653446Smrj {
7663446Smrj 	drv_usecwait(Microseconds);
7673446Smrj }
7683446Smrj 
7693446Smrj 
7703446Smrj /*
7713446Smrj  * Implementation of "Windows 2001" compatible I/O permission map
7723446Smrj  *
7733446Smrj  */
7743446Smrj #define	OSL_IO_NONE	(0)
7753446Smrj #define	OSL_IO_READ	(1<<0)
7763446Smrj #define	OSL_IO_WRITE	(1<<1)
7773446Smrj #define	OSL_IO_RW	(OSL_IO_READ | OSL_IO_WRITE)
7783446Smrj #define	OSL_IO_TERM	(1<<2)
7793446Smrj #define	OSL_IO_DEFAULT	OSL_IO_RW
7803446Smrj 
7813446Smrj static struct io_perm  {
7823446Smrj 	ACPI_IO_ADDRESS	low;
7833446Smrj 	ACPI_IO_ADDRESS	high;
7843446Smrj 	uint8_t		perm;
7853446Smrj } osl_io_perm[] = {
78610457SSaurabh.Mishra@Sun.COM 	{ 0xcf8, 0xd00, OSL_IO_TERM | OSL_IO_RW}
7873446Smrj };
7883446Smrj 
7893446Smrj 
7903446Smrj /*
7913446Smrj  *
7923446Smrj  */
7933446Smrj static struct io_perm *
osl_io_find_perm(ACPI_IO_ADDRESS addr)7943446Smrj osl_io_find_perm(ACPI_IO_ADDRESS addr)
7953446Smrj {
7963446Smrj 	struct io_perm *p;
7973446Smrj 
7983446Smrj 	p = osl_io_perm;
7993446Smrj 	while (p != NULL) {
8003446Smrj 		if ((p->low <= addr) && (addr <= p->high))
8013446Smrj 			break;
8023446Smrj 		p = (p->perm & OSL_IO_TERM) ? NULL : p+1;
8033446Smrj 	}
8043446Smrj 
8053446Smrj 	return (p);
8063446Smrj }
8073446Smrj 
8083446Smrj /*
8093446Smrj  *
8103446Smrj  */
8113446Smrj ACPI_STATUS
AcpiOsReadPort(ACPI_IO_ADDRESS Address,UINT32 * Value,UINT32 Width)8123446Smrj AcpiOsReadPort(ACPI_IO_ADDRESS Address, UINT32 *Value, UINT32 Width)
8133446Smrj {
8143446Smrj 	struct io_perm *p;
8153446Smrj 
8163446Smrj 	/* verify permission */
8173446Smrj 	p = osl_io_find_perm(Address);
8183446Smrj 	if (p && (p->perm & OSL_IO_READ) == 0) {
8193446Smrj 		cmn_err(CE_WARN, "!AcpiOsReadPort: %lx %u not permitted",
8204476Smyers 		    (long)Address, Width);
8213446Smrj 		*Value = 0xffffffff;
8223446Smrj 		return (AE_ERROR);
8233446Smrj 	}
8243446Smrj 
8253446Smrj 	switch (Width) {
8263446Smrj 	case 8:
8273446Smrj 		*Value = inb(Address);
8283446Smrj 		break;
8293446Smrj 	case 16:
8303446Smrj 		*Value = inw(Address);
8313446Smrj 		break;
8323446Smrj 	case 32:
8333446Smrj 		*Value = inl(Address);
8343446Smrj 		break;
8353446Smrj 	default:
8363446Smrj 		cmn_err(CE_WARN, "!AcpiOsReadPort: %lx %u failed",
8374476Smyers 		    (long)Address, Width);
8383446Smrj 		return (AE_BAD_PARAMETER);
8393446Smrj 	}
8403446Smrj 	return (AE_OK);
8413446Smrj }
8423446Smrj 
8433446Smrj ACPI_STATUS
AcpiOsWritePort(ACPI_IO_ADDRESS Address,UINT32 Value,UINT32 Width)8443446Smrj AcpiOsWritePort(ACPI_IO_ADDRESS Address, UINT32 Value, UINT32 Width)
8453446Smrj {
8463446Smrj 	struct io_perm *p;
8473446Smrj 
8483446Smrj 	/* verify permission */
8493446Smrj 	p = osl_io_find_perm(Address);
8503446Smrj 	if (p && (p->perm & OSL_IO_WRITE) == 0) {
8513446Smrj 		cmn_err(CE_WARN, "!AcpiOsWritePort: %lx %u not permitted",
8523446Smrj 		    (long)Address, Width);
8533446Smrj 		return (AE_ERROR);
8543446Smrj 	}
8553446Smrj 
8563446Smrj 	switch (Width) {
8573446Smrj 	case 8:
8583446Smrj 		outb(Address, Value);
8593446Smrj 		break;
8603446Smrj 	case 16:
8613446Smrj 		outw(Address, Value);
8623446Smrj 		break;
8633446Smrj 	case 32:
8643446Smrj 		outl(Address, Value);
8653446Smrj 		break;
8663446Smrj 	default:
8673446Smrj 		cmn_err(CE_WARN, "!AcpiOsWritePort: %lx %u failed",
8683446Smrj 		    (long)Address, Width);
8693446Smrj 		return (AE_BAD_PARAMETER);
8703446Smrj 	}
8713446Smrj 	return (AE_OK);
8723446Smrj }
8733446Smrj 
8743446Smrj 
8753446Smrj /*
8763446Smrj  *
8773446Smrj  */
8783446Smrj 
8793446Smrj #define	OSL_RW(ptr, val, type, rw) \
8803446Smrj 	{ if (rw) *((type *)(ptr)) = *((type *) val); \
8813446Smrj 	    else *((type *) val) = *((type *)(ptr)); }
8823446Smrj 
8833446Smrj 
8843446Smrj static void
osl_rw_memory(ACPI_PHYSICAL_ADDRESS Address,UINT32 * Value,UINT32 Width,int write)8853446Smrj osl_rw_memory(ACPI_PHYSICAL_ADDRESS Address, UINT32 *Value,
8863446Smrj     UINT32 Width, int write)
8873446Smrj {
8883446Smrj 	size_t	maplen = Width / 8;
8893446Smrj 	caddr_t	ptr;
8903446Smrj 
8913446Smrj 	ptr = psm_map_new((paddr_t)Address, maplen,
8923446Smrj 	    PSM_PROT_WRITE | PSM_PROT_READ);
8933446Smrj 
8943446Smrj 	switch (maplen) {
8953446Smrj 	case 1:
8963446Smrj 		OSL_RW(ptr, Value, uint8_t, write);
8973446Smrj 		break;
8983446Smrj 	case 2:
8993446Smrj 		OSL_RW(ptr, Value, uint16_t, write);
9003446Smrj 		break;
9013446Smrj 	case 4:
9023446Smrj 		OSL_RW(ptr, Value, uint32_t, write);
9033446Smrj 		break;
9043446Smrj 	default:
9053446Smrj 		cmn_err(CE_WARN, "!osl_rw_memory: invalid size %d",
9063446Smrj 		    Width);
9073446Smrj 		break;
9083446Smrj 	}
9093446Smrj 
9103446Smrj 	psm_unmap(ptr, maplen);
9113446Smrj }
9123446Smrj 
9133446Smrj ACPI_STATUS
AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address,UINT32 * Value,UINT32 Width)9143446Smrj AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address,
9153446Smrj 		UINT32 *Value, UINT32 Width)
9163446Smrj {
9173446Smrj 	osl_rw_memory(Address, Value, Width, 0);
9183446Smrj 	return (AE_OK);
9193446Smrj }
9203446Smrj 
9213446Smrj ACPI_STATUS
AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address,UINT32 Value,UINT32 Width)9223446Smrj AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address,
9233446Smrj 		UINT32 Value, UINT32 Width)
9243446Smrj {
9253446Smrj 	osl_rw_memory(Address, &Value, Width, 1);
9263446Smrj 	return (AE_OK);
9273446Smrj }
9283446Smrj 
9293446Smrj 
9303446Smrj ACPI_STATUS
AcpiOsReadPciConfiguration(ACPI_PCI_ID * PciId,UINT32 Register,void * Value,UINT32 Width)9313446Smrj AcpiOsReadPciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register,
9323446Smrj 			void *Value, UINT32 Width)
9333446Smrj {
9343446Smrj 
9353446Smrj 	switch (Width) {
9363446Smrj 	case 8:
9373446Smrj 		*((UINT64 *)Value) = (UINT64)(*pci_getb_func)
9384476Smyers 		    (PciId->Bus, PciId->Device, PciId->Function, Register);
9393446Smrj 		break;
9403446Smrj 	case 16:
9413446Smrj 		*((UINT64 *)Value) = (UINT64)(*pci_getw_func)
9424476Smyers 		    (PciId->Bus, PciId->Device, PciId->Function, Register);
9433446Smrj 		break;
9443446Smrj 	case 32:
9453446Smrj 		*((UINT64 *)Value) = (UINT64)(*pci_getl_func)
9464476Smyers 		    (PciId->Bus, PciId->Device, PciId->Function, Register);
9473446Smrj 		break;
9483446Smrj 	case 64:
9493446Smrj 	default:
9503446Smrj 		cmn_err(CE_WARN, "!AcpiOsReadPciConfiguration: %x %u failed",
9513446Smrj 		    Register, Width);
9523446Smrj 		return (AE_BAD_PARAMETER);
9533446Smrj 	}
9543446Smrj 	return (AE_OK);
9553446Smrj }
9563446Smrj 
9573446Smrj /*
9583446Smrj  *
9593446Smrj  */
9603446Smrj int acpica_write_pci_config_ok = 1;
9613446Smrj 
9623446Smrj ACPI_STATUS
AcpiOsWritePciConfiguration(ACPI_PCI_ID * PciId,UINT32 Register,ACPI_INTEGER Value,UINT32 Width)9633446Smrj AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register,
9643446Smrj 		ACPI_INTEGER Value, UINT32 Width)
9653446Smrj {
9663446Smrj 
9673446Smrj 	if (!acpica_write_pci_config_ok) {
9683446Smrj 		cmn_err(CE_NOTE, "!write to PCI cfg %x/%x/%x %x"
9693446Smrj 		    " %lx %d not permitted", PciId->Bus, PciId->Device,
9703446Smrj 		    PciId->Function, Register, (long)Value, Width);
9713446Smrj 		return (AE_OK);
9723446Smrj 	}
9733446Smrj 
9743446Smrj 	switch (Width) {
9753446Smrj 	case 8:
9763446Smrj 		(*pci_putb_func)(PciId->Bus, PciId->Device, PciId->Function,
9774476Smyers 		    Register, (uint8_t)Value);
9783446Smrj 		break;
9793446Smrj 	case 16:
9803446Smrj 		(*pci_putw_func)(PciId->Bus, PciId->Device, PciId->Function,
9814476Smyers 		    Register, (uint16_t)Value);
9823446Smrj 		break;
9833446Smrj 	case 32:
9843446Smrj 		(*pci_putl_func)(PciId->Bus, PciId->Device, PciId->Function,
9854476Smyers 		    Register, (uint32_t)Value);
9863446Smrj 		break;
9873446Smrj 	case 64:
9883446Smrj 	default:
9893446Smrj 		cmn_err(CE_WARN, "!AcpiOsWritePciConfiguration: %x %u failed",
9903446Smrj 		    Register, Width);
9913446Smrj 		return (AE_BAD_PARAMETER);
9923446Smrj 	}
9933446Smrj 	return (AE_OK);
9943446Smrj }
9953446Smrj 
9963446Smrj /*
9973446Smrj  * Called with ACPI_HANDLEs for both a PCI Config Space
9983446Smrj  * OpRegion and (what ACPI CA thinks is) the PCI device
99911335SDana.Myers@Sun.COM  * to which this ConfigSpace OpRegion belongs.
10003446Smrj  *
100111335SDana.Myers@Sun.COM  * ACPI CA uses _BBN and _ADR objects to determine the default
100211335SDana.Myers@Sun.COM  * values for bus, segment, device and function; anything ACPI CA
100311335SDana.Myers@Sun.COM  * can't figure out from the ACPI tables will be 0.  One very
100411335SDana.Myers@Sun.COM  * old 32-bit x86 system is known to have broken _BBN; this is
100511335SDana.Myers@Sun.COM  * not addressed here.
10063446Smrj  *
10073446Smrj  * Some BIOSes implement _BBN() by reading PCI config space
10084476Smyers  * on bus #0 - which means that we'll recurse when we attempt
10093446Smrj  * to create the devinfo-to-ACPI map.  If Derive is called during
10104667Smh27603  * scan_d2a_map, we don't translate the bus # and return.
10114667Smh27603  *
10124667Smh27603  * We get the parent of the OpRegion, which must be a PCI
10134667Smh27603  * node, fetch the associated devinfo node and snag the
10144667Smh27603  * b/d/f from it.
10153446Smrj  */
10163446Smrj void
AcpiOsDerivePciId(ACPI_HANDLE rhandle,ACPI_HANDLE chandle,ACPI_PCI_ID ** PciId)10173446Smrj AcpiOsDerivePciId(ACPI_HANDLE rhandle, ACPI_HANDLE chandle,
10183446Smrj 		ACPI_PCI_ID **PciId)
10193446Smrj {
10203446Smrj 	ACPI_HANDLE handle;
10214667Smh27603 	dev_info_t *dip;
10224667Smh27603 	int bus, device, func, devfn;
10233446Smrj 
10243446Smrj 	/*
10254667Smh27603 	 * See above - avoid recursing during scanning_d2a_map.
10263446Smrj 	 */
10274667Smh27603 	if (scanning_d2a_map)
10283446Smrj 		return;
10293446Smrj 
10303446Smrj 	/*
10314667Smh27603 	 * Get the OpRegion's parent
10323446Smrj 	 */
10333446Smrj 	if (AcpiGetParent(chandle, &handle) != AE_OK)
10343446Smrj 		return;
10353446Smrj 
10364667Smh27603 	/*
10374667Smh27603 	 * If we've mapped the ACPI node to the devinfo
10384667Smh27603 	 * tree, use the devinfo reg property
10394667Smh27603 	 */
104011335SDana.Myers@Sun.COM 	if (ACPI_SUCCESS(acpica_get_devinfo(handle, &dip)) &&
104111335SDana.Myers@Sun.COM 	    (acpica_get_bdf(dip, &bus, &device, &func) >= 0)) {
10424667Smh27603 		(*PciId)->Bus = bus;
10434667Smh27603 		(*PciId)->Device = device;
10444667Smh27603 		(*PciId)->Function = func;
10453446Smrj 	}
10463446Smrj }
10473446Smrj 
10483446Smrj 
10493446Smrj /*ARGSUSED*/
10503446Smrj BOOLEAN
AcpiOsReadable(void * Pointer,ACPI_SIZE Length)10513446Smrj AcpiOsReadable(void *Pointer, ACPI_SIZE Length)
10523446Smrj {
10533446Smrj 
10543446Smrj 	/* Always says yes; all mapped memory assumed readable */
10553446Smrj 	return (1);
10563446Smrj }
10573446Smrj 
10583446Smrj /*ARGSUSED*/
10593446Smrj BOOLEAN
AcpiOsWritable(void * Pointer,ACPI_SIZE Length)10603446Smrj AcpiOsWritable(void *Pointer, ACPI_SIZE Length)
10613446Smrj {
10623446Smrj 
10633446Smrj 	/* Always says yes; all mapped memory assumed writable */
10643446Smrj 	return (1);
10653446Smrj }
10663446Smrj 
10673446Smrj UINT64
AcpiOsGetTimer(void)10683446Smrj AcpiOsGetTimer(void)
10693446Smrj {
10703446Smrj 	/* gethrtime() returns 1nS resolution; convert to 100nS granules */
10713446Smrj 	return ((gethrtime() + 50) / 100);
10723446Smrj }
10733446Smrj 
10749652SMichael.Corcoran@Sun.COM static struct AcpiOSIFeature_s {
10759652SMichael.Corcoran@Sun.COM 	uint64_t	control_flag;
10769652SMichael.Corcoran@Sun.COM 	const char	*feature_name;
10779652SMichael.Corcoran@Sun.COM } AcpiOSIFeatures[] = {
10789652SMichael.Corcoran@Sun.COM 	{ ACPI_FEATURE_OSI_MODULE,	"Module Device" },
10799652SMichael.Corcoran@Sun.COM 	{ 0,				"Processor Device" }
10809652SMichael.Corcoran@Sun.COM };
10819652SMichael.Corcoran@Sun.COM 
10823446Smrj /*ARGSUSED*/
10833446Smrj ACPI_STATUS
AcpiOsValidateInterface(char * feature)10849652SMichael.Corcoran@Sun.COM AcpiOsValidateInterface(char *feature)
10853446Smrj {
10869652SMichael.Corcoran@Sun.COM 	int i;
10879652SMichael.Corcoran@Sun.COM 
10889652SMichael.Corcoran@Sun.COM 	ASSERT(feature != NULL);
10899652SMichael.Corcoran@Sun.COM 	for (i = 0; i < sizeof (AcpiOSIFeatures) / sizeof (AcpiOSIFeatures[0]);
10909652SMichael.Corcoran@Sun.COM 	    i++) {
10919652SMichael.Corcoran@Sun.COM 		if (strcmp(feature, AcpiOSIFeatures[i].feature_name) != 0) {
10929652SMichael.Corcoran@Sun.COM 			continue;
10939652SMichael.Corcoran@Sun.COM 		}
10949652SMichael.Corcoran@Sun.COM 		/* Check whether required core features are available. */
10959652SMichael.Corcoran@Sun.COM 		if (AcpiOSIFeatures[i].control_flag != 0 &&
10969652SMichael.Corcoran@Sun.COM 		    acpica_get_core_feature(AcpiOSIFeatures[i].control_flag) !=
10979652SMichael.Corcoran@Sun.COM 		    AcpiOSIFeatures[i].control_flag) {
10989652SMichael.Corcoran@Sun.COM 			break;
10999652SMichael.Corcoran@Sun.COM 		}
11009652SMichael.Corcoran@Sun.COM 		/* Feature supported. */
11019652SMichael.Corcoran@Sun.COM 		return (AE_OK);
11029652SMichael.Corcoran@Sun.COM 	}
11039652SMichael.Corcoran@Sun.COM 
11043446Smrj 	return (AE_SUPPORT);
11053446Smrj }
11063446Smrj 
11073446Smrj /*ARGSUSED*/
11083446Smrj ACPI_STATUS
AcpiOsValidateAddress(UINT8 spaceid,ACPI_PHYSICAL_ADDRESS addr,ACPI_SIZE length)11093446Smrj AcpiOsValidateAddress(UINT8 spaceid, ACPI_PHYSICAL_ADDRESS addr,
11103446Smrj     ACPI_SIZE length)
11113446Smrj {
11123446Smrj 	return (AE_OK);
11133446Smrj }
11143446Smrj 
11153446Smrj ACPI_STATUS
AcpiOsSignal(UINT32 Function,void * Info)11163446Smrj AcpiOsSignal(UINT32 Function, void *Info)
11173446Smrj {
11183446Smrj 	_NOTE(ARGUNUSED(Function, Info))
11193446Smrj 
11203446Smrj 	/* FUTUREWORK: debugger support */
11213446Smrj 
11223446Smrj 	cmn_err(CE_NOTE, "!OsSignal unimplemented");
11233446Smrj 	return (AE_OK);
11243446Smrj }
11253446Smrj 
11263446Smrj void ACPI_INTERNAL_VAR_XFACE
AcpiOsPrintf(const char * Format,...)11273446Smrj AcpiOsPrintf(const char *Format, ...)
11283446Smrj {
11293446Smrj 	va_list ap;
11303446Smrj 
11313446Smrj 	va_start(ap, Format);
11323446Smrj 	AcpiOsVprintf(Format, ap);
11333446Smrj 	va_end(ap);
11343446Smrj }
11353446Smrj 
11363446Smrj /*
11373446Smrj  * When != 0, sends output to console
11383446Smrj  * Patchable with kmdb or /etc/system.
11393446Smrj  */
11403446Smrj int acpica_console_out = 0;
11413446Smrj 
11423446Smrj #define	ACPICA_OUTBUF_LEN	160
11433446Smrj char	acpica_outbuf[ACPICA_OUTBUF_LEN];
11443446Smrj int	acpica_outbuf_offset;
11453446Smrj 
11463446Smrj /*
11473446Smrj  *
11483446Smrj  */
11493446Smrj static void
acpica_pr_buf(char * buf)11505155Smyers acpica_pr_buf(char *buf)
11513446Smrj {
11523446Smrj 	char c, *bufp, *outp;
11533446Smrj 	int	out_remaining;
11543446Smrj 
11553446Smrj 	/*
11563446Smrj 	 * copy the supplied buffer into the output buffer
11573446Smrj 	 * when we hit a '\n' or overflow the output buffer,
11583446Smrj 	 * output and reset the output buffer
11593446Smrj 	 */
11603446Smrj 	bufp = buf;
11613446Smrj 	outp = acpica_outbuf + acpica_outbuf_offset;
11623446Smrj 	out_remaining = ACPICA_OUTBUF_LEN - acpica_outbuf_offset - 1;
11633446Smrj 	while (c = *bufp++) {
11643446Smrj 		*outp++ = c;
11653446Smrj 		if (c == '\n' || --out_remaining == 0) {
11663446Smrj 			*outp = '\0';
116710235SDana.Myers@Sun.COM 			switch (acpica_console_out) {
116810235SDana.Myers@Sun.COM 			case 1:
11693446Smrj 				printf(acpica_outbuf);
117010235SDana.Myers@Sun.COM 				break;
117110235SDana.Myers@Sun.COM 			case 2:
117210235SDana.Myers@Sun.COM 				prom_printf(acpica_outbuf);
117310235SDana.Myers@Sun.COM 				break;
117410235SDana.Myers@Sun.COM 			case 0:
117510235SDana.Myers@Sun.COM 			default:
11763446Smrj 				(void) strlog(0, 0, 0,
11773446Smrj 				    SL_CONSOLE | SL_NOTE | SL_LOGONLY,
11783446Smrj 				    acpica_outbuf);
117910235SDana.Myers@Sun.COM 				break;
118010235SDana.Myers@Sun.COM 			}
11813446Smrj 			acpica_outbuf_offset = 0;
11823446Smrj 			outp = acpica_outbuf;
11833446Smrj 			out_remaining = ACPICA_OUTBUF_LEN - 1;
11843446Smrj 		}
11853446Smrj 	}
11863446Smrj 
11873446Smrj 	acpica_outbuf_offset = outp - acpica_outbuf;
11883446Smrj }
11893446Smrj 
11903446Smrj void
AcpiOsVprintf(const char * Format,va_list Args)11913446Smrj AcpiOsVprintf(const char *Format, va_list Args)
11923446Smrj {
11933446Smrj 
11943446Smrj 	/*
11955155Smyers 	 * If AcpiOsInitialize() failed to allocate a string buffer,
11965155Smyers 	 * resort to vprintf().
11973446Smrj 	 */
11985155Smyers 	if (acpi_osl_pr_buffer == NULL) {
11993446Smrj 		vprintf(Format, Args);
12003446Smrj 		return;
12013446Smrj 	}
12025155Smyers 
12035155Smyers 	/*
12045155Smyers 	 * It is possible that a very long debug output statement will
12055155Smyers 	 * be truncated; this is silently ignored.
12065155Smyers 	 */
12075155Smyers 	(void) vsnprintf(acpi_osl_pr_buffer, acpi_osl_pr_buflen, Format, Args);
12085155Smyers 	acpica_pr_buf(acpi_osl_pr_buffer);
12093446Smrj }
12103446Smrj 
12113446Smrj void
AcpiOsRedirectOutput(void * Destination)12123446Smrj AcpiOsRedirectOutput(void *Destination)
12133446Smrj {
12143446Smrj 	_NOTE(ARGUNUSED(Destination))
12153446Smrj 
12163446Smrj 	/* FUTUREWORK: debugger support */
12173446Smrj 
12183446Smrj #ifdef	DEBUG
12193446Smrj 	cmn_err(CE_WARN, "!acpica: AcpiOsRedirectOutput called");
12203446Smrj #endif
12213446Smrj }
12223446Smrj 
12233446Smrj 
12243446Smrj UINT32
AcpiOsGetLine(char * Buffer)12253446Smrj AcpiOsGetLine(char *Buffer)
12263446Smrj {
12273446Smrj 	_NOTE(ARGUNUSED(Buffer))
12283446Smrj 
12293446Smrj 	/* FUTUREWORK: debugger support */
12303446Smrj 
12313446Smrj 	return (0);
12323446Smrj }
12333446Smrj 
12343446Smrj /*
12353446Smrj  * Device tree binding
12363446Smrj  */
12379652SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpica_find_pcibus_walker(ACPI_HANDLE hdl,UINT32 lvl,void * ctxp,void ** rvpp)12389652SMichael.Corcoran@Sun.COM acpica_find_pcibus_walker(ACPI_HANDLE hdl, UINT32 lvl, void *ctxp, void **rvpp)
12399652SMichael.Corcoran@Sun.COM {
12409652SMichael.Corcoran@Sun.COM 	_NOTE(ARGUNUSED(lvl));
12419652SMichael.Corcoran@Sun.COM 
12429652SMichael.Corcoran@Sun.COM 	int sta, hid, bbn;
12439652SMichael.Corcoran@Sun.COM 	int busno = (intptr_t)ctxp;
12449652SMichael.Corcoran@Sun.COM 	ACPI_HANDLE *hdlp = (ACPI_HANDLE *)rvpp;
12459652SMichael.Corcoran@Sun.COM 
12469652SMichael.Corcoran@Sun.COM 	/* Check whether device exists. */
12479652SMichael.Corcoran@Sun.COM 	if (ACPI_SUCCESS(acpica_eval_int(hdl, "_STA", &sta)) &&
12489652SMichael.Corcoran@Sun.COM 	    !(sta & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING))) {
12499652SMichael.Corcoran@Sun.COM 		/*
12509652SMichael.Corcoran@Sun.COM 		 * Skip object if device doesn't exist.
12519652SMichael.Corcoran@Sun.COM 		 * According to ACPI Spec,
12529652SMichael.Corcoran@Sun.COM 		 * 1) setting either bit 0 or bit 3 means that device exists.
12539652SMichael.Corcoran@Sun.COM 		 * 2) Absence of _STA method means all status bits set.
12549652SMichael.Corcoran@Sun.COM 		 */
12559652SMichael.Corcoran@Sun.COM 		return (AE_CTRL_DEPTH);
12569652SMichael.Corcoran@Sun.COM 	}
12579652SMichael.Corcoran@Sun.COM 
12589652SMichael.Corcoran@Sun.COM 	if (ACPI_FAILURE(acpica_eval_hid(hdl, "_HID", &hid)) ||
12599652SMichael.Corcoran@Sun.COM 	    (hid != HID_PCI_BUS && hid != HID_PCI_EXPRESS_BUS)) {
12609652SMichael.Corcoran@Sun.COM 		/* Non PCI/PCIe host bridge. */
12619652SMichael.Corcoran@Sun.COM 		return (AE_OK);
12629652SMichael.Corcoran@Sun.COM 	}
12639652SMichael.Corcoran@Sun.COM 
12649652SMichael.Corcoran@Sun.COM 	if (acpi_has_broken_bbn) {
12659652SMichael.Corcoran@Sun.COM 		ACPI_BUFFER rb;
12669652SMichael.Corcoran@Sun.COM 		rb.Pointer = NULL;
12679652SMichael.Corcoran@Sun.COM 		rb.Length = ACPI_ALLOCATE_BUFFER;
12689652SMichael.Corcoran@Sun.COM 
12699652SMichael.Corcoran@Sun.COM 		/* Decree _BBN == n from PCI<n> */
12709652SMichael.Corcoran@Sun.COM 		if (AcpiGetName(hdl, ACPI_SINGLE_NAME, &rb) != AE_OK) {
12719652SMichael.Corcoran@Sun.COM 			return (AE_CTRL_TERMINATE);
12729652SMichael.Corcoran@Sun.COM 		}
12739652SMichael.Corcoran@Sun.COM 		bbn = ((char *)rb.Pointer)[3] - '0';
12749652SMichael.Corcoran@Sun.COM 		AcpiOsFree(rb.Pointer);
12759652SMichael.Corcoran@Sun.COM 		if (bbn == busno || busno == 0) {
12769652SMichael.Corcoran@Sun.COM 			*hdlp = hdl;
12779652SMichael.Corcoran@Sun.COM 			return (AE_CTRL_TERMINATE);
12789652SMichael.Corcoran@Sun.COM 		}
12799652SMichael.Corcoran@Sun.COM 	} else if (ACPI_SUCCESS(acpica_eval_int(hdl, "_BBN", &bbn))) {
12809652SMichael.Corcoran@Sun.COM 		if (bbn == busno) {
12819652SMichael.Corcoran@Sun.COM 			*hdlp = hdl;
12829652SMichael.Corcoran@Sun.COM 			return (AE_CTRL_TERMINATE);
12839652SMichael.Corcoran@Sun.COM 		}
12849652SMichael.Corcoran@Sun.COM 	} else if (busno == 0) {
12859652SMichael.Corcoran@Sun.COM 		*hdlp = hdl;
12869652SMichael.Corcoran@Sun.COM 		return (AE_CTRL_TERMINATE);
12879652SMichael.Corcoran@Sun.COM 	}
12889652SMichael.Corcoran@Sun.COM 
12899652SMichael.Corcoran@Sun.COM 	return (AE_CTRL_DEPTH);
12909652SMichael.Corcoran@Sun.COM }
12913446Smrj 
12923446Smrj static int
acpica_find_pcibus(int busno,ACPI_HANDLE * rh)12933446Smrj acpica_find_pcibus(int busno, ACPI_HANDLE *rh)
12943446Smrj {
12953446Smrj 	ACPI_HANDLE sbobj, busobj;
12963446Smrj 
12973446Smrj 	/* initialize static flag by querying ACPI namespace for bug */
12983446Smrj 	if (acpi_has_broken_bbn == -1)
12993446Smrj 		acpi_has_broken_bbn = acpica_query_bbn_problem();
13003446Smrj 
13019652SMichael.Corcoran@Sun.COM 	if (ACPI_SUCCESS(AcpiGetHandle(NULL, "\\_SB", &sbobj))) {
13029652SMichael.Corcoran@Sun.COM 		busobj = NULL;
13039652SMichael.Corcoran@Sun.COM 		(void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, sbobj, UINT32_MAX,
130411225SDana.Myers@Sun.COM 		    acpica_find_pcibus_walker, NULL, (void *)(intptr_t)busno,
13059652SMichael.Corcoran@Sun.COM 		    (void **)&busobj);
13069652SMichael.Corcoran@Sun.COM 		if (busobj != NULL) {
13079652SMichael.Corcoran@Sun.COM 			*rh = busobj;
13089652SMichael.Corcoran@Sun.COM 			return (AE_OK);
13093446Smrj 		}
13103446Smrj 	}
13119652SMichael.Corcoran@Sun.COM 
13123446Smrj 	return (AE_ERROR);
13133446Smrj }
13143446Smrj 
13159652SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpica_query_bbn_walker(ACPI_HANDLE hdl,UINT32 lvl,void * ctxp,void ** rvpp)13169652SMichael.Corcoran@Sun.COM acpica_query_bbn_walker(ACPI_HANDLE hdl, UINT32 lvl, void *ctxp, void **rvpp)
13179652SMichael.Corcoran@Sun.COM {
13189652SMichael.Corcoran@Sun.COM 	_NOTE(ARGUNUSED(lvl));
13199652SMichael.Corcoran@Sun.COM 	_NOTE(ARGUNUSED(rvpp));
13209652SMichael.Corcoran@Sun.COM 
13219652SMichael.Corcoran@Sun.COM 	int sta, hid, bbn;
13229652SMichael.Corcoran@Sun.COM 	int *cntp = (int *)ctxp;
13239652SMichael.Corcoran@Sun.COM 
13249652SMichael.Corcoran@Sun.COM 	/* Check whether device exists. */
13259652SMichael.Corcoran@Sun.COM 	if (ACPI_SUCCESS(acpica_eval_int(hdl, "_STA", &sta)) &&
13269652SMichael.Corcoran@Sun.COM 	    !(sta & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING))) {
13279652SMichael.Corcoran@Sun.COM 		/*
13289652SMichael.Corcoran@Sun.COM 		 * Skip object if device doesn't exist.
13299652SMichael.Corcoran@Sun.COM 		 * According to ACPI Spec,
13309652SMichael.Corcoran@Sun.COM 		 * 1) setting either bit 0 or bit 3 means that device exists.
13319652SMichael.Corcoran@Sun.COM 		 * 2) Absence of _STA method means all status bits set.
13329652SMichael.Corcoran@Sun.COM 		 */
13339652SMichael.Corcoran@Sun.COM 		return (AE_CTRL_DEPTH);
13349652SMichael.Corcoran@Sun.COM 	}
13359652SMichael.Corcoran@Sun.COM 
13369652SMichael.Corcoran@Sun.COM 	if (ACPI_FAILURE(acpica_eval_hid(hdl, "_HID", &hid)) ||
13379652SMichael.Corcoran@Sun.COM 	    (hid != HID_PCI_BUS && hid != HID_PCI_EXPRESS_BUS)) {
13389652SMichael.Corcoran@Sun.COM 		/* Non PCI/PCIe host bridge. */
13399652SMichael.Corcoran@Sun.COM 		return (AE_OK);
13409652SMichael.Corcoran@Sun.COM 	} else if (ACPI_SUCCESS(acpica_eval_int(hdl, "_BBN", &bbn)) &&
13419652SMichael.Corcoran@Sun.COM 	    bbn == 0 && ++(*cntp) > 1) {
13429652SMichael.Corcoran@Sun.COM 		/*
13439652SMichael.Corcoran@Sun.COM 		 * If we find more than one bus with a 0 _BBN
13449652SMichael.Corcoran@Sun.COM 		 * we have the problem that BigBear's BIOS shows
13459652SMichael.Corcoran@Sun.COM 		 */
13469652SMichael.Corcoran@Sun.COM 		return (AE_CTRL_TERMINATE);
13479652SMichael.Corcoran@Sun.COM 	} else {
13489652SMichael.Corcoran@Sun.COM 		/*
13499652SMichael.Corcoran@Sun.COM 		 * Skip children of PCI/PCIe host bridge.
13509652SMichael.Corcoran@Sun.COM 		 */
13519652SMichael.Corcoran@Sun.COM 		return (AE_CTRL_DEPTH);
13529652SMichael.Corcoran@Sun.COM 	}
13539652SMichael.Corcoran@Sun.COM }
13543446Smrj 
13553446Smrj /*
13563446Smrj  * Look for ACPI problem where _BBN is zero for multiple PCI buses
13573446Smrj  * This is a clear ACPI bug, but we have a workaround in acpica_find_pcibus()
13583446Smrj  * below if it exists.
13593446Smrj  */
13603446Smrj static int
acpica_query_bbn_problem(void)13613446Smrj acpica_query_bbn_problem(void)
13623446Smrj {
13639652SMichael.Corcoran@Sun.COM 	ACPI_HANDLE sbobj;
13643446Smrj 	int zerobbncnt;
13659652SMichael.Corcoran@Sun.COM 	void *rv;
13663446Smrj 
13679652SMichael.Corcoran@Sun.COM 	zerobbncnt = 0;
13689652SMichael.Corcoran@Sun.COM 	if (ACPI_SUCCESS(AcpiGetHandle(NULL, "\\_SB", &sbobj))) {
13699652SMichael.Corcoran@Sun.COM 		(void) AcpiWalkNamespace(ACPI_TYPE_DEVICE, sbobj, UINT32_MAX,
137011225SDana.Myers@Sun.COM 		    acpica_query_bbn_walker, NULL, &zerobbncnt, &rv);
13713446Smrj 	}
13729652SMichael.Corcoran@Sun.COM 
13739652SMichael.Corcoran@Sun.COM 	return (zerobbncnt > 1 ? 1 : 0);
13743446Smrj }
13753446Smrj 
13763446Smrj static const char hextab[] = "0123456789ABCDEF";
13773446Smrj 
13783446Smrj static int
hexdig(int c)13793446Smrj hexdig(int c)
13803446Smrj {
13813446Smrj 	/*
13823446Smrj 	 *  Get hex digit:
13833446Smrj 	 *
13843446Smrj 	 *  Returns the 4-bit hex digit named by the input character.  Returns
13853446Smrj 	 *  zero if the input character is not valid hex!
13863446Smrj 	 */
13873446Smrj 
13883446Smrj 	int x = ((c < 'a') || (c > 'z')) ? c : (c - ' ');
13893446Smrj 	int j = sizeof (hextab);
13903446Smrj 
13914476Smyers 	while (--j && (x != hextab[j])) {
13924476Smyers 	}
13933446Smrj 	return (j);
13943446Smrj }
13953446Smrj 
13963446Smrj static int
CompressEisaID(char * np)13973446Smrj CompressEisaID(char *np)
13983446Smrj {
13993446Smrj 	/*
14003446Smrj 	 *  Compress an EISA device name:
14013446Smrj 	 *
14023446Smrj 	 *  This routine converts a 7-byte ASCII device name into the 4-byte
14033446Smrj 	 *  compressed form used by EISA (50 bytes of ROM to save 1 byte of
14043446Smrj 	 *  NV-RAM!)
14053446Smrj 	 */
14063446Smrj 
14073446Smrj 	union { char octets[4]; int retval; } myu;
14083446Smrj 
14093446Smrj 	myu.octets[0] = ((np[0] & 0x1F) << 2) + ((np[1] >> 3) & 0x03);
14103446Smrj 	myu.octets[1] = ((np[1] & 0x07) << 5) + (np[2] & 0x1F);
14113446Smrj 	myu.octets[2] = (hexdig(np[3]) << 4) + hexdig(np[4]);
14123446Smrj 	myu.octets[3] = (hexdig(np[5]) << 4) + hexdig(np[6]);
14133446Smrj 
14143446Smrj 	return (myu.retval);
14153446Smrj }
14163446Smrj 
14174667Smh27603 ACPI_STATUS
acpica_eval_int(ACPI_HANDLE dev,char * method,int * rint)14183446Smrj acpica_eval_int(ACPI_HANDLE dev, char *method, int *rint)
14193446Smrj {
14203446Smrj 	ACPI_STATUS status;
14213446Smrj 	ACPI_BUFFER rb;
14223446Smrj 	ACPI_OBJECT ro;
14233446Smrj 
14243446Smrj 	rb.Pointer = &ro;
14253446Smrj 	rb.Length = sizeof (ro);
14263446Smrj 	if ((status = AcpiEvaluateObjectTyped(dev, method, NULL, &rb,
14274476Smyers 	    ACPI_TYPE_INTEGER)) == AE_OK)
14283446Smrj 		*rint = ro.Integer.Value;
14293446Smrj 
14303446Smrj 	return (status);
14313446Smrj }
14323446Smrj 
14333446Smrj static int
acpica_eval_hid(ACPI_HANDLE dev,char * method,int * rint)14343446Smrj acpica_eval_hid(ACPI_HANDLE dev, char *method, int *rint)
14353446Smrj {
14363446Smrj 	ACPI_BUFFER rb;
14373446Smrj 	ACPI_OBJECT *rv;
14383446Smrj 
14393446Smrj 	rb.Pointer = NULL;
14403446Smrj 	rb.Length = ACPI_ALLOCATE_BUFFER;
14417851SDana.Myers@Sun.COM 	if (AcpiEvaluateObject(dev, method, NULL, &rb) == AE_OK &&
14427851SDana.Myers@Sun.COM 	    rb.Length != 0) {
14433446Smrj 		rv = rb.Pointer;
14443446Smrj 		if (rv->Type == ACPI_TYPE_INTEGER) {
14453446Smrj 			*rint = rv->Integer.Value;
14463446Smrj 			AcpiOsFree(rv);
14473446Smrj 			return (AE_OK);
14483446Smrj 		} else if (rv->Type == ACPI_TYPE_STRING) {
14493446Smrj 			char *stringData;
14503446Smrj 
14513446Smrj 			/* Convert the string into an EISA ID */
14523446Smrj 			if (rv->String.Pointer == NULL) {
14533446Smrj 				AcpiOsFree(rv);
14543446Smrj 				return (AE_ERROR);
14553446Smrj 			}
14563446Smrj 
14573446Smrj 			stringData = rv->String.Pointer;
14583446Smrj 
14593446Smrj 			/*
14603446Smrj 			 * If the string is an EisaID, it must be 7
14613446Smrj 			 * characters; if it's an ACPI ID, it will be 8
14623446Smrj 			 * (and we don't care about ACPI ids here).
14633446Smrj 			 */
14643446Smrj 			if (strlen(stringData) != 7) {
14653446Smrj 				AcpiOsFree(rv);
14663446Smrj 				return (AE_ERROR);
14673446Smrj 			}
14683446Smrj 
14693446Smrj 			*rint = CompressEisaID(stringData);
14703446Smrj 			AcpiOsFree(rv);
14713446Smrj 			return (AE_OK);
14723446Smrj 		} else
14733446Smrj 			AcpiOsFree(rv);
14743446Smrj 	}
14753446Smrj 	return (AE_ERROR);
14763446Smrj }
14773446Smrj 
14783446Smrj /*
14794667Smh27603  * Create linkage between devinfo nodes and ACPI nodes
14803446Smrj  */
14819652SMichael.Corcoran@Sun.COM ACPI_STATUS
acpica_tag_devinfo(dev_info_t * dip,ACPI_HANDLE acpiobj)14824667Smh27603 acpica_tag_devinfo(dev_info_t *dip, ACPI_HANDLE acpiobj)
14833446Smrj {
14844667Smh27603 	ACPI_STATUS status;
14854667Smh27603 	ACPI_BUFFER rb;
14863446Smrj 
14874667Smh27603 	/*
14884667Smh27603 	 * Tag the devinfo node with the ACPI name
14894667Smh27603 	 */
14904667Smh27603 	rb.Pointer = NULL;
14914667Smh27603 	rb.Length = ACPI_ALLOCATE_BUFFER;
14929652SMichael.Corcoran@Sun.COM 	status = AcpiGetName(acpiobj, ACPI_FULL_PATHNAME, &rb);
14939652SMichael.Corcoran@Sun.COM 	if (ACPI_FAILURE(status)) {
14949652SMichael.Corcoran@Sun.COM 		cmn_err(CE_WARN, "acpica: could not get ACPI path!");
14959652SMichael.Corcoran@Sun.COM 	} else {
14964667Smh27603 		(void) ndi_prop_update_string(DDI_DEV_T_NONE, dip,
14974667Smh27603 		    "acpi-namespace", (char *)rb.Pointer);
14984667Smh27603 		AcpiOsFree(rb.Pointer);
14999652SMichael.Corcoran@Sun.COM 
15009652SMichael.Corcoran@Sun.COM 		/*
15019652SMichael.Corcoran@Sun.COM 		 * Tag the ACPI node with the dip
15029652SMichael.Corcoran@Sun.COM 		 */
15039652SMichael.Corcoran@Sun.COM 		status = acpica_set_devinfo(acpiobj, dip);
15049652SMichael.Corcoran@Sun.COM 		ASSERT(ACPI_SUCCESS(status));
15054667Smh27603 	}
15069652SMichael.Corcoran@Sun.COM 
15079652SMichael.Corcoran@Sun.COM 	return (status);
15083446Smrj }
15093446Smrj 
15109652SMichael.Corcoran@Sun.COM /*
15119652SMichael.Corcoran@Sun.COM  * Destroy linkage between devinfo nodes and ACPI nodes
15129652SMichael.Corcoran@Sun.COM  */
15139652SMichael.Corcoran@Sun.COM ACPI_STATUS
acpica_untag_devinfo(dev_info_t * dip,ACPI_HANDLE acpiobj)15149652SMichael.Corcoran@Sun.COM acpica_untag_devinfo(dev_info_t *dip, ACPI_HANDLE acpiobj)
15153446Smrj {
15169652SMichael.Corcoran@Sun.COM 	(void) acpica_unset_devinfo(acpiobj);
15179652SMichael.Corcoran@Sun.COM 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, "acpi-namespace");
15183446Smrj 
15199652SMichael.Corcoran@Sun.COM 	return (AE_OK);
15203446Smrj }
15213446Smrj 
15223446Smrj /*
15234687Smh27603  * Return the ACPI device node matching the CPU dev_info node.
15243446Smrj  */
15254667Smh27603 ACPI_STATUS
acpica_get_handle_cpu(int cpu_id,ACPI_HANDLE * rh)15268906SEric.Saxe@Sun.COM acpica_get_handle_cpu(int cpu_id, ACPI_HANDLE *rh)
15273446Smrj {
15289652SMichael.Corcoran@Sun.COM 	int i;
15299652SMichael.Corcoran@Sun.COM 
15304667Smh27603 	/*
15314667Smh27603 	 * if cpu_map itself is NULL, we're a uppc system and
15324667Smh27603 	 * acpica_build_processor_map() hasn't been called yet.
15334667Smh27603 	 * So call it here
15344667Smh27603 	 */
15354667Smh27603 	if (cpu_map == NULL) {
15364667Smh27603 		(void) acpica_build_processor_map();
15374667Smh27603 		if (cpu_map == NULL)
15384667Smh27603 			return (AE_ERROR);
15394667Smh27603 	}
15403446Smrj 
15419652SMichael.Corcoran@Sun.COM 	if (cpu_id < 0) {
15424667Smh27603 		return (AE_ERROR);
15439652SMichael.Corcoran@Sun.COM 	}
15444667Smh27603 
15459652SMichael.Corcoran@Sun.COM 	/*
15469652SMichael.Corcoran@Sun.COM 	 * search object with cpuid in cpu_map
15479652SMichael.Corcoran@Sun.COM 	 */
15489652SMichael.Corcoran@Sun.COM 	mutex_enter(&cpu_map_lock);
15499652SMichael.Corcoran@Sun.COM 	for (i = 0; i < cpu_map_count; i++) {
15509652SMichael.Corcoran@Sun.COM 		if (cpu_map[i]->cpu_id == cpu_id) {
15519652SMichael.Corcoran@Sun.COM 			break;
15529652SMichael.Corcoran@Sun.COM 		}
15539652SMichael.Corcoran@Sun.COM 	}
155410394SMichael.Corcoran@Sun.COM 	if (i < cpu_map_count && (cpu_map[i]->obj != NULL)) {
1555*12004Sjiang.liu@intel.com 		*rh = cpu_map[i]->obj;
15569652SMichael.Corcoran@Sun.COM 		mutex_exit(&cpu_map_lock);
155710394SMichael.Corcoran@Sun.COM 		return (AE_OK);
15589652SMichael.Corcoran@Sun.COM 	}
155910394SMichael.Corcoran@Sun.COM 
156010394SMichael.Corcoran@Sun.COM 	/* Handle special case for uppc-only systems. */
156110394SMichael.Corcoran@Sun.COM 	if (cpu_map_called == 0) {
156210394SMichael.Corcoran@Sun.COM 		uint32_t apicid = cpuid_get_apicid(CPU);
156310394SMichael.Corcoran@Sun.COM 		if (apicid != UINT32_MAX) {
156410394SMichael.Corcoran@Sun.COM 			for (i = 0; i < cpu_map_count; i++) {
156510394SMichael.Corcoran@Sun.COM 				if (cpu_map[i]->apic_id == apicid) {
156610394SMichael.Corcoran@Sun.COM 					break;
156710394SMichael.Corcoran@Sun.COM 				}
156810394SMichael.Corcoran@Sun.COM 			}
156910394SMichael.Corcoran@Sun.COM 			if (i < cpu_map_count && (cpu_map[i]->obj != NULL)) {
1570*12004Sjiang.liu@intel.com 				*rh = cpu_map[i]->obj;
157110394SMichael.Corcoran@Sun.COM 				mutex_exit(&cpu_map_lock);
157210394SMichael.Corcoran@Sun.COM 				return (AE_OK);
157310394SMichael.Corcoran@Sun.COM 			}
157410394SMichael.Corcoran@Sun.COM 		}
157510394SMichael.Corcoran@Sun.COM 	}
15769652SMichael.Corcoran@Sun.COM 	mutex_exit(&cpu_map_lock);
15779652SMichael.Corcoran@Sun.COM 
157810394SMichael.Corcoran@Sun.COM 	return (AE_ERROR);
15794667Smh27603 }
15803446Smrj 
15814667Smh27603 /*
15824667Smh27603  * Determine if this object is a processor
15834667Smh27603  */
15844667Smh27603 static ACPI_STATUS
acpica_probe_processor(ACPI_HANDLE obj,UINT32 level,void * ctx,void ** rv)15854667Smh27603 acpica_probe_processor(ACPI_HANDLE obj, UINT32 level, void *ctx, void **rv)
15864667Smh27603 {
15874667Smh27603 	ACPI_STATUS status;
15884667Smh27603 	ACPI_OBJECT_TYPE objtype;
15898973SDana.Myers@Sun.COM 	unsigned long acpi_id;
15904667Smh27603 	ACPI_BUFFER rb;
159111225SDana.Myers@Sun.COM 	ACPI_DEVICE_INFO *di;
15924667Smh27603 
15934667Smh27603 	if (AcpiGetType(obj, &objtype) != AE_OK)
15944667Smh27603 		return (AE_OK);
15954667Smh27603 
15964667Smh27603 	if (objtype == ACPI_TYPE_PROCESSOR) {
15974667Smh27603 		/* process a Processor */
15983446Smrj 		rb.Pointer = NULL;
15993446Smrj 		rb.Length = ACPI_ALLOCATE_BUFFER;
16007851SDana.Myers@Sun.COM 		status = AcpiEvaluateObjectTyped(obj, NULL, NULL, &rb,
16017851SDana.Myers@Sun.COM 		    ACPI_TYPE_PROCESSOR);
16024667Smh27603 		if (status != AE_OK) {
16038973SDana.Myers@Sun.COM 			cmn_err(CE_WARN, "!acpica: error probing Processor");
16044667Smh27603 			return (status);
16054667Smh27603 		}
16064667Smh27603 		acpi_id = ((ACPI_OBJECT *)rb.Pointer)->Processor.ProcId;
16074667Smh27603 		AcpiOsFree(rb.Pointer);
16084667Smh27603 	} else if (objtype == ACPI_TYPE_DEVICE) {
16094667Smh27603 		/* process a processor Device */
161011225SDana.Myers@Sun.COM 		status = AcpiGetObjectInfo(obj, &di);
16117282Smishra 		if (status != AE_OK) {
16127282Smishra 			cmn_err(CE_WARN,
16138973SDana.Myers@Sun.COM 			    "!acpica: error probing Processor Device\n");
16147282Smishra 			return (status);
16157282Smishra 		}
16168973SDana.Myers@Sun.COM 
161711225SDana.Myers@Sun.COM 		if (!(di->Valid & ACPI_VALID_UID) ||
161811225SDana.Myers@Sun.COM 		    ddi_strtoul(di->UniqueId.String, NULL, 10, &acpi_id) != 0) {
161911225SDana.Myers@Sun.COM 			ACPI_FREE(di);
16208973SDana.Myers@Sun.COM 			cmn_err(CE_WARN,
16218973SDana.Myers@Sun.COM 			    "!acpica: error probing Processor Device _UID\n");
16228973SDana.Myers@Sun.COM 			return (AE_ERROR);
16238973SDana.Myers@Sun.COM 		}
162411225SDana.Myers@Sun.COM 		ACPI_FREE(di);
16254667Smh27603 	}
16269652SMichael.Corcoran@Sun.COM 	(void) acpica_add_processor_to_map(acpi_id, obj, UINT32_MAX);
16273446Smrj 
16284667Smh27603 	return (AE_OK);
16293446Smrj }
16303446Smrj 
163111177SDana.Myers@Sun.COM void
scan_d2a_map(void)16324667Smh27603 scan_d2a_map(void)
16333446Smrj {
16343446Smrj 	dev_info_t *dip, *cdip;
16353446Smrj 	ACPI_HANDLE acpiobj;
16363446Smrj 	char *device_type_prop;
16373446Smrj 	int bus;
16383446Smrj 	static int map_error = 0;
16393446Smrj 
164011177SDana.Myers@Sun.COM 	if (map_error || (d2a_done != 0))
16413446Smrj 		return;
16423446Smrj 
16434667Smh27603 	scanning_d2a_map = 1;
16443446Smrj 
16453446Smrj 	/*
16463446Smrj 	 * Find all child-of-root PCI buses, and find their corresponding
16473446Smrj 	 * ACPI child-of-root PCI nodes.  For each one, add to the
16483446Smrj 	 * d2a table.
16493446Smrj 	 */
16503446Smrj 
16513446Smrj 	for (dip = ddi_get_child(ddi_root_node());
16523446Smrj 	    dip != NULL;
16533446Smrj 	    dip = ddi_get_next_sibling(dip)) {
16543446Smrj 
16553446Smrj 		/* prune non-PCI nodes */
16569652SMichael.Corcoran@Sun.COM 		if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
16579652SMichael.Corcoran@Sun.COM 		    DDI_PROP_DONTPASS,
16583446Smrj 		    "device_type", &device_type_prop) != DDI_PROP_SUCCESS)
16593446Smrj 			continue;
16603446Smrj 
16613446Smrj 		if ((strcmp("pci", device_type_prop) != 0) &&
16623446Smrj 		    (strcmp("pciex", device_type_prop) != 0)) {
16633446Smrj 			ddi_prop_free(device_type_prop);
16643446Smrj 			continue;
16653446Smrj 		}
16663446Smrj 
16673446Smrj 		ddi_prop_free(device_type_prop);
16683446Smrj 
16693446Smrj 		/*
16703446Smrj 		 * To get bus number of dip, get first child and get its
16713446Smrj 		 * bus number.  If NULL, just continue, because we don't
16723446Smrj 		 * care about bus nodes with no children anyway.
16733446Smrj 		 */
16743446Smrj 		if ((cdip = ddi_get_child(dip)) == NULL)
16753446Smrj 			continue;
16763446Smrj 
16773446Smrj 		if (acpica_get_bdf(cdip, &bus, NULL, NULL) < 0) {
16783446Smrj #ifdef D2ADEBUG
16793446Smrj 			cmn_err(CE_WARN, "Can't get bus number of PCI child?");
16803446Smrj #endif
16813446Smrj 			map_error = 1;
16824667Smh27603 			scanning_d2a_map = 0;
16834667Smh27603 			d2a_done = 1;
16843446Smrj 			return;
16853446Smrj 		}
16863446Smrj 
16873446Smrj 		if (acpica_find_pcibus(bus, &acpiobj) == AE_ERROR) {
16883446Smrj #ifdef D2ADEBUG
16893446Smrj 			cmn_err(CE_WARN, "No ACPI bus obj for bus %d?\n", bus);
16903446Smrj #endif
16913446Smrj 			map_error = 1;
16923446Smrj 			continue;
16933446Smrj 		}
16943446Smrj 
16954667Smh27603 		acpica_tag_devinfo(dip, acpiobj);
16963446Smrj 
16974667Smh27603 		/* call recursively to enumerate subtrees */
16984667Smh27603 		scan_d2a_subtree(dip, acpiobj, bus);
16994667Smh27603 	}
17003446Smrj 
17014667Smh27603 	scanning_d2a_map = 0;
17024667Smh27603 	d2a_done = 1;
17033446Smrj }
17043446Smrj 
17053446Smrj /*
17063446Smrj  * For all acpi child devices of acpiobj, find their matching
17073446Smrj  * dip under "dip" argument.  (matching means "matches dev/fn").
17083446Smrj  * bus is assumed to already be a match from caller, and is
17093446Smrj  * used here only to record in the d2a entry.  Recurse if necessary.
17103446Smrj  */
17113446Smrj static void
scan_d2a_subtree(dev_info_t * dip,ACPI_HANDLE acpiobj,int bus)17124667Smh27603 scan_d2a_subtree(dev_info_t *dip, ACPI_HANDLE acpiobj, int bus)
17133446Smrj {
17143446Smrj 	int acpi_devfn, hid;
17153446Smrj 	ACPI_HANDLE acld;
17163446Smrj 	dev_info_t *dcld;
17173446Smrj 	int dcld_b, dcld_d, dcld_f;
17183446Smrj 	int dev, func;
17194667Smh27603 	char *device_type_prop;
17203446Smrj 
17213446Smrj 	acld = NULL;
17223446Smrj 	while (AcpiGetNextObject(ACPI_TYPE_DEVICE, acpiobj, acld, &acld)
17233446Smrj 	    == AE_OK) {
17243446Smrj 		/* get the dev/func we're looking for in the devinfo tree */
17253446Smrj 		if (acpica_eval_int(acld, "_ADR", &acpi_devfn) != AE_OK)
17263446Smrj 			continue;
17273446Smrj 		dev = (acpi_devfn >> 16) & 0xFFFF;
17283446Smrj 		func = acpi_devfn & 0xFFFF;
17293446Smrj 
17303446Smrj 		/* look through all the immediate children of dip */
17313446Smrj 		for (dcld = ddi_get_child(dip); dcld != NULL;
17323446Smrj 		    dcld = ddi_get_next_sibling(dcld)) {
17333446Smrj 			if (acpica_get_bdf(dcld, &dcld_b, &dcld_d, &dcld_f) < 0)
17343446Smrj 				continue;
17353446Smrj 
17363446Smrj 			/* dev must match; function must match or wildcard */
17373446Smrj 			if (dcld_d != dev ||
17383446Smrj 			    (func != 0xFFFF && func != dcld_f))
17393446Smrj 				continue;
17403446Smrj 			bus = dcld_b;
17413446Smrj 
17423446Smrj 			/* found a match, record it */
17434667Smh27603 			acpica_tag_devinfo(dcld, acld);
17443446Smrj 
17454667Smh27603 			/* if we find a bridge, recurse from here */
17469652SMichael.Corcoran@Sun.COM 			if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dcld,
17479652SMichael.Corcoran@Sun.COM 			    DDI_PROP_DONTPASS, "device_type",
17489652SMichael.Corcoran@Sun.COM 			    &device_type_prop) == DDI_PROP_SUCCESS) {
17494667Smh27603 				if ((strcmp("pci", device_type_prop) == 0) ||
17504667Smh27603 				    (strcmp("pciex", device_type_prop) == 0))
17514667Smh27603 					scan_d2a_subtree(dcld, acld, bus);
17524667Smh27603 				ddi_prop_free(device_type_prop);
17534667Smh27603 			}
17543446Smrj 
17553446Smrj 			/* done finding a match, so break now */
17563446Smrj 			break;
17573446Smrj 		}
17583446Smrj 	}
17593446Smrj }
17603446Smrj 
17613446Smrj /*
17623446Smrj  * Return bus/dev/fn for PCI dip (note: not the parent "pci" node).
17633446Smrj  */
17643446Smrj int
acpica_get_bdf(dev_info_t * dip,int * bus,int * device,int * func)17653446Smrj acpica_get_bdf(dev_info_t *dip, int *bus, int *device, int *func)
17663446Smrj {
17673446Smrj 	pci_regspec_t *pci_rp;
17683446Smrj 	int len;
17693446Smrj 
17703446Smrj 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
17713446Smrj 	    "reg", (int **)&pci_rp, (uint_t *)&len) != DDI_SUCCESS)
17723446Smrj 		return (-1);
17733446Smrj 
17743446Smrj 	if (len < (sizeof (pci_regspec_t) / sizeof (int))) {
17753446Smrj 		ddi_prop_free(pci_rp);
17763446Smrj 		return (-1);
17773446Smrj 	}
17783446Smrj 	if (bus != NULL)
17793446Smrj 		*bus = (int)PCI_REG_BUS_G(pci_rp->pci_phys_hi);
17803446Smrj 	if (device != NULL)
17813446Smrj 		*device = (int)PCI_REG_DEV_G(pci_rp->pci_phys_hi);
17823446Smrj 	if (func != NULL)
17833446Smrj 		*func = (int)PCI_REG_FUNC_G(pci_rp->pci_phys_hi);
17843446Smrj 	ddi_prop_free(pci_rp);
17853446Smrj 	return (0);
17863446Smrj }
17874667Smh27603 
17884667Smh27603 /*
17894667Smh27603  * Return the ACPI device node matching this dev_info node, if it
17904667Smh27603  * exists in the ACPI tree.
17914667Smh27603  */
17924667Smh27603 ACPI_STATUS
acpica_get_handle(dev_info_t * dip,ACPI_HANDLE * rh)17934667Smh27603 acpica_get_handle(dev_info_t *dip, ACPI_HANDLE *rh)
17944667Smh27603 {
17954667Smh27603 	ACPI_STATUS status;
17964667Smh27603 	char *acpiname;
17974667Smh27603 
179811277SDana.Myers@Sun.COM #ifdef	DEBUG
179911277SDana.Myers@Sun.COM 	if (d2a_done == 0)
180011277SDana.Myers@Sun.COM 		cmn_err(CE_WARN, "!acpica_get_handle:"
180111277SDana.Myers@Sun.COM 		    " no ACPI mapping for %s", ddi_node_name(dip));
180211277SDana.Myers@Sun.COM #endif
18034667Smh27603 
18044667Smh27603 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
18054667Smh27603 	    "acpi-namespace", &acpiname) != DDI_PROP_SUCCESS) {
18068906SEric.Saxe@Sun.COM 		return (AE_ERROR);
18074667Smh27603 	}
18084667Smh27603 
18094667Smh27603 	status = AcpiGetHandle(NULL, acpiname, rh);
18104667Smh27603 	ddi_prop_free((void *)acpiname);
18114667Smh27603 	return (status);
18124667Smh27603 }
18134667Smh27603 
18144667Smh27603 
18154667Smh27603 
18164667Smh27603 /*
18174667Smh27603  * Manage OS data attachment to ACPI nodes
18184667Smh27603  */
18194667Smh27603 
18204667Smh27603 /*
18214667Smh27603  * Return the (dev_info_t *) associated with the ACPI node.
18224667Smh27603  */
18234667Smh27603 ACPI_STATUS
acpica_get_devinfo(ACPI_HANDLE obj,dev_info_t ** dipp)18244667Smh27603 acpica_get_devinfo(ACPI_HANDLE obj, dev_info_t **dipp)
18254667Smh27603 {
18264667Smh27603 	ACPI_STATUS status;
18274667Smh27603 	void *ptr;
18284667Smh27603 
18294667Smh27603 	status = AcpiGetData(obj, acpica_devinfo_handler, &ptr);
18304667Smh27603 	if (status == AE_OK)
18314667Smh27603 		*dipp = (dev_info_t *)ptr;
18324667Smh27603 
18334667Smh27603 	return (status);
18344667Smh27603 }
18354667Smh27603 
18364667Smh27603 /*
18374667Smh27603  * Set the dev_info_t associated with the ACPI node.
18384667Smh27603  */
18394667Smh27603 static ACPI_STATUS
acpica_set_devinfo(ACPI_HANDLE obj,dev_info_t * dip)18404667Smh27603 acpica_set_devinfo(ACPI_HANDLE obj, dev_info_t *dip)
18414667Smh27603 {
18424667Smh27603 	ACPI_STATUS status;
18434667Smh27603 
18444667Smh27603 	status = AcpiAttachData(obj, acpica_devinfo_handler, (void *)dip);
18454667Smh27603 	return (status);
18464667Smh27603 }
18474667Smh27603 
18489652SMichael.Corcoran@Sun.COM /*
18499652SMichael.Corcoran@Sun.COM  * Unset the dev_info_t associated with the ACPI node.
18509652SMichael.Corcoran@Sun.COM  */
18519652SMichael.Corcoran@Sun.COM static ACPI_STATUS
acpica_unset_devinfo(ACPI_HANDLE obj)18529652SMichael.Corcoran@Sun.COM acpica_unset_devinfo(ACPI_HANDLE obj)
18539652SMichael.Corcoran@Sun.COM {
18549652SMichael.Corcoran@Sun.COM 	return (AcpiDetachData(obj, acpica_devinfo_handler));
18559652SMichael.Corcoran@Sun.COM }
18564667Smh27603 
18574667Smh27603 /*
18584667Smh27603  *
18594667Smh27603  */
18604667Smh27603 void
acpica_devinfo_handler(ACPI_HANDLE obj,void * data)186111225SDana.Myers@Sun.COM acpica_devinfo_handler(ACPI_HANDLE obj, void *data)
18624667Smh27603 {
186311225SDana.Myers@Sun.COM 	/* no-op */
18644667Smh27603 }
18654667Smh27603 
18669652SMichael.Corcoran@Sun.COM ACPI_STATUS
acpica_build_processor_map(void)18679652SMichael.Corcoran@Sun.COM acpica_build_processor_map(void)
18684667Smh27603 {
18694667Smh27603 	ACPI_STATUS status;
18704667Smh27603 	void *rv;
18714667Smh27603 
18724667Smh27603 	/*
18734667Smh27603 	 * shouldn't be called more than once anyway
18744667Smh27603 	 */
18754667Smh27603 	if (cpu_map_built)
18769652SMichael.Corcoran@Sun.COM 		return (AE_OK);
18779652SMichael.Corcoran@Sun.COM 
18789652SMichael.Corcoran@Sun.COM 	/*
18799652SMichael.Corcoran@Sun.COM 	 * ACPI device configuration driver has built mapping information
18809652SMichael.Corcoran@Sun.COM 	 * among processor id and object handle, no need to probe again.
18819652SMichael.Corcoran@Sun.COM 	 */
18829652SMichael.Corcoran@Sun.COM 	if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
18839652SMichael.Corcoran@Sun.COM 		cpu_map_built = 1;
18849652SMichael.Corcoran@Sun.COM 		return (AE_OK);
18859652SMichael.Corcoran@Sun.COM 	}
18864667Smh27603 
18874667Smh27603 	/*
18884667Smh27603 	 * Look for Processor objects
18894667Smh27603 	 */
18904667Smh27603 	status = AcpiWalkNamespace(ACPI_TYPE_PROCESSOR,
18914667Smh27603 	    ACPI_ROOT_OBJECT,
18924667Smh27603 	    4,
18934667Smh27603 	    acpica_probe_processor,
18944667Smh27603 	    NULL,
189511225SDana.Myers@Sun.COM 	    NULL,
18964667Smh27603 	    &rv);
18974667Smh27603 	ASSERT(status == AE_OK);
18984667Smh27603 
18994667Smh27603 	/*
19004667Smh27603 	 * Look for processor Device objects
19014667Smh27603 	 */
19024667Smh27603 	status = AcpiGetDevices("ACPI0007",
19034667Smh27603 	    acpica_probe_processor,
19044667Smh27603 	    NULL,
19054667Smh27603 	    &rv);
19064667Smh27603 	ASSERT(status == AE_OK);
19074667Smh27603 	cpu_map_built = 1;
19089652SMichael.Corcoran@Sun.COM 
19099652SMichael.Corcoran@Sun.COM 	return (status);
19109652SMichael.Corcoran@Sun.COM }
19119652SMichael.Corcoran@Sun.COM 
19129652SMichael.Corcoran@Sun.COM /*
19139652SMichael.Corcoran@Sun.COM  * Grow cpu map table on demand.
19149652SMichael.Corcoran@Sun.COM  */
19159652SMichael.Corcoran@Sun.COM static void
acpica_grow_cpu_map(void)19169652SMichael.Corcoran@Sun.COM acpica_grow_cpu_map(void)
19179652SMichael.Corcoran@Sun.COM {
19189652SMichael.Corcoran@Sun.COM 	if (cpu_map_count == cpu_map_count_max) {
19199652SMichael.Corcoran@Sun.COM 		size_t sz;
19209652SMichael.Corcoran@Sun.COM 		struct cpu_map_item **new_map;
19219652SMichael.Corcoran@Sun.COM 
19229652SMichael.Corcoran@Sun.COM 		ASSERT(cpu_map_count_max < INT_MAX / 2);
19239652SMichael.Corcoran@Sun.COM 		cpu_map_count_max += max_ncpus;
19249652SMichael.Corcoran@Sun.COM 		new_map = kmem_zalloc(sizeof (cpu_map[0]) * cpu_map_count_max,
19259652SMichael.Corcoran@Sun.COM 		    KM_SLEEP);
19269652SMichael.Corcoran@Sun.COM 		if (cpu_map_count != 0) {
19279652SMichael.Corcoran@Sun.COM 			ASSERT(cpu_map != NULL);
19289652SMichael.Corcoran@Sun.COM 			sz = sizeof (cpu_map[0]) * cpu_map_count;
19299652SMichael.Corcoran@Sun.COM 			kcopy(cpu_map, new_map, sz);
19309652SMichael.Corcoran@Sun.COM 			kmem_free(cpu_map, sz);
19319652SMichael.Corcoran@Sun.COM 		}
19329652SMichael.Corcoran@Sun.COM 		cpu_map = new_map;
19339652SMichael.Corcoran@Sun.COM 	}
19349652SMichael.Corcoran@Sun.COM }
19359652SMichael.Corcoran@Sun.COM 
19369652SMichael.Corcoran@Sun.COM /*
19379652SMichael.Corcoran@Sun.COM  * Maintain mapping information among (cpu id, ACPI processor id, APIC id,
19389652SMichael.Corcoran@Sun.COM  * ACPI handle). The mapping table will be setup in two steps:
19399652SMichael.Corcoran@Sun.COM  * 1) acpica_add_processor_to_map() builds mapping among APIC id, ACPI
19409652SMichael.Corcoran@Sun.COM  *    processor id and ACPI object handle.
19419652SMichael.Corcoran@Sun.COM  * 2) acpica_map_cpu() builds mapping among cpu id and ACPI processor id.
194210394SMichael.Corcoran@Sun.COM  * On systems with which have ACPI device configuration for CPUs enabled,
194310394SMichael.Corcoran@Sun.COM  * acpica_map_cpu() will be called after acpica_add_processor_to_map(),
194410394SMichael.Corcoran@Sun.COM  * otherwise acpica_map_cpu() will be called before
194510394SMichael.Corcoran@Sun.COM  * acpica_add_processor_to_map().
19469652SMichael.Corcoran@Sun.COM  */
19479652SMichael.Corcoran@Sun.COM ACPI_STATUS
acpica_add_processor_to_map(UINT32 acpi_id,ACPI_HANDLE obj,UINT32 apic_id)19489652SMichael.Corcoran@Sun.COM acpica_add_processor_to_map(UINT32 acpi_id, ACPI_HANDLE obj, UINT32 apic_id)
19499652SMichael.Corcoran@Sun.COM {
19509652SMichael.Corcoran@Sun.COM 	int i;
19519652SMichael.Corcoran@Sun.COM 	ACPI_STATUS rc = AE_OK;
19529652SMichael.Corcoran@Sun.COM 	struct cpu_map_item *item = NULL;
19539652SMichael.Corcoran@Sun.COM 
19549652SMichael.Corcoran@Sun.COM 	ASSERT(obj != NULL);
19559652SMichael.Corcoran@Sun.COM 	if (obj == NULL) {
19569652SMichael.Corcoran@Sun.COM 		return (AE_ERROR);
19579652SMichael.Corcoran@Sun.COM 	}
19589652SMichael.Corcoran@Sun.COM 
19599652SMichael.Corcoran@Sun.COM 	mutex_enter(&cpu_map_lock);
19609652SMichael.Corcoran@Sun.COM 
19619652SMichael.Corcoran@Sun.COM 	/*
19629652SMichael.Corcoran@Sun.COM 	 * Special case for uppc
19639652SMichael.Corcoran@Sun.COM 	 * If we're a uppc system and ACPI device configuration for CPU has
19649652SMichael.Corcoran@Sun.COM 	 * been disabled, there won't be a CPU map yet because uppc psm doesn't
19659652SMichael.Corcoran@Sun.COM 	 * call acpica_map_cpu(). So create one and use the passed-in processor
19669652SMichael.Corcoran@Sun.COM 	 * as CPU 0
196710394SMichael.Corcoran@Sun.COM 	 * Assumption: the first CPU returned by
196810394SMichael.Corcoran@Sun.COM 	 * AcpiGetDevices/AcpiWalkNamespace will be the BSP.
196910394SMichael.Corcoran@Sun.COM 	 * Unfortunately there appears to be no good way to ASSERT this.
19709652SMichael.Corcoran@Sun.COM 	 */
19719652SMichael.Corcoran@Sun.COM 	if (cpu_map == NULL &&
19729652SMichael.Corcoran@Sun.COM 	    !acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
19739652SMichael.Corcoran@Sun.COM 		acpica_grow_cpu_map();
19749652SMichael.Corcoran@Sun.COM 		ASSERT(cpu_map != NULL);
19759652SMichael.Corcoran@Sun.COM 		item = kmem_zalloc(sizeof (*item), KM_SLEEP);
19769652SMichael.Corcoran@Sun.COM 		item->cpu_id = 0;
19779652SMichael.Corcoran@Sun.COM 		item->proc_id = acpi_id;
19789652SMichael.Corcoran@Sun.COM 		item->apic_id = apic_id;
19799652SMichael.Corcoran@Sun.COM 		item->obj = obj;
19809652SMichael.Corcoran@Sun.COM 		cpu_map[0] = item;
19819652SMichael.Corcoran@Sun.COM 		cpu_map_count = 1;
19829652SMichael.Corcoran@Sun.COM 		mutex_exit(&cpu_map_lock);
19839652SMichael.Corcoran@Sun.COM 		return (AE_OK);
19849652SMichael.Corcoran@Sun.COM 	}
19859652SMichael.Corcoran@Sun.COM 
19869652SMichael.Corcoran@Sun.COM 	for (i = 0; i < cpu_map_count; i++) {
19879652SMichael.Corcoran@Sun.COM 		if (cpu_map[i]->obj == obj) {
19889652SMichael.Corcoran@Sun.COM 			rc = AE_ALREADY_EXISTS;
19899652SMichael.Corcoran@Sun.COM 			break;
19909652SMichael.Corcoran@Sun.COM 		} else if (cpu_map[i]->proc_id == acpi_id) {
19919652SMichael.Corcoran@Sun.COM 			ASSERT(item == NULL);
19929652SMichael.Corcoran@Sun.COM 			item = cpu_map[i];
19939652SMichael.Corcoran@Sun.COM 		}
19949652SMichael.Corcoran@Sun.COM 	}
19959652SMichael.Corcoran@Sun.COM 
19969652SMichael.Corcoran@Sun.COM 	if (rc == AE_OK) {
19979652SMichael.Corcoran@Sun.COM 		if (item != NULL) {
19989652SMichael.Corcoran@Sun.COM 			/*
19999652SMichael.Corcoran@Sun.COM 			 * ACPI alias objects may cause more than one objects
20009652SMichael.Corcoran@Sun.COM 			 * with the same ACPI processor id, only remember the
20019652SMichael.Corcoran@Sun.COM 			 * the first object encountered.
20029652SMichael.Corcoran@Sun.COM 			 */
20039652SMichael.Corcoran@Sun.COM 			if (item->obj == NULL) {
20049652SMichael.Corcoran@Sun.COM 				item->obj = obj;
20059652SMichael.Corcoran@Sun.COM 				item->apic_id = apic_id;
20069652SMichael.Corcoran@Sun.COM 			} else {
20079652SMichael.Corcoran@Sun.COM 				rc = AE_ALREADY_EXISTS;
20089652SMichael.Corcoran@Sun.COM 			}
20099652SMichael.Corcoran@Sun.COM 		} else if (cpu_map_count >= INT_MAX / 2) {
20109652SMichael.Corcoran@Sun.COM 			rc = AE_NO_MEMORY;
20119652SMichael.Corcoran@Sun.COM 		} else {
20129652SMichael.Corcoran@Sun.COM 			acpica_grow_cpu_map();
20139652SMichael.Corcoran@Sun.COM 			ASSERT(cpu_map != NULL);
20149652SMichael.Corcoran@Sun.COM 			ASSERT(cpu_map_count < cpu_map_count_max);
20159652SMichael.Corcoran@Sun.COM 			item = kmem_zalloc(sizeof (*item), KM_SLEEP);
20169652SMichael.Corcoran@Sun.COM 			item->cpu_id = -1;
20179652SMichael.Corcoran@Sun.COM 			item->proc_id = acpi_id;
20189652SMichael.Corcoran@Sun.COM 			item->apic_id = apic_id;
20199652SMichael.Corcoran@Sun.COM 			item->obj = obj;
20209652SMichael.Corcoran@Sun.COM 			cpu_map[cpu_map_count] = item;
20219652SMichael.Corcoran@Sun.COM 			cpu_map_count++;
20229652SMichael.Corcoran@Sun.COM 		}
20239652SMichael.Corcoran@Sun.COM 	}
20249652SMichael.Corcoran@Sun.COM 
20259652SMichael.Corcoran@Sun.COM 	mutex_exit(&cpu_map_lock);
20269652SMichael.Corcoran@Sun.COM 
20279652SMichael.Corcoran@Sun.COM 	return (rc);
20289652SMichael.Corcoran@Sun.COM }
20299652SMichael.Corcoran@Sun.COM 
20309652SMichael.Corcoran@Sun.COM ACPI_STATUS
acpica_remove_processor_from_map(UINT32 acpi_id)20319652SMichael.Corcoran@Sun.COM acpica_remove_processor_from_map(UINT32 acpi_id)
20329652SMichael.Corcoran@Sun.COM {
20339652SMichael.Corcoran@Sun.COM 	int i;
20349652SMichael.Corcoran@Sun.COM 	ACPI_STATUS rc = AE_NOT_EXIST;
20359652SMichael.Corcoran@Sun.COM 
20369652SMichael.Corcoran@Sun.COM 	mutex_enter(&cpu_map_lock);
20379652SMichael.Corcoran@Sun.COM 	for (i = 0; i < cpu_map_count; i++) {
20389652SMichael.Corcoran@Sun.COM 		if (cpu_map[i]->proc_id != acpi_id) {
20399652SMichael.Corcoran@Sun.COM 			continue;
20409652SMichael.Corcoran@Sun.COM 		}
20419652SMichael.Corcoran@Sun.COM 		cpu_map[i]->obj = NULL;
20429652SMichael.Corcoran@Sun.COM 		/* Free item if no more reference to it. */
20439652SMichael.Corcoran@Sun.COM 		if (cpu_map[i]->cpu_id == -1) {
20449652SMichael.Corcoran@Sun.COM 			kmem_free(cpu_map[i], sizeof (struct cpu_map_item));
20459652SMichael.Corcoran@Sun.COM 			cpu_map[i] = NULL;
20469652SMichael.Corcoran@Sun.COM 			cpu_map_count--;
20479652SMichael.Corcoran@Sun.COM 			if (i != cpu_map_count) {
20489652SMichael.Corcoran@Sun.COM 				cpu_map[i] = cpu_map[cpu_map_count];
20499652SMichael.Corcoran@Sun.COM 				cpu_map[cpu_map_count] = NULL;
20509652SMichael.Corcoran@Sun.COM 			}
20519652SMichael.Corcoran@Sun.COM 		}
20529652SMichael.Corcoran@Sun.COM 		rc = AE_OK;
20539652SMichael.Corcoran@Sun.COM 		break;
20549652SMichael.Corcoran@Sun.COM 	}
20559652SMichael.Corcoran@Sun.COM 	mutex_exit(&cpu_map_lock);
20569652SMichael.Corcoran@Sun.COM 
20579652SMichael.Corcoran@Sun.COM 	return (rc);
20589652SMichael.Corcoran@Sun.COM }
20599652SMichael.Corcoran@Sun.COM 
20609652SMichael.Corcoran@Sun.COM ACPI_STATUS
acpica_map_cpu(processorid_t cpuid,UINT32 acpi_id)20619652SMichael.Corcoran@Sun.COM acpica_map_cpu(processorid_t cpuid, UINT32 acpi_id)
20629652SMichael.Corcoran@Sun.COM {
20639652SMichael.Corcoran@Sun.COM 	int i;
20649652SMichael.Corcoran@Sun.COM 	ACPI_STATUS rc = AE_OK;
20659652SMichael.Corcoran@Sun.COM 	struct cpu_map_item *item = NULL;
20669652SMichael.Corcoran@Sun.COM 
20679652SMichael.Corcoran@Sun.COM 	ASSERT(cpuid != -1);
20689652SMichael.Corcoran@Sun.COM 	if (cpuid == -1) {
20699652SMichael.Corcoran@Sun.COM 		return (AE_ERROR);
20709652SMichael.Corcoran@Sun.COM 	}
20719652SMichael.Corcoran@Sun.COM 
20729652SMichael.Corcoran@Sun.COM 	mutex_enter(&cpu_map_lock);
207310394SMichael.Corcoran@Sun.COM 	cpu_map_called = 1;
20749652SMichael.Corcoran@Sun.COM 	for (i = 0; i < cpu_map_count; i++) {
20759652SMichael.Corcoran@Sun.COM 		if (cpu_map[i]->cpu_id == cpuid) {
20769652SMichael.Corcoran@Sun.COM 			rc = AE_ALREADY_EXISTS;
20779652SMichael.Corcoran@Sun.COM 			break;
20789652SMichael.Corcoran@Sun.COM 		} else if (cpu_map[i]->proc_id == acpi_id) {
20799652SMichael.Corcoran@Sun.COM 			ASSERT(item == NULL);
20809652SMichael.Corcoran@Sun.COM 			item = cpu_map[i];
20819652SMichael.Corcoran@Sun.COM 		}
20829652SMichael.Corcoran@Sun.COM 	}
20839652SMichael.Corcoran@Sun.COM 	if (rc == AE_OK) {
20849652SMichael.Corcoran@Sun.COM 		if (item != NULL) {
20859652SMichael.Corcoran@Sun.COM 			if (item->cpu_id == -1) {
20869652SMichael.Corcoran@Sun.COM 				item->cpu_id = cpuid;
20879652SMichael.Corcoran@Sun.COM 			} else {
20889652SMichael.Corcoran@Sun.COM 				rc = AE_ALREADY_EXISTS;
20899652SMichael.Corcoran@Sun.COM 			}
20909652SMichael.Corcoran@Sun.COM 		} else if (cpu_map_count >= INT_MAX / 2) {
20919652SMichael.Corcoran@Sun.COM 			rc = AE_NO_MEMORY;
20929652SMichael.Corcoran@Sun.COM 		} else {
20939652SMichael.Corcoran@Sun.COM 			acpica_grow_cpu_map();
20949652SMichael.Corcoran@Sun.COM 			ASSERT(cpu_map != NULL);
20959652SMichael.Corcoran@Sun.COM 			ASSERT(cpu_map_count < cpu_map_count_max);
20969652SMichael.Corcoran@Sun.COM 			item = kmem_zalloc(sizeof (*item), KM_SLEEP);
20979652SMichael.Corcoran@Sun.COM 			item->cpu_id = cpuid;
20989652SMichael.Corcoran@Sun.COM 			item->proc_id = acpi_id;
20999652SMichael.Corcoran@Sun.COM 			item->apic_id = UINT32_MAX;
21009652SMichael.Corcoran@Sun.COM 			item->obj = NULL;
21019652SMichael.Corcoran@Sun.COM 			cpu_map[cpu_map_count] = item;
21029652SMichael.Corcoran@Sun.COM 			cpu_map_count++;
21039652SMichael.Corcoran@Sun.COM 		}
21049652SMichael.Corcoran@Sun.COM 	}
21059652SMichael.Corcoran@Sun.COM 	mutex_exit(&cpu_map_lock);
21069652SMichael.Corcoran@Sun.COM 
21079652SMichael.Corcoran@Sun.COM 	return (rc);
21089652SMichael.Corcoran@Sun.COM }
21099652SMichael.Corcoran@Sun.COM 
21109652SMichael.Corcoran@Sun.COM ACPI_STATUS
acpica_unmap_cpu(processorid_t cpuid)21119652SMichael.Corcoran@Sun.COM acpica_unmap_cpu(processorid_t cpuid)
21129652SMichael.Corcoran@Sun.COM {
21139652SMichael.Corcoran@Sun.COM 	int i;
21149652SMichael.Corcoran@Sun.COM 	ACPI_STATUS rc = AE_NOT_EXIST;
21159652SMichael.Corcoran@Sun.COM 
21169652SMichael.Corcoran@Sun.COM 	ASSERT(cpuid != -1);
21179652SMichael.Corcoran@Sun.COM 	if (cpuid == -1) {
21189652SMichael.Corcoran@Sun.COM 		return (rc);
21199652SMichael.Corcoran@Sun.COM 	}
21209652SMichael.Corcoran@Sun.COM 
21219652SMichael.Corcoran@Sun.COM 	mutex_enter(&cpu_map_lock);
21229652SMichael.Corcoran@Sun.COM 	for (i = 0; i < cpu_map_count; i++) {
21239652SMichael.Corcoran@Sun.COM 		if (cpu_map[i]->cpu_id != cpuid) {
21249652SMichael.Corcoran@Sun.COM 			continue;
21259652SMichael.Corcoran@Sun.COM 		}
21269652SMichael.Corcoran@Sun.COM 		cpu_map[i]->cpu_id = -1;
21279652SMichael.Corcoran@Sun.COM 		/* Free item if no more reference. */
21289652SMichael.Corcoran@Sun.COM 		if (cpu_map[i]->obj == NULL) {
21299652SMichael.Corcoran@Sun.COM 			kmem_free(cpu_map[i], sizeof (struct cpu_map_item));
21309652SMichael.Corcoran@Sun.COM 			cpu_map[i] = NULL;
21319652SMichael.Corcoran@Sun.COM 			cpu_map_count--;
21329652SMichael.Corcoran@Sun.COM 			if (i != cpu_map_count) {
21339652SMichael.Corcoran@Sun.COM 				cpu_map[i] = cpu_map[cpu_map_count];
21349652SMichael.Corcoran@Sun.COM 				cpu_map[cpu_map_count] = NULL;
21359652SMichael.Corcoran@Sun.COM 			}
21369652SMichael.Corcoran@Sun.COM 		}
21379652SMichael.Corcoran@Sun.COM 		rc = AE_OK;
21389652SMichael.Corcoran@Sun.COM 		break;
21399652SMichael.Corcoran@Sun.COM 	}
21409652SMichael.Corcoran@Sun.COM 	mutex_exit(&cpu_map_lock);
21419652SMichael.Corcoran@Sun.COM 
21429652SMichael.Corcoran@Sun.COM 	return (rc);
21439652SMichael.Corcoran@Sun.COM }
21449652SMichael.Corcoran@Sun.COM 
21459652SMichael.Corcoran@Sun.COM ACPI_STATUS
acpica_get_cpu_object_by_cpuid(processorid_t cpuid,ACPI_HANDLE * hdlp)21469652SMichael.Corcoran@Sun.COM acpica_get_cpu_object_by_cpuid(processorid_t cpuid, ACPI_HANDLE *hdlp)
21479652SMichael.Corcoran@Sun.COM {
21489652SMichael.Corcoran@Sun.COM 	int i;
21499652SMichael.Corcoran@Sun.COM 	ACPI_STATUS rc = AE_NOT_EXIST;
21509652SMichael.Corcoran@Sun.COM 
21519652SMichael.Corcoran@Sun.COM 	ASSERT(cpuid != -1);
21529652SMichael.Corcoran@Sun.COM 	if (cpuid == -1) {
21539652SMichael.Corcoran@Sun.COM 		return (rc);
21549652SMichael.Corcoran@Sun.COM 	}
21559652SMichael.Corcoran@Sun.COM 
21569652SMichael.Corcoran@Sun.COM 	mutex_enter(&cpu_map_lock);
21579652SMichael.Corcoran@Sun.COM 	for (i = 0; i < cpu_map_count; i++) {
21589652SMichael.Corcoran@Sun.COM 		if (cpu_map[i]->cpu_id == cpuid && cpu_map[i]->obj != NULL) {
21599652SMichael.Corcoran@Sun.COM 			*hdlp = cpu_map[i]->obj;
21609652SMichael.Corcoran@Sun.COM 			rc = AE_OK;
21619652SMichael.Corcoran@Sun.COM 			break;
21629652SMichael.Corcoran@Sun.COM 		}
21639652SMichael.Corcoran@Sun.COM 	}
21649652SMichael.Corcoran@Sun.COM 	mutex_exit(&cpu_map_lock);
21659652SMichael.Corcoran@Sun.COM 
21669652SMichael.Corcoran@Sun.COM 	return (rc);
21679652SMichael.Corcoran@Sun.COM }
21689652SMichael.Corcoran@Sun.COM 
21699652SMichael.Corcoran@Sun.COM ACPI_STATUS
acpica_get_cpu_object_by_procid(UINT32 procid,ACPI_HANDLE * hdlp)21709652SMichael.Corcoran@Sun.COM acpica_get_cpu_object_by_procid(UINT32 procid, ACPI_HANDLE *hdlp)
21719652SMichael.Corcoran@Sun.COM {
21729652SMichael.Corcoran@Sun.COM 	int i;
21739652SMichael.Corcoran@Sun.COM 	ACPI_STATUS rc = AE_NOT_EXIST;
21749652SMichael.Corcoran@Sun.COM 
21759652SMichael.Corcoran@Sun.COM 	mutex_enter(&cpu_map_lock);
21769652SMichael.Corcoran@Sun.COM 	for (i = 0; i < cpu_map_count; i++) {
21779652SMichael.Corcoran@Sun.COM 		if (cpu_map[i]->proc_id == procid && cpu_map[i]->obj != NULL) {
21789652SMichael.Corcoran@Sun.COM 			*hdlp = cpu_map[i]->obj;
21799652SMichael.Corcoran@Sun.COM 			rc = AE_OK;
21809652SMichael.Corcoran@Sun.COM 			break;
21819652SMichael.Corcoran@Sun.COM 		}
21829652SMichael.Corcoran@Sun.COM 	}
21839652SMichael.Corcoran@Sun.COM 	mutex_exit(&cpu_map_lock);
21849652SMichael.Corcoran@Sun.COM 
21859652SMichael.Corcoran@Sun.COM 	return (rc);
21869652SMichael.Corcoran@Sun.COM }
21879652SMichael.Corcoran@Sun.COM 
21889652SMichael.Corcoran@Sun.COM ACPI_STATUS
acpica_get_cpu_object_by_apicid(UINT32 apicid,ACPI_HANDLE * hdlp)21899652SMichael.Corcoran@Sun.COM acpica_get_cpu_object_by_apicid(UINT32 apicid, ACPI_HANDLE *hdlp)
21909652SMichael.Corcoran@Sun.COM {
21919652SMichael.Corcoran@Sun.COM 	int i;
21929652SMichael.Corcoran@Sun.COM 	ACPI_STATUS rc = AE_NOT_EXIST;
21939652SMichael.Corcoran@Sun.COM 
21949652SMichael.Corcoran@Sun.COM 	ASSERT(apicid != UINT32_MAX);
21959652SMichael.Corcoran@Sun.COM 	if (apicid == UINT32_MAX) {
21969652SMichael.Corcoran@Sun.COM 		return (rc);
21979652SMichael.Corcoran@Sun.COM 	}
21989652SMichael.Corcoran@Sun.COM 
21999652SMichael.Corcoran@Sun.COM 	mutex_enter(&cpu_map_lock);
22009652SMichael.Corcoran@Sun.COM 	for (i = 0; i < cpu_map_count; i++) {
22019652SMichael.Corcoran@Sun.COM 		if (cpu_map[i]->apic_id == apicid && cpu_map[i]->obj != NULL) {
22029652SMichael.Corcoran@Sun.COM 			*hdlp = cpu_map[i]->obj;
22039652SMichael.Corcoran@Sun.COM 			rc = AE_OK;
22049652SMichael.Corcoran@Sun.COM 			break;
22059652SMichael.Corcoran@Sun.COM 		}
22069652SMichael.Corcoran@Sun.COM 	}
22079652SMichael.Corcoran@Sun.COM 	mutex_exit(&cpu_map_lock);
22089652SMichael.Corcoran@Sun.COM 
22099652SMichael.Corcoran@Sun.COM 	return (rc);
22109652SMichael.Corcoran@Sun.COM }
22119652SMichael.Corcoran@Sun.COM 
2212*12004Sjiang.liu@intel.com ACPI_STATUS
acpica_get_cpu_id_by_object(ACPI_HANDLE hdl,processorid_t * cpuidp)2213*12004Sjiang.liu@intel.com acpica_get_cpu_id_by_object(ACPI_HANDLE hdl, processorid_t *cpuidp)
2214*12004Sjiang.liu@intel.com {
2215*12004Sjiang.liu@intel.com 	int i;
2216*12004Sjiang.liu@intel.com 	ACPI_STATUS rc = AE_NOT_EXIST;
2217*12004Sjiang.liu@intel.com 
2218*12004Sjiang.liu@intel.com 	ASSERT(cpuidp != NULL);
2219*12004Sjiang.liu@intel.com 	if (hdl == NULL || cpuidp == NULL) {
2220*12004Sjiang.liu@intel.com 		return (rc);
2221*12004Sjiang.liu@intel.com 	}
2222*12004Sjiang.liu@intel.com 
2223*12004Sjiang.liu@intel.com 	*cpuidp = -1;
2224*12004Sjiang.liu@intel.com 	mutex_enter(&cpu_map_lock);
2225*12004Sjiang.liu@intel.com 	for (i = 0; i < cpu_map_count; i++) {
2226*12004Sjiang.liu@intel.com 		if (cpu_map[i]->obj == hdl && cpu_map[i]->cpu_id != -1) {
2227*12004Sjiang.liu@intel.com 			*cpuidp = cpu_map[i]->cpu_id;
2228*12004Sjiang.liu@intel.com 			rc = AE_OK;
2229*12004Sjiang.liu@intel.com 			break;
2230*12004Sjiang.liu@intel.com 		}
2231*12004Sjiang.liu@intel.com 	}
2232*12004Sjiang.liu@intel.com 	mutex_exit(&cpu_map_lock);
2233*12004Sjiang.liu@intel.com 
2234*12004Sjiang.liu@intel.com 	return (rc);
2235*12004Sjiang.liu@intel.com }
2236*12004Sjiang.liu@intel.com 
2237*12004Sjiang.liu@intel.com ACPI_STATUS
acpica_get_apicid_by_object(ACPI_HANDLE hdl,UINT32 * rp)2238*12004Sjiang.liu@intel.com acpica_get_apicid_by_object(ACPI_HANDLE hdl, UINT32 *rp)
2239*12004Sjiang.liu@intel.com {
2240*12004Sjiang.liu@intel.com 	int i;
2241*12004Sjiang.liu@intel.com 	ACPI_STATUS rc = AE_NOT_EXIST;
2242*12004Sjiang.liu@intel.com 
2243*12004Sjiang.liu@intel.com 	ASSERT(rp != NULL);
2244*12004Sjiang.liu@intel.com 	if (hdl == NULL || rp == NULL) {
2245*12004Sjiang.liu@intel.com 		return (rc);
2246*12004Sjiang.liu@intel.com 	}
2247*12004Sjiang.liu@intel.com 
2248*12004Sjiang.liu@intel.com 	*rp = UINT32_MAX;
2249*12004Sjiang.liu@intel.com 	mutex_enter(&cpu_map_lock);
2250*12004Sjiang.liu@intel.com 	for (i = 0; i < cpu_map_count; i++) {
2251*12004Sjiang.liu@intel.com 		if (cpu_map[i]->obj == hdl &&
2252*12004Sjiang.liu@intel.com 		    cpu_map[i]->apic_id != UINT32_MAX) {
2253*12004Sjiang.liu@intel.com 			*rp = cpu_map[i]->apic_id;
2254*12004Sjiang.liu@intel.com 			rc = AE_OK;
2255*12004Sjiang.liu@intel.com 			break;
2256*12004Sjiang.liu@intel.com 		}
2257*12004Sjiang.liu@intel.com 	}
2258*12004Sjiang.liu@intel.com 	mutex_exit(&cpu_map_lock);
2259*12004Sjiang.liu@intel.com 
2260*12004Sjiang.liu@intel.com 	return (rc);
2261*12004Sjiang.liu@intel.com }
2262*12004Sjiang.liu@intel.com 
2263*12004Sjiang.liu@intel.com ACPI_STATUS
acpica_get_procid_by_object(ACPI_HANDLE hdl,UINT32 * rp)2264*12004Sjiang.liu@intel.com acpica_get_procid_by_object(ACPI_HANDLE hdl, UINT32 *rp)
2265*12004Sjiang.liu@intel.com {
2266*12004Sjiang.liu@intel.com 	int i;
2267*12004Sjiang.liu@intel.com 	ACPI_STATUS rc = AE_NOT_EXIST;
2268*12004Sjiang.liu@intel.com 
2269*12004Sjiang.liu@intel.com 	ASSERT(rp != NULL);
2270*12004Sjiang.liu@intel.com 	if (hdl == NULL || rp == NULL) {
2271*12004Sjiang.liu@intel.com 		return (rc);
2272*12004Sjiang.liu@intel.com 	}
2273*12004Sjiang.liu@intel.com 
2274*12004Sjiang.liu@intel.com 	*rp = UINT32_MAX;
2275*12004Sjiang.liu@intel.com 	mutex_enter(&cpu_map_lock);
2276*12004Sjiang.liu@intel.com 	for (i = 0; i < cpu_map_count; i++) {
2277*12004Sjiang.liu@intel.com 		if (cpu_map[i]->obj == hdl) {
2278*12004Sjiang.liu@intel.com 			*rp = cpu_map[i]->proc_id;
2279*12004Sjiang.liu@intel.com 			rc = AE_OK;
2280*12004Sjiang.liu@intel.com 			break;
2281*12004Sjiang.liu@intel.com 		}
2282*12004Sjiang.liu@intel.com 	}
2283*12004Sjiang.liu@intel.com 	mutex_exit(&cpu_map_lock);
2284*12004Sjiang.liu@intel.com 
2285*12004Sjiang.liu@intel.com 	return (rc);
2286*12004Sjiang.liu@intel.com }
2287*12004Sjiang.liu@intel.com 
22889652SMichael.Corcoran@Sun.COM void
acpica_set_core_feature(uint64_t features)22899652SMichael.Corcoran@Sun.COM acpica_set_core_feature(uint64_t features)
22909652SMichael.Corcoran@Sun.COM {
22919652SMichael.Corcoran@Sun.COM 	atomic_or_64(&acpica_core_features, features);
22929652SMichael.Corcoran@Sun.COM }
22939652SMichael.Corcoran@Sun.COM 
22949652SMichael.Corcoran@Sun.COM void
acpica_clear_core_feature(uint64_t features)22959652SMichael.Corcoran@Sun.COM acpica_clear_core_feature(uint64_t features)
22969652SMichael.Corcoran@Sun.COM {
22979652SMichael.Corcoran@Sun.COM 	atomic_and_64(&acpica_core_features, ~features);
22989652SMichael.Corcoran@Sun.COM }
22999652SMichael.Corcoran@Sun.COM 
23009652SMichael.Corcoran@Sun.COM uint64_t
acpica_get_core_feature(uint64_t features)23019652SMichael.Corcoran@Sun.COM acpica_get_core_feature(uint64_t features)
23029652SMichael.Corcoran@Sun.COM {
23039652SMichael.Corcoran@Sun.COM 	return (acpica_core_features & features);
23049652SMichael.Corcoran@Sun.COM }
23059652SMichael.Corcoran@Sun.COM 
23069652SMichael.Corcoran@Sun.COM void
acpica_set_devcfg_feature(uint64_t features)23079652SMichael.Corcoran@Sun.COM acpica_set_devcfg_feature(uint64_t features)
23089652SMichael.Corcoran@Sun.COM {
23099652SMichael.Corcoran@Sun.COM 	atomic_or_64(&acpica_devcfg_features, features);
23109652SMichael.Corcoran@Sun.COM }
23119652SMichael.Corcoran@Sun.COM 
23129652SMichael.Corcoran@Sun.COM void
acpica_clear_devcfg_feature(uint64_t features)23139652SMichael.Corcoran@Sun.COM acpica_clear_devcfg_feature(uint64_t features)
23149652SMichael.Corcoran@Sun.COM {
23159652SMichael.Corcoran@Sun.COM 	atomic_and_64(&acpica_devcfg_features, ~features);
23169652SMichael.Corcoran@Sun.COM }
23179652SMichael.Corcoran@Sun.COM 
23189652SMichael.Corcoran@Sun.COM uint64_t
acpica_get_devcfg_feature(uint64_t features)23199652SMichael.Corcoran@Sun.COM acpica_get_devcfg_feature(uint64_t features)
23209652SMichael.Corcoran@Sun.COM {
23219652SMichael.Corcoran@Sun.COM 	return (acpica_devcfg_features & features);
23224667Smh27603 }
23238906SEric.Saxe@Sun.COM 
23248906SEric.Saxe@Sun.COM void
acpica_get_global_FADT(ACPI_TABLE_FADT ** gbl_FADT)23258906SEric.Saxe@Sun.COM acpica_get_global_FADT(ACPI_TABLE_FADT **gbl_FADT)
23268906SEric.Saxe@Sun.COM {
23278906SEric.Saxe@Sun.COM 	*gbl_FADT = &AcpiGbl_FADT;
23288906SEric.Saxe@Sun.COM }
232910147SMark.Haywood@Sun.COM 
233010147SMark.Haywood@Sun.COM void
acpica_write_cpupm_capabilities(boolean_t pstates,boolean_t cstates)233110147SMark.Haywood@Sun.COM acpica_write_cpupm_capabilities(boolean_t pstates, boolean_t cstates)
233210147SMark.Haywood@Sun.COM {
233310147SMark.Haywood@Sun.COM 	if (pstates && AcpiGbl_FADT.PstateControl != 0)
233410147SMark.Haywood@Sun.COM 		(void) AcpiHwRegisterWrite(ACPI_REGISTER_SMI_COMMAND_BLOCK,
233510147SMark.Haywood@Sun.COM 		    AcpiGbl_FADT.PstateControl);
233610147SMark.Haywood@Sun.COM 
233710147SMark.Haywood@Sun.COM 	if (cstates && AcpiGbl_FADT.CstControl != 0)
233810147SMark.Haywood@Sun.COM 		(void) AcpiHwRegisterWrite(ACPI_REGISTER_SMI_COMMAND_BLOCK,
233910147SMark.Haywood@Sun.COM 		    AcpiGbl_FADT.CstControl);
234010147SMark.Haywood@Sun.COM }
2341