xref: /onnv-gate/usr/src/uts/i86pc/io/amd_iommu/amd_iommu_acpi.c (revision 12203:bc736fbbcb75)
110535SVikram.Hegde@Sun.COM /*
210535SVikram.Hegde@Sun.COM  * CDDL HEADER START
310535SVikram.Hegde@Sun.COM  *
410535SVikram.Hegde@Sun.COM  * The contents of this file are subject to the terms of the
510535SVikram.Hegde@Sun.COM  * Common Development and Distribution License (the "License").
610535SVikram.Hegde@Sun.COM  * You may not use this file except in compliance with the License.
710535SVikram.Hegde@Sun.COM  *
810535SVikram.Hegde@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910535SVikram.Hegde@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1010535SVikram.Hegde@Sun.COM  * See the License for the specific language governing permissions
1110535SVikram.Hegde@Sun.COM  * and limitations under the License.
1210535SVikram.Hegde@Sun.COM  *
1310535SVikram.Hegde@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1410535SVikram.Hegde@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510535SVikram.Hegde@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1610535SVikram.Hegde@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1710535SVikram.Hegde@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1810535SVikram.Hegde@Sun.COM  *
1910535SVikram.Hegde@Sun.COM  * CDDL HEADER END
2010535SVikram.Hegde@Sun.COM  */
2110535SVikram.Hegde@Sun.COM 
2210535SVikram.Hegde@Sun.COM /*
23*12203SJerry.Gilliam@Sun.COM  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2410535SVikram.Hegde@Sun.COM  */
2510535SVikram.Hegde@Sun.COM 
2610535SVikram.Hegde@Sun.COM #include "amd_iommu_acpi.h"
2710535SVikram.Hegde@Sun.COM #include "amd_iommu_impl.h"
2810535SVikram.Hegde@Sun.COM 
2910535SVikram.Hegde@Sun.COM static int create_acpi_hash(amd_iommu_acpi_t *acpi);
3010535SVikram.Hegde@Sun.COM static void amd_iommu_acpi_table_fini(amd_iommu_acpi_t **acpipp);
3110535SVikram.Hegde@Sun.COM 
3210535SVikram.Hegde@Sun.COM static void dump_acpi_aliases(void);
3310535SVikram.Hegde@Sun.COM 
3410535SVikram.Hegde@Sun.COM 
3510535SVikram.Hegde@Sun.COM /*
3610535SVikram.Hegde@Sun.COM  * Globals
3710535SVikram.Hegde@Sun.COM  */
3810535SVikram.Hegde@Sun.COM static amd_iommu_acpi_global_t *amd_iommu_acpi_global;
3910535SVikram.Hegde@Sun.COM static amd_iommu_acpi_ivhd_t **amd_iommu_acpi_ivhd_hash;
4010535SVikram.Hegde@Sun.COM static amd_iommu_acpi_ivmd_t **amd_iommu_acpi_ivmd_hash;
4110535SVikram.Hegde@Sun.COM 
4210535SVikram.Hegde@Sun.COM static int
type_byte_size(char * cp)4310535SVikram.Hegde@Sun.COM type_byte_size(char *cp)
4410535SVikram.Hegde@Sun.COM {
4510535SVikram.Hegde@Sun.COM 	uint8_t type8 = *((uint8_t *)cp);
4610535SVikram.Hegde@Sun.COM 	uint8_t len_bits;
4710535SVikram.Hegde@Sun.COM 
4810535SVikram.Hegde@Sun.COM 	len_bits = AMD_IOMMU_REG_GET8(&type8, AMD_IOMMU_ACPI_DEVENTRY_LEN);
4910535SVikram.Hegde@Sun.COM 
5010535SVikram.Hegde@Sun.COM 	switch (len_bits) {
5110535SVikram.Hegde@Sun.COM 	case 0:
5210535SVikram.Hegde@Sun.COM 			return (4);
5310535SVikram.Hegde@Sun.COM 	case 1:
5410535SVikram.Hegde@Sun.COM 			return (8);
5510535SVikram.Hegde@Sun.COM 	case 2:
5610535SVikram.Hegde@Sun.COM 			return (16);
5710535SVikram.Hegde@Sun.COM 	case 3:
5810535SVikram.Hegde@Sun.COM 			return (32);
5910535SVikram.Hegde@Sun.COM 	default:
6010535SVikram.Hegde@Sun.COM 			cmn_err(CE_WARN, "%s: Invalid deventry len: %d",
6110535SVikram.Hegde@Sun.COM 			    amd_iommu_modname, len_bits);
6210535SVikram.Hegde@Sun.COM 			return (len_bits);
6310535SVikram.Hegde@Sun.COM 	}
6410535SVikram.Hegde@Sun.COM 	/*NOTREACHED*/
6510535SVikram.Hegde@Sun.COM }
6610535SVikram.Hegde@Sun.COM 
6710535SVikram.Hegde@Sun.COM static void
process_4byte_deventry(ivhd_container_t * c,char * cp)6810535SVikram.Hegde@Sun.COM process_4byte_deventry(ivhd_container_t *c, char *cp)
6910535SVikram.Hegde@Sun.COM {
7010535SVikram.Hegde@Sun.COM 	int entry_type = *((uint8_t *)cp);
7110535SVikram.Hegde@Sun.COM 	ivhd_deventry_t deventry = {0};
7210535SVikram.Hegde@Sun.COM 	ivhd_deventry_t *devp;
7310535SVikram.Hegde@Sun.COM 	uint8_t datsetting8;
7410535SVikram.Hegde@Sun.COM 	align_16_t al = {0};
7510535SVikram.Hegde@Sun.COM 	int i;
7610535SVikram.Hegde@Sun.COM 
7710535SVikram.Hegde@Sun.COM 	/* 4 byte entry */
7810535SVikram.Hegde@Sun.COM 	deventry.idev_len = 4;
7910535SVikram.Hegde@Sun.COM 	deventry.idev_deviceid = -1;
8010535SVikram.Hegde@Sun.COM 	deventry.idev_src_deviceid = -1;
8110535SVikram.Hegde@Sun.COM 
8210535SVikram.Hegde@Sun.COM 	for (i = 0; i < 2; i++) {
8310535SVikram.Hegde@Sun.COM 		al.ent8[i] = *((uint8_t *)&cp[i + 1]);
8410535SVikram.Hegde@Sun.COM 	}
8510535SVikram.Hegde@Sun.COM 
8610535SVikram.Hegde@Sun.COM 	switch (entry_type) {
8710535SVikram.Hegde@Sun.COM 	case 1:
8810535SVikram.Hegde@Sun.COM 		deventry.idev_type = DEVENTRY_ALL;
8910535SVikram.Hegde@Sun.COM 		break;
9010535SVikram.Hegde@Sun.COM 	case 2:
9110535SVikram.Hegde@Sun.COM 		deventry.idev_type = DEVENTRY_SELECT;
9210535SVikram.Hegde@Sun.COM 		deventry.idev_deviceid = al.ent16;
9310535SVikram.Hegde@Sun.COM 		break;
9410535SVikram.Hegde@Sun.COM 	case 3:
9510535SVikram.Hegde@Sun.COM 		deventry.idev_type = DEVENTRY_RANGE;
9610535SVikram.Hegde@Sun.COM 		deventry.idev_deviceid = al.ent16;
9710535SVikram.Hegde@Sun.COM 		break;
9810535SVikram.Hegde@Sun.COM 	case 4:
9910535SVikram.Hegde@Sun.COM 		deventry.idev_type = DEVENTRY_RANGE_END;
10010535SVikram.Hegde@Sun.COM 		deventry.idev_deviceid = al.ent16;
10110535SVikram.Hegde@Sun.COM 		ASSERT(cp[3] == 0);
10210535SVikram.Hegde@Sun.COM 		break;
10310535SVikram.Hegde@Sun.COM 	case 0:
10410535SVikram.Hegde@Sun.COM 		ASSERT(al.ent16 == 0);
10510535SVikram.Hegde@Sun.COM 		ASSERT(cp[3] == 0);
10610535SVikram.Hegde@Sun.COM 	default:
10710535SVikram.Hegde@Sun.COM 		return;
10810535SVikram.Hegde@Sun.COM 	}
10910535SVikram.Hegde@Sun.COM 
11010535SVikram.Hegde@Sun.COM 
11110535SVikram.Hegde@Sun.COM 	devp = kmem_alloc(sizeof (ivhd_deventry_t), KM_SLEEP);
11210535SVikram.Hegde@Sun.COM 	*devp = deventry;
11310535SVikram.Hegde@Sun.COM 
11410535SVikram.Hegde@Sun.COM 	if (c->ivhdc_first_deventry == NULL)
11510535SVikram.Hegde@Sun.COM 		c->ivhdc_first_deventry =  devp;
11610535SVikram.Hegde@Sun.COM 	else
11710535SVikram.Hegde@Sun.COM 		c->ivhdc_last_deventry->idev_next = devp;
11810535SVikram.Hegde@Sun.COM 
11910535SVikram.Hegde@Sun.COM 	c->ivhdc_last_deventry = devp;
12010535SVikram.Hegde@Sun.COM 
12110535SVikram.Hegde@Sun.COM 	if (entry_type == 4)
12210535SVikram.Hegde@Sun.COM 		return;
12310535SVikram.Hegde@Sun.COM 
12410535SVikram.Hegde@Sun.COM 	datsetting8 = (*((uint8_t *)&cp[3]));
12510535SVikram.Hegde@Sun.COM 
12610535SVikram.Hegde@Sun.COM 	devp->idev_Lint1Pass = AMD_IOMMU_REG_GET8(&datsetting8,
12710535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_LINT1PASS);
12810535SVikram.Hegde@Sun.COM 
12910535SVikram.Hegde@Sun.COM 	devp->idev_Lint0Pass = AMD_IOMMU_REG_GET8(&datsetting8,
13010535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_LINT0PASS);
13110535SVikram.Hegde@Sun.COM 
13210535SVikram.Hegde@Sun.COM 	devp->idev_SysMgt = AMD_IOMMU_REG_GET8(&datsetting8,
13310535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_SYSMGT);
13410535SVikram.Hegde@Sun.COM 
13510535SVikram.Hegde@Sun.COM 	ASSERT(AMD_IOMMU_REG_GET8(&datsetting8,
13610535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_DATRSV) == 0);
13710535SVikram.Hegde@Sun.COM 
13810535SVikram.Hegde@Sun.COM 	devp->idev_NMIPass = AMD_IOMMU_REG_GET8(&datsetting8,
13910535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_NMIPASS);
14010535SVikram.Hegde@Sun.COM 
14110535SVikram.Hegde@Sun.COM 	devp->idev_ExtIntPass = AMD_IOMMU_REG_GET8(&datsetting8,
14210535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_EXTINTPASS);
14310535SVikram.Hegde@Sun.COM 
14410535SVikram.Hegde@Sun.COM 	devp->idev_INITPass = AMD_IOMMU_REG_GET8(&datsetting8,
14510535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_INITPASS);
14610535SVikram.Hegde@Sun.COM }
14710535SVikram.Hegde@Sun.COM 
14810535SVikram.Hegde@Sun.COM static void
process_8byte_deventry(ivhd_container_t * c,char * cp)14910535SVikram.Hegde@Sun.COM process_8byte_deventry(ivhd_container_t *c, char *cp)
15010535SVikram.Hegde@Sun.COM {
15110535SVikram.Hegde@Sun.COM 	uint8_t datsetting8;
15210535SVikram.Hegde@Sun.COM 	int entry_type = (uint8_t)*cp;
15310535SVikram.Hegde@Sun.COM 	ivhd_deventry_t deventry = {0};
15410535SVikram.Hegde@Sun.COM 	ivhd_deventry_t *devp;
15510535SVikram.Hegde@Sun.COM 	align_16_t al1 = {0};
15610535SVikram.Hegde@Sun.COM 	align_16_t al2 = {0};
15710535SVikram.Hegde@Sun.COM 	align_32_t al3 = {0};
15810535SVikram.Hegde@Sun.COM 	int i;
15910535SVikram.Hegde@Sun.COM 
16010535SVikram.Hegde@Sun.COM 	/* Length is 8 bytes */
16110535SVikram.Hegde@Sun.COM 	deventry.idev_len = 8;
16210535SVikram.Hegde@Sun.COM 	deventry.idev_deviceid = -1;
16310535SVikram.Hegde@Sun.COM 	deventry.idev_src_deviceid = -1;
16410535SVikram.Hegde@Sun.COM 
16510535SVikram.Hegde@Sun.COM 	for (i = 0; i < 2; i++) {
16610535SVikram.Hegde@Sun.COM 		al1.ent8[i] = *((uint8_t *)&cp[i+1]);
16710535SVikram.Hegde@Sun.COM 		al2.ent8[i] = *((uint8_t *)&cp[i+5]);
16810535SVikram.Hegde@Sun.COM 	}
16910535SVikram.Hegde@Sun.COM 
17010535SVikram.Hegde@Sun.COM 	datsetting8 = *((uint8_t *)&cp[3]);
17110535SVikram.Hegde@Sun.COM 
17210535SVikram.Hegde@Sun.COM 	switch (entry_type) {
17310535SVikram.Hegde@Sun.COM 	case 66:
17410535SVikram.Hegde@Sun.COM 		deventry.idev_type = DEVENTRY_ALIAS_SELECT;
17510535SVikram.Hegde@Sun.COM 		deventry.idev_deviceid = al1.ent16;
17610535SVikram.Hegde@Sun.COM 		deventry.idev_src_deviceid = al2.ent16;
17710535SVikram.Hegde@Sun.COM 		ASSERT(cp[4] == 0);
17810535SVikram.Hegde@Sun.COM 		ASSERT(cp[7] == 0);
17910535SVikram.Hegde@Sun.COM 		break;
18010535SVikram.Hegde@Sun.COM 	case 67:
18110535SVikram.Hegde@Sun.COM 		deventry.idev_type = DEVENTRY_ALIAS_RANGE;
18210535SVikram.Hegde@Sun.COM 		deventry.idev_deviceid = al1.ent16;
18310535SVikram.Hegde@Sun.COM 		deventry.idev_src_deviceid = al2.ent16;
18410535SVikram.Hegde@Sun.COM 		ASSERT(cp[4] == 0);
18510535SVikram.Hegde@Sun.COM 		ASSERT(cp[7] == 0);
18610535SVikram.Hegde@Sun.COM 		break;
18710535SVikram.Hegde@Sun.COM 	case 70:
18810535SVikram.Hegde@Sun.COM 		deventry.idev_type = DEVENTRY_EXTENDED_SELECT;
18910535SVikram.Hegde@Sun.COM 		deventry.idev_deviceid = al1.ent16;
19010535SVikram.Hegde@Sun.COM 		break;
19110535SVikram.Hegde@Sun.COM 	case 71:
19210535SVikram.Hegde@Sun.COM 		deventry.idev_type = DEVENTRY_EXTENDED_RANGE;
19310535SVikram.Hegde@Sun.COM 		deventry.idev_deviceid = al1.ent16;
19410535SVikram.Hegde@Sun.COM 		break;
19510535SVikram.Hegde@Sun.COM 	case 72:
19610535SVikram.Hegde@Sun.COM 		deventry.idev_type = DEVENTRY_SPECIAL_DEVICE;
19710535SVikram.Hegde@Sun.COM 		ASSERT(al1.ent16 == 0);
19810535SVikram.Hegde@Sun.COM 		deventry.idev_deviceid = -1;
19910535SVikram.Hegde@Sun.COM 		deventry.idev_handle = cp[4];
20010535SVikram.Hegde@Sun.COM 		deventry.idev_variety = cp[7];
20110535SVikram.Hegde@Sun.COM 		deventry.idev_src_deviceid = al2.ent16;
20210535SVikram.Hegde@Sun.COM 	default:
20310535SVikram.Hegde@Sun.COM #ifdef BROKEN_ASSERT
20410535SVikram.Hegde@Sun.COM 		for (i = 0; i < 7; i++) {
20510535SVikram.Hegde@Sun.COM 			ASSERT(cp[i] == 0);
20610535SVikram.Hegde@Sun.COM 		}
20710535SVikram.Hegde@Sun.COM #endif
20810535SVikram.Hegde@Sun.COM 		return;
20910535SVikram.Hegde@Sun.COM 	}
21010535SVikram.Hegde@Sun.COM 
21110535SVikram.Hegde@Sun.COM 
21210535SVikram.Hegde@Sun.COM 	devp = kmem_alloc(sizeof (ivhd_deventry_t), KM_SLEEP);
21310535SVikram.Hegde@Sun.COM 	*devp = deventry;
21410535SVikram.Hegde@Sun.COM 
21510535SVikram.Hegde@Sun.COM 	if (c->ivhdc_first_deventry == NULL)
21610535SVikram.Hegde@Sun.COM 		c->ivhdc_first_deventry =  devp;
21710535SVikram.Hegde@Sun.COM 	else
21810535SVikram.Hegde@Sun.COM 		c->ivhdc_last_deventry->idev_next = devp;
21910535SVikram.Hegde@Sun.COM 
22010535SVikram.Hegde@Sun.COM 	c->ivhdc_last_deventry = devp;
22110535SVikram.Hegde@Sun.COM 
22210535SVikram.Hegde@Sun.COM 	devp->idev_Lint1Pass = AMD_IOMMU_REG_GET8(&datsetting8,
22310535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_LINT1PASS);
22410535SVikram.Hegde@Sun.COM 
22510535SVikram.Hegde@Sun.COM 	devp->idev_Lint0Pass = AMD_IOMMU_REG_GET8(&datsetting8,
22610535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_LINT0PASS);
22710535SVikram.Hegde@Sun.COM 
22810535SVikram.Hegde@Sun.COM 	devp->idev_SysMgt = AMD_IOMMU_REG_GET8(&datsetting8,
22910535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_SYSMGT);
23010535SVikram.Hegde@Sun.COM 
23110535SVikram.Hegde@Sun.COM 	ASSERT(AMD_IOMMU_REG_GET8(&datsetting8,
23210535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_DATRSV) == 0);
23310535SVikram.Hegde@Sun.COM 
23410535SVikram.Hegde@Sun.COM 	devp->idev_NMIPass = AMD_IOMMU_REG_GET8(&datsetting8,
23510535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_NMIPASS);
23610535SVikram.Hegde@Sun.COM 
23710535SVikram.Hegde@Sun.COM 	devp->idev_ExtIntPass = AMD_IOMMU_REG_GET8(&datsetting8,
23810535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_EXTINTPASS);
23910535SVikram.Hegde@Sun.COM 
24010535SVikram.Hegde@Sun.COM 	devp->idev_INITPass = AMD_IOMMU_REG_GET8(&datsetting8,
24110535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_INITPASS);
24210535SVikram.Hegde@Sun.COM 
24310535SVikram.Hegde@Sun.COM 	if (entry_type != 70 && entry_type != 71) {
24410535SVikram.Hegde@Sun.COM 		return;
24510535SVikram.Hegde@Sun.COM 	}
24610535SVikram.Hegde@Sun.COM 
24710535SVikram.Hegde@Sun.COM 	/* Type 70 and 71 */
24810535SVikram.Hegde@Sun.COM 	for (i = 0; i < 4; i++) {
24910535SVikram.Hegde@Sun.COM 		al3.ent8[i] = *((uint8_t *)&cp[i+4]);
25010535SVikram.Hegde@Sun.COM 	}
25110535SVikram.Hegde@Sun.COM 
25210535SVikram.Hegde@Sun.COM 	devp->idev_AtsDisabled = AMD_IOMMU_REG_GET8(&al3.ent32,
25310535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_ATSDISABLED);
25410535SVikram.Hegde@Sun.COM 
25510535SVikram.Hegde@Sun.COM 	ASSERT(AMD_IOMMU_REG_GET8(&al3.ent32, AMD_IOMMU_ACPI_EXTDATRSV) == 0);
25610535SVikram.Hegde@Sun.COM }
25710535SVikram.Hegde@Sun.COM 
25810535SVikram.Hegde@Sun.COM static void
process_ivhd(amd_iommu_acpi_t * acpi,ivhd_t * ivhdp)25910535SVikram.Hegde@Sun.COM process_ivhd(amd_iommu_acpi_t *acpi, ivhd_t *ivhdp)
26010535SVikram.Hegde@Sun.COM {
26110535SVikram.Hegde@Sun.COM 	ivhd_container_t *c;
26210535SVikram.Hegde@Sun.COM 	caddr_t ivhd_end;
26310535SVikram.Hegde@Sun.COM 	caddr_t ivhd_tot_end;
26410535SVikram.Hegde@Sun.COM 	caddr_t cp;
26510535SVikram.Hegde@Sun.COM 
26610535SVikram.Hegde@Sun.COM 	ASSERT(ivhdp->ivhd_type == 0x10);
26710535SVikram.Hegde@Sun.COM 
26810535SVikram.Hegde@Sun.COM 	c = kmem_zalloc(sizeof (ivhd_container_t), KM_SLEEP);
26910535SVikram.Hegde@Sun.COM 	c->ivhdc_ivhd = kmem_alloc(sizeof (ivhd_t), KM_SLEEP);
27010535SVikram.Hegde@Sun.COM 	*(c->ivhdc_ivhd) = *ivhdp;
27110535SVikram.Hegde@Sun.COM 
27210535SVikram.Hegde@Sun.COM 	if (acpi->acp_first_ivhdc == NULL)
27310535SVikram.Hegde@Sun.COM 		acpi->acp_first_ivhdc = c;
27410535SVikram.Hegde@Sun.COM 	else
27510535SVikram.Hegde@Sun.COM 		acpi->acp_last_ivhdc->ivhdc_next = c;
27610535SVikram.Hegde@Sun.COM 
27710535SVikram.Hegde@Sun.COM 	acpi->acp_last_ivhdc = c;
27810535SVikram.Hegde@Sun.COM 
27910535SVikram.Hegde@Sun.COM 	ivhd_end = (caddr_t)ivhdp + sizeof (ivhd_t);
28010535SVikram.Hegde@Sun.COM 	ivhd_tot_end = (caddr_t)ivhdp + ivhdp->ivhd_len;
28110535SVikram.Hegde@Sun.COM 
28210535SVikram.Hegde@Sun.COM 	for (cp = ivhd_end; cp < ivhd_tot_end; cp += type_byte_size(cp)) {
28310535SVikram.Hegde@Sun.COM 		/* 16 byte and 32 byte size are currently reserved */
28410535SVikram.Hegde@Sun.COM 		switch (type_byte_size(cp)) {
28510535SVikram.Hegde@Sun.COM 		case 4:
28610535SVikram.Hegde@Sun.COM 			process_4byte_deventry(c, cp);
28710535SVikram.Hegde@Sun.COM 			break;
28810535SVikram.Hegde@Sun.COM 		case 8:
28910535SVikram.Hegde@Sun.COM 			process_8byte_deventry(c, cp);
29010535SVikram.Hegde@Sun.COM 			break;
29110535SVikram.Hegde@Sun.COM 		case 16:
29210535SVikram.Hegde@Sun.COM 		case 32:
29310535SVikram.Hegde@Sun.COM 			/* Reserved */
29410535SVikram.Hegde@Sun.COM 			break;
29510535SVikram.Hegde@Sun.COM 		default:
29610535SVikram.Hegde@Sun.COM 			cmn_err(CE_WARN, "%s: unsupported length for device "
29710535SVikram.Hegde@Sun.COM 			    "entry in ACPI IVRS table's IVHD entry",
29810535SVikram.Hegde@Sun.COM 			    amd_iommu_modname);
29910535SVikram.Hegde@Sun.COM 			break;
30010535SVikram.Hegde@Sun.COM 		}
30110535SVikram.Hegde@Sun.COM 	}
30210535SVikram.Hegde@Sun.COM }
30310535SVikram.Hegde@Sun.COM 
30410535SVikram.Hegde@Sun.COM static void
process_ivmd(amd_iommu_acpi_t * acpi,ivmd_t * ivmdp)30510535SVikram.Hegde@Sun.COM process_ivmd(amd_iommu_acpi_t *acpi, ivmd_t *ivmdp)
30610535SVikram.Hegde@Sun.COM {
30710535SVikram.Hegde@Sun.COM 	ivmd_container_t *c;
30810535SVikram.Hegde@Sun.COM 
30910535SVikram.Hegde@Sun.COM 	ASSERT(ivmdp->ivmd_type != 0x10);
31010535SVikram.Hegde@Sun.COM 
31110535SVikram.Hegde@Sun.COM 	c = kmem_zalloc(sizeof (ivmd_container_t), KM_SLEEP);
31210535SVikram.Hegde@Sun.COM 	c->ivmdc_ivmd = kmem_alloc(sizeof (ivmd_t), KM_SLEEP);
31310535SVikram.Hegde@Sun.COM 	*(c->ivmdc_ivmd) = *ivmdp;
31410535SVikram.Hegde@Sun.COM 
31510535SVikram.Hegde@Sun.COM 	if (acpi->acp_first_ivmdc == NULL)
31610535SVikram.Hegde@Sun.COM 		acpi->acp_first_ivmdc = c;
31710535SVikram.Hegde@Sun.COM 	else
31810535SVikram.Hegde@Sun.COM 		acpi->acp_last_ivmdc->ivmdc_next = c;
31910535SVikram.Hegde@Sun.COM 
32010535SVikram.Hegde@Sun.COM 	acpi->acp_last_ivmdc = c;
32110535SVikram.Hegde@Sun.COM }
32210535SVikram.Hegde@Sun.COM 
32310535SVikram.Hegde@Sun.COM int
amd_iommu_acpi_init(void)32410535SVikram.Hegde@Sun.COM amd_iommu_acpi_init(void)
32510535SVikram.Hegde@Sun.COM {
32610535SVikram.Hegde@Sun.COM 	ivrs_t *ivrsp;
32710535SVikram.Hegde@Sun.COM 	caddr_t ivrsp_end;
32810535SVikram.Hegde@Sun.COM 	caddr_t table_end;
32910535SVikram.Hegde@Sun.COM 	caddr_t cp;
33010535SVikram.Hegde@Sun.COM 	uint8_t type8;
33110535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_t *acpi;
33210535SVikram.Hegde@Sun.COM 	align_ivhd_t al_vhd = {0};
33310535SVikram.Hegde@Sun.COM 	align_ivmd_t al_vmd = {0};
33410535SVikram.Hegde@Sun.COM 
33510535SVikram.Hegde@Sun.COM 	if (AcpiGetTable(IVRS_SIG, 1, (ACPI_TABLE_HEADER **)&ivrsp) != AE_OK) {
33610535SVikram.Hegde@Sun.COM 		cmn_err(CE_NOTE, "!amd_iommu: No AMD IOMMU ACPI IVRS table");
33710535SVikram.Hegde@Sun.COM 		return (DDI_FAILURE);
33810535SVikram.Hegde@Sun.COM 	}
33910535SVikram.Hegde@Sun.COM 
34010535SVikram.Hegde@Sun.COM 	/*
34110535SVikram.Hegde@Sun.COM 	 * Reserved field must be 0
34210535SVikram.Hegde@Sun.COM 	 */
34310535SVikram.Hegde@Sun.COM 	ASSERT(ivrsp->ivrs_resv == 0);
34410535SVikram.Hegde@Sun.COM 
34510535SVikram.Hegde@Sun.COM 	ASSERT(AMD_IOMMU_REG_GET32(&ivrsp->ivrs_ivinfo,
34610535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVINFO_RSV1) == 0);
34710535SVikram.Hegde@Sun.COM 	ASSERT(AMD_IOMMU_REG_GET32(&ivrsp->ivrs_ivinfo,
34810535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVINFO_RSV2) == 0);
34910535SVikram.Hegde@Sun.COM 
35010535SVikram.Hegde@Sun.COM 	ivrsp_end = (caddr_t)ivrsp + sizeof (struct ivrs);
35110535SVikram.Hegde@Sun.COM 	table_end = (caddr_t)ivrsp + ivrsp->ivrs_hdr.Length;
35210535SVikram.Hegde@Sun.COM 
35310535SVikram.Hegde@Sun.COM 	acpi = kmem_zalloc(sizeof (amd_iommu_acpi_t), KM_SLEEP);
35410535SVikram.Hegde@Sun.COM 	acpi->acp_ivrs = kmem_alloc(sizeof (ivrs_t), KM_SLEEP);
35510535SVikram.Hegde@Sun.COM 	*(acpi->acp_ivrs) = *ivrsp;
35610535SVikram.Hegde@Sun.COM 
35710535SVikram.Hegde@Sun.COM 	for (cp = ivrsp_end; cp < table_end; cp += (al_vhd.ivhdp)->ivhd_len) {
35810535SVikram.Hegde@Sun.COM 		al_vhd.cp = cp;
35910535SVikram.Hegde@Sun.COM 		if (al_vhd.ivhdp->ivhd_type == 0x10)
36010535SVikram.Hegde@Sun.COM 			process_ivhd(acpi, al_vhd.ivhdp);
36110535SVikram.Hegde@Sun.COM 	}
36210535SVikram.Hegde@Sun.COM 
36310535SVikram.Hegde@Sun.COM 	for (cp = ivrsp_end; cp < table_end; cp += (al_vmd.ivmdp)->ivmd_len) {
36410535SVikram.Hegde@Sun.COM 		al_vmd.cp = cp;
36510535SVikram.Hegde@Sun.COM 		type8 = al_vmd.ivmdp->ivmd_type;
36610535SVikram.Hegde@Sun.COM 		if (type8 == 0x20 || type8 == 0x21 || type8 == 0x22)
36710535SVikram.Hegde@Sun.COM 			process_ivmd(acpi, al_vmd.ivmdp);
36810535SVikram.Hegde@Sun.COM 	}
36910535SVikram.Hegde@Sun.COM 
37010535SVikram.Hegde@Sun.COM 	if (create_acpi_hash(acpi) != DDI_SUCCESS) {
37110535SVikram.Hegde@Sun.COM 		return (DDI_FAILURE);
37210535SVikram.Hegde@Sun.COM 	}
37310535SVikram.Hegde@Sun.COM 
37410535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_table_fini(&acpi);
37510535SVikram.Hegde@Sun.COM 
37610535SVikram.Hegde@Sun.COM 	ASSERT(acpi == NULL);
37710535SVikram.Hegde@Sun.COM 
37810535SVikram.Hegde@Sun.COM 	if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
37910535SVikram.Hegde@Sun.COM 		dump_acpi_aliases();
38010535SVikram.Hegde@Sun.COM 		debug_enter("dump");
38110535SVikram.Hegde@Sun.COM 	}
38210535SVikram.Hegde@Sun.COM 
38310535SVikram.Hegde@Sun.COM 	return (DDI_SUCCESS);
38410535SVikram.Hegde@Sun.COM }
38510535SVikram.Hegde@Sun.COM 
38610535SVikram.Hegde@Sun.COM static ivhd_deventry_t *
free_ivhd_deventry(ivhd_deventry_t * devp)38710535SVikram.Hegde@Sun.COM free_ivhd_deventry(ivhd_deventry_t *devp)
38810535SVikram.Hegde@Sun.COM {
38910535SVikram.Hegde@Sun.COM 	ivhd_deventry_t *next = devp->idev_next;
39010535SVikram.Hegde@Sun.COM 
39110535SVikram.Hegde@Sun.COM 	kmem_free(devp, sizeof (ivhd_deventry_t));
39210535SVikram.Hegde@Sun.COM 
39310535SVikram.Hegde@Sun.COM 	return (next);
39410535SVikram.Hegde@Sun.COM }
39510535SVikram.Hegde@Sun.COM 
39610535SVikram.Hegde@Sun.COM static ivhd_container_t *
free_ivhd_container(ivhd_container_t * ivhdcp)39710535SVikram.Hegde@Sun.COM free_ivhd_container(ivhd_container_t *ivhdcp)
39810535SVikram.Hegde@Sun.COM {
39910535SVikram.Hegde@Sun.COM 	ivhd_container_t *next = ivhdcp->ivhdc_next;
40010535SVikram.Hegde@Sun.COM 	ivhd_deventry_t *devp;
40110535SVikram.Hegde@Sun.COM 
40210535SVikram.Hegde@Sun.COM 	for (devp = ivhdcp->ivhdc_first_deventry; devp; ) {
40310535SVikram.Hegde@Sun.COM 		devp = free_ivhd_deventry(devp);
40410535SVikram.Hegde@Sun.COM 	}
40510535SVikram.Hegde@Sun.COM 
40610535SVikram.Hegde@Sun.COM 	kmem_free(ivhdcp->ivhdc_ivhd, sizeof (ivhd_t));
40710535SVikram.Hegde@Sun.COM 	kmem_free(ivhdcp, sizeof (ivhd_container_t));
40810535SVikram.Hegde@Sun.COM 
40910535SVikram.Hegde@Sun.COM 	return (next);
41010535SVikram.Hegde@Sun.COM }
41110535SVikram.Hegde@Sun.COM 
41210535SVikram.Hegde@Sun.COM static ivmd_container_t *
free_ivmd_container(ivmd_container_t * ivmdcp)41310535SVikram.Hegde@Sun.COM free_ivmd_container(ivmd_container_t *ivmdcp)
41410535SVikram.Hegde@Sun.COM {
41510535SVikram.Hegde@Sun.COM 	ivmd_container_t *next = ivmdcp->ivmdc_next;
41610535SVikram.Hegde@Sun.COM 
41710535SVikram.Hegde@Sun.COM 	kmem_free(ivmdcp->ivmdc_ivmd, sizeof (ivmd_t));
41810535SVikram.Hegde@Sun.COM 	kmem_free(ivmdcp, sizeof (ivmd_container_t));
41910535SVikram.Hegde@Sun.COM 
42010535SVikram.Hegde@Sun.COM 	return (next);
42110535SVikram.Hegde@Sun.COM }
42210535SVikram.Hegde@Sun.COM 
42310535SVikram.Hegde@Sun.COM void
amd_iommu_acpi_fini(void)42410535SVikram.Hegde@Sun.COM amd_iommu_acpi_fini(void)
42510535SVikram.Hegde@Sun.COM {
42610535SVikram.Hegde@Sun.COM }
42710535SVikram.Hegde@Sun.COM 
42810535SVikram.Hegde@Sun.COM /*
42910535SVikram.Hegde@Sun.COM  * TODO: Do we need to free the ACPI table for om GetFirmwareTable()
43010535SVikram.Hegde@Sun.COM  */
43110535SVikram.Hegde@Sun.COM static void
amd_iommu_acpi_table_fini(amd_iommu_acpi_t ** acpipp)43210535SVikram.Hegde@Sun.COM amd_iommu_acpi_table_fini(amd_iommu_acpi_t **acpipp)
43310535SVikram.Hegde@Sun.COM {
43410535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_t *acpi = *acpipp;
43510535SVikram.Hegde@Sun.COM 	ivhd_container_t *ivhdcp;
43610535SVikram.Hegde@Sun.COM 	ivmd_container_t *ivmdcp;
43710535SVikram.Hegde@Sun.COM 
43810535SVikram.Hegde@Sun.COM 	ASSERT(acpi);
43910535SVikram.Hegde@Sun.COM 
44010535SVikram.Hegde@Sun.COM 	for (ivhdcp = acpi->acp_first_ivhdc; ivhdcp; ) {
44110535SVikram.Hegde@Sun.COM 		ivhdcp = free_ivhd_container(ivhdcp);
44210535SVikram.Hegde@Sun.COM 	}
44310535SVikram.Hegde@Sun.COM 	for (ivmdcp = acpi->acp_first_ivmdc; ivmdcp; ) {
44410535SVikram.Hegde@Sun.COM 		ivmdcp = free_ivmd_container(ivmdcp);
44510535SVikram.Hegde@Sun.COM 	}
44610535SVikram.Hegde@Sun.COM 
44710535SVikram.Hegde@Sun.COM 	kmem_free(acpi->acp_ivrs, sizeof (struct ivrs));
44810535SVikram.Hegde@Sun.COM 	kmem_free(acpi, sizeof (amd_iommu_acpi_t));
44910535SVikram.Hegde@Sun.COM 
45010535SVikram.Hegde@Sun.COM 	*acpipp = NULL;
45110535SVikram.Hegde@Sun.COM }
45210535SVikram.Hegde@Sun.COM 
45310535SVikram.Hegde@Sun.COM static uint16_t
deviceid_hashfn(uint16_t deviceid)45410535SVikram.Hegde@Sun.COM deviceid_hashfn(uint16_t deviceid)
45510535SVikram.Hegde@Sun.COM {
45610535SVikram.Hegde@Sun.COM 	return (deviceid % AMD_IOMMU_ACPI_INFO_HASH_SZ);
45710535SVikram.Hegde@Sun.COM }
45810535SVikram.Hegde@Sun.COM 
45910535SVikram.Hegde@Sun.COM static void
add_deventry_info(ivhd_t * ivhdp,ivhd_deventry_t * deventry,amd_iommu_acpi_ivhd_t ** hash)46010535SVikram.Hegde@Sun.COM add_deventry_info(ivhd_t *ivhdp, ivhd_deventry_t *deventry,
46110535SVikram.Hegde@Sun.COM     amd_iommu_acpi_ivhd_t **hash)
46210535SVikram.Hegde@Sun.COM {
46310535SVikram.Hegde@Sun.COM 	static amd_iommu_acpi_ivhd_t *last;
46410535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_ivhd_t *acpi_ivhdp;
46510535SVikram.Hegde@Sun.COM 	uint8_t uint8_flags;
46610535SVikram.Hegde@Sun.COM 	uint16_t uint16_info;
46710535SVikram.Hegde@Sun.COM 	uint16_t idx;
46810535SVikram.Hegde@Sun.COM 
46910535SVikram.Hegde@Sun.COM 	if (deventry->idev_type == DEVENTRY_RANGE_END) {
47010535SVikram.Hegde@Sun.COM 		ASSERT(last);
47110535SVikram.Hegde@Sun.COM 		acpi_ivhdp = last;
47210535SVikram.Hegde@Sun.COM 		last = NULL;
47310535SVikram.Hegde@Sun.COM 		ASSERT(acpi_ivhdp->ach_dev_type == DEVENTRY_RANGE ||
47410535SVikram.Hegde@Sun.COM 		    acpi_ivhdp->ach_dev_type == DEVENTRY_ALIAS_RANGE ||
47510535SVikram.Hegde@Sun.COM 		    acpi_ivhdp->ach_dev_type == DEVENTRY_EXTENDED_RANGE);
47610535SVikram.Hegde@Sun.COM 		ASSERT(acpi_ivhdp->ach_deviceid_end == -1);
47710535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid;
47810535SVikram.Hegde@Sun.COM 		/* TODO ASSERT data is 0 */
47910535SVikram.Hegde@Sun.COM 		return;
48010535SVikram.Hegde@Sun.COM 	}
48110535SVikram.Hegde@Sun.COM 
48210535SVikram.Hegde@Sun.COM 	ASSERT(last == NULL);
48310535SVikram.Hegde@Sun.COM 	acpi_ivhdp = kmem_zalloc(sizeof (*acpi_ivhdp), KM_SLEEP);
48410535SVikram.Hegde@Sun.COM 
48510535SVikram.Hegde@Sun.COM 	uint8_flags = ivhdp->ivhd_flags;
48610535SVikram.Hegde@Sun.COM 
48710535SVikram.Hegde@Sun.COM #ifdef BROKEN_ASSERT
48810535SVikram.Hegde@Sun.COM 	ASSERT(AMD_IOMMU_REG_GET8(&uint8_flags,
48910535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVHD_FLAGS_RSV) == 0);
49010535SVikram.Hegde@Sun.COM #endif
49110535SVikram.Hegde@Sun.COM 
49210535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_IotlbSup = AMD_IOMMU_REG_GET8(&uint8_flags,
49310535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVHD_FLAGS_IOTLBSUP);
49410535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_Isoc = AMD_IOMMU_REG_GET8(&uint8_flags,
49510535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVHD_FLAGS_ISOC);
49610535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_ResPassPW = AMD_IOMMU_REG_GET8(&uint8_flags,
49710535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVHD_FLAGS_RESPASSPW);
49810535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_PassPW = AMD_IOMMU_REG_GET8(&uint8_flags,
49910535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVHD_FLAGS_PASSPW);
50010535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_HtTunEn = AMD_IOMMU_REG_GET8(&uint8_flags,
50110535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVHD_FLAGS_HTTUNEN);
50210535SVikram.Hegde@Sun.COM 
50310535SVikram.Hegde@Sun.COM 	/* IVHD fields */
50410535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_IOMMU_deviceid = ivhdp->ivhd_deviceid;
50510535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_IOMMU_cap_off = ivhdp->ivhd_cap_off;
50610535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_IOMMU_reg_base = ivhdp->ivhd_reg_base;
50710535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_IOMMU_pci_seg = ivhdp->ivhd_pci_seg;
50810535SVikram.Hegde@Sun.COM 
50910535SVikram.Hegde@Sun.COM 	/* IVHD IOMMU info fields */
51010535SVikram.Hegde@Sun.COM 	uint16_info = ivhdp->ivhd_iommu_info;
51110535SVikram.Hegde@Sun.COM 
51210535SVikram.Hegde@Sun.COM #ifdef BROKEN_ASSERT
51310535SVikram.Hegde@Sun.COM 	ASSERT(AMD_IOMMU_REG_GET16(&uint16_info,
51410535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IOMMU_INFO_RSV1) == 0);
51510535SVikram.Hegde@Sun.COM #endif
51610535SVikram.Hegde@Sun.COM 
51710535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_IOMMU_UnitID = AMD_IOMMU_REG_GET16(&uint16_info,
51810535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IOMMU_INFO_UNITID);
51910535SVikram.Hegde@Sun.COM 	ASSERT(AMD_IOMMU_REG_GET16(&uint16_info,
52010535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IOMMU_INFO_RSV2) == 0);
52110535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_IOMMU_MSInum = AMD_IOMMU_REG_GET16(&uint16_info,
52210535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IOMMU_INFO_MSINUM);
52310535SVikram.Hegde@Sun.COM 
52410535SVikram.Hegde@Sun.COM 	/* Initialize  deviceids to -1 */
52510535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_deviceid_start = -1;
52610535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_deviceid_end = -1;
52710535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_src_deviceid = -1;
52810535SVikram.Hegde@Sun.COM 
52910535SVikram.Hegde@Sun.COM 	/* All range type entries are put on hash entry 0 */
53010535SVikram.Hegde@Sun.COM 	switch (deventry->idev_type) {
53110535SVikram.Hegde@Sun.COM 	case DEVENTRY_ALL:
53210535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_start = 0;
53310535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_end = (uint16_t)-1;
53410535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_dev_type = DEVENTRY_ALL;
53510535SVikram.Hegde@Sun.COM 		idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
53610535SVikram.Hegde@Sun.COM 		break;
53710535SVikram.Hegde@Sun.COM 	case DEVENTRY_SELECT:
53810535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
53910535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid;
54010535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_dev_type = DEVENTRY_SELECT;
54110535SVikram.Hegde@Sun.COM 		idx = deviceid_hashfn(deventry->idev_deviceid);
54210535SVikram.Hegde@Sun.COM 		break;
54310535SVikram.Hegde@Sun.COM 	case DEVENTRY_RANGE:
54410535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
54510535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_end = -1;
54610535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_dev_type = DEVENTRY_RANGE;
54710535SVikram.Hegde@Sun.COM 		idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
54810535SVikram.Hegde@Sun.COM 		last = acpi_ivhdp;
54910535SVikram.Hegde@Sun.COM 		break;
55010535SVikram.Hegde@Sun.COM 	case DEVENTRY_RANGE_END:
55110535SVikram.Hegde@Sun.COM 		cmn_err(CE_PANIC, "%s: Unexpected Range End Deventry",
55210535SVikram.Hegde@Sun.COM 		    amd_iommu_modname);
55310535SVikram.Hegde@Sun.COM 		/*NOTREACHED*/
55410535SVikram.Hegde@Sun.COM 	case DEVENTRY_ALIAS_SELECT:
55510535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
55610535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid;
55710535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid;
55810535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_dev_type = DEVENTRY_ALIAS_SELECT;
55910535SVikram.Hegde@Sun.COM 		idx = deviceid_hashfn(deventry->idev_deviceid);
56010535SVikram.Hegde@Sun.COM 		break;
56110535SVikram.Hegde@Sun.COM 	case DEVENTRY_ALIAS_RANGE:
56210535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
56310535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_end = -1;
56410535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid;
56510535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_dev_type = DEVENTRY_ALIAS_RANGE;
56610535SVikram.Hegde@Sun.COM 		idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
56710535SVikram.Hegde@Sun.COM 		last = acpi_ivhdp;
56810535SVikram.Hegde@Sun.COM 		break;
56910535SVikram.Hegde@Sun.COM 	case DEVENTRY_EXTENDED_SELECT:
57010535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
57110535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid;
57210535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_dev_type = DEVENTRY_EXTENDED_SELECT;
57310535SVikram.Hegde@Sun.COM 		idx = deviceid_hashfn(deventry->idev_deviceid);
57410535SVikram.Hegde@Sun.COM 		break;
57510535SVikram.Hegde@Sun.COM 	case DEVENTRY_EXTENDED_RANGE:
57610535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
57710535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_end = -1;
57810535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_dev_type = DEVENTRY_EXTENDED_RANGE;
57910535SVikram.Hegde@Sun.COM 		idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
58010535SVikram.Hegde@Sun.COM 		last = acpi_ivhdp;
58110535SVikram.Hegde@Sun.COM 		break;
58210535SVikram.Hegde@Sun.COM 	case DEVENTRY_SPECIAL_DEVICE:
58310535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_start = -1;
58410535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_deviceid_end = -1;
58510535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid;
58610535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_special_handle = deventry->idev_handle;
58710535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_special_variety = deventry->idev_variety;
58810535SVikram.Hegde@Sun.COM 		idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
58910535SVikram.Hegde@Sun.COM 	default:
59010535SVikram.Hegde@Sun.COM 		cmn_err(CE_PANIC, "%s: Unsupported deventry type",
59110535SVikram.Hegde@Sun.COM 		    amd_iommu_modname);
59210535SVikram.Hegde@Sun.COM 		/*NOTREACHED*/
59310535SVikram.Hegde@Sun.COM 	}
59410535SVikram.Hegde@Sun.COM 
59510535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_Lint1Pass = deventry->idev_Lint1Pass;
59610535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_Lint0Pass = deventry->idev_Lint0Pass;
59710535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_SysMgt = deventry->idev_SysMgt;
59810535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_NMIPass = deventry->idev_NMIPass;
59910535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_ExtIntPass = deventry->idev_ExtIntPass;
60010535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_INITPass = deventry->idev_INITPass;
60110535SVikram.Hegde@Sun.COM 
60210535SVikram.Hegde@Sun.COM 
60310535SVikram.Hegde@Sun.COM 	/* extended data */
60410535SVikram.Hegde@Sun.COM 	if (acpi_ivhdp->ach_dev_type == DEVENTRY_EXTENDED_SELECT ||
60510535SVikram.Hegde@Sun.COM 	    acpi_ivhdp->ach_dev_type == DEVENTRY_EXTENDED_RANGE) {
60610535SVikram.Hegde@Sun.COM 		acpi_ivhdp->ach_AtsDisabled = deventry->idev_AtsDisabled;
60710535SVikram.Hegde@Sun.COM 	}
60810535SVikram.Hegde@Sun.COM 
60910535SVikram.Hegde@Sun.COM 	/*
61010535SVikram.Hegde@Sun.COM 	 * Now add it to the hash
61110535SVikram.Hegde@Sun.COM 	 */
61210535SVikram.Hegde@Sun.COM 	ASSERT(hash[idx] != acpi_ivhdp);
61310535SVikram.Hegde@Sun.COM 	acpi_ivhdp->ach_next = hash[idx];
61410535SVikram.Hegde@Sun.COM 	hash[idx] = acpi_ivhdp;
61510535SVikram.Hegde@Sun.COM }
61610535SVikram.Hegde@Sun.COM 
617*12203SJerry.Gilliam@Sun.COM /*
618*12203SJerry.Gilliam@Sun.COM  * A device entry may be declared implicitly as a source device ID
619*12203SJerry.Gilliam@Sun.COM  * in an alias entry. This routine adds it to the hash
620*12203SJerry.Gilliam@Sun.COM  */
621*12203SJerry.Gilliam@Sun.COM static void
add_implicit_deventry(ivhd_container_t * ivhdcp,amd_iommu_acpi_ivhd_t ** hash)622*12203SJerry.Gilliam@Sun.COM add_implicit_deventry(ivhd_container_t *ivhdcp, amd_iommu_acpi_ivhd_t **hash)
623*12203SJerry.Gilliam@Sun.COM {
624*12203SJerry.Gilliam@Sun.COM 	ivhd_deventry_t *d;
625*12203SJerry.Gilliam@Sun.COM 	int deviceid;
626*12203SJerry.Gilliam@Sun.COM 
627*12203SJerry.Gilliam@Sun.COM 	for (d = ivhdcp->ivhdc_first_deventry; d; d = d->idev_next) {
628*12203SJerry.Gilliam@Sun.COM 
629*12203SJerry.Gilliam@Sun.COM 		if ((d->idev_type != DEVENTRY_ALIAS_SELECT) &&
630*12203SJerry.Gilliam@Sun.COM 		    (d->idev_type != DEVENTRY_ALIAS_RANGE))
631*12203SJerry.Gilliam@Sun.COM 			continue;
632*12203SJerry.Gilliam@Sun.COM 
633*12203SJerry.Gilliam@Sun.COM 		deviceid = d->idev_src_deviceid;
634*12203SJerry.Gilliam@Sun.COM 
635*12203SJerry.Gilliam@Sun.COM 		if (amd_iommu_lookup_ivhd(deviceid) == NULL) {
636*12203SJerry.Gilliam@Sun.COM 			ivhd_deventry_t deventry;
637*12203SJerry.Gilliam@Sun.COM 
638*12203SJerry.Gilliam@Sun.COM 			/* Fake a SELECT entry */
639*12203SJerry.Gilliam@Sun.COM 			deventry.idev_type = DEVENTRY_SELECT;
640*12203SJerry.Gilliam@Sun.COM 			deventry.idev_len = 4;
641*12203SJerry.Gilliam@Sun.COM 			deventry.idev_deviceid = deviceid;
642*12203SJerry.Gilliam@Sun.COM 			deventry.idev_src_deviceid = -1;
643*12203SJerry.Gilliam@Sun.COM 
644*12203SJerry.Gilliam@Sun.COM 			deventry.idev_Lint1Pass = d->idev_Lint1Pass;
645*12203SJerry.Gilliam@Sun.COM 			deventry.idev_Lint0Pass = d->idev_Lint0Pass;
646*12203SJerry.Gilliam@Sun.COM 			deventry.idev_SysMgt = d->idev_SysMgt;
647*12203SJerry.Gilliam@Sun.COM 			deventry.idev_NMIPass = d->idev_NMIPass;
648*12203SJerry.Gilliam@Sun.COM 			deventry.idev_ExtIntPass = d->idev_ExtIntPass;
649*12203SJerry.Gilliam@Sun.COM 			deventry.idev_INITPass = d->idev_INITPass;
650*12203SJerry.Gilliam@Sun.COM 
651*12203SJerry.Gilliam@Sun.COM 			add_deventry_info(ivhdcp->ivhdc_ivhd, &deventry, hash);
652*12203SJerry.Gilliam@Sun.COM 
653*12203SJerry.Gilliam@Sun.COM 			if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
654*12203SJerry.Gilliam@Sun.COM 				cmn_err(CE_NOTE, "Added implicit IVHD entry "
655*12203SJerry.Gilliam@Sun.COM 				    "for: deviceid = %u", deviceid);
656*12203SJerry.Gilliam@Sun.COM 			}
657*12203SJerry.Gilliam@Sun.COM 		}
658*12203SJerry.Gilliam@Sun.COM 	}
659*12203SJerry.Gilliam@Sun.COM }
660*12203SJerry.Gilliam@Sun.COM 
66110535SVikram.Hegde@Sun.COM static void
add_ivhdc_info(ivhd_container_t * ivhdcp,amd_iommu_acpi_ivhd_t ** hash)66210535SVikram.Hegde@Sun.COM add_ivhdc_info(ivhd_container_t *ivhdcp, amd_iommu_acpi_ivhd_t **hash)
66310535SVikram.Hegde@Sun.COM {
66410535SVikram.Hegde@Sun.COM 	ivhd_deventry_t *deventry;
66510535SVikram.Hegde@Sun.COM 	ivhd_t *ivhdp = ivhdcp->ivhdc_ivhd;
66610535SVikram.Hegde@Sun.COM 
66710535SVikram.Hegde@Sun.COM 	for (deventry = ivhdcp->ivhdc_first_deventry; deventry;
66810535SVikram.Hegde@Sun.COM 	    deventry = deventry->idev_next) {
66910535SVikram.Hegde@Sun.COM 		add_deventry_info(ivhdp, deventry, hash);
67010535SVikram.Hegde@Sun.COM 	}
671*12203SJerry.Gilliam@Sun.COM 
672*12203SJerry.Gilliam@Sun.COM 	add_implicit_deventry(ivhdcp, hash);
673*12203SJerry.Gilliam@Sun.COM 
67410535SVikram.Hegde@Sun.COM }
67510535SVikram.Hegde@Sun.COM 
67610535SVikram.Hegde@Sun.COM static void
add_ivhd_info(amd_iommu_acpi_t * acpi,amd_iommu_acpi_ivhd_t ** hash)67710535SVikram.Hegde@Sun.COM add_ivhd_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_ivhd_t **hash)
67810535SVikram.Hegde@Sun.COM {
67910535SVikram.Hegde@Sun.COM 	ivhd_container_t *ivhdcp;
68010535SVikram.Hegde@Sun.COM 
68110535SVikram.Hegde@Sun.COM 	for (ivhdcp = acpi->acp_first_ivhdc; ivhdcp;
68210535SVikram.Hegde@Sun.COM 	    ivhdcp = ivhdcp->ivhdc_next) {
68310535SVikram.Hegde@Sun.COM 		add_ivhdc_info(ivhdcp, hash);
68410535SVikram.Hegde@Sun.COM 	}
68510535SVikram.Hegde@Sun.COM }
68610535SVikram.Hegde@Sun.COM 
68710535SVikram.Hegde@Sun.COM static void
set_ivmd_info(ivmd_t * ivmdp,amd_iommu_acpi_ivmd_t ** hash)68810535SVikram.Hegde@Sun.COM set_ivmd_info(ivmd_t *ivmdp, amd_iommu_acpi_ivmd_t **hash)
68910535SVikram.Hegde@Sun.COM {
69010535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_ivmd_t *acpi_ivmdp;
69110535SVikram.Hegde@Sun.COM 	uint8_t uint8_flags;
69210535SVikram.Hegde@Sun.COM 	uint16_t idx;
69310535SVikram.Hegde@Sun.COM 
69410535SVikram.Hegde@Sun.COM 	uint8_flags = ivmdp->ivmd_flags;
69510535SVikram.Hegde@Sun.COM 
69610535SVikram.Hegde@Sun.COM 	acpi_ivmdp = kmem_zalloc(sizeof (*acpi_ivmdp), KM_SLEEP);
69710535SVikram.Hegde@Sun.COM 
69810535SVikram.Hegde@Sun.COM 	switch (ivmdp->ivmd_type) {
69910535SVikram.Hegde@Sun.COM 	case 0x20:
70010535SVikram.Hegde@Sun.COM 		acpi_ivmdp->acm_deviceid_start = 0;
70110535SVikram.Hegde@Sun.COM 		acpi_ivmdp->acm_deviceid_end = (uint16_t)-1;
70210535SVikram.Hegde@Sun.COM 		acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_ALL;
70310535SVikram.Hegde@Sun.COM 		idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
70410535SVikram.Hegde@Sun.COM 		break;
70510535SVikram.Hegde@Sun.COM 	case 0x21:
70610535SVikram.Hegde@Sun.COM 		acpi_ivmdp->acm_deviceid_start = ivmdp->ivmd_deviceid;
70710535SVikram.Hegde@Sun.COM 		acpi_ivmdp->acm_deviceid_end = ivmdp->ivmd_deviceid;
70810535SVikram.Hegde@Sun.COM 		acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_SELECT;
70910535SVikram.Hegde@Sun.COM 		idx = deviceid_hashfn(ivmdp->ivmd_deviceid);
71010535SVikram.Hegde@Sun.COM 		break;
71110535SVikram.Hegde@Sun.COM 	case 0x22:
71210535SVikram.Hegde@Sun.COM 		acpi_ivmdp->acm_deviceid_start = ivmdp->ivmd_deviceid;
71310535SVikram.Hegde@Sun.COM 		acpi_ivmdp->acm_deviceid_end = ivmdp->ivmd_auxdata;
71410535SVikram.Hegde@Sun.COM 		acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_RANGE;
71510535SVikram.Hegde@Sun.COM 		idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
71610535SVikram.Hegde@Sun.COM 		break;
71710535SVikram.Hegde@Sun.COM 	default:
71810535SVikram.Hegde@Sun.COM 		cmn_err(CE_PANIC, "Unknown AMD IOMMU ACPI IVMD deviceid type: "
71910535SVikram.Hegde@Sun.COM 		    "%x", ivmdp->ivmd_type);
72010535SVikram.Hegde@Sun.COM 		/*NOTREACHED*/
72110535SVikram.Hegde@Sun.COM 	}
72210535SVikram.Hegde@Sun.COM 
72310535SVikram.Hegde@Sun.COM 	ASSERT(AMD_IOMMU_REG_GET8(&uint8_flags,
72410535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVMD_RSV) == 0);
72510535SVikram.Hegde@Sun.COM 
72610535SVikram.Hegde@Sun.COM 	acpi_ivmdp->acm_ExclRange = AMD_IOMMU_REG_GET8(&uint8_flags,
72710535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVMD_EXCL_RANGE);
72810535SVikram.Hegde@Sun.COM 	acpi_ivmdp->acm_IW = AMD_IOMMU_REG_GET8(&uint8_flags,
72910535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVMD_IW);
73010535SVikram.Hegde@Sun.COM 	acpi_ivmdp->acm_IR = AMD_IOMMU_REG_GET8(&uint8_flags,
73110535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVMD_IR);
73210535SVikram.Hegde@Sun.COM 	acpi_ivmdp->acm_Unity = AMD_IOMMU_REG_GET8(&uint8_flags,
73310535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_ACPI_IVMD_UNITY);
73410535SVikram.Hegde@Sun.COM 
73510535SVikram.Hegde@Sun.COM 	acpi_ivmdp->acm_ivmd_phys_start = ivmdp->ivmd_phys_start;
73610535SVikram.Hegde@Sun.COM 	acpi_ivmdp->acm_ivmd_phys_len = ivmdp->ivmd_phys_len;
73710535SVikram.Hegde@Sun.COM 
73810535SVikram.Hegde@Sun.COM 	acpi_ivmdp->acm_next = hash[idx];
73910535SVikram.Hegde@Sun.COM 	hash[idx] = acpi_ivmdp;
74010535SVikram.Hegde@Sun.COM }
74110535SVikram.Hegde@Sun.COM 
74210535SVikram.Hegde@Sun.COM static void
add_ivmdc_info(ivmd_container_t * ivmdcp,amd_iommu_acpi_ivmd_t ** hash)74310535SVikram.Hegde@Sun.COM add_ivmdc_info(ivmd_container_t *ivmdcp, amd_iommu_acpi_ivmd_t **hash)
74410535SVikram.Hegde@Sun.COM {
74510535SVikram.Hegde@Sun.COM 	set_ivmd_info(ivmdcp->ivmdc_ivmd, hash);
74610535SVikram.Hegde@Sun.COM }
74710535SVikram.Hegde@Sun.COM 
74810535SVikram.Hegde@Sun.COM static void
add_ivmd_info(amd_iommu_acpi_t * acpi,amd_iommu_acpi_ivmd_t ** hash)74910535SVikram.Hegde@Sun.COM add_ivmd_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_ivmd_t **hash)
75010535SVikram.Hegde@Sun.COM {
75110535SVikram.Hegde@Sun.COM 	ivmd_container_t *ivmdcp;
75210535SVikram.Hegde@Sun.COM 
75310535SVikram.Hegde@Sun.COM 	for (ivmdcp = acpi->acp_first_ivmdc; ivmdcp;
75410535SVikram.Hegde@Sun.COM 	    ivmdcp = ivmdcp->ivmdc_next) {
75510535SVikram.Hegde@Sun.COM 		add_ivmdc_info(ivmdcp, hash);
75610535SVikram.Hegde@Sun.COM 	}
75710535SVikram.Hegde@Sun.COM }
75810535SVikram.Hegde@Sun.COM 
75910535SVikram.Hegde@Sun.COM static void
add_global_info(amd_iommu_acpi_t * acpi,amd_iommu_acpi_global_t * global)76010535SVikram.Hegde@Sun.COM add_global_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_global_t *global)
76110535SVikram.Hegde@Sun.COM {
76210535SVikram.Hegde@Sun.COM 	uint32_t ivrs_ivinfo = acpi->acp_ivrs->ivrs_ivinfo;
76310535SVikram.Hegde@Sun.COM 
76410535SVikram.Hegde@Sun.COM 	global->acg_HtAtsResv =
76510535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_HT_ATSRSV);
76610535SVikram.Hegde@Sun.COM 	global->acg_VAsize =
76710535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_VA_SIZE);
76810535SVikram.Hegde@Sun.COM 	global->acg_PAsize =
76910535SVikram.Hegde@Sun.COM 	    AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_PA_SIZE);
77010535SVikram.Hegde@Sun.COM }
77110535SVikram.Hegde@Sun.COM 
77210535SVikram.Hegde@Sun.COM static int
create_acpi_hash(amd_iommu_acpi_t * acpi)77310535SVikram.Hegde@Sun.COM create_acpi_hash(amd_iommu_acpi_t *acpi)
77410535SVikram.Hegde@Sun.COM {
77510535SVikram.Hegde@Sun.COM 	/* Last hash entry is for deviceid ranges including "all" */
77610535SVikram.Hegde@Sun.COM 
77710535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_global = kmem_zalloc(sizeof (amd_iommu_acpi_global_t),
77810535SVikram.Hegde@Sun.COM 	    KM_SLEEP);
77910535SVikram.Hegde@Sun.COM 
78010535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_ivhd_hash = kmem_zalloc(sizeof (amd_iommu_acpi_ivhd_t *)
78110535SVikram.Hegde@Sun.COM 	    * (AMD_IOMMU_ACPI_INFO_HASH_SZ + 1), KM_SLEEP);
78210535SVikram.Hegde@Sun.COM 
78310535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_ivmd_hash = kmem_zalloc(sizeof (amd_iommu_acpi_ivmd_t *)
78410535SVikram.Hegde@Sun.COM 	    * (AMD_IOMMU_ACPI_INFO_HASH_SZ + 1), KM_SLEEP);
78510535SVikram.Hegde@Sun.COM 
78610535SVikram.Hegde@Sun.COM 	add_global_info(acpi, amd_iommu_acpi_global);
78710535SVikram.Hegde@Sun.COM 
78810535SVikram.Hegde@Sun.COM 	add_ivhd_info(acpi, amd_iommu_acpi_ivhd_hash);
78910535SVikram.Hegde@Sun.COM 
79010535SVikram.Hegde@Sun.COM 	add_ivmd_info(acpi, amd_iommu_acpi_ivmd_hash);
79110535SVikram.Hegde@Sun.COM 
79210535SVikram.Hegde@Sun.COM 	return (DDI_SUCCESS);
79310535SVikram.Hegde@Sun.COM }
79410535SVikram.Hegde@Sun.COM 
795*12203SJerry.Gilliam@Sun.COM static void
set_deventry(amd_iommu_t * iommu,int entry,amd_iommu_acpi_ivhd_t * hinfop)796*12203SJerry.Gilliam@Sun.COM set_deventry(amd_iommu_t *iommu, int entry, amd_iommu_acpi_ivhd_t *hinfop)
797*12203SJerry.Gilliam@Sun.COM {
798*12203SJerry.Gilliam@Sun.COM 	uint64_t *dentry;
799*12203SJerry.Gilliam@Sun.COM 
800*12203SJerry.Gilliam@Sun.COM 	dentry = (uint64_t *)(intptr_t)
801*12203SJerry.Gilliam@Sun.COM 	    &iommu->aiomt_devtbl[entry * AMD_IOMMU_DEVTBL_ENTRY_SZ];
802*12203SJerry.Gilliam@Sun.COM 
803*12203SJerry.Gilliam@Sun.COM 	AMD_IOMMU_REG_SET64(&(dentry[1]), AMD_IOMMU_DEVTBL_SYSMGT,
804*12203SJerry.Gilliam@Sun.COM 	    hinfop->ach_SysMgt);
805*12203SJerry.Gilliam@Sun.COM }
806*12203SJerry.Gilliam@Sun.COM 
807*12203SJerry.Gilliam@Sun.COM /* Initialize device table according to IVHD */
808*12203SJerry.Gilliam@Sun.COM int
amd_iommu_acpi_init_devtbl(amd_iommu_t * iommu)809*12203SJerry.Gilliam@Sun.COM amd_iommu_acpi_init_devtbl(amd_iommu_t *iommu)
810*12203SJerry.Gilliam@Sun.COM {
811*12203SJerry.Gilliam@Sun.COM 	int i, j;
812*12203SJerry.Gilliam@Sun.COM 	amd_iommu_acpi_ivhd_t *hinfop;
813*12203SJerry.Gilliam@Sun.COM 
814*12203SJerry.Gilliam@Sun.COM 	for (i = 0; i <= AMD_IOMMU_ACPI_INFO_HASH_SZ; i++) {
815*12203SJerry.Gilliam@Sun.COM 		for (hinfop = amd_iommu_acpi_ivhd_hash[i];
816*12203SJerry.Gilliam@Sun.COM 		    hinfop; hinfop = hinfop->ach_next) {
817*12203SJerry.Gilliam@Sun.COM 
818*12203SJerry.Gilliam@Sun.COM 			if (hinfop->ach_IOMMU_deviceid != iommu->aiomt_bdf)
819*12203SJerry.Gilliam@Sun.COM 				continue;
820*12203SJerry.Gilliam@Sun.COM 
821*12203SJerry.Gilliam@Sun.COM 			switch (hinfop->ach_dev_type) {
822*12203SJerry.Gilliam@Sun.COM 			case DEVENTRY_ALL:
823*12203SJerry.Gilliam@Sun.COM 				for (j = 0; j < AMD_IOMMU_MAX_DEVICEID; j++)
824*12203SJerry.Gilliam@Sun.COM 					set_deventry(iommu, j, hinfop);
825*12203SJerry.Gilliam@Sun.COM 				break;
826*12203SJerry.Gilliam@Sun.COM 			case DEVENTRY_SELECT:
827*12203SJerry.Gilliam@Sun.COM 			case DEVENTRY_EXTENDED_SELECT:
828*12203SJerry.Gilliam@Sun.COM 				set_deventry(iommu,
829*12203SJerry.Gilliam@Sun.COM 				    hinfop->ach_deviceid_start,
830*12203SJerry.Gilliam@Sun.COM 				    hinfop);
831*12203SJerry.Gilliam@Sun.COM 				break;
832*12203SJerry.Gilliam@Sun.COM 			case DEVENTRY_RANGE:
833*12203SJerry.Gilliam@Sun.COM 			case DEVENTRY_EXTENDED_RANGE:
834*12203SJerry.Gilliam@Sun.COM 				for (j = hinfop->ach_deviceid_start;
835*12203SJerry.Gilliam@Sun.COM 				    j <= hinfop->ach_deviceid_end;
836*12203SJerry.Gilliam@Sun.COM 				    j++)
837*12203SJerry.Gilliam@Sun.COM 					set_deventry(iommu, j, hinfop);
838*12203SJerry.Gilliam@Sun.COM 				break;
839*12203SJerry.Gilliam@Sun.COM 			case DEVENTRY_ALIAS_SELECT:
840*12203SJerry.Gilliam@Sun.COM 			case DEVENTRY_ALIAS_RANGE:
841*12203SJerry.Gilliam@Sun.COM 			case DEVENTRY_SPECIAL_DEVICE:
842*12203SJerry.Gilliam@Sun.COM 				set_deventry(iommu,
843*12203SJerry.Gilliam@Sun.COM 				    hinfop->ach_src_deviceid,
844*12203SJerry.Gilliam@Sun.COM 				    hinfop);
845*12203SJerry.Gilliam@Sun.COM 				break;
846*12203SJerry.Gilliam@Sun.COM 			default:
847*12203SJerry.Gilliam@Sun.COM 				cmn_err(CE_WARN,
848*12203SJerry.Gilliam@Sun.COM 				    "%s: Unknown deventry type",
849*12203SJerry.Gilliam@Sun.COM 				    amd_iommu_modname);
850*12203SJerry.Gilliam@Sun.COM 				return (DDI_FAILURE);
851*12203SJerry.Gilliam@Sun.COM 			}
852*12203SJerry.Gilliam@Sun.COM 		}
853*12203SJerry.Gilliam@Sun.COM 	}
854*12203SJerry.Gilliam@Sun.COM 
855*12203SJerry.Gilliam@Sun.COM 	return (DDI_SUCCESS);
856*12203SJerry.Gilliam@Sun.COM }
857*12203SJerry.Gilliam@Sun.COM 
85810535SVikram.Hegde@Sun.COM amd_iommu_acpi_global_t *
amd_iommu_lookup_acpi_global(void)85910535SVikram.Hegde@Sun.COM amd_iommu_lookup_acpi_global(void)
86010535SVikram.Hegde@Sun.COM {
86110535SVikram.Hegde@Sun.COM 	ASSERT(amd_iommu_acpi_global);
86210535SVikram.Hegde@Sun.COM 
86310535SVikram.Hegde@Sun.COM 	return (amd_iommu_acpi_global);
86410535SVikram.Hegde@Sun.COM }
86510535SVikram.Hegde@Sun.COM 
86610535SVikram.Hegde@Sun.COM amd_iommu_acpi_ivhd_t *
amd_iommu_lookup_all_ivhd(void)86710535SVikram.Hegde@Sun.COM amd_iommu_lookup_all_ivhd(void)
86810535SVikram.Hegde@Sun.COM {
86910535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_ivhd_t *hinfop;
87010535SVikram.Hegde@Sun.COM 
87110535SVikram.Hegde@Sun.COM 	hinfop = amd_iommu_acpi_ivhd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ];
87210535SVikram.Hegde@Sun.COM 	for (; hinfop; hinfop = hinfop->ach_next) {
87310535SVikram.Hegde@Sun.COM 		if (hinfop->ach_deviceid_start == 0 &&
87410535SVikram.Hegde@Sun.COM 		    hinfop->ach_deviceid_end == (uint16_t)-1) {
87510535SVikram.Hegde@Sun.COM 			break;
87610535SVikram.Hegde@Sun.COM 		}
87710535SVikram.Hegde@Sun.COM 	}
87810535SVikram.Hegde@Sun.COM 
87910535SVikram.Hegde@Sun.COM 	return (hinfop);
88010535SVikram.Hegde@Sun.COM }
88110535SVikram.Hegde@Sun.COM 
88210535SVikram.Hegde@Sun.COM amd_iommu_acpi_ivmd_t *
amd_iommu_lookup_all_ivmd(void)88310535SVikram.Hegde@Sun.COM amd_iommu_lookup_all_ivmd(void)
88410535SVikram.Hegde@Sun.COM {
88510535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_ivmd_t *minfop;
88610535SVikram.Hegde@Sun.COM 
88710535SVikram.Hegde@Sun.COM 	minfop = amd_iommu_acpi_ivmd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ];
88810535SVikram.Hegde@Sun.COM 	for (; minfop; minfop = minfop->acm_next) {
88910535SVikram.Hegde@Sun.COM 		if (minfop->acm_deviceid_start == 0 &&
89010535SVikram.Hegde@Sun.COM 		    minfop->acm_deviceid_end == (uint16_t)-1) {
89110535SVikram.Hegde@Sun.COM 			break;
89210535SVikram.Hegde@Sun.COM 		}
89310535SVikram.Hegde@Sun.COM 	}
89410535SVikram.Hegde@Sun.COM 
89510535SVikram.Hegde@Sun.COM 	return (minfop);
89610535SVikram.Hegde@Sun.COM }
89710535SVikram.Hegde@Sun.COM 
89810535SVikram.Hegde@Sun.COM amd_iommu_acpi_ivhd_t *
amd_iommu_lookup_any_ivhd(amd_iommu_t * iommu)899*12203SJerry.Gilliam@Sun.COM amd_iommu_lookup_any_ivhd(amd_iommu_t *iommu)
90010535SVikram.Hegde@Sun.COM {
90110535SVikram.Hegde@Sun.COM 	int i;
90210535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_ivhd_t *hinfop;
90310535SVikram.Hegde@Sun.COM 
90410535SVikram.Hegde@Sun.COM 	for (i = AMD_IOMMU_ACPI_INFO_HASH_SZ; i >= 0; i--) {
905*12203SJerry.Gilliam@Sun.COM 		hinfop = amd_iommu_acpi_ivhd_hash[i];
906*12203SJerry.Gilliam@Sun.COM 		if ((hinfop != NULL) &&
907*12203SJerry.Gilliam@Sun.COM 		    hinfop->ach_IOMMU_deviceid == iommu->aiomt_bdf)
90810535SVikram.Hegde@Sun.COM 			break;
90910535SVikram.Hegde@Sun.COM 	}
91010535SVikram.Hegde@Sun.COM 
91110535SVikram.Hegde@Sun.COM 	return (hinfop);
91210535SVikram.Hegde@Sun.COM }
91310535SVikram.Hegde@Sun.COM 
91410535SVikram.Hegde@Sun.COM amd_iommu_acpi_ivmd_t *
amd_iommu_lookup_any_ivmd(void)91510535SVikram.Hegde@Sun.COM amd_iommu_lookup_any_ivmd(void)
91610535SVikram.Hegde@Sun.COM {
91710535SVikram.Hegde@Sun.COM 	int i;
91810535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_ivmd_t *minfop;
91910535SVikram.Hegde@Sun.COM 
92010535SVikram.Hegde@Sun.COM 	for (i = AMD_IOMMU_ACPI_INFO_HASH_SZ; i >= 0; i--) {
921*12203SJerry.Gilliam@Sun.COM 		if ((minfop = amd_iommu_acpi_ivmd_hash[i]) != NULL)
92210535SVikram.Hegde@Sun.COM 			break;
92310535SVikram.Hegde@Sun.COM 	}
92410535SVikram.Hegde@Sun.COM 
92510535SVikram.Hegde@Sun.COM 	return (minfop);
92610535SVikram.Hegde@Sun.COM }
92710535SVikram.Hegde@Sun.COM 
92810535SVikram.Hegde@Sun.COM static void
dump_acpi_aliases(void)92910535SVikram.Hegde@Sun.COM dump_acpi_aliases(void)
93010535SVikram.Hegde@Sun.COM {
93110535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_ivhd_t *hinfop;
93210535SVikram.Hegde@Sun.COM 	uint16_t idx;
93310535SVikram.Hegde@Sun.COM 
93410535SVikram.Hegde@Sun.COM 	for (idx = 0; idx <= AMD_IOMMU_ACPI_INFO_HASH_SZ; idx++) {
93510535SVikram.Hegde@Sun.COM 		hinfop = amd_iommu_acpi_ivhd_hash[idx];
93610535SVikram.Hegde@Sun.COM 		for (; hinfop; hinfop = hinfop->ach_next) {
93710535SVikram.Hegde@Sun.COM 			cmn_err(CE_NOTE, "start=%d, end=%d, src_bdf=%d",
93810535SVikram.Hegde@Sun.COM 			    hinfop->ach_deviceid_start,
93910535SVikram.Hegde@Sun.COM 			    hinfop->ach_deviceid_end,
94010535SVikram.Hegde@Sun.COM 			    hinfop->ach_src_deviceid);
94110535SVikram.Hegde@Sun.COM 		}
94210535SVikram.Hegde@Sun.COM 	}
94310535SVikram.Hegde@Sun.COM }
94410535SVikram.Hegde@Sun.COM 
94510535SVikram.Hegde@Sun.COM amd_iommu_acpi_ivhd_t *
amd_iommu_lookup_ivhd(int32_t deviceid)94610535SVikram.Hegde@Sun.COM amd_iommu_lookup_ivhd(int32_t deviceid)
94710535SVikram.Hegde@Sun.COM {
94810535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_ivhd_t *hinfop;
94910535SVikram.Hegde@Sun.COM 	uint16_t idx;
95010535SVikram.Hegde@Sun.COM 
951*12203SJerry.Gilliam@Sun.COM 	if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
95210535SVikram.Hegde@Sun.COM 		cmn_err(CE_NOTE, "Attempting to get ACPI IVHD info "
95310535SVikram.Hegde@Sun.COM 		    "for deviceid: %d", deviceid);
95410535SVikram.Hegde@Sun.COM 	}
95510535SVikram.Hegde@Sun.COM 
95610535SVikram.Hegde@Sun.COM 	ASSERT(amd_iommu_acpi_ivhd_hash);
95710535SVikram.Hegde@Sun.COM 
95810535SVikram.Hegde@Sun.COM 	/* check if special device */
95910535SVikram.Hegde@Sun.COM 	if (deviceid == -1) {
96010535SVikram.Hegde@Sun.COM 		hinfop = amd_iommu_acpi_ivhd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ];
96110535SVikram.Hegde@Sun.COM 		for (; hinfop; hinfop = hinfop->ach_next) {
96210535SVikram.Hegde@Sun.COM 			if (hinfop->ach_deviceid_start  == -1 &&
96310535SVikram.Hegde@Sun.COM 			    hinfop->ach_deviceid_end == -1) {
96410535SVikram.Hegde@Sun.COM 				break;
96510535SVikram.Hegde@Sun.COM 			}
96610535SVikram.Hegde@Sun.COM 		}
96710535SVikram.Hegde@Sun.COM 		return (hinfop);
96810535SVikram.Hegde@Sun.COM 	}
96910535SVikram.Hegde@Sun.COM 
97010535SVikram.Hegde@Sun.COM 	/* First search for an exact match */
97110535SVikram.Hegde@Sun.COM 
97210535SVikram.Hegde@Sun.COM 	idx = deviceid_hashfn(deviceid);
97310535SVikram.Hegde@Sun.COM 
97410535SVikram.Hegde@Sun.COM 
97510535SVikram.Hegde@Sun.COM range:
97610535SVikram.Hegde@Sun.COM 	hinfop = amd_iommu_acpi_ivhd_hash[idx];
97710535SVikram.Hegde@Sun.COM 
97810535SVikram.Hegde@Sun.COM 	for (; hinfop; hinfop = hinfop->ach_next) {
97910535SVikram.Hegde@Sun.COM 		if (deviceid < hinfop->ach_deviceid_start ||
98010535SVikram.Hegde@Sun.COM 		    deviceid > hinfop->ach_deviceid_end)
98110535SVikram.Hegde@Sun.COM 			continue;
98210535SVikram.Hegde@Sun.COM 
983*12203SJerry.Gilliam@Sun.COM 		if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
98410535SVikram.Hegde@Sun.COM 			cmn_err(CE_NOTE, "Found ACPI IVHD match: %p, "
98510535SVikram.Hegde@Sun.COM 			    "actual deviceid = %u, start = %u, end = %u",
98610535SVikram.Hegde@Sun.COM 			    (void *)hinfop, deviceid,
98710535SVikram.Hegde@Sun.COM 			    hinfop->ach_deviceid_start,
98810535SVikram.Hegde@Sun.COM 			    hinfop->ach_deviceid_end);
98910535SVikram.Hegde@Sun.COM 		}
99010535SVikram.Hegde@Sun.COM 		goto out;
99110535SVikram.Hegde@Sun.COM 	}
99210535SVikram.Hegde@Sun.COM 
99310535SVikram.Hegde@Sun.COM 	if (idx !=  AMD_IOMMU_ACPI_INFO_HASH_SZ) {
99410535SVikram.Hegde@Sun.COM 		idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
99510535SVikram.Hegde@Sun.COM 		goto range;
99610535SVikram.Hegde@Sun.COM 	}
99710535SVikram.Hegde@Sun.COM 
99810535SVikram.Hegde@Sun.COM out:
999*12203SJerry.Gilliam@Sun.COM 	if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
100010535SVikram.Hegde@Sun.COM 		cmn_err(CE_NOTE, "%u: %s ACPI IVHD %p", deviceid,
100110535SVikram.Hegde@Sun.COM 		    hinfop ? "GOT" : "Did NOT get", (void *)hinfop);
100210535SVikram.Hegde@Sun.COM 	}
100310535SVikram.Hegde@Sun.COM 
100410535SVikram.Hegde@Sun.COM 	return (hinfop);
100510535SVikram.Hegde@Sun.COM }
100610535SVikram.Hegde@Sun.COM 
100710535SVikram.Hegde@Sun.COM amd_iommu_acpi_ivmd_t *
amd_iommu_lookup_ivmd(int32_t deviceid)100810535SVikram.Hegde@Sun.COM amd_iommu_lookup_ivmd(int32_t deviceid)
100910535SVikram.Hegde@Sun.COM {
101010535SVikram.Hegde@Sun.COM 	amd_iommu_acpi_ivmd_t *minfop;
101110535SVikram.Hegde@Sun.COM 	uint16_t idx;
101210535SVikram.Hegde@Sun.COM 
1013*12203SJerry.Gilliam@Sun.COM 	if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
101410535SVikram.Hegde@Sun.COM 		cmn_err(CE_NOTE, "Attempting to get ACPI IVMD info "
101510535SVikram.Hegde@Sun.COM 		    "for deviceid: %u", deviceid);
101610535SVikram.Hegde@Sun.COM 	}
101710535SVikram.Hegde@Sun.COM 
101810535SVikram.Hegde@Sun.COM 	ASSERT(amd_iommu_acpi_ivmd_hash);
101910535SVikram.Hegde@Sun.COM 
102010535SVikram.Hegde@Sun.COM 	/* First search for an exact match */
102110535SVikram.Hegde@Sun.COM 
102210535SVikram.Hegde@Sun.COM 	idx = deviceid_hashfn(deviceid);
102310535SVikram.Hegde@Sun.COM 
102410535SVikram.Hegde@Sun.COM range:
102510535SVikram.Hegde@Sun.COM 	minfop = amd_iommu_acpi_ivmd_hash[idx];
102610535SVikram.Hegde@Sun.COM 
102710535SVikram.Hegde@Sun.COM 	for (; minfop; minfop = minfop->acm_next) {
102810535SVikram.Hegde@Sun.COM 		if (deviceid < minfop->acm_deviceid_start &&
102910535SVikram.Hegde@Sun.COM 		    deviceid > minfop->acm_deviceid_end)
103010535SVikram.Hegde@Sun.COM 			continue;
103110535SVikram.Hegde@Sun.COM 
1032*12203SJerry.Gilliam@Sun.COM 		if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
103310535SVikram.Hegde@Sun.COM 			cmn_err(CE_NOTE, "Found ACPI IVMD match: %p, "
103410535SVikram.Hegde@Sun.COM 			    "actual deviceid = %u, start = %u, end = %u",
103510535SVikram.Hegde@Sun.COM 			    (void *)minfop, deviceid,
103610535SVikram.Hegde@Sun.COM 			    minfop->acm_deviceid_start,
103710535SVikram.Hegde@Sun.COM 			    minfop->acm_deviceid_end);
103810535SVikram.Hegde@Sun.COM 		}
103910535SVikram.Hegde@Sun.COM 
104010535SVikram.Hegde@Sun.COM 		goto out;
104110535SVikram.Hegde@Sun.COM 	}
104210535SVikram.Hegde@Sun.COM 
104310535SVikram.Hegde@Sun.COM 	if (idx !=  AMD_IOMMU_ACPI_INFO_HASH_SZ) {
104410535SVikram.Hegde@Sun.COM 		idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
104510535SVikram.Hegde@Sun.COM 		goto range;
104610535SVikram.Hegde@Sun.COM 	}
104710535SVikram.Hegde@Sun.COM 
104810535SVikram.Hegde@Sun.COM out:
1049*12203SJerry.Gilliam@Sun.COM 	if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
105010535SVikram.Hegde@Sun.COM 		cmn_err(CE_NOTE, "%u: %s ACPI IVMD info %p", deviceid,
105110535SVikram.Hegde@Sun.COM 		    minfop ? "GOT" : "Did NOT get", (void *)minfop);
105210535SVikram.Hegde@Sun.COM 	}
105310535SVikram.Hegde@Sun.COM 
105410535SVikram.Hegde@Sun.COM 	return (minfop);
105510535SVikram.Hegde@Sun.COM }
1056