1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 #include "amd_iommu_acpi.h"
27 #include "amd_iommu_impl.h"
28
29 static int create_acpi_hash(amd_iommu_acpi_t *acpi);
30 static void amd_iommu_acpi_table_fini(amd_iommu_acpi_t **acpipp);
31
32 static void dump_acpi_aliases(void);
33
34
35 /*
36 * Globals
37 */
38 static amd_iommu_acpi_global_t *amd_iommu_acpi_global;
39 static amd_iommu_acpi_ivhd_t **amd_iommu_acpi_ivhd_hash;
40 static amd_iommu_acpi_ivmd_t **amd_iommu_acpi_ivmd_hash;
41
42 static int
type_byte_size(char * cp)43 type_byte_size(char *cp)
44 {
45 uint8_t type8 = *((uint8_t *)cp);
46 uint8_t len_bits;
47
48 len_bits = AMD_IOMMU_REG_GET8(&type8, AMD_IOMMU_ACPI_DEVENTRY_LEN);
49
50 switch (len_bits) {
51 case 0:
52 return (4);
53 case 1:
54 return (8);
55 case 2:
56 return (16);
57 case 3:
58 return (32);
59 default:
60 cmn_err(CE_WARN, "%s: Invalid deventry len: %d",
61 amd_iommu_modname, len_bits);
62 return (len_bits);
63 }
64 /*NOTREACHED*/
65 }
66
67 static void
process_4byte_deventry(ivhd_container_t * c,char * cp)68 process_4byte_deventry(ivhd_container_t *c, char *cp)
69 {
70 int entry_type = *((uint8_t *)cp);
71 ivhd_deventry_t deventry = {0};
72 ivhd_deventry_t *devp;
73 uint8_t datsetting8;
74 align_16_t al = {0};
75 int i;
76
77 /* 4 byte entry */
78 deventry.idev_len = 4;
79 deventry.idev_deviceid = -1;
80 deventry.idev_src_deviceid = -1;
81
82 for (i = 0; i < 2; i++) {
83 al.ent8[i] = *((uint8_t *)&cp[i + 1]);
84 }
85
86 switch (entry_type) {
87 case 1:
88 deventry.idev_type = DEVENTRY_ALL;
89 break;
90 case 2:
91 deventry.idev_type = DEVENTRY_SELECT;
92 deventry.idev_deviceid = al.ent16;
93 break;
94 case 3:
95 deventry.idev_type = DEVENTRY_RANGE;
96 deventry.idev_deviceid = al.ent16;
97 break;
98 case 4:
99 deventry.idev_type = DEVENTRY_RANGE_END;
100 deventry.idev_deviceid = al.ent16;
101 ASSERT(cp[3] == 0);
102 break;
103 case 0:
104 ASSERT(al.ent16 == 0);
105 ASSERT(cp[3] == 0);
106 default:
107 return;
108 }
109
110
111 devp = kmem_alloc(sizeof (ivhd_deventry_t), KM_SLEEP);
112 *devp = deventry;
113
114 if (c->ivhdc_first_deventry == NULL)
115 c->ivhdc_first_deventry = devp;
116 else
117 c->ivhdc_last_deventry->idev_next = devp;
118
119 c->ivhdc_last_deventry = devp;
120
121 if (entry_type == 4)
122 return;
123
124 datsetting8 = (*((uint8_t *)&cp[3]));
125
126 devp->idev_Lint1Pass = AMD_IOMMU_REG_GET8(&datsetting8,
127 AMD_IOMMU_ACPI_LINT1PASS);
128
129 devp->idev_Lint0Pass = AMD_IOMMU_REG_GET8(&datsetting8,
130 AMD_IOMMU_ACPI_LINT0PASS);
131
132 devp->idev_SysMgt = AMD_IOMMU_REG_GET8(&datsetting8,
133 AMD_IOMMU_ACPI_SYSMGT);
134
135 ASSERT(AMD_IOMMU_REG_GET8(&datsetting8,
136 AMD_IOMMU_ACPI_DATRSV) == 0);
137
138 devp->idev_NMIPass = AMD_IOMMU_REG_GET8(&datsetting8,
139 AMD_IOMMU_ACPI_NMIPASS);
140
141 devp->idev_ExtIntPass = AMD_IOMMU_REG_GET8(&datsetting8,
142 AMD_IOMMU_ACPI_EXTINTPASS);
143
144 devp->idev_INITPass = AMD_IOMMU_REG_GET8(&datsetting8,
145 AMD_IOMMU_ACPI_INITPASS);
146 }
147
148 static void
process_8byte_deventry(ivhd_container_t * c,char * cp)149 process_8byte_deventry(ivhd_container_t *c, char *cp)
150 {
151 uint8_t datsetting8;
152 int entry_type = (uint8_t)*cp;
153 ivhd_deventry_t deventry = {0};
154 ivhd_deventry_t *devp;
155 align_16_t al1 = {0};
156 align_16_t al2 = {0};
157 align_32_t al3 = {0};
158 int i;
159
160 /* Length is 8 bytes */
161 deventry.idev_len = 8;
162 deventry.idev_deviceid = -1;
163 deventry.idev_src_deviceid = -1;
164
165 for (i = 0; i < 2; i++) {
166 al1.ent8[i] = *((uint8_t *)&cp[i+1]);
167 al2.ent8[i] = *((uint8_t *)&cp[i+5]);
168 }
169
170 datsetting8 = *((uint8_t *)&cp[3]);
171
172 switch (entry_type) {
173 case 66:
174 deventry.idev_type = DEVENTRY_ALIAS_SELECT;
175 deventry.idev_deviceid = al1.ent16;
176 deventry.idev_src_deviceid = al2.ent16;
177 ASSERT(cp[4] == 0);
178 ASSERT(cp[7] == 0);
179 break;
180 case 67:
181 deventry.idev_type = DEVENTRY_ALIAS_RANGE;
182 deventry.idev_deviceid = al1.ent16;
183 deventry.idev_src_deviceid = al2.ent16;
184 ASSERT(cp[4] == 0);
185 ASSERT(cp[7] == 0);
186 break;
187 case 70:
188 deventry.idev_type = DEVENTRY_EXTENDED_SELECT;
189 deventry.idev_deviceid = al1.ent16;
190 break;
191 case 71:
192 deventry.idev_type = DEVENTRY_EXTENDED_RANGE;
193 deventry.idev_deviceid = al1.ent16;
194 break;
195 case 72:
196 deventry.idev_type = DEVENTRY_SPECIAL_DEVICE;
197 ASSERT(al1.ent16 == 0);
198 deventry.idev_deviceid = -1;
199 deventry.idev_handle = cp[4];
200 deventry.idev_variety = cp[7];
201 deventry.idev_src_deviceid = al2.ent16;
202 default:
203 #ifdef BROKEN_ASSERT
204 for (i = 0; i < 7; i++) {
205 ASSERT(cp[i] == 0);
206 }
207 #endif
208 return;
209 }
210
211
212 devp = kmem_alloc(sizeof (ivhd_deventry_t), KM_SLEEP);
213 *devp = deventry;
214
215 if (c->ivhdc_first_deventry == NULL)
216 c->ivhdc_first_deventry = devp;
217 else
218 c->ivhdc_last_deventry->idev_next = devp;
219
220 c->ivhdc_last_deventry = devp;
221
222 devp->idev_Lint1Pass = AMD_IOMMU_REG_GET8(&datsetting8,
223 AMD_IOMMU_ACPI_LINT1PASS);
224
225 devp->idev_Lint0Pass = AMD_IOMMU_REG_GET8(&datsetting8,
226 AMD_IOMMU_ACPI_LINT0PASS);
227
228 devp->idev_SysMgt = AMD_IOMMU_REG_GET8(&datsetting8,
229 AMD_IOMMU_ACPI_SYSMGT);
230
231 ASSERT(AMD_IOMMU_REG_GET8(&datsetting8,
232 AMD_IOMMU_ACPI_DATRSV) == 0);
233
234 devp->idev_NMIPass = AMD_IOMMU_REG_GET8(&datsetting8,
235 AMD_IOMMU_ACPI_NMIPASS);
236
237 devp->idev_ExtIntPass = AMD_IOMMU_REG_GET8(&datsetting8,
238 AMD_IOMMU_ACPI_EXTINTPASS);
239
240 devp->idev_INITPass = AMD_IOMMU_REG_GET8(&datsetting8,
241 AMD_IOMMU_ACPI_INITPASS);
242
243 if (entry_type != 70 && entry_type != 71) {
244 return;
245 }
246
247 /* Type 70 and 71 */
248 for (i = 0; i < 4; i++) {
249 al3.ent8[i] = *((uint8_t *)&cp[i+4]);
250 }
251
252 devp->idev_AtsDisabled = AMD_IOMMU_REG_GET8(&al3.ent32,
253 AMD_IOMMU_ACPI_ATSDISABLED);
254
255 ASSERT(AMD_IOMMU_REG_GET8(&al3.ent32, AMD_IOMMU_ACPI_EXTDATRSV) == 0);
256 }
257
258 static void
process_ivhd(amd_iommu_acpi_t * acpi,ivhd_t * ivhdp)259 process_ivhd(amd_iommu_acpi_t *acpi, ivhd_t *ivhdp)
260 {
261 ivhd_container_t *c;
262 caddr_t ivhd_end;
263 caddr_t ivhd_tot_end;
264 caddr_t cp;
265
266 ASSERT(ivhdp->ivhd_type == 0x10);
267
268 c = kmem_zalloc(sizeof (ivhd_container_t), KM_SLEEP);
269 c->ivhdc_ivhd = kmem_alloc(sizeof (ivhd_t), KM_SLEEP);
270 *(c->ivhdc_ivhd) = *ivhdp;
271
272 if (acpi->acp_first_ivhdc == NULL)
273 acpi->acp_first_ivhdc = c;
274 else
275 acpi->acp_last_ivhdc->ivhdc_next = c;
276
277 acpi->acp_last_ivhdc = c;
278
279 ivhd_end = (caddr_t)ivhdp + sizeof (ivhd_t);
280 ivhd_tot_end = (caddr_t)ivhdp + ivhdp->ivhd_len;
281
282 for (cp = ivhd_end; cp < ivhd_tot_end; cp += type_byte_size(cp)) {
283 /* 16 byte and 32 byte size are currently reserved */
284 switch (type_byte_size(cp)) {
285 case 4:
286 process_4byte_deventry(c, cp);
287 break;
288 case 8:
289 process_8byte_deventry(c, cp);
290 break;
291 case 16:
292 case 32:
293 /* Reserved */
294 break;
295 default:
296 cmn_err(CE_WARN, "%s: unsupported length for device "
297 "entry in ACPI IVRS table's IVHD entry",
298 amd_iommu_modname);
299 break;
300 }
301 }
302 }
303
304 static void
process_ivmd(amd_iommu_acpi_t * acpi,ivmd_t * ivmdp)305 process_ivmd(amd_iommu_acpi_t *acpi, ivmd_t *ivmdp)
306 {
307 ivmd_container_t *c;
308
309 ASSERT(ivmdp->ivmd_type != 0x10);
310
311 c = kmem_zalloc(sizeof (ivmd_container_t), KM_SLEEP);
312 c->ivmdc_ivmd = kmem_alloc(sizeof (ivmd_t), KM_SLEEP);
313 *(c->ivmdc_ivmd) = *ivmdp;
314
315 if (acpi->acp_first_ivmdc == NULL)
316 acpi->acp_first_ivmdc = c;
317 else
318 acpi->acp_last_ivmdc->ivmdc_next = c;
319
320 acpi->acp_last_ivmdc = c;
321 }
322
323 int
amd_iommu_acpi_init(void)324 amd_iommu_acpi_init(void)
325 {
326 ivrs_t *ivrsp;
327 caddr_t ivrsp_end;
328 caddr_t table_end;
329 caddr_t cp;
330 uint8_t type8;
331 amd_iommu_acpi_t *acpi;
332 align_ivhd_t al_vhd = {0};
333 align_ivmd_t al_vmd = {0};
334
335 if (AcpiGetTable(IVRS_SIG, 1, (ACPI_TABLE_HEADER **)&ivrsp) != AE_OK) {
336 cmn_err(CE_NOTE, "!amd_iommu: No AMD IOMMU ACPI IVRS table");
337 return (DDI_FAILURE);
338 }
339
340 /*
341 * Reserved field must be 0
342 */
343 ASSERT(ivrsp->ivrs_resv == 0);
344
345 ASSERT(AMD_IOMMU_REG_GET32(&ivrsp->ivrs_ivinfo,
346 AMD_IOMMU_ACPI_IVINFO_RSV1) == 0);
347 ASSERT(AMD_IOMMU_REG_GET32(&ivrsp->ivrs_ivinfo,
348 AMD_IOMMU_ACPI_IVINFO_RSV2) == 0);
349
350 ivrsp_end = (caddr_t)ivrsp + sizeof (struct ivrs);
351 table_end = (caddr_t)ivrsp + ivrsp->ivrs_hdr.Length;
352
353 acpi = kmem_zalloc(sizeof (amd_iommu_acpi_t), KM_SLEEP);
354 acpi->acp_ivrs = kmem_alloc(sizeof (ivrs_t), KM_SLEEP);
355 *(acpi->acp_ivrs) = *ivrsp;
356
357 for (cp = ivrsp_end; cp < table_end; cp += (al_vhd.ivhdp)->ivhd_len) {
358 al_vhd.cp = cp;
359 if (al_vhd.ivhdp->ivhd_type == 0x10)
360 process_ivhd(acpi, al_vhd.ivhdp);
361 }
362
363 for (cp = ivrsp_end; cp < table_end; cp += (al_vmd.ivmdp)->ivmd_len) {
364 al_vmd.cp = cp;
365 type8 = al_vmd.ivmdp->ivmd_type;
366 if (type8 == 0x20 || type8 == 0x21 || type8 == 0x22)
367 process_ivmd(acpi, al_vmd.ivmdp);
368 }
369
370 if (create_acpi_hash(acpi) != DDI_SUCCESS) {
371 return (DDI_FAILURE);
372 }
373
374 amd_iommu_acpi_table_fini(&acpi);
375
376 ASSERT(acpi == NULL);
377
378 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
379 dump_acpi_aliases();
380 debug_enter("dump");
381 }
382
383 return (DDI_SUCCESS);
384 }
385
386 static ivhd_deventry_t *
free_ivhd_deventry(ivhd_deventry_t * devp)387 free_ivhd_deventry(ivhd_deventry_t *devp)
388 {
389 ivhd_deventry_t *next = devp->idev_next;
390
391 kmem_free(devp, sizeof (ivhd_deventry_t));
392
393 return (next);
394 }
395
396 static ivhd_container_t *
free_ivhd_container(ivhd_container_t * ivhdcp)397 free_ivhd_container(ivhd_container_t *ivhdcp)
398 {
399 ivhd_container_t *next = ivhdcp->ivhdc_next;
400 ivhd_deventry_t *devp;
401
402 for (devp = ivhdcp->ivhdc_first_deventry; devp; ) {
403 devp = free_ivhd_deventry(devp);
404 }
405
406 kmem_free(ivhdcp->ivhdc_ivhd, sizeof (ivhd_t));
407 kmem_free(ivhdcp, sizeof (ivhd_container_t));
408
409 return (next);
410 }
411
412 static ivmd_container_t *
free_ivmd_container(ivmd_container_t * ivmdcp)413 free_ivmd_container(ivmd_container_t *ivmdcp)
414 {
415 ivmd_container_t *next = ivmdcp->ivmdc_next;
416
417 kmem_free(ivmdcp->ivmdc_ivmd, sizeof (ivmd_t));
418 kmem_free(ivmdcp, sizeof (ivmd_container_t));
419
420 return (next);
421 }
422
423 void
amd_iommu_acpi_fini(void)424 amd_iommu_acpi_fini(void)
425 {
426 }
427
428 /*
429 * TODO: Do we need to free the ACPI table for om GetFirmwareTable()
430 */
431 static void
amd_iommu_acpi_table_fini(amd_iommu_acpi_t ** acpipp)432 amd_iommu_acpi_table_fini(amd_iommu_acpi_t **acpipp)
433 {
434 amd_iommu_acpi_t *acpi = *acpipp;
435 ivhd_container_t *ivhdcp;
436 ivmd_container_t *ivmdcp;
437
438 ASSERT(acpi);
439
440 for (ivhdcp = acpi->acp_first_ivhdc; ivhdcp; ) {
441 ivhdcp = free_ivhd_container(ivhdcp);
442 }
443 for (ivmdcp = acpi->acp_first_ivmdc; ivmdcp; ) {
444 ivmdcp = free_ivmd_container(ivmdcp);
445 }
446
447 kmem_free(acpi->acp_ivrs, sizeof (struct ivrs));
448 kmem_free(acpi, sizeof (amd_iommu_acpi_t));
449
450 *acpipp = NULL;
451 }
452
453 static uint16_t
deviceid_hashfn(uint16_t deviceid)454 deviceid_hashfn(uint16_t deviceid)
455 {
456 return (deviceid % AMD_IOMMU_ACPI_INFO_HASH_SZ);
457 }
458
459 static void
add_deventry_info(ivhd_t * ivhdp,ivhd_deventry_t * deventry,amd_iommu_acpi_ivhd_t ** hash)460 add_deventry_info(ivhd_t *ivhdp, ivhd_deventry_t *deventry,
461 amd_iommu_acpi_ivhd_t **hash)
462 {
463 static amd_iommu_acpi_ivhd_t *last;
464 amd_iommu_acpi_ivhd_t *acpi_ivhdp;
465 uint8_t uint8_flags;
466 uint16_t uint16_info;
467 uint16_t idx;
468
469 if (deventry->idev_type == DEVENTRY_RANGE_END) {
470 ASSERT(last);
471 acpi_ivhdp = last;
472 last = NULL;
473 ASSERT(acpi_ivhdp->ach_dev_type == DEVENTRY_RANGE ||
474 acpi_ivhdp->ach_dev_type == DEVENTRY_ALIAS_RANGE ||
475 acpi_ivhdp->ach_dev_type == DEVENTRY_EXTENDED_RANGE);
476 ASSERT(acpi_ivhdp->ach_deviceid_end == -1);
477 acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid;
478 /* TODO ASSERT data is 0 */
479 return;
480 }
481
482 ASSERT(last == NULL);
483 acpi_ivhdp = kmem_zalloc(sizeof (*acpi_ivhdp), KM_SLEEP);
484
485 uint8_flags = ivhdp->ivhd_flags;
486
487 #ifdef BROKEN_ASSERT
488 ASSERT(AMD_IOMMU_REG_GET8(&uint8_flags,
489 AMD_IOMMU_ACPI_IVHD_FLAGS_RSV) == 0);
490 #endif
491
492 acpi_ivhdp->ach_IotlbSup = AMD_IOMMU_REG_GET8(&uint8_flags,
493 AMD_IOMMU_ACPI_IVHD_FLAGS_IOTLBSUP);
494 acpi_ivhdp->ach_Isoc = AMD_IOMMU_REG_GET8(&uint8_flags,
495 AMD_IOMMU_ACPI_IVHD_FLAGS_ISOC);
496 acpi_ivhdp->ach_ResPassPW = AMD_IOMMU_REG_GET8(&uint8_flags,
497 AMD_IOMMU_ACPI_IVHD_FLAGS_RESPASSPW);
498 acpi_ivhdp->ach_PassPW = AMD_IOMMU_REG_GET8(&uint8_flags,
499 AMD_IOMMU_ACPI_IVHD_FLAGS_PASSPW);
500 acpi_ivhdp->ach_HtTunEn = AMD_IOMMU_REG_GET8(&uint8_flags,
501 AMD_IOMMU_ACPI_IVHD_FLAGS_HTTUNEN);
502
503 /* IVHD fields */
504 acpi_ivhdp->ach_IOMMU_deviceid = ivhdp->ivhd_deviceid;
505 acpi_ivhdp->ach_IOMMU_cap_off = ivhdp->ivhd_cap_off;
506 acpi_ivhdp->ach_IOMMU_reg_base = ivhdp->ivhd_reg_base;
507 acpi_ivhdp->ach_IOMMU_pci_seg = ivhdp->ivhd_pci_seg;
508
509 /* IVHD IOMMU info fields */
510 uint16_info = ivhdp->ivhd_iommu_info;
511
512 #ifdef BROKEN_ASSERT
513 ASSERT(AMD_IOMMU_REG_GET16(&uint16_info,
514 AMD_IOMMU_ACPI_IOMMU_INFO_RSV1) == 0);
515 #endif
516
517 acpi_ivhdp->ach_IOMMU_UnitID = AMD_IOMMU_REG_GET16(&uint16_info,
518 AMD_IOMMU_ACPI_IOMMU_INFO_UNITID);
519 ASSERT(AMD_IOMMU_REG_GET16(&uint16_info,
520 AMD_IOMMU_ACPI_IOMMU_INFO_RSV2) == 0);
521 acpi_ivhdp->ach_IOMMU_MSInum = AMD_IOMMU_REG_GET16(&uint16_info,
522 AMD_IOMMU_ACPI_IOMMU_INFO_MSINUM);
523
524 /* Initialize deviceids to -1 */
525 acpi_ivhdp->ach_deviceid_start = -1;
526 acpi_ivhdp->ach_deviceid_end = -1;
527 acpi_ivhdp->ach_src_deviceid = -1;
528
529 /* All range type entries are put on hash entry 0 */
530 switch (deventry->idev_type) {
531 case DEVENTRY_ALL:
532 acpi_ivhdp->ach_deviceid_start = 0;
533 acpi_ivhdp->ach_deviceid_end = (uint16_t)-1;
534 acpi_ivhdp->ach_dev_type = DEVENTRY_ALL;
535 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
536 break;
537 case DEVENTRY_SELECT:
538 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
539 acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid;
540 acpi_ivhdp->ach_dev_type = DEVENTRY_SELECT;
541 idx = deviceid_hashfn(deventry->idev_deviceid);
542 break;
543 case DEVENTRY_RANGE:
544 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
545 acpi_ivhdp->ach_deviceid_end = -1;
546 acpi_ivhdp->ach_dev_type = DEVENTRY_RANGE;
547 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
548 last = acpi_ivhdp;
549 break;
550 case DEVENTRY_RANGE_END:
551 cmn_err(CE_PANIC, "%s: Unexpected Range End Deventry",
552 amd_iommu_modname);
553 /*NOTREACHED*/
554 case DEVENTRY_ALIAS_SELECT:
555 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
556 acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid;
557 acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid;
558 acpi_ivhdp->ach_dev_type = DEVENTRY_ALIAS_SELECT;
559 idx = deviceid_hashfn(deventry->idev_deviceid);
560 break;
561 case DEVENTRY_ALIAS_RANGE:
562 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
563 acpi_ivhdp->ach_deviceid_end = -1;
564 acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid;
565 acpi_ivhdp->ach_dev_type = DEVENTRY_ALIAS_RANGE;
566 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
567 last = acpi_ivhdp;
568 break;
569 case DEVENTRY_EXTENDED_SELECT:
570 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
571 acpi_ivhdp->ach_deviceid_end = deventry->idev_deviceid;
572 acpi_ivhdp->ach_dev_type = DEVENTRY_EXTENDED_SELECT;
573 idx = deviceid_hashfn(deventry->idev_deviceid);
574 break;
575 case DEVENTRY_EXTENDED_RANGE:
576 acpi_ivhdp->ach_deviceid_start = deventry->idev_deviceid;
577 acpi_ivhdp->ach_deviceid_end = -1;
578 acpi_ivhdp->ach_dev_type = DEVENTRY_EXTENDED_RANGE;
579 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
580 last = acpi_ivhdp;
581 break;
582 case DEVENTRY_SPECIAL_DEVICE:
583 acpi_ivhdp->ach_deviceid_start = -1;
584 acpi_ivhdp->ach_deviceid_end = -1;
585 acpi_ivhdp->ach_src_deviceid = deventry->idev_src_deviceid;
586 acpi_ivhdp->ach_special_handle = deventry->idev_handle;
587 acpi_ivhdp->ach_special_variety = deventry->idev_variety;
588 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
589 default:
590 cmn_err(CE_PANIC, "%s: Unsupported deventry type",
591 amd_iommu_modname);
592 /*NOTREACHED*/
593 }
594
595 acpi_ivhdp->ach_Lint1Pass = deventry->idev_Lint1Pass;
596 acpi_ivhdp->ach_Lint0Pass = deventry->idev_Lint0Pass;
597 acpi_ivhdp->ach_SysMgt = deventry->idev_SysMgt;
598 acpi_ivhdp->ach_NMIPass = deventry->idev_NMIPass;
599 acpi_ivhdp->ach_ExtIntPass = deventry->idev_ExtIntPass;
600 acpi_ivhdp->ach_INITPass = deventry->idev_INITPass;
601
602
603 /* extended data */
604 if (acpi_ivhdp->ach_dev_type == DEVENTRY_EXTENDED_SELECT ||
605 acpi_ivhdp->ach_dev_type == DEVENTRY_EXTENDED_RANGE) {
606 acpi_ivhdp->ach_AtsDisabled = deventry->idev_AtsDisabled;
607 }
608
609 /*
610 * Now add it to the hash
611 */
612 ASSERT(hash[idx] != acpi_ivhdp);
613 acpi_ivhdp->ach_next = hash[idx];
614 hash[idx] = acpi_ivhdp;
615 }
616
617 /*
618 * A device entry may be declared implicitly as a source device ID
619 * in an alias entry. This routine adds it to the hash
620 */
621 static void
add_implicit_deventry(ivhd_container_t * ivhdcp,amd_iommu_acpi_ivhd_t ** hash)622 add_implicit_deventry(ivhd_container_t *ivhdcp, amd_iommu_acpi_ivhd_t **hash)
623 {
624 ivhd_deventry_t *d;
625 int deviceid;
626
627 for (d = ivhdcp->ivhdc_first_deventry; d; d = d->idev_next) {
628
629 if ((d->idev_type != DEVENTRY_ALIAS_SELECT) &&
630 (d->idev_type != DEVENTRY_ALIAS_RANGE))
631 continue;
632
633 deviceid = d->idev_src_deviceid;
634
635 if (amd_iommu_lookup_ivhd(deviceid) == NULL) {
636 ivhd_deventry_t deventry;
637
638 /* Fake a SELECT entry */
639 deventry.idev_type = DEVENTRY_SELECT;
640 deventry.idev_len = 4;
641 deventry.idev_deviceid = deviceid;
642 deventry.idev_src_deviceid = -1;
643
644 deventry.idev_Lint1Pass = d->idev_Lint1Pass;
645 deventry.idev_Lint0Pass = d->idev_Lint0Pass;
646 deventry.idev_SysMgt = d->idev_SysMgt;
647 deventry.idev_NMIPass = d->idev_NMIPass;
648 deventry.idev_ExtIntPass = d->idev_ExtIntPass;
649 deventry.idev_INITPass = d->idev_INITPass;
650
651 add_deventry_info(ivhdcp->ivhdc_ivhd, &deventry, hash);
652
653 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
654 cmn_err(CE_NOTE, "Added implicit IVHD entry "
655 "for: deviceid = %u", deviceid);
656 }
657 }
658 }
659 }
660
661 static void
add_ivhdc_info(ivhd_container_t * ivhdcp,amd_iommu_acpi_ivhd_t ** hash)662 add_ivhdc_info(ivhd_container_t *ivhdcp, amd_iommu_acpi_ivhd_t **hash)
663 {
664 ivhd_deventry_t *deventry;
665 ivhd_t *ivhdp = ivhdcp->ivhdc_ivhd;
666
667 for (deventry = ivhdcp->ivhdc_first_deventry; deventry;
668 deventry = deventry->idev_next) {
669 add_deventry_info(ivhdp, deventry, hash);
670 }
671
672 add_implicit_deventry(ivhdcp, hash);
673
674 }
675
676 static void
add_ivhd_info(amd_iommu_acpi_t * acpi,amd_iommu_acpi_ivhd_t ** hash)677 add_ivhd_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_ivhd_t **hash)
678 {
679 ivhd_container_t *ivhdcp;
680
681 for (ivhdcp = acpi->acp_first_ivhdc; ivhdcp;
682 ivhdcp = ivhdcp->ivhdc_next) {
683 add_ivhdc_info(ivhdcp, hash);
684 }
685 }
686
687 static void
set_ivmd_info(ivmd_t * ivmdp,amd_iommu_acpi_ivmd_t ** hash)688 set_ivmd_info(ivmd_t *ivmdp, amd_iommu_acpi_ivmd_t **hash)
689 {
690 amd_iommu_acpi_ivmd_t *acpi_ivmdp;
691 uint8_t uint8_flags;
692 uint16_t idx;
693
694 uint8_flags = ivmdp->ivmd_flags;
695
696 acpi_ivmdp = kmem_zalloc(sizeof (*acpi_ivmdp), KM_SLEEP);
697
698 switch (ivmdp->ivmd_type) {
699 case 0x20:
700 acpi_ivmdp->acm_deviceid_start = 0;
701 acpi_ivmdp->acm_deviceid_end = (uint16_t)-1;
702 acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_ALL;
703 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
704 break;
705 case 0x21:
706 acpi_ivmdp->acm_deviceid_start = ivmdp->ivmd_deviceid;
707 acpi_ivmdp->acm_deviceid_end = ivmdp->ivmd_deviceid;
708 acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_SELECT;
709 idx = deviceid_hashfn(ivmdp->ivmd_deviceid);
710 break;
711 case 0x22:
712 acpi_ivmdp->acm_deviceid_start = ivmdp->ivmd_deviceid;
713 acpi_ivmdp->acm_deviceid_end = ivmdp->ivmd_auxdata;
714 acpi_ivmdp->acm_dev_type = IVMD_DEVICEID_RANGE;
715 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
716 break;
717 default:
718 cmn_err(CE_PANIC, "Unknown AMD IOMMU ACPI IVMD deviceid type: "
719 "%x", ivmdp->ivmd_type);
720 /*NOTREACHED*/
721 }
722
723 ASSERT(AMD_IOMMU_REG_GET8(&uint8_flags,
724 AMD_IOMMU_ACPI_IVMD_RSV) == 0);
725
726 acpi_ivmdp->acm_ExclRange = AMD_IOMMU_REG_GET8(&uint8_flags,
727 AMD_IOMMU_ACPI_IVMD_EXCL_RANGE);
728 acpi_ivmdp->acm_IW = AMD_IOMMU_REG_GET8(&uint8_flags,
729 AMD_IOMMU_ACPI_IVMD_IW);
730 acpi_ivmdp->acm_IR = AMD_IOMMU_REG_GET8(&uint8_flags,
731 AMD_IOMMU_ACPI_IVMD_IR);
732 acpi_ivmdp->acm_Unity = AMD_IOMMU_REG_GET8(&uint8_flags,
733 AMD_IOMMU_ACPI_IVMD_UNITY);
734
735 acpi_ivmdp->acm_ivmd_phys_start = ivmdp->ivmd_phys_start;
736 acpi_ivmdp->acm_ivmd_phys_len = ivmdp->ivmd_phys_len;
737
738 acpi_ivmdp->acm_next = hash[idx];
739 hash[idx] = acpi_ivmdp;
740 }
741
742 static void
add_ivmdc_info(ivmd_container_t * ivmdcp,amd_iommu_acpi_ivmd_t ** hash)743 add_ivmdc_info(ivmd_container_t *ivmdcp, amd_iommu_acpi_ivmd_t **hash)
744 {
745 set_ivmd_info(ivmdcp->ivmdc_ivmd, hash);
746 }
747
748 static void
add_ivmd_info(amd_iommu_acpi_t * acpi,amd_iommu_acpi_ivmd_t ** hash)749 add_ivmd_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_ivmd_t **hash)
750 {
751 ivmd_container_t *ivmdcp;
752
753 for (ivmdcp = acpi->acp_first_ivmdc; ivmdcp;
754 ivmdcp = ivmdcp->ivmdc_next) {
755 add_ivmdc_info(ivmdcp, hash);
756 }
757 }
758
759 static void
add_global_info(amd_iommu_acpi_t * acpi,amd_iommu_acpi_global_t * global)760 add_global_info(amd_iommu_acpi_t *acpi, amd_iommu_acpi_global_t *global)
761 {
762 uint32_t ivrs_ivinfo = acpi->acp_ivrs->ivrs_ivinfo;
763
764 global->acg_HtAtsResv =
765 AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_HT_ATSRSV);
766 global->acg_VAsize =
767 AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_VA_SIZE);
768 global->acg_PAsize =
769 AMD_IOMMU_REG_GET32(&ivrs_ivinfo, AMD_IOMMU_ACPI_PA_SIZE);
770 }
771
772 static int
create_acpi_hash(amd_iommu_acpi_t * acpi)773 create_acpi_hash(amd_iommu_acpi_t *acpi)
774 {
775 /* Last hash entry is for deviceid ranges including "all" */
776
777 amd_iommu_acpi_global = kmem_zalloc(sizeof (amd_iommu_acpi_global_t),
778 KM_SLEEP);
779
780 amd_iommu_acpi_ivhd_hash = kmem_zalloc(sizeof (amd_iommu_acpi_ivhd_t *)
781 * (AMD_IOMMU_ACPI_INFO_HASH_SZ + 1), KM_SLEEP);
782
783 amd_iommu_acpi_ivmd_hash = kmem_zalloc(sizeof (amd_iommu_acpi_ivmd_t *)
784 * (AMD_IOMMU_ACPI_INFO_HASH_SZ + 1), KM_SLEEP);
785
786 add_global_info(acpi, amd_iommu_acpi_global);
787
788 add_ivhd_info(acpi, amd_iommu_acpi_ivhd_hash);
789
790 add_ivmd_info(acpi, amd_iommu_acpi_ivmd_hash);
791
792 return (DDI_SUCCESS);
793 }
794
795 static void
set_deventry(amd_iommu_t * iommu,int entry,amd_iommu_acpi_ivhd_t * hinfop)796 set_deventry(amd_iommu_t *iommu, int entry, amd_iommu_acpi_ivhd_t *hinfop)
797 {
798 uint64_t *dentry;
799
800 dentry = (uint64_t *)(intptr_t)
801 &iommu->aiomt_devtbl[entry * AMD_IOMMU_DEVTBL_ENTRY_SZ];
802
803 AMD_IOMMU_REG_SET64(&(dentry[1]), AMD_IOMMU_DEVTBL_SYSMGT,
804 hinfop->ach_SysMgt);
805 }
806
807 /* Initialize device table according to IVHD */
808 int
amd_iommu_acpi_init_devtbl(amd_iommu_t * iommu)809 amd_iommu_acpi_init_devtbl(amd_iommu_t *iommu)
810 {
811 int i, j;
812 amd_iommu_acpi_ivhd_t *hinfop;
813
814 for (i = 0; i <= AMD_IOMMU_ACPI_INFO_HASH_SZ; i++) {
815 for (hinfop = amd_iommu_acpi_ivhd_hash[i];
816 hinfop; hinfop = hinfop->ach_next) {
817
818 if (hinfop->ach_IOMMU_deviceid != iommu->aiomt_bdf)
819 continue;
820
821 switch (hinfop->ach_dev_type) {
822 case DEVENTRY_ALL:
823 for (j = 0; j < AMD_IOMMU_MAX_DEVICEID; j++)
824 set_deventry(iommu, j, hinfop);
825 break;
826 case DEVENTRY_SELECT:
827 case DEVENTRY_EXTENDED_SELECT:
828 set_deventry(iommu,
829 hinfop->ach_deviceid_start,
830 hinfop);
831 break;
832 case DEVENTRY_RANGE:
833 case DEVENTRY_EXTENDED_RANGE:
834 for (j = hinfop->ach_deviceid_start;
835 j <= hinfop->ach_deviceid_end;
836 j++)
837 set_deventry(iommu, j, hinfop);
838 break;
839 case DEVENTRY_ALIAS_SELECT:
840 case DEVENTRY_ALIAS_RANGE:
841 case DEVENTRY_SPECIAL_DEVICE:
842 set_deventry(iommu,
843 hinfop->ach_src_deviceid,
844 hinfop);
845 break;
846 default:
847 cmn_err(CE_WARN,
848 "%s: Unknown deventry type",
849 amd_iommu_modname);
850 return (DDI_FAILURE);
851 }
852 }
853 }
854
855 return (DDI_SUCCESS);
856 }
857
858 amd_iommu_acpi_global_t *
amd_iommu_lookup_acpi_global(void)859 amd_iommu_lookup_acpi_global(void)
860 {
861 ASSERT(amd_iommu_acpi_global);
862
863 return (amd_iommu_acpi_global);
864 }
865
866 amd_iommu_acpi_ivhd_t *
amd_iommu_lookup_all_ivhd(void)867 amd_iommu_lookup_all_ivhd(void)
868 {
869 amd_iommu_acpi_ivhd_t *hinfop;
870
871 hinfop = amd_iommu_acpi_ivhd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ];
872 for (; hinfop; hinfop = hinfop->ach_next) {
873 if (hinfop->ach_deviceid_start == 0 &&
874 hinfop->ach_deviceid_end == (uint16_t)-1) {
875 break;
876 }
877 }
878
879 return (hinfop);
880 }
881
882 amd_iommu_acpi_ivmd_t *
amd_iommu_lookup_all_ivmd(void)883 amd_iommu_lookup_all_ivmd(void)
884 {
885 amd_iommu_acpi_ivmd_t *minfop;
886
887 minfop = amd_iommu_acpi_ivmd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ];
888 for (; minfop; minfop = minfop->acm_next) {
889 if (minfop->acm_deviceid_start == 0 &&
890 minfop->acm_deviceid_end == (uint16_t)-1) {
891 break;
892 }
893 }
894
895 return (minfop);
896 }
897
898 amd_iommu_acpi_ivhd_t *
amd_iommu_lookup_any_ivhd(amd_iommu_t * iommu)899 amd_iommu_lookup_any_ivhd(amd_iommu_t *iommu)
900 {
901 int i;
902 amd_iommu_acpi_ivhd_t *hinfop;
903
904 for (i = AMD_IOMMU_ACPI_INFO_HASH_SZ; i >= 0; i--) {
905 hinfop = amd_iommu_acpi_ivhd_hash[i];
906 if ((hinfop != NULL) &&
907 hinfop->ach_IOMMU_deviceid == iommu->aiomt_bdf)
908 break;
909 }
910
911 return (hinfop);
912 }
913
914 amd_iommu_acpi_ivmd_t *
amd_iommu_lookup_any_ivmd(void)915 amd_iommu_lookup_any_ivmd(void)
916 {
917 int i;
918 amd_iommu_acpi_ivmd_t *minfop;
919
920 for (i = AMD_IOMMU_ACPI_INFO_HASH_SZ; i >= 0; i--) {
921 if ((minfop = amd_iommu_acpi_ivmd_hash[i]) != NULL)
922 break;
923 }
924
925 return (minfop);
926 }
927
928 static void
dump_acpi_aliases(void)929 dump_acpi_aliases(void)
930 {
931 amd_iommu_acpi_ivhd_t *hinfop;
932 uint16_t idx;
933
934 for (idx = 0; idx <= AMD_IOMMU_ACPI_INFO_HASH_SZ; idx++) {
935 hinfop = amd_iommu_acpi_ivhd_hash[idx];
936 for (; hinfop; hinfop = hinfop->ach_next) {
937 cmn_err(CE_NOTE, "start=%d, end=%d, src_bdf=%d",
938 hinfop->ach_deviceid_start,
939 hinfop->ach_deviceid_end,
940 hinfop->ach_src_deviceid);
941 }
942 }
943 }
944
945 amd_iommu_acpi_ivhd_t *
amd_iommu_lookup_ivhd(int32_t deviceid)946 amd_iommu_lookup_ivhd(int32_t deviceid)
947 {
948 amd_iommu_acpi_ivhd_t *hinfop;
949 uint16_t idx;
950
951 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
952 cmn_err(CE_NOTE, "Attempting to get ACPI IVHD info "
953 "for deviceid: %d", deviceid);
954 }
955
956 ASSERT(amd_iommu_acpi_ivhd_hash);
957
958 /* check if special device */
959 if (deviceid == -1) {
960 hinfop = amd_iommu_acpi_ivhd_hash[AMD_IOMMU_ACPI_INFO_HASH_SZ];
961 for (; hinfop; hinfop = hinfop->ach_next) {
962 if (hinfop->ach_deviceid_start == -1 &&
963 hinfop->ach_deviceid_end == -1) {
964 break;
965 }
966 }
967 return (hinfop);
968 }
969
970 /* First search for an exact match */
971
972 idx = deviceid_hashfn(deviceid);
973
974
975 range:
976 hinfop = amd_iommu_acpi_ivhd_hash[idx];
977
978 for (; hinfop; hinfop = hinfop->ach_next) {
979 if (deviceid < hinfop->ach_deviceid_start ||
980 deviceid > hinfop->ach_deviceid_end)
981 continue;
982
983 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
984 cmn_err(CE_NOTE, "Found ACPI IVHD match: %p, "
985 "actual deviceid = %u, start = %u, end = %u",
986 (void *)hinfop, deviceid,
987 hinfop->ach_deviceid_start,
988 hinfop->ach_deviceid_end);
989 }
990 goto out;
991 }
992
993 if (idx != AMD_IOMMU_ACPI_INFO_HASH_SZ) {
994 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
995 goto range;
996 }
997
998 out:
999 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
1000 cmn_err(CE_NOTE, "%u: %s ACPI IVHD %p", deviceid,
1001 hinfop ? "GOT" : "Did NOT get", (void *)hinfop);
1002 }
1003
1004 return (hinfop);
1005 }
1006
1007 amd_iommu_acpi_ivmd_t *
amd_iommu_lookup_ivmd(int32_t deviceid)1008 amd_iommu_lookup_ivmd(int32_t deviceid)
1009 {
1010 amd_iommu_acpi_ivmd_t *minfop;
1011 uint16_t idx;
1012
1013 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
1014 cmn_err(CE_NOTE, "Attempting to get ACPI IVMD info "
1015 "for deviceid: %u", deviceid);
1016 }
1017
1018 ASSERT(amd_iommu_acpi_ivmd_hash);
1019
1020 /* First search for an exact match */
1021
1022 idx = deviceid_hashfn(deviceid);
1023
1024 range:
1025 minfop = amd_iommu_acpi_ivmd_hash[idx];
1026
1027 for (; minfop; minfop = minfop->acm_next) {
1028 if (deviceid < minfop->acm_deviceid_start &&
1029 deviceid > minfop->acm_deviceid_end)
1030 continue;
1031
1032 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
1033 cmn_err(CE_NOTE, "Found ACPI IVMD match: %p, "
1034 "actual deviceid = %u, start = %u, end = %u",
1035 (void *)minfop, deviceid,
1036 minfop->acm_deviceid_start,
1037 minfop->acm_deviceid_end);
1038 }
1039
1040 goto out;
1041 }
1042
1043 if (idx != AMD_IOMMU_ACPI_INFO_HASH_SZ) {
1044 idx = AMD_IOMMU_ACPI_INFO_HASH_SZ;
1045 goto range;
1046 }
1047
1048 out:
1049 if (amd_iommu_debug & AMD_IOMMU_DEBUG_ACPI) {
1050 cmn_err(CE_NOTE, "%u: %s ACPI IVMD info %p", deviceid,
1051 minfop ? "GOT" : "Did NOT get", (void *)minfop);
1052 }
1053
1054 return (minfop);
1055 }
1056