1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2016, Anish Gupta (anish@freebsd.org)
5  * Copyright (c) 2021 The FreeBSD Foundation
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice unmodified, this list of conditions, and the following
13  *    disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD: stable/12/sys/amd64/vmm/amd/ivrs_drv.c 373320 2024-04-28 05:23:19Z git2svn $");
32 
33 #include "opt_acpi.h"
34 #include <sys/param.h>
35 #include <sys/bus.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/malloc.h>
39 
40 #include <machine/vmparam.h>
41 
42 #include <vm/vm.h>
43 #include <vm/pmap.h>
44 
45 #include <contrib/dev/acpica/include/acpi.h>
46 #include <contrib/dev/acpica/include/accommon.h>
47 #include <dev/acpica/acpivar.h>
48 #include <dev/pci/pcireg.h>
49 #include <dev/pci/pcivar.h>
50 
51 #include "io/iommu.h"
52 #include "amdvi_priv.h"
53 
54 device_t *ivhd_devs;			/* IVHD or AMD-Vi device list. */
55 int	ivhd_count;			/* Number of IVHD header. */
56 /*
57  * Cached IVHD header list.
58  * Single entry for each IVHD, filtered the legacy one.
59  */
60 ACPI_IVRS_HARDWARE1 **ivhd_hdrs;
61 
62 extern int amdvi_ptp_level;		/* Page table levels. */
63 
64 typedef int (*ivhd_iter_t)(ACPI_IVRS_HEADER *ptr, void *arg);
65 /*
66  * Iterate IVRS table for IVHD and IVMD device type.
67  */
68 static void
ivrs_hdr_iterate_tbl(ivhd_iter_t iter,void * arg)69 ivrs_hdr_iterate_tbl(ivhd_iter_t iter, void *arg)
70 {
71 	ACPI_TABLE_IVRS *ivrs;
72 	ACPI_IVRS_HEADER *ivrs_hdr, *end;
73 	ACPI_STATUS status;
74 
75 	status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs);
76 	if (ACPI_FAILURE(status))
77 		return;
78 
79 	if (ivrs->Header.Length == 0) {
80 		return;
81 	}
82 
83 	ivrs_hdr = (ACPI_IVRS_HEADER *)(ivrs + 1);
84 	end = (ACPI_IVRS_HEADER *)((char *)ivrs + ivrs->Header.Length);
85 
86 	while (ivrs_hdr < end) {
87 		if ((uint8_t *)ivrs_hdr + ivrs_hdr->Length > (uint8_t *)end) {
88 			printf("AMD-Vi:IVHD/IVMD is corrupted, length : %d\n",
89 			    ivrs_hdr->Length);
90 			break;
91 		}
92 
93 		switch (ivrs_hdr->Type) {
94 		case IVRS_TYPE_HARDWARE_LEGACY:	/* Legacy */
95 		case IVRS_TYPE_HARDWARE_EFR:
96 		case IVRS_TYPE_HARDWARE_MIXED:
97 			if (!iter(ivrs_hdr, arg))
98 				return;
99 			break;
100 
101 		case ACPI_IVRS_TYPE_MEMORY1:
102 		case ACPI_IVRS_TYPE_MEMORY2:
103 		case ACPI_IVRS_TYPE_MEMORY3:
104 			if (!iter(ivrs_hdr, arg))
105 				return;
106 
107 			break;
108 
109 		default:
110 			printf("AMD-Vi:Not IVHD/IVMD type(%d)", ivrs_hdr->Type);
111 
112 		}
113 
114 		ivrs_hdr = (ACPI_IVRS_HEADER *)((uint8_t *)ivrs_hdr +
115 			ivrs_hdr->Length);
116 	}
117 }
118 
119 static bool
ivrs_is_ivhd(UINT8 type)120 ivrs_is_ivhd(UINT8 type)
121 {
122 
123 	switch(type) {
124 	case IVRS_TYPE_HARDWARE_LEGACY:
125 	case IVRS_TYPE_HARDWARE_EFR:
126 	case IVRS_TYPE_HARDWARE_MIXED:
127 		return (true);
128 
129 	default:
130 		return (false);
131 	}
132 }
133 
134 /* Count the number of AMD-Vi devices in the system. */
135 static int
ivhd_count_iter(ACPI_IVRS_HEADER * ivrs_he,void * arg)136 ivhd_count_iter(ACPI_IVRS_HEADER * ivrs_he, void *arg)
137 {
138 	int *count;
139 
140 	count = (int *)arg;
141 	if (ivrs_is_ivhd(ivrs_he->Type))
142 		(*count)++;
143 
144 	return (1);
145 }
146 
147 struct find_ivrs_hdr_args {
148 	int	i;
149 	ACPI_IVRS_HEADER *ptr;
150 };
151 
152 static int
ivrs_hdr_find_iter(ACPI_IVRS_HEADER * ivrs_hdr,void * args)153 ivrs_hdr_find_iter(ACPI_IVRS_HEADER * ivrs_hdr, void *args)
154 {
155 	struct find_ivrs_hdr_args *fi;
156 
157 	fi = (struct find_ivrs_hdr_args *)args;
158 	if (ivrs_is_ivhd(ivrs_hdr->Type)) {
159 		if (fi->i == 0) {
160 			fi->ptr = ivrs_hdr;
161 			return (0);
162 		}
163 		fi->i--;
164 	}
165 
166 	return (1);
167 }
168 
169 static ACPI_IVRS_HARDWARE1 *
ivhd_find_by_index(int idx)170 ivhd_find_by_index(int idx)
171 {
172 	struct find_ivrs_hdr_args fi;
173 
174 	fi.i = idx;
175 	fi.ptr = NULL;
176 
177 	ivrs_hdr_iterate_tbl(ivrs_hdr_find_iter, &fi);
178 
179 	return ((ACPI_IVRS_HARDWARE1 *)fi.ptr);
180 }
181 
182 static void
ivhd_dev_add_entry(struct amdvi_softc * softc,uint32_t start_id,uint32_t end_id,uint8_t cfg,bool ats)183 ivhd_dev_add_entry(struct amdvi_softc *softc, uint32_t start_id,
184     uint32_t end_id, uint8_t cfg, bool ats)
185 {
186 	struct ivhd_dev_cfg *dev_cfg;
187 
188 	KASSERT(softc->dev_cfg_cap >= softc->dev_cfg_cnt,
189 	    ("Impossible case: number of dev_cfg exceeding capacity"));
190 	if (softc->dev_cfg_cap == softc->dev_cfg_cnt) {
191 		if (softc->dev_cfg_cap == 0)
192 			softc->dev_cfg_cap = 1;
193 		else
194 			softc->dev_cfg_cap <<= 2;
195 		softc->dev_cfg = realloc(softc->dev_cfg,
196 		    sizeof(*softc->dev_cfg) * softc->dev_cfg_cap, M_DEVBUF,
197 		    M_WAITOK);
198 	}
199 
200 	dev_cfg = &softc->dev_cfg[softc->dev_cfg_cnt++];
201 	dev_cfg->start_id = start_id;
202 	dev_cfg->end_id = end_id;
203 	dev_cfg->data = cfg;
204 	dev_cfg->enable_ats = ats;
205 }
206 
207 /*
208  * Record device attributes as suggested by BIOS.
209  */
210 static int
ivhd_dev_parse(ACPI_IVRS_HARDWARE1 * ivhd,struct amdvi_softc * softc)211 ivhd_dev_parse(ACPI_IVRS_HARDWARE1 *ivhd, struct amdvi_softc *softc)
212 {
213 	ACPI_IVRS_DE_HEADER *de;
214 	uint8_t *p, *end;
215 	int range_start_id = -1, range_end_id = -1, i;
216 	uint32_t *extended;
217 	uint8_t all_data = 0, range_data = 0;
218 	bool range_enable_ats = false, enable_ats;
219 
220 	switch (ivhd->Header.Type) {
221 		case IVRS_TYPE_HARDWARE_LEGACY:
222 			p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE1);
223 			break;
224 
225 		case IVRS_TYPE_HARDWARE_EFR:
226 		case IVRS_TYPE_HARDWARE_MIXED:
227 			p = (uint8_t *)ivhd + sizeof(ACPI_IVRS_HARDWARE2);
228 			break;
229 
230 		default:
231 			device_printf(softc->dev,
232 				"unknown type: 0x%x\n", ivhd->Header.Type);
233 			return (-1);
234 	}
235 
236 	end = (uint8_t *)ivhd + ivhd->Header.Length;
237 
238 	while (p < end) {
239 		de = (ACPI_IVRS_DE_HEADER *)p;
240 		switch (de->Type) {
241 		case ACPI_IVRS_TYPE_ALL:
242 			all_data = de->DataSetting;
243 			for (i = 0; i < softc->dev_cfg_cnt; i++)
244 				softc->dev_cfg[i].data |= all_data;
245 			break;
246 
247 		case ACPI_IVRS_TYPE_SELECT:
248 		case ACPI_IVRS_TYPE_ALIAS_SELECT:
249 		case ACPI_IVRS_TYPE_EXT_SELECT:
250 			enable_ats = false;
251 			if (de->Type == ACPI_IVRS_TYPE_EXT_SELECT) {
252 				extended = (uint32_t *)(de + 1);
253 				enable_ats =
254 				    (*extended & IVHD_DEV_EXT_ATS_DISABLE) ?
255 					false : true;
256 			}
257 			ivhd_dev_add_entry(softc, de->Id, de->Id,
258 			    de->DataSetting | all_data, enable_ats);
259 			break;
260 
261 		case ACPI_IVRS_TYPE_START:
262 		case ACPI_IVRS_TYPE_ALIAS_START:
263 		case ACPI_IVRS_TYPE_EXT_START:
264 			if (range_start_id != -1) {
265 				device_printf(softc->dev,
266 				    "Unexpected start-of-range device entry\n");
267 				return (EINVAL);
268 			}
269 			range_start_id = de->Id;
270 			range_data = de->DataSetting;
271 			if (de->Type == ACPI_IVRS_TYPE_EXT_START) {
272 				extended = (uint32_t *)(de + 1);
273 				range_enable_ats =
274 				    (*extended & IVHD_DEV_EXT_ATS_DISABLE) ?
275 					false : true;
276 			}
277 			break;
278 
279 		case ACPI_IVRS_TYPE_END:
280 			if (range_start_id == -1) {
281 				device_printf(softc->dev,
282 				    "Unexpected end-of-range device entry\n");
283 				return (EINVAL);
284 			}
285 			range_end_id = de->Id;
286 			if (range_end_id < range_start_id) {
287 				device_printf(softc->dev,
288 				    "Device entry range going backward\n");
289 				return (EINVAL);
290 			}
291 			ivhd_dev_add_entry(softc, range_start_id, range_end_id,
292 			    range_data | all_data, range_enable_ats);
293 			range_start_id = range_end_id = -1;
294 			range_data = 0;
295 			all_data = 0;
296 			break;
297 
298 		case ACPI_IVRS_TYPE_PAD4:
299 			break;
300 
301 		case ACPI_IVRS_TYPE_SPECIAL:
302 			/* HPET or IOAPIC */
303 			break;
304 		default:
305 			if ((de->Type < 5) ||
306 			    (de->Type >= ACPI_IVRS_TYPE_PAD8))
307 				device_printf(softc->dev,
308 				    "Unknown dev entry:0x%x\n", de->Type);
309 		}
310 
311 		if (de->Type < 0x40)
312 			p += sizeof(ACPI_IVRS_DEVICE4);
313 		else if (de->Type < 0x80)
314 			p += sizeof(ACPI_IVRS_DEVICE8A);
315 		else {
316 			printf("Variable size IVHD type 0x%x not supported\n",
317 			    de->Type);
318 			break;
319 		}
320 	}
321 
322 	return (0);
323 }
324 
325 static bool
ivhd_is_newer(ACPI_IVRS_HEADER * old,ACPI_IVRS_HEADER * new)326 ivhd_is_newer(ACPI_IVRS_HEADER *old, ACPI_IVRS_HEADER  *new)
327 {
328 	if (old->DeviceId == new->DeviceId) {
329 		/*
330 		 * Newer IVRS header type take precedence.
331 		 */
332 		if (old->Type == IVRS_TYPE_HARDWARE_LEGACY &&
333 		    ((new->Type == IVRS_TYPE_HARDWARE_EFR) ||
334 		    (new->Type == IVRS_TYPE_HARDWARE_MIXED)))
335 			return (true);
336 
337 		/*
338 		 * Mixed format IVHD header type take precedence
339 		 * over fixed format IVHD header types.
340 		 */
341 		if (old->Type == IVRS_TYPE_HARDWARE_EFR &&
342 		    new->Type == IVRS_TYPE_HARDWARE_MIXED)
343 			return (true);
344 	}
345 
346 	return (false);
347 }
348 
349 static void
ivhd_identify(driver_t * driver,device_t parent)350 ivhd_identify(driver_t *driver, device_t parent)
351 {
352 	ACPI_TABLE_IVRS *ivrs;
353 	ACPI_IVRS_HARDWARE1 *ivhd;
354 	ACPI_STATUS status;
355 	int i, j, count = 0;
356 	uint32_t ivrs_ivinfo;
357 
358 	if (acpi_disabled("ivhd"))
359 		return;
360 
361 	status = AcpiGetTable(ACPI_SIG_IVRS, 1, (ACPI_TABLE_HEADER **)&ivrs);
362 	if (ACPI_FAILURE(status))
363 		return;
364 
365 	if (ivrs->Header.Length == 0) {
366 		return;
367 	}
368 
369 	ivrs_ivinfo = ivrs->Info;
370 	printf("AMD-Vi: IVRS Info VAsize = %d PAsize = %d GVAsize = %d"
371 	       " flags:%b\n",
372 		REG_BITS(ivrs_ivinfo, 21, 15), REG_BITS(ivrs_ivinfo, 14, 8),
373 		REG_BITS(ivrs_ivinfo, 7, 5), REG_BITS(ivrs_ivinfo, 22, 22),
374 		"\020\001EFRSup");
375 
376 	ivrs_hdr_iterate_tbl(ivhd_count_iter, &count);
377 	if (!count)
378 		return;
379 
380 	ivhd_hdrs = malloc(sizeof(void *) * count, M_DEVBUF,
381 		M_WAITOK | M_ZERO);
382 	for (i = 0; i < count; i++) {
383 		ivhd = ivhd_find_by_index(i);
384 		KASSERT(ivhd, ("ivhd%d is NULL\n", i));
385 
386 		/*
387 		 * Scan for presence of legacy and non-legacy device type
388 		 * for same IOMMU device and override the old one.
389 		 *
390 		 * If there is no existing IVHD to the same IOMMU device,
391 		 * the IVHD header pointer is appended.
392 		 */
393 		for (j = 0; j < ivhd_count; j++) {
394 			if (ivhd_is_newer(&ivhd_hdrs[j]->Header, &ivhd->Header))
395 				break;
396 		}
397 		ivhd_hdrs[j] = ivhd;
398 		if (j == ivhd_count)
399 			ivhd_count++;
400 	}
401 
402 	ivhd_devs = malloc(sizeof(device_t) * ivhd_count, M_DEVBUF,
403 		M_WAITOK | M_ZERO);
404 	for (i = 0, j = 0; i < ivhd_count; i++) {
405 		ivhd = ivhd_hdrs[i];
406 		KASSERT(ivhd, ("ivhd%d is NULL\n", i));
407 
408 		/*
409 		 * Use a high order to ensure that this driver is probed after
410 		 * the Host-PCI bridge and the root PCI bus.
411 		 */
412 		ivhd_devs[i] = BUS_ADD_CHILD(parent,
413 		    ACPI_DEV_BASE_ORDER + 10 * 10, "ivhd", i);
414 
415 		/*
416 		 * XXX: In case device was not destroyed before, add will fail.
417 		 * locate the old device instance.
418 		 */
419 		if (ivhd_devs[i] == NULL) {
420 			ivhd_devs[i] = device_find_child(parent, "ivhd", i);
421 			if (ivhd_devs[i] == NULL) {
422 				printf("AMD-Vi: can't find ivhd%d\n", i);
423 				break;
424 			}
425 		}
426 		j++;
427 	}
428 
429 	/*
430 	 * Update device count in case failed to attach.
431 	 */
432 	ivhd_count = j;
433 }
434 
435 static int
ivhd_probe(device_t dev)436 ivhd_probe(device_t dev)
437 {
438 	ACPI_IVRS_HARDWARE1 *ivhd;
439 	int unit;
440 
441 	if (acpi_get_handle(dev) != NULL)
442 		return (ENXIO);
443 
444 	unit = device_get_unit(dev);
445 	KASSERT((unit < ivhd_count),
446 		("ivhd unit %d > count %d", unit, ivhd_count));
447 	ivhd = ivhd_hdrs[unit];
448 	KASSERT(ivhd, ("ivhd is NULL"));
449 
450 	switch (ivhd->Header.Type) {
451 	case IVRS_TYPE_HARDWARE_EFR:
452 		device_set_desc(dev, "AMD-Vi/IOMMU ivhd with EFR");
453 		break;
454 
455 	case IVRS_TYPE_HARDWARE_MIXED:
456 		device_set_desc(dev, "AMD-Vi/IOMMU ivhd in mixed format");
457 		break;
458 
459 	case IVRS_TYPE_HARDWARE_LEGACY:
460         default:
461 		device_set_desc(dev, "AMD-Vi/IOMMU ivhd");
462 		break;
463 	}
464 
465 	return (BUS_PROBE_NOWILDCARD);
466 }
467 
468 static void
ivhd_print_flag(device_t dev,enum IvrsType ivhd_type,uint8_t flag)469 ivhd_print_flag(device_t dev, enum IvrsType ivhd_type, uint8_t flag)
470 {
471 	/*
472 	 * IVHD lgeacy type has two extra high bits in flag which has
473 	 * been moved to EFR for non-legacy device.
474 	 */
475 	switch (ivhd_type) {
476 	case IVRS_TYPE_HARDWARE_LEGACY:
477 		device_printf(dev, "Flag:%b\n", flag,
478 			"\020"
479 			"\001HtTunEn"
480 			"\002PassPW"
481 			"\003ResPassPW"
482 			"\004Isoc"
483 			"\005IotlbSup"
484 			"\006Coherent"
485 			"\007PreFSup"
486 			"\010PPRSup");
487 		break;
488 
489 	case IVRS_TYPE_HARDWARE_EFR:
490 	case IVRS_TYPE_HARDWARE_MIXED:
491 		device_printf(dev, "Flag:%b\n", flag,
492 			"\020"
493 			"\001HtTunEn"
494 			"\002PassPW"
495 			"\003ResPassPW"
496 			"\004Isoc"
497 			"\005IotlbSup"
498 			"\006Coherent");
499 		break;
500 
501 	default:
502 		device_printf(dev, "Can't decode flag of ivhd type :0x%x\n",
503 			ivhd_type);
504 		break;
505 	}
506 }
507 
508 /*
509  * Feature in legacy IVHD type(0x10) and attribute in newer type(0x11 and 0x40).
510  */
511 static void
ivhd_print_feature(device_t dev,enum IvrsType ivhd_type,uint32_t feature)512 ivhd_print_feature(device_t dev, enum IvrsType ivhd_type, uint32_t feature)
513 {
514 	switch (ivhd_type) {
515 	case IVRS_TYPE_HARDWARE_LEGACY:
516 		device_printf(dev, "Features(type:0x%x) HATS = %d GATS = %d"
517 			" MsiNumPPR = %d PNBanks= %d PNCounters= %d\n",
518 			ivhd_type,
519 			REG_BITS(feature, 31, 30),
520 			REG_BITS(feature, 29, 28),
521 			REG_BITS(feature, 27, 23),
522 			REG_BITS(feature, 22, 17),
523 			REG_BITS(feature, 16, 13));
524 		device_printf(dev, "max PASID = %d GLXSup = %d Feature:%b\n",
525 			REG_BITS(feature, 12, 8),
526 			REG_BITS(feature, 4, 3),
527 			feature,
528 			"\020"
529 			"\002NXSup"
530 			"\003GTSup"
531 			"\004<b4>"
532 			"\005IASup"
533 			"\006GASup"
534 			"\007HESup");
535 		break;
536 
537 	/* Fewer features or attributes are reported in non-legacy type. */
538 	case IVRS_TYPE_HARDWARE_EFR:
539 	case IVRS_TYPE_HARDWARE_MIXED:
540 		device_printf(dev, "Features(type:0x%x) MsiNumPPR = %d"
541 			" PNBanks= %d PNCounters= %d\n",
542 			ivhd_type,
543 			REG_BITS(feature, 27, 23),
544 			REG_BITS(feature, 22, 17),
545 			REG_BITS(feature, 16, 13));
546 		break;
547 
548 	default: /* Other ivhd type features are not decoded. */
549 		device_printf(dev, "Can't decode ivhd type :0x%x\n", ivhd_type);
550 	}
551 }
552 
553 /* Print extended features of IOMMU. */
554 static void
ivhd_print_ext_feature(device_t dev,uint64_t ext_feature)555 ivhd_print_ext_feature(device_t dev, uint64_t ext_feature)
556 {
557 	uint32_t ext_low, ext_high;
558 
559 	if (!ext_feature)
560 		return;
561 
562 	ext_low = ext_feature;
563 	device_printf(dev, "Extended features[31:0]:%b "
564 		"HATS = 0x%x GATS = 0x%x "
565 		"GLXSup = 0x%x SmiFSup = 0x%x SmiFRC = 0x%x "
566 		"GAMSup = 0x%x DualPortLogSup = 0x%x DualEventLogSup = 0x%x\n",
567 		(int)ext_low,
568 		"\020"
569 		"\001PreFSup"
570 		"\002PPRSup"
571 		"\003<b2>"
572 		"\004NXSup"
573 		"\005GTSup"
574 		"\006<b5>"
575 		"\007IASup"
576 		"\010GASup"
577 		"\011HESup"
578 		"\012PCSup",
579 		REG_BITS(ext_low, 11, 10),
580 		REG_BITS(ext_low, 13, 12),
581 		REG_BITS(ext_low, 15, 14),
582 		REG_BITS(ext_low, 17, 16),
583 		REG_BITS(ext_low, 20, 18),
584 		REG_BITS(ext_low, 23, 21),
585 		REG_BITS(ext_low, 25, 24),
586 		REG_BITS(ext_low, 29, 28));
587 
588 	ext_high = ext_feature >> 32;
589 	device_printf(dev, "Extended features[62:32]:%b "
590 		"Max PASID: 0x%x DevTblSegSup = 0x%x "
591 		"MarcSup = 0x%x\n",
592 		(int)(ext_high),
593 		"\020"
594 		"\006USSup"
595 		"\011PprOvrflwEarlySup"
596 		"\012PPRAutoRspSup"
597 		"\015BlKStopMrkSup"
598 		"\016PerfOptSup"
599 		"\017MsiCapMmioSup"
600 		"\021GIOSup"
601 		"\022HASup"
602 		"\023EPHSup"
603 		"\024AttrFWSup"
604 		"\025HDSup"
605 		"\027InvIotlbSup",
606 	    	REG_BITS(ext_high, 5, 0),
607 	    	REG_BITS(ext_high, 8, 7),
608 	    	REG_BITS(ext_high, 11, 10));
609 }
610 
611 static int
ivhd_print_cap(struct amdvi_softc * softc,ACPI_IVRS_HARDWARE1 * ivhd)612 ivhd_print_cap(struct amdvi_softc *softc, ACPI_IVRS_HARDWARE1 * ivhd)
613 {
614 	device_t dev;
615 	int max_ptp_level;
616 
617 	dev = softc->dev;
618 
619 	ivhd_print_flag(dev, softc->ivhd_type, softc->ivhd_flag);
620 	ivhd_print_feature(dev, softc->ivhd_type, softc->ivhd_feature);
621 	ivhd_print_ext_feature(dev, softc->ext_feature);
622 	max_ptp_level = 7;
623 	/* Make sure device support minimum page level as requested by user. */
624 	if (max_ptp_level < amdvi_ptp_level) {
625 		device_printf(dev, "insufficient PTP level:%d\n",
626 			max_ptp_level);
627 		return (EINVAL);
628 	} else {
629 		device_printf(softc->dev, "supported paging level:%d, will use only: %d\n",
630 	    		max_ptp_level, amdvi_ptp_level);
631 	}
632 
633 	return (0);
634 }
635 
636 static int
ivhd_attach(device_t dev)637 ivhd_attach(device_t dev)
638 {
639 	ACPI_IVRS_HARDWARE1 *ivhd;
640 	ACPI_IVRS_HARDWARE2 *ivhd_efr;
641 	struct amdvi_softc *softc;
642 	int status, unit;
643 
644 	unit = device_get_unit(dev);
645 	KASSERT((unit < ivhd_count),
646 		("ivhd unit %d > count %d", unit, ivhd_count));
647 	/* Make sure its same device for which attach is called. */
648 	KASSERT((ivhd_devs[unit] == dev),
649 		("Not same device old %p new %p", ivhd_devs[unit], dev));
650 
651 	softc = device_get_softc(dev);
652 	softc->dev = dev;
653 	ivhd = ivhd_hdrs[unit];
654 	KASSERT(ivhd, ("ivhd is NULL"));
655 	softc->pci_dev = pci_find_bsf(PCI_RID2BUS(ivhd->Header.DeviceId),
656 	    PCI_RID2SLOT(ivhd->Header.DeviceId),
657 	    PCI_RID2FUNC(ivhd->Header.DeviceId));
658 
659 	softc->ivhd_type = ivhd->Header.Type;
660 	softc->pci_seg = ivhd->PciSegmentGroup;
661 	softc->pci_rid = ivhd->Header.DeviceId;
662 	softc->ivhd_flag = ivhd->Header.Flags;
663 	/*
664 	 * On lgeacy IVHD type(0x10), it is documented as feature
665 	 * but in newer type it is attribute.
666 	 */
667 	softc->ivhd_feature = ivhd->FeatureReporting;
668 	/*
669 	 * PCI capability has more capabilities that are not part of IVRS.
670 	 */
671 	softc->cap_off = ivhd->CapabilityOffset;
672 
673 #ifdef notyet
674 	/* IVHD Info bit[4:0] is event MSI/X number. */
675 	softc->event_msix = ivhd->Info & 0x1F;
676 #endif
677 	switch (ivhd->Header.Type) {
678 	case IVRS_TYPE_HARDWARE_EFR:
679 	case IVRS_TYPE_HARDWARE_MIXED:
680 		ivhd_efr = (ACPI_IVRS_HARDWARE2 *)ivhd;
681 		softc->ext_feature = ivhd_efr->EfrRegisterImage;
682 		break;
683 	}
684 
685 	softc->ctrl = (struct amdvi_ctrl *) PHYS_TO_DMAP(ivhd->BaseAddress);
686 	status = ivhd_dev_parse(ivhd, softc);
687 	if (status != 0) {
688 		device_printf(dev,
689 		    "endpoint device parsing error=%d\n", status);
690 		goto fail;
691 	}
692 
693 	status = ivhd_print_cap(softc, ivhd);
694 	if (status != 0)
695 		goto fail;
696 
697 	status = amdvi_setup_hw(softc);
698 	if (status != 0) {
699 		device_printf(dev, "couldn't be initialised, error=%d\n",
700 		    status);
701 		goto fail;
702 	}
703 
704 	return (0);
705 
706 fail:
707 	free(softc->dev_cfg, M_DEVBUF);
708 	return (status);
709 }
710 
711 static int
ivhd_detach(device_t dev)712 ivhd_detach(device_t dev)
713 {
714 	struct amdvi_softc *softc;
715 
716 	softc = device_get_softc(dev);
717 
718 	amdvi_teardown_hw(softc);
719 	free(softc->dev_cfg, M_DEVBUF);
720 
721 	/*
722 	 * XXX: delete the device.
723 	 * don't allow detach, return EBUSY.
724 	 */
725 	return (0);
726 }
727 
728 static int
ivhd_suspend(device_t dev)729 ivhd_suspend(device_t dev)
730 {
731 
732 	return (0);
733 }
734 
735 static int
ivhd_resume(device_t dev)736 ivhd_resume(device_t dev)
737 {
738 
739 	return (0);
740 }
741 
742 static device_method_t ivhd_methods[] = {
743 	DEVMETHOD(device_identify, ivhd_identify),
744 	DEVMETHOD(device_probe, ivhd_probe),
745 	DEVMETHOD(device_attach, ivhd_attach),
746 	DEVMETHOD(device_detach, ivhd_detach),
747 	DEVMETHOD(device_suspend, ivhd_suspend),
748 	DEVMETHOD(device_resume, ivhd_resume),
749 	DEVMETHOD_END
750 };
751 
752 static driver_t ivhd_driver = {
753 	"ivhd",
754 	ivhd_methods,
755 	sizeof(struct amdvi_softc),
756 };
757 
758 static devclass_t ivhd_devclass;
759 
760 /*
761  * Load this module at the end after PCI re-probing to configure interrupt.
762  */
763 DRIVER_MODULE_ORDERED(ivhd, acpi, ivhd_driver, ivhd_devclass, 0, 0,
764 		      SI_ORDER_ANY);
765 MODULE_DEPEND(ivhd, acpi, 1, 1, 1);
766 MODULE_DEPEND(ivhd, pci, 1, 1, 1);
767