xref: /freebsd/sys/amd64/vmm/amd/amdvi_hw.c (revision d93a896e)
1 /*-
2  * Copyright (c) 2016, Anish Gupta (anish@freebsd.org)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/module.h>
35 #include <sys/malloc.h>
36 #include <sys/pcpu.h>
37 #include <sys/rman.h>
38 #include <sys/smp.h>
39 #include <sys/sysctl.h>
40 
41 #include <vm/vm.h>
42 #include <vm/pmap.h>
43 
44 #include <dev/pci/pcivar.h>
45 #include <dev/pci/pcireg.h>
46 
47 #include <machine/resource.h>
48 #include <machine/vmm.h>
49 #include <machine/pmap.h>
50 #include <machine/vmparam.h>
51 #include <machine/pci_cfgreg.h>
52 
53 #include "pcib_if.h"
54 
55 #include "io/iommu.h"
56 #include "amdvi_priv.h"
57 
58 SYSCTL_DECL(_hw_vmm);
59 SYSCTL_NODE(_hw_vmm, OID_AUTO, amdvi, CTLFLAG_RW, NULL, NULL);
60 
61 #define MOD_INC(a, s, m) (((a) + (s)) % ((m) * (s)))
62 #define MOD_DEC(a, s, m) (((a) - (s)) % ((m) * (s)))
63 
64 /* Print RID or device ID in PCI string format. */
65 #define RID2PCI_STR(d) PCI_RID2BUS(d), PCI_RID2SLOT(d), PCI_RID2FUNC(d)
66 
67 static void amdvi_dump_cmds(struct amdvi_softc *softc);
68 static void amdvi_print_dev_cap(struct amdvi_softc *softc);
69 
70 MALLOC_DEFINE(M_AMDVI, "amdvi", "amdvi");
71 
72 extern device_t *ivhd_devs;
73 
74 extern int ivhd_count;
75 SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, count, CTLFLAG_RDTUN, &ivhd_count,
76     0, NULL);
77 
78 static int amdvi_enable_user = 0;
79 SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, enable, CTLFLAG_RDTUN,
80     &amdvi_enable_user, 0, NULL);
81 TUNABLE_INT("hw.vmm.amdvi_enable", &amdvi_enable_user);
82 
83 #ifdef AMDVI_ATS_ENABLE
84 /* XXX: ATS is not tested. */
85 static int amdvi_enable_iotlb = 1;
86 SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, iotlb_enabled, CTLFLAG_RDTUN,
87     &amdvi_enable_iotlb, 0, NULL);
88 TUNABLE_INT("hw.vmm.enable_iotlb", &amdvi_enable_iotlb);
89 #endif
90 
91 static int amdvi_host_ptp = 1;	/* Use page tables for host. */
92 SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, host_ptp, CTLFLAG_RDTUN,
93     &amdvi_host_ptp, 0, NULL);
94 TUNABLE_INT("hw.vmm.amdvi.host_ptp", &amdvi_host_ptp);
95 
96 /* Page table level used <= supported by h/w[v1=7]. */
97 static int amdvi_ptp_level = 4;
98 SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, ptp_level, CTLFLAG_RDTUN,
99     &amdvi_ptp_level, 0, NULL);
100 TUNABLE_INT("hw.vmm.amdvi.ptp_level", &amdvi_ptp_level);
101 
102 /* Disable fault event reporting. */
103 static int amdvi_disable_io_fault = 0;
104 SYSCTL_INT(_hw_vmm_amdvi, OID_AUTO, disable_io_fault, CTLFLAG_RDTUN,
105     &amdvi_disable_io_fault, 0, NULL);
106 TUNABLE_INT("hw.vmm.amdvi.disable_io_fault", &amdvi_disable_io_fault);
107 
108 static uint32_t amdvi_dom_id = 0;	/* 0 is reserved for host. */
109 SYSCTL_UINT(_hw_vmm_amdvi, OID_AUTO, domain_id, CTLFLAG_RD,
110     &amdvi_dom_id, 0, NULL);
111 /*
112  * Device table entry.
113  * Bus(256) x Dev(32) x Fun(8) x DTE(256 bits or 32 bytes).
114  *	= 256 * 2 * PAGE_SIZE.
115  */
116 static struct amdvi_dte amdvi_dte[PCI_NUM_DEV_MAX] __aligned(PAGE_SIZE);
117 CTASSERT(PCI_NUM_DEV_MAX == 0x10000);
118 CTASSERT(sizeof(amdvi_dte) == 0x200000);
119 
120 static SLIST_HEAD (, amdvi_domain) dom_head;
121 
122 static inline void
123 amdvi_pci_write(struct amdvi_softc *softc, int off, uint32_t data)
124 {
125 
126 	pci_cfgregwrite(PCI_RID2BUS(softc->pci_rid),
127 	    PCI_RID2SLOT(softc->pci_rid), PCI_RID2FUNC(softc->pci_rid),
128 	    off, data, 4);
129 }
130 
131 static inline uint32_t
132 amdvi_pci_read(struct amdvi_softc *softc, int off)
133 {
134 
135 	return (pci_cfgregread(PCI_RID2BUS(softc->pci_rid),
136 	    PCI_RID2SLOT(softc->pci_rid), PCI_RID2FUNC(softc->pci_rid),
137 	    off, 4));
138 }
139 
140 static int
141 amdvi_find_pci_cap(struct amdvi_softc *softc, uint8_t capability, int *off)
142 {
143 	uint32_t read;
144 	uint8_t ptr;
145 
146 	read = amdvi_pci_read(softc, PCIR_COMMAND);
147 	if (((read >> 16) & PCIM_STATUS_CAPPRESENT) == 0)
148 		return (ENXIO);
149 
150 	/* Read the starting of capability pointer. */
151 	read = amdvi_pci_read(softc, PCIR_CAP_PTR);
152 	ptr = read & 0xFF;
153 
154 	while (ptr != 0) {
155 		read = amdvi_pci_read(softc, ptr);
156 		if ((read & 0xFF) == capability) {
157 			*off = ptr;
158 			return (0);
159 		}
160 		ptr = (read >> 8) & 0xFF;
161 	}
162 
163 	return (ENOENT);
164 }
165 
166 #ifdef AMDVI_ATS_ENABLE
167 /* XXX: Should be in pci.c */
168 /*
169  * Check if device has ATS capability and its enabled.
170  * If ATS is absent or disabled, return (-1), otherwise ATS
171  * queue length.
172  */
173 static int
174 amdvi_find_ats_qlen(uint16_t devid)
175 {
176 	device_t dev;
177 	uint32_t off, cap;
178 	int qlen = -1;
179 
180 	dev = pci_find_bsf(PCI_RID2BUS(devid), PCI_RID2SLOT(devid),
181 			   PCI_RID2FUNC(devid));
182 
183 	if (!dev) {
184 		return (-1);
185 	}
186 #define PCIM_ATS_EN	BIT(31)
187 
188 	if (pci_find_extcap(dev, PCIZ_ATS, &off) == 0) {
189 		cap = pci_read_config(dev, off + 4, 4);
190 		qlen = (cap & 0x1F);
191 		qlen = qlen ? qlen : 32;
192 		printf("AMD-Vi: PCI device %d.%d.%d ATS %s qlen=%d\n",
193 		       RID2PCI_STR(devid),
194 		       (cap & PCIM_ATS_EN) ? "enabled" : "Disabled",
195 		       qlen);
196 		qlen = (cap & PCIM_ATS_EN) ? qlen : -1;
197 	}
198 
199 	return (qlen);
200 }
201 
202 /*
203  * Check if an endpoint device support device IOTLB or ATS.
204  */
205 static inline bool
206 amdvi_dev_support_iotlb(struct amdvi_softc *softc, uint16_t devid)
207 {
208 	struct ivhd_dev_cfg *cfg;
209 	int qlen, i;
210 	bool pci_ats, ivhd_ats;
211 
212 	qlen = amdvi_find_ats_qlen(devid);
213 	if (qlen < 0)
214 		return (false);
215 
216 	KASSERT(softc, ("softc is NULL"));
217 	cfg = softc->dev_cfg;
218 
219 	ivhd_ats = false;
220 	for (i = 0; i < softc->dev_cfg_cnt; i++) {
221 		if ((cfg->start_id <= devid) && (cfg->end_id >= devid)) {
222 			ivhd_ats = cfg->enable_ats;
223 			break;
224 		}
225 		cfg++;
226 	}
227 
228 	pci_ats = (qlen < 0) ? false : true;
229 	if (pci_ats != ivhd_ats)
230 		device_printf(softc->dev,
231 		    "BIOS bug: mismatch in ATS setting for %d.%d.%d,"
232 		    "ATS inv qlen = %d\n", RID2PCI_STR(devid), qlen);
233 
234 	/* Ignore IVRS setting and respect PCI setting. */
235 	return (pci_ats);
236 }
237 #endif
238 
239 /* Enable IOTLB support for IOMMU if its supported. */
240 static inline void
241 amdvi_hw_enable_iotlb(struct amdvi_softc *softc)
242 {
243 #ifndef AMDVI_ATS_ENABLE
244 	softc->iotlb = false;
245 #else
246 	bool supported;
247 
248 	supported = (softc->ivhd_flag & IVHD_FLAG_IOTLB) ? true : false;
249 
250 	if (softc->pci_cap & AMDVI_PCI_CAP_IOTLB) {
251 		if (!supported)
252 			device_printf(softc->dev, "IOTLB disabled by BIOS.\n");
253 
254 		if (supported && !amdvi_enable_iotlb) {
255 			device_printf(softc->dev, "IOTLB disabled by user.\n");
256 			supported = false;
257 		}
258 	} else
259 		supported = false;
260 
261 	softc->iotlb = supported;
262 
263 #endif
264 }
265 
266 static int
267 amdvi_init_cmd(struct amdvi_softc *softc)
268 {
269 	struct amdvi_ctrl *ctrl = softc->ctrl;
270 
271 	ctrl->cmd.len = 8;	/* Use 256 command buffer entries. */
272 	softc->cmd_max = 1 << ctrl->cmd.len;
273 
274 	softc->cmd = malloc(sizeof(struct amdvi_cmd) *
275 	    softc->cmd_max, M_AMDVI, M_WAITOK | M_ZERO);
276 
277 	if ((uintptr_t)softc->cmd & PAGE_MASK)
278 		panic("AMDVi: Command buffer not aligned on page boundary.");
279 
280 	ctrl->cmd.base = vtophys(softc->cmd) / PAGE_SIZE;
281 	/*
282 	 * XXX: Reset the h/w pointers in case IOMMU is restarting,
283 	 * h/w doesn't clear these pointers based on empirical data.
284 	 */
285 	ctrl->cmd_tail = 0;
286 	ctrl->cmd_head = 0;
287 
288 	return (0);
289 }
290 
291 /*
292  * Note: Update tail pointer after we have written the command since tail
293  * pointer update cause h/w to execute new commands, see section 3.3
294  * of AMD IOMMU spec ver 2.0.
295  */
296 /* Get the command tail pointer w/o updating it. */
297 static struct amdvi_cmd *
298 amdvi_get_cmd_tail(struct amdvi_softc *softc)
299 {
300 	struct amdvi_ctrl *ctrl;
301 	struct amdvi_cmd *tail;
302 
303 	KASSERT(softc, ("softc is NULL"));
304 	KASSERT(softc->cmd != NULL, ("cmd is NULL"));
305 
306 	ctrl = softc->ctrl;
307 	KASSERT(ctrl != NULL, ("ctrl is NULL"));
308 
309 	tail = (struct amdvi_cmd *)((uint8_t *)softc->cmd +
310 	    ctrl->cmd_tail);
311 
312 	return (tail);
313 }
314 
315 /*
316  * Update the command tail pointer which will start command execution.
317  */
318 static void
319 amdvi_update_cmd_tail(struct amdvi_softc *softc)
320 {
321 	struct amdvi_ctrl *ctrl;
322 	int size;
323 
324 	size = sizeof(struct amdvi_cmd);
325 	KASSERT(softc->cmd != NULL, ("cmd is NULL"));
326 
327 	ctrl = softc->ctrl;
328 	KASSERT(ctrl != NULL, ("ctrl is NULL"));
329 
330 	ctrl->cmd_tail = MOD_INC(ctrl->cmd_tail, size, softc->cmd_max);
331 	softc->total_cmd++;
332 
333 #ifdef AMDVI_DEBUG_CMD
334 	device_printf(softc->dev, "cmd_tail: %s Tail:0x%x, Head:0x%x.\n",
335 	    ctrl->cmd_tail,
336 	    ctrl->cmd_head);
337 #endif
338 
339 }
340 
341 /*
342  * Various commands supported by IOMMU.
343  */
344 
345 /* Completion wait command. */
346 static void
347 amdvi_cmd_cmp(struct amdvi_softc *softc, const uint64_t data)
348 {
349 	struct amdvi_cmd *cmd;
350 	uint64_t pa;
351 
352 	cmd = amdvi_get_cmd_tail(softc);
353 	KASSERT(cmd != NULL, ("Cmd is NULL"));
354 
355 	pa = vtophys(&softc->cmp_data);
356 	cmd->opcode = AMDVI_CMP_WAIT_OPCODE;
357 	cmd->word0 = (pa & 0xFFFFFFF8) |
358 	    (AMDVI_CMP_WAIT_STORE);
359 	//(AMDVI_CMP_WAIT_FLUSH | AMDVI_CMP_WAIT_STORE);
360 	cmd->word1 = (pa >> 32) & 0xFFFFF;
361 	cmd->addr = data;
362 
363 	amdvi_update_cmd_tail(softc);
364 }
365 
366 /* Invalidate device table entry. */
367 static void
368 amdvi_cmd_inv_dte(struct amdvi_softc *softc, uint16_t devid)
369 {
370 	struct amdvi_cmd *cmd;
371 
372 	cmd = amdvi_get_cmd_tail(softc);
373 	KASSERT(cmd != NULL, ("Cmd is NULL"));
374 	cmd->opcode = AMDVI_INVD_DTE_OPCODE;
375 	cmd->word0 = devid;
376 	amdvi_update_cmd_tail(softc);
377 #ifdef AMDVI_DEBUG_CMD
378 	device_printf(softc->dev, "Invalidated DTE:0x%x\n", devid);
379 #endif
380 }
381 
382 /* Invalidate IOMMU page, use for invalidation of domain. */
383 static void
384 amdvi_cmd_inv_iommu_pages(struct amdvi_softc *softc, uint16_t domain_id,
385 			  uint64_t addr, bool guest_nested,
386 			  bool pde, bool page)
387 {
388 	struct amdvi_cmd *cmd;
389 
390 	cmd = amdvi_get_cmd_tail(softc);
391 	KASSERT(cmd != NULL, ("Cmd is NULL"));
392 
393 
394 	cmd->opcode = AMDVI_INVD_PAGE_OPCODE;
395 	cmd->word1 = domain_id;
396 	/*
397 	 * Invalidate all addresses for this domain.
398 	 */
399 	cmd->addr = addr;
400 	cmd->addr |= pde ? AMDVI_INVD_PAGE_PDE : 0;
401 	cmd->addr |= page ? AMDVI_INVD_PAGE_S : 0;
402 
403 	amdvi_update_cmd_tail(softc);
404 }
405 
406 #ifdef AMDVI_ATS_ENABLE
407 /* Invalidate device IOTLB. */
408 static void
409 amdvi_cmd_inv_iotlb(struct amdvi_softc *softc, uint16_t devid)
410 {
411 	struct amdvi_cmd *cmd;
412 	int qlen;
413 
414 	if (!softc->iotlb)
415 		return;
416 
417 	qlen = amdvi_find_ats_qlen(devid);
418 	if (qlen < 0) {
419 		panic("AMDVI: Invalid ATS qlen(%d) for device %d.%d.%d\n",
420 		      qlen, RID2PCI_STR(devid));
421 	}
422 	cmd = amdvi_get_cmd_tail(softc);
423 	KASSERT(cmd != NULL, ("Cmd is NULL"));
424 
425 #ifdef AMDVI_DEBUG_CMD
426 	device_printf(softc->dev, "Invalidate IOTLB devID 0x%x"
427 		      " Qlen:%d\n", devid, qlen);
428 #endif
429 	cmd->opcode = AMDVI_INVD_IOTLB_OPCODE;
430 	cmd->word0 = devid;
431 	cmd->word1 = qlen;
432 	cmd->addr = AMDVI_INVD_IOTLB_ALL_ADDR |
433 		AMDVI_INVD_IOTLB_S;
434 	amdvi_update_cmd_tail(softc);
435 }
436 #endif
437 
438 #ifdef notyet				/* For Interrupt Remap. */
439 static void
440 amdvi_cmd_inv_intr_map(struct amdvi_softc *softc,
441 		       uint16_t devid)
442 {
443 	struct amdvi_cmd *cmd;
444 
445 	cmd = amdvi_get_cmd_tail(softc);
446 	KASSERT(cmd != NULL, ("Cmd is NULL"));
447 	cmd->opcode = AMDVI_INVD_INTR_OPCODE;
448 	cmd->word0 = devid;
449 	amdvi_update_cmd_tail(softc);
450 #ifdef AMDVI_DEBUG_CMD
451 	device_printf(softc->dev, "Invalidate INTR map of devID 0x%x\n", devid);
452 #endif
453 }
454 #endif
455 
456 /* Invalidate domain using INVALIDATE_IOMMU_PAGES command. */
457 static void
458 amdvi_inv_domain(struct amdvi_softc *softc, uint16_t domain_id)
459 {
460 	struct amdvi_cmd *cmd;
461 
462 	cmd = amdvi_get_cmd_tail(softc);
463 	KASSERT(cmd != NULL, ("Cmd is NULL"));
464 
465 	/*
466 	 * See section 3.3.3 of IOMMU spec rev 2.0, software note
467 	 * for invalidating domain.
468 	 */
469 	amdvi_cmd_inv_iommu_pages(softc, domain_id, AMDVI_INVD_PAGE_ALL_ADDR,
470 				false, true, true);
471 
472 #ifdef AMDVI_DEBUG_CMD
473 	device_printf(softc->dev, "Invalidate domain:0x%x\n", domain_id);
474 
475 #endif
476 }
477 
478 static	bool
479 amdvi_cmp_wait(struct amdvi_softc *softc)
480 {
481 	struct amdvi_ctrl *ctrl;
482 	const uint64_t VERIFY = 0xA5A5;
483 	volatile uint64_t *read;
484 	int i;
485 	bool status;
486 
487 	ctrl = softc->ctrl;
488 	read = &softc->cmp_data;
489 	*read = 0;
490 	amdvi_cmd_cmp(softc, VERIFY);
491 	/* Wait for h/w to update completion data. */
492 	for (i = 0; i < 100 && (*read != VERIFY); i++) {
493 		DELAY(1000);		/* 1 ms */
494 	}
495 	status = (VERIFY == softc->cmp_data) ? true : false;
496 
497 #ifdef AMDVI_DEBUG_CMD
498 	if (status)
499 		device_printf(softc->dev, "CMD completion DONE Tail:0x%x, "
500 			      "Head:0x%x, loop:%d.\n", ctrl->cmd_tail,
501 			      ctrl->cmd_head, loop);
502 #endif
503 	return (status);
504 }
505 
506 static void
507 amdvi_wait(struct amdvi_softc *softc)
508 {
509 	struct amdvi_ctrl *ctrl;
510 	int i;
511 
512 	KASSERT(softc, ("softc is NULL"));
513 
514 	ctrl = softc->ctrl;
515 	KASSERT(ctrl != NULL, ("ctrl is NULL"));
516 	/* Don't wait if h/w is not enabled. */
517 	if ((ctrl->control & AMDVI_CTRL_EN) == 0)
518 		return;
519 
520 	for (i = 0; i < 10; i++) {
521 		if (amdvi_cmp_wait(softc))
522 			return;
523 	}
524 
525 	device_printf(softc->dev, "Error: completion failed"
526 		      " tail:0x%x, head:0x%x.\n",
527 		      ctrl->cmd_tail, ctrl->cmd_head);
528 	amdvi_dump_cmds(softc);
529 }
530 
531 static void
532 amdvi_dump_cmds(struct amdvi_softc *softc)
533 {
534 	struct amdvi_ctrl *ctrl;
535 	struct amdvi_cmd *cmd;
536 	int off, i;
537 
538 	ctrl = softc->ctrl;
539 	device_printf(softc->dev, "Dump all the commands:\n");
540 	/*
541 	 * If h/w is stuck in completion, it is the previous command,
542 	 * start dumping from previous command onward.
543 	 */
544 	off = MOD_DEC(ctrl->cmd_head, sizeof(struct amdvi_cmd),
545 	    softc->cmd_max);
546 	for (i = 0; off != ctrl->cmd_tail &&
547 	    i < softc->cmd_max; i++) {
548 		cmd = (struct amdvi_cmd *)((uint8_t *)softc->cmd + off);
549 		printf("  [CMD%d, off:0x%x] opcode= 0x%x 0x%x"
550 		    " 0x%x 0x%lx\n", i, off, cmd->opcode,
551 		    cmd->word0, cmd->word1, cmd->addr);
552 		off = (off + sizeof(struct amdvi_cmd)) %
553 		    (softc->cmd_max * sizeof(struct amdvi_cmd));
554 	}
555 }
556 
557 static int
558 amdvi_init_event(struct amdvi_softc *softc)
559 {
560 	struct amdvi_ctrl *ctrl;
561 
562 	ctrl = softc->ctrl;
563 	ctrl->event.len = 8;
564 	softc->event_max = 1 << ctrl->event.len;
565 	softc->event = malloc(sizeof(struct amdvi_event) *
566 	    softc->event_max, M_AMDVI, M_WAITOK | M_ZERO);
567 	if ((uintptr_t)softc->event & PAGE_MASK) {
568 		device_printf(softc->dev, "Event buffer not aligned on page.");
569 		return (false);
570 	}
571 	ctrl->event.base = vtophys(softc->event) / PAGE_SIZE;
572 
573 	/* Reset the pointers. */
574 	ctrl->evt_head = 0;
575 	ctrl->evt_tail = 0;
576 
577 	return (0);
578 }
579 
580 static inline void
581 amdvi_decode_evt_flag(uint16_t flag)
582 {
583 
584 	flag &= AMDVI_EVENT_FLAG_MASK;
585 	printf("0x%b]\n", flag,
586 		"\020"
587 		"\001GN"
588 		"\002NX"
589 		"\003US"
590 		"\004I"
591 		"\005PR"
592 		"\006RW"
593 		"\007PE"
594 		"\010RZ"
595 		"\011TR"
596 		);
597 }
598 
599 /* See section 2.5.4 of AMD IOMMU spec ver 2.62.*/
600 static inline void
601 amdvi_decode_evt_flag_type(uint8_t type)
602 {
603 
604 	switch (AMDVI_EVENT_FLAG_TYPE(type)) {
605 	case 0:
606 		printf("RSVD\n");
607 		break;
608 	case 1:
609 		printf("Master Abort\n");
610 		break;
611 	case 2:
612 		printf("Target Abort\n");
613 		break;
614 	case 3:
615 		printf("Data Err\n");
616 		break;
617 	default:
618 		break;
619 	}
620 }
621 
622 static void
623 amdvi_decode_inv_dte_evt(uint16_t devid, uint16_t domid, uint64_t addr,
624     uint16_t flag)
625 {
626 
627 	printf("\t[IO_PAGE_FAULT EVT: devId:0x%x DomId:0x%x"
628 	    " Addr:0x%lx",
629 	    devid, domid, addr);
630 	amdvi_decode_evt_flag(flag);
631 }
632 
633 static void
634 amdvi_decode_pf_evt(uint16_t devid, uint16_t domid, uint64_t addr,
635     uint16_t flag)
636 {
637 
638 	printf("\t[IO_PAGE_FAULT EVT: devId:0x%x DomId:0x%x"
639 	    " Addr:0x%lx",
640 	    devid, domid, addr);
641 	amdvi_decode_evt_flag(flag);
642 }
643 
644 static void
645 amdvi_decode_dte_hwerr_evt(uint16_t devid, uint16_t domid,
646     uint64_t addr, uint16_t flag)
647 {
648 
649 	printf("\t[DEV_TAB_HW_ERR EVT: devId:0x%x DomId:0x%x"
650 	    " Addr:0x%lx", devid, domid, addr);
651 	amdvi_decode_evt_flag(flag);
652 	amdvi_decode_evt_flag_type(flag);
653 }
654 
655 static void
656 amdvi_decode_page_hwerr_evt(uint16_t devid, uint16_t domid, uint64_t addr,
657     uint16_t flag)
658 {
659 
660 	printf("\t[PAGE_TAB_HW_ERR EVT: devId:0x%x DomId:0x%x"
661 	    " Addr:0x%lx", devid, domid, addr);
662 	amdvi_decode_evt_flag(flag);
663 	amdvi_decode_evt_flag_type(AMDVI_EVENT_FLAG_TYPE(flag));
664 }
665 
666 static void
667 amdvi_decode_evt(struct amdvi_event *evt)
668 {
669 	struct amdvi_cmd *cmd;
670 
671 	switch (evt->opcode) {
672 	case AMDVI_EVENT_INVALID_DTE:
673 		amdvi_decode_inv_dte_evt(evt->devid, evt->pasid_domid,
674 		    evt->addr, evt->flag);
675 		break;
676 
677 	case AMDVI_EVENT_PFAULT:
678 		amdvi_decode_pf_evt(evt->devid, evt->pasid_domid,
679 		    evt->addr, evt->flag);
680 		break;
681 
682 	case AMDVI_EVENT_DTE_HW_ERROR:
683 		amdvi_decode_dte_hwerr_evt(evt->devid, evt->pasid_domid,
684 		    evt->addr, evt->flag);
685 		break;
686 
687 	case AMDVI_EVENT_PAGE_HW_ERROR:
688 		amdvi_decode_page_hwerr_evt(evt->devid, evt->pasid_domid,
689 		    evt->addr, evt->flag);
690 		break;
691 
692 	case AMDVI_EVENT_ILLEGAL_CMD:
693 		/* FALL THROUGH */
694 	case AMDVI_EVENT_CMD_HW_ERROR:
695 		printf("\t[%s EVT]", (evt->opcode == AMDVI_EVENT_ILLEGAL_CMD) ?
696 		    "ILLEGAL CMD" : "CMD HW ERR");
697 		cmd = (struct amdvi_cmd *)PHYS_TO_DMAP(evt->addr);
698 		printf("\tCMD opcode= 0x%x 0x%x 0x%x 0x%lx\n",
699 		    cmd->opcode, cmd->word0, cmd->word1, cmd->addr);
700 		break;
701 
702 	case AMDVI_EVENT_IOTLB_TIMEOUT:
703 		printf("\t[IOTLB_INV_TIMEOUT devid:0x%x addr:0x%lx",
704 		    evt->devid, evt->addr);
705 		break;
706 
707 	case AMDVI_EVENT_INVALID_DTE_REQ:
708 		printf("\t[INV_DTE devid:0x%x addr:0x%lx",
709 		    evt->devid, evt->addr);
710 		break;
711 
712 	case AMDVI_EVENT_INVALID_PPR_REQ:
713 	case AMDVI_EVENT_COUNTER_ZERO:
714 		printf("AMD-Vi: v2 events.\n");
715 		break;
716 
717 	default:
718 		printf("Unsupported AMD-Vi event:%d", evt->opcode);
719 	}
720 }
721 
722 static void
723 amdvi_print_events(struct amdvi_softc *softc)
724 {
725 	struct amdvi_ctrl *ctrl;
726 	struct amdvi_event *event;
727 	int i, size;
728 
729 	ctrl = softc->ctrl;
730 	size = sizeof(struct amdvi_event);
731 	for (i = 0; i < softc->event_max; i++) {
732 		event = &softc->event[ctrl->evt_head / size];
733 		if (!event->opcode)
734 			break;
735 		device_printf(softc->dev, "\t[Event%d: Head:0x%x Tail:0x%x]\n",
736 		    i, ctrl->evt_head, ctrl->evt_tail);
737 		amdvi_decode_evt(event);
738 		ctrl->evt_head = MOD_INC(ctrl->evt_head, size,
739 		    softc->event_max);
740 	}
741 }
742 
743 static int
744 amdvi_init_dte(struct amdvi_softc *softc)
745 {
746 	struct amdvi_ctrl *ctrl;
747 
748 	ctrl = softc->ctrl;
749 	ctrl->dte.base = vtophys(amdvi_dte) / PAGE_SIZE;
750 	ctrl->dte.size = 0x1FF;		/* 2MB device table. */
751 
752 	return (0);
753 }
754 
755 /*
756  * Not all capabilities of IOMMU are available in ACPI IVHD flag
757  * or EFR entry, read directly from device.
758  */
759 static int
760 amdvi_print_pci_cap(device_t dev)
761 {
762 	struct amdvi_softc *softc;
763 	uint32_t off, cap;
764 
765 
766 	softc = device_get_softc(dev);
767 	off = softc->cap_off;
768 
769 	/*
770 	 * Section 3.7.1 of IOMMU sepc rev 2.0.
771 	 * Read capability from device.
772 	 */
773 	cap = amdvi_pci_read(softc, off);
774 
775 	/* Make sure capability type[18:16] is 3. */
776 	KASSERT((((cap >> 16) & 0x7) == 0x3),
777 	    ("Not a IOMMU capability 0x%x@0x%x", cap, off));
778 
779 	softc->pci_cap = cap >> 24;
780 	device_printf(softc->dev, "PCI cap 0x%x@0x%x feature:%b\n",
781 	    cap, off, softc->pci_cap,
782 	    "\020\001IOTLB\002HT\003NPCache\004EFR");
783 
784 	/* IOMMU spec Rev 2.0, section 3.7.2.1 */
785 	softc->pci_efr = softc->ctrl->ex_feature;
786 	if (softc->pci_efr) {
787 		device_printf(softc->dev, "PCI extended Feature:%b\n",
788 		    (int)softc->pci_efr,
789 		    "\020\001PreFSup\002PPRSup\003XTSup\004NXSup\006IASup"
790 		    "\007GASup\008HESup\009PCSup");
791 		device_printf(softc->dev,
792 		    "PCI HATS = %d GATS = %d GLXSup = %d, max PASID: 0x%x ",
793 		    (int)((softc->pci_efr >> 10) & 0x3),
794 		    (int)((softc->pci_efr >> 12) & 0x3),
795 		    (int)((softc->pci_efr >> 14) & 0x3),
796 		    (int)((softc->pci_efr >> 32) & 0x1F) + 1);
797 	}
798 
799 	return (0);
800 }
801 
802 static void
803 amdvi_event_intr(void *arg)
804 {
805 	struct amdvi_softc *softc;
806 	struct amdvi_ctrl *ctrl;
807 
808 	softc = (struct amdvi_softc *)arg;
809 	ctrl = softc->ctrl;
810 	device_printf(softc->dev, "EVT INTR %ld Status:0x%x"
811 	    " EVT Head:0x%x Tail:0x%x]\n", softc->event_intr_cnt++,
812 	    ctrl->status, ctrl->evt_head, ctrl->evt_tail);
813 	printf("  [CMD Total 0x%lx] Tail:0x%x, Head:0x%x.\n",
814 	    softc->total_cmd, ctrl->cmd_tail, ctrl->cmd_head);
815 
816 	amdvi_print_events(softc);
817 }
818 
819 static void
820 amdvi_free_evt_intr_res(device_t dev)
821 {
822 
823 	struct amdvi_softc *softc;
824 
825 	softc = device_get_softc(dev);
826 	if (softc->event_tag != NULL) {
827 		bus_teardown_intr(dev, softc->event_res, softc->event_tag);
828 	}
829 	if (softc->event_res != NULL) {
830 		bus_release_resource(dev, SYS_RES_IRQ, softc->event_rid,
831 		    softc->event_res);
832 	}
833 	bus_delete_resource(dev, SYS_RES_IRQ, softc->event_rid);
834 	PCIB_RELEASE_MSI(device_get_parent(device_get_parent(dev)),
835 	    dev, 1, &softc->event_irq);
836 }
837 
838 static	bool
839 amdvi_alloc_intr_resources(struct amdvi_softc *softc)
840 {
841 	device_t dev, pcib;
842 	uint64_t msi_addr;
843 	uint32_t msi_data, temp;
844 	int err, msi_off;
845 
846 	dev = softc->dev;
847 	pcib = device_get_parent(device_get_parent(dev));
848 	softc->event_irq = -1;
849 	softc->event_rid = 0;
850 	/*
851 	 * Section 3.7.1 of IOMMU rev 2.0. With MSI, there is only one
852 	 * interrupt. XXX: Enable MSI/X support.
853 	 */
854 
855 	err = PCIB_ALLOC_MSI(pcib, dev, 1, 1, &softc->event_irq);
856 	if (err) {
857 		device_printf(dev,
858 		    "Couldn't find event MSI IRQ resource.\n");
859 		return (ENOENT);
860 	}
861 	err = bus_set_resource(dev, SYS_RES_IRQ, softc->event_rid,
862 	    softc->event_irq, 1);
863 	if (err) {
864 		device_printf(dev, "Couldn't set event MSI resource.\n");
865 		return (ENXIO);
866 	}
867 	softc->event_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
868 	    &softc->event_rid, RF_ACTIVE);
869 	if (!softc->event_res) {
870 		device_printf(dev,
871 		    "Unable to allocate event INTR resource.\n");
872 		return (ENOMEM);
873 	}
874 
875 	if (bus_setup_intr(dev, softc->event_res,
876 	    INTR_TYPE_MISC | INTR_MPSAFE, NULL, amdvi_event_intr,
877 	    softc, &softc->event_tag)) {
878 		device_printf(dev, "Fail to setup event intr\n");
879 		bus_release_resource(softc->dev, SYS_RES_IRQ,
880 		    softc->event_rid, softc->event_res);
881 		softc->event_res = NULL;
882 		return (ENXIO);
883 	}
884 
885 	bus_describe_intr(dev, softc->event_res, softc->event_tag,
886 	    "fault");
887 
888 	err = amdvi_find_pci_cap(softc, PCIY_MSI, &msi_off);
889 	if (err) {
890 		device_printf(dev, "Couldn't find MSI capability, err = %d.\n",
891 			      err);
892 		return (err);
893 	}
894 
895 	err = PCIB_MAP_MSI(pcib, dev, softc->event_irq, &msi_addr,
896 	    &msi_data);
897 	if (err) {
898 		device_printf(dev,
899 		    "Event interrupt config failed, err=%d.\n",
900 		    err);
901 		amdvi_free_evt_intr_res(softc->dev);
902 		return (err);
903 	}
904 
905 	/* Configure MSI */
906 	amdvi_pci_write(softc, msi_off + PCIR_MSI_ADDR, msi_addr);
907 	amdvi_pci_write(softc, msi_off + PCIR_MSI_ADDR_HIGH,
908 	    msi_addr >> 32);
909 	amdvi_pci_write(softc, msi_off + PCIR_MSI_DATA_64BIT, msi_data);
910 
911 	/* Now enable MSI interrupt. */
912 	temp = amdvi_pci_read(softc, msi_off);
913 	temp |= (PCIM_MSICTRL_MSI_ENABLE << 16);	/* MSI enable. */
914 	amdvi_pci_write(softc, msi_off, temp);
915 
916 	return (0);
917 }
918 
919 
920 static void
921 amdvi_print_dev_cap(struct amdvi_softc *softc)
922 {
923 	struct ivhd_dev_cfg *cfg;
924 	int i;
925 
926 	cfg = softc->dev_cfg;
927 	for (i = 0; i < softc->dev_cfg_cnt; i++) {
928 		device_printf(softc->dev, "device [0x%x - 0x%x]"
929 		    "config:%b%s\n", cfg->start_id, cfg->end_id,
930 		    cfg->data,
931 		    "\020\001INIT\002ExtInt\003NMI"
932 		    "\007LINT0\008LINT1",
933 		    cfg->enable_ats ? "ATS enabled" : "");
934 		cfg++;
935 	}
936 }
937 
938 static int
939 amdvi_handle_sysctl(SYSCTL_HANDLER_ARGS)
940 {
941 	struct amdvi_softc *softc;
942 	int result, type, error = 0;
943 
944 	softc = (struct amdvi_softc *)arg1;
945 	type = arg2;
946 
947 	switch (type) {
948 	case 0:
949 		result = softc->ctrl->cmd_head;
950 		error = sysctl_handle_int(oidp, &result, 0,
951 		    req);
952 		break;
953 	case 1:
954 		result = softc->ctrl->cmd_tail;
955 		error = sysctl_handle_int(oidp, &result, 0,
956 		    req);
957 		break;
958 	case 2:
959 		result = softc->ctrl->evt_head;
960 		error = sysctl_handle_int(oidp, &result, 0,
961 		    req);
962 		break;
963 	case 3:
964 		result = softc->ctrl->evt_tail;
965 		error = sysctl_handle_int(oidp, &result, 0,
966 		    req);
967 		break;
968 
969 	default:
970 		device_printf(softc->dev, "Unknown sysctl:%d\n", type);
971 	}
972 
973 	return (error);
974 }
975 
976 static void
977 amdvi_add_sysctl(struct amdvi_softc *softc)
978 {
979 	struct sysctl_oid_list *child;
980 	struct sysctl_ctx_list *ctx;
981 	device_t dev;
982 
983 	dev = softc->dev;
984 	ctx = device_get_sysctl_ctx(dev);
985 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
986 
987 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "event_intr_count", CTLFLAG_RD,
988 	    &softc->event_intr_cnt, "Event interrupt count");
989 	SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "command_count", CTLFLAG_RD,
990 	    &softc->total_cmd, "Command submitted count");
991 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "pci_rid", CTLFLAG_RD,
992 	    (int *)&softc->pci_rid, 0,
993 	    "IOMMU RID");
994 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "start_dev_rid", CTLFLAG_RD,
995 	    (int *)&softc->start_dev_rid, 0,
996 	    "Start of device under this IOMMU");
997 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "end_dev_rid", CTLFLAG_RD,
998 	    (int *)&softc->end_dev_rid, 0,
999 	    "End of device under this IOMMU");
1000 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "command_head",
1001 	    CTLTYPE_UINT | CTLFLAG_RD, softc, 0,
1002 	    amdvi_handle_sysctl, "IU", "Command head");
1003 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "command_tail",
1004 	    CTLTYPE_UINT | CTLFLAG_RD, softc, 1,
1005 	    amdvi_handle_sysctl, "IU", "Command tail");
1006 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "event_head",
1007 	    CTLTYPE_UINT | CTLFLAG_RD, softc, 2,
1008 	    amdvi_handle_sysctl, "IU", "Command head");
1009 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "event_tail",
1010 	    CTLTYPE_UINT | CTLFLAG_RD, softc, 3,
1011 	    amdvi_handle_sysctl, "IU", "Command tail");
1012 }
1013 
1014 int
1015 amdvi_setup_hw(struct amdvi_softc *softc)
1016 {
1017 	device_t dev;
1018 	int status;
1019 
1020 	dev = softc->dev;
1021 
1022 	amdvi_hw_enable_iotlb(softc);
1023 
1024 	amdvi_print_dev_cap(softc);
1025 
1026 	if ((status = amdvi_print_pci_cap(dev)) != 0) {
1027 		device_printf(dev, "PCI capability.\n");
1028 		return (status);
1029 	}
1030 	if ((status = amdvi_init_cmd(softc)) != 0) {
1031 		device_printf(dev, "Couldn't configure command buffer.\n");
1032 		return (status);
1033 	}
1034 	if ((status = amdvi_init_event(softc)) != 0) {
1035 		device_printf(dev, "Couldn't configure event buffer.\n");
1036 		return (status);
1037 	}
1038 	if ((status = amdvi_init_dte(softc)) != 0) {
1039 		device_printf(dev, "Couldn't configure device table.\n");
1040 		return (status);
1041 	}
1042 	if ((status = amdvi_alloc_intr_resources(softc)) != 0) {
1043 		return (status);
1044 	}
1045 	amdvi_add_sysctl(softc);
1046 	return (0);
1047 }
1048 
1049 int
1050 amdvi_teardown_hw(struct amdvi_softc *softc)
1051 {
1052 	device_t dev;
1053 
1054 	dev = softc->dev;
1055 
1056 	/*
1057 	 * Called after disable, h/w is stopped by now, free all the resources.
1058 	 */
1059 	amdvi_free_evt_intr_res(dev);
1060 
1061 	if (softc->cmd)
1062 		free(softc->cmd, M_AMDVI);
1063 
1064 	if (softc->event)
1065 		free(softc->event, M_AMDVI);
1066 
1067 	return (0);
1068 }
1069 
1070 /*********** bhyve interfaces *********************/
1071 static int
1072 amdvi_init(void)
1073 {
1074 	if (!ivhd_count) {
1075 		return (EIO);
1076 	}
1077 	if (!amdvi_enable_user && ivhd_count) {
1078 		printf("bhyve: Found %d AMD-Vi/IOMMU device(s), "
1079 		    	"use hw.vmm.amdvi_enable=1 to enable pass-through.\n",
1080 		    ivhd_count);
1081 		return (EINVAL);
1082 	}
1083 	return (0);
1084 }
1085 
1086 static void
1087 amdvi_cleanup(void)
1088 {
1089 	/* Nothing. */
1090 }
1091 
1092 static uint16_t
1093 amdvi_domainId(void)
1094 {
1095 
1096 	/*
1097 	 * If we hit maximum domain limit, rollover leaving host
1098 	 * domain(0).
1099 	 * XXX: make sure that this domain is not used.
1100 	 */
1101 	if (amdvi_dom_id == AMDVI_MAX_DOMAIN)
1102 		amdvi_dom_id = 1;
1103 
1104 	return ((uint16_t)amdvi_dom_id++);
1105 }
1106 
1107 static void
1108 amdvi_do_inv_domain(uint16_t domain_id, bool create)
1109 {
1110 	struct amdvi_softc *softc;
1111 	int i;
1112 
1113 	for (i = 0; i < ivhd_count; i++) {
1114 		softc = device_get_softc(ivhd_devs[i]);
1115 		KASSERT(softc, ("softc is NULL"));
1116 		/*
1117 		 * If not present pages are cached, invalidate page after
1118 		 * creating domain.
1119 		 */
1120 #if 0
1121 		if (create && ((softc->pci_cap & AMDVI_PCI_CAP_NPCACHE) == 0))
1122 			continue;
1123 #endif
1124 		amdvi_inv_domain(softc, domain_id);
1125 		amdvi_wait(softc);
1126 	}
1127 }
1128 
1129 static void *
1130 amdvi_create_domain(vm_paddr_t maxaddr)
1131 {
1132 	struct amdvi_domain *dom;
1133 
1134 	dom = malloc(sizeof(struct amdvi_domain), M_AMDVI, M_ZERO | M_WAITOK);
1135 	dom->id = amdvi_domainId();
1136 	//dom->maxaddr = maxaddr;
1137 #ifdef AMDVI_DEBUG_CMD
1138 	printf("Created domain #%d\n", dom->id);
1139 #endif
1140 	/*
1141 	 * Host domain(#0) don't create translation table.
1142 	 */
1143 	if (dom->id || amdvi_host_ptp)
1144 		dom->ptp = malloc(PAGE_SIZE, M_AMDVI, M_WAITOK | M_ZERO);
1145 
1146 	dom->ptp_level = amdvi_ptp_level;
1147 
1148 	amdvi_do_inv_domain(dom->id, true);
1149 	SLIST_INSERT_HEAD(&dom_head, dom, next);
1150 
1151 	return (dom);
1152 }
1153 
1154 static void
1155 amdvi_free_ptp(uint64_t *ptp, int level)
1156 {
1157 	int i;
1158 
1159 	if (level < 1)
1160 		return;
1161 
1162 	for (i = 0; i < NPTEPG ; i++) {
1163 		if ((ptp[i] & AMDVI_PT_PRESENT) == 0)
1164 			continue;
1165 		/* XXX: Add super-page or PTE mapping > 4KB. */
1166 #ifdef notyet
1167 		/* Super-page mapping. */
1168 		if (AMDVI_PD_SUPER(ptp[i]))
1169 			continue;
1170 #endif
1171 
1172 		amdvi_free_ptp((uint64_t *)PHYS_TO_DMAP(ptp[i]
1173 		    & AMDVI_PT_MASK), level - 1);
1174 
1175 	}
1176 
1177 	free(ptp, M_AMDVI);
1178 }
1179 
1180 static void
1181 amdvi_destroy_domain(void *arg)
1182 {
1183 	struct amdvi_domain *domain;
1184 
1185 	domain = (struct amdvi_domain *)arg;
1186 	KASSERT(domain, ("domain is NULL"));
1187 #ifdef AMDVI_DEBUG_CMD
1188 	printf("Destroying domain %d\n", domain->id);
1189 #endif
1190 	if (domain->ptp)
1191 		amdvi_free_ptp(domain->ptp, domain->ptp_level);
1192 
1193 	amdvi_do_inv_domain(domain->id, false);
1194 	SLIST_REMOVE(&dom_head, domain, amdvi_domain, next);
1195 	free(domain, M_AMDVI);
1196 }
1197 
1198 static uint64_t
1199 amdvi_set_pt(uint64_t *pt, int level, vm_paddr_t gpa,
1200     vm_paddr_t hpa, uint64_t pg_size, bool create)
1201 {
1202 	uint64_t *page, pa;
1203 	int shift, index;
1204 	const int PT_SHIFT = 9;
1205 	const int PT_INDEX_MASK = (1 << PT_SHIFT) - 1;	/* Based on PT_SHIFT */
1206 
1207 	if (!pg_size)
1208 		return (0);
1209 
1210 	if (hpa & (pg_size - 1)) {
1211 		printf("HPA is not size aligned.\n");
1212 		return (0);
1213 	}
1214 	if (gpa & (pg_size - 1)) {
1215 		printf("HPA is not size aligned.\n");
1216 		return (0);
1217 	}
1218 	shift = PML4SHIFT;
1219 	while ((shift > PAGE_SHIFT) && (pg_size < (1UL << shift))) {
1220 		index = (gpa >> shift) & PT_INDEX_MASK;
1221 
1222 		if ((pt[index] == 0) && create) {
1223 			page = malloc(PAGE_SIZE, M_AMDVI, M_WAITOK | M_ZERO);
1224 			pa = vtophys(page);
1225 			pt[index] = pa | AMDVI_PT_PRESENT | AMDVI_PT_RW |
1226 			    ((level - 1) << AMDVI_PD_LEVEL_SHIFT);
1227 		}
1228 #ifdef AMDVI_DEBUG_PTE
1229 		if ((gpa % 0x1000000) == 0)
1230 			printf("[level%d, shift = %d]PTE:0x%lx\n",
1231 			    level, shift, pt[index]);
1232 #endif
1233 #define PTE2PA(x)	((uint64_t)(x) & AMDVI_PT_MASK)
1234 		pa = PTE2PA(pt[index]);
1235 		pt = (uint64_t *)PHYS_TO_DMAP(pa);
1236 		shift -= PT_SHIFT;
1237 		level--;
1238 	}
1239 
1240 	/* Leaf entry. */
1241 	index = (gpa >> shift) & PT_INDEX_MASK;
1242 
1243 	if (create) {
1244 		pt[index] = hpa | AMDVI_PT_RW | AMDVI_PT_PRESENT;
1245 	} else
1246 		pt[index] = 0;
1247 
1248 #ifdef AMDVI_DEBUG_PTE
1249 	if ((gpa % 0x1000000) == 0)
1250 		printf("[Last level%d, shift = %d]PTE:0x%lx\n",
1251 		    level, shift, pt[index]);
1252 #endif
1253 	return (1ULL << shift);
1254 }
1255 
1256 static uint64_t
1257 amdvi_update_mapping(struct amdvi_domain *domain, vm_paddr_t gpa,
1258     vm_paddr_t hpa, uint64_t size, bool create)
1259 {
1260 	uint64_t mapped, *ptp, len;
1261 	int level;
1262 
1263 	KASSERT(domain, ("domain is NULL"));
1264 	level = domain->ptp_level;
1265 	KASSERT(level, ("Page table level is 0"));
1266 
1267 	ptp = domain->ptp;
1268 	KASSERT(ptp, ("PTP is NULL"));
1269 	mapped = 0;
1270 	while (mapped < size) {
1271 		len = amdvi_set_pt(ptp, level, gpa + mapped, hpa + mapped,
1272 		    PAGE_SIZE, create);
1273 		if (!len) {
1274 			printf("Error: Couldn't map HPA:0x%lx GPA:0x%lx\n",
1275 			    hpa, gpa);
1276 			return (0);
1277 		}
1278 		mapped += len;
1279 	}
1280 
1281 	return (mapped);
1282 }
1283 
1284 static uint64_t
1285 amdvi_create_mapping(void *arg, vm_paddr_t gpa, vm_paddr_t hpa,
1286     uint64_t len)
1287 {
1288 	struct amdvi_domain *domain;
1289 
1290 	domain = (struct amdvi_domain *)arg;
1291 
1292 	if (domain->id && !domain->ptp) {
1293 		printf("ptp is NULL");
1294 		return (-1);
1295 	}
1296 
1297 	/*
1298 	 * If host domain is created w/o page table, skip IOMMU page
1299 	 * table set-up.
1300 	 */
1301 	if (domain->ptp)
1302 		return (amdvi_update_mapping(domain, gpa, hpa, len, true));
1303 	else
1304 		return (len);
1305 }
1306 
1307 static uint64_t
1308 amdvi_destroy_mapping(void *arg, vm_paddr_t gpa, uint64_t len)
1309 {
1310 	struct amdvi_domain *domain;
1311 
1312 	domain = (struct amdvi_domain *)arg;
1313 	/*
1314 	 * If host domain is created w/o page table, skip IOMMU page
1315 	 * table set-up.
1316 	 */
1317 	if (domain->ptp)
1318 		return (amdvi_update_mapping(domain, gpa, 0, len, false));
1319 	return
1320 	    (len);
1321 }
1322 
1323 static struct amdvi_softc *
1324 amdvi_find_iommu(uint16_t devid)
1325 {
1326 	struct amdvi_softc *softc;
1327 	int i;
1328 
1329 	for (i = 0; i < ivhd_count; i++) {
1330 		softc = device_get_softc(ivhd_devs[i]);
1331 		if ((devid >= softc->start_dev_rid) &&
1332 		    (devid <= softc->end_dev_rid))
1333 			return (softc);
1334 	}
1335 
1336 	/*
1337 	 * XXX: BIOS bug, device not in IVRS table, assume its from first IOMMU.
1338 	 */
1339 	printf("BIOS bug device(%d.%d.%d) doesn't have IVHD entry.\n",
1340 	    RID2PCI_STR(devid));
1341 
1342 	return (device_get_softc(ivhd_devs[0]));
1343 }
1344 
1345 /*
1346  * Set-up device table entry.
1347  * IOMMU spec Rev 2.0, section 3.2.2.2, some of the fields must
1348  * be set concurrently, e.g. read and write bits.
1349  */
1350 static void
1351 amdvi_set_dte(struct amdvi_domain *domain, uint16_t devid, bool enable)
1352 {
1353 	struct amdvi_softc *softc;
1354 	struct amdvi_dte temp;
1355 
1356 	softc = amdvi_find_iommu(devid);
1357 	KASSERT(softc, ("softc is NULL for pci_rid:0x%x\n", devid));
1358 
1359 	memset(&temp, 0, sizeof(struct amdvi_dte));
1360 
1361 #ifdef AMDVI_ATS_ENABLE
1362 	/* If IOMMU and device support IOTLB, enable it. */
1363 	if (amdvi_dev_support_iotlb(softc, devid) && softc->iotlb)
1364 		temp.iotlb_enable = 1;
1365 #endif
1366 
1367 	/* Avoid duplicate I/O faults. */
1368 	temp.sup_second_io_fault = 1;
1369 	temp.sup_all_io_fault = amdvi_disable_io_fault;
1370 
1371 	temp.dt_valid = 1;
1372 	temp.domain_id = domain->id;
1373 
1374 	if (enable) {
1375 		if (domain->ptp) {
1376 			temp.pt_base = vtophys(domain->ptp) >> 12;
1377 			temp.pt_level = amdvi_ptp_level;
1378 		}
1379 		/*
1380 		 * XXX: Page table valid[TV] bit must be set even if host domain
1381 		 * page tables are not enabled.
1382 		 */
1383 		temp.pt_valid = 1;
1384 		temp.read_allow = 1;
1385 		temp.write_allow = 1;
1386 	}
1387 	amdvi_dte[devid] = temp;
1388 }
1389 
1390 static void
1391 amdvi_inv_device(uint16_t devid)
1392 {
1393 	struct amdvi_softc *softc;
1394 
1395 	softc = amdvi_find_iommu(devid);
1396 	KASSERT(softc, ("softc is NULL"));
1397 
1398 	amdvi_cmd_inv_dte(softc, devid);
1399 #ifdef AMDVI_ATS_ENABLE
1400 	if (amdvi_dev_support_iotlb(softc, devid))
1401 		amdvi_cmd_inv_iotlb(softc, devid);
1402 #endif
1403 	amdvi_wait(softc);
1404 }
1405 
1406 static void
1407 amdvi_add_device(void *arg, uint16_t devid)
1408 {
1409 	struct amdvi_domain *domain;
1410 
1411 	domain = (struct amdvi_domain *)arg;
1412 	KASSERT(domain != NULL, ("domain is NULL"));
1413 #ifdef AMDVI_DEBUG_CMD
1414 	printf("Assigning device(%d.%d.%d) to domain:%d\n",
1415 	    RID2PCI_STR(devid), domain->id);
1416 #endif
1417 	amdvi_set_dte(domain, devid, true);
1418 	amdvi_inv_device(devid);
1419 }
1420 
1421 static void
1422 amdvi_remove_device(void *arg, uint16_t devid)
1423 {
1424 	struct amdvi_domain *domain;
1425 
1426 	domain = (struct amdvi_domain *)arg;
1427 #ifdef AMDVI_DEBUG_CMD
1428 	printf("Remove device(0x%x) from domain:%d\n",
1429 	       devid, domain->id);
1430 #endif
1431 	amdvi_set_dte(domain, devid, false);
1432 	amdvi_inv_device(devid);
1433 }
1434 
1435 static void
1436 amdvi_enable(void)
1437 {
1438 	struct amdvi_ctrl *ctrl;
1439 	struct amdvi_softc *softc;
1440 	uint64_t val;
1441 	int i;
1442 
1443 	for (i = 0; i < ivhd_count; i++) {
1444 		softc = device_get_softc(ivhd_devs[i]);
1445 		KASSERT(softc, ("softc is NULL\n"));
1446 		ctrl = softc->ctrl;
1447 		KASSERT(ctrl, ("ctrl is NULL\n"));
1448 
1449 		val = (	AMDVI_CTRL_EN 		|
1450 			AMDVI_CTRL_CMD 		|
1451 		    	AMDVI_CTRL_ELOG 	|
1452 		    	AMDVI_CTRL_ELOGINT 	|
1453 		    	AMDVI_CTRL_INV_TO_1S);
1454 
1455 		if (softc->ivhd_flag & IVHD_FLAG_COH)
1456 			val |= AMDVI_CTRL_COH;
1457 		if (softc->ivhd_flag & IVHD_FLAG_HTT)
1458 			val |= AMDVI_CTRL_HTT;
1459 		if (softc->ivhd_flag & IVHD_FLAG_RPPW)
1460 			val |= AMDVI_CTRL_RPPW;
1461 		if (softc->ivhd_flag & IVHD_FLAG_PPW)
1462 			val |= AMDVI_CTRL_PPW;
1463 		if (softc->ivhd_flag & IVHD_FLAG_ISOC)
1464 			val |= AMDVI_CTRL_ISOC;
1465 
1466 		ctrl->control = val;
1467 	}
1468 }
1469 
1470 static void
1471 amdvi_disable(void)
1472 {
1473 	struct amdvi_ctrl *ctrl;
1474 	struct amdvi_softc *softc;
1475 	int i;
1476 
1477 	for (i = 0; i < ivhd_count; i++) {
1478 		softc = device_get_softc(ivhd_devs[i]);
1479 		KASSERT(softc, ("softc is NULL\n"));
1480 		ctrl = softc->ctrl;
1481 		KASSERT(ctrl, ("ctrl is NULL\n"));
1482 
1483 		ctrl->control = 0;
1484 	}
1485 }
1486 
1487 static void
1488 amdvi_inv_tlb(void *arg)
1489 {
1490 	struct amdvi_domain *domain;
1491 
1492 	domain = (struct amdvi_domain *)arg;
1493 	KASSERT(domain, ("domain is NULL"));
1494 	amdvi_do_inv_domain(domain->id, false);
1495 }
1496 
1497 struct iommu_ops iommu_ops_amd = {
1498 	amdvi_init,
1499 	amdvi_cleanup,
1500 	amdvi_enable,
1501 	amdvi_disable,
1502 	amdvi_create_domain,
1503 	amdvi_destroy_domain,
1504 	amdvi_create_mapping,
1505 	amdvi_destroy_mapping,
1506 	amdvi_add_device,
1507 	amdvi_remove_device,
1508 	amdvi_inv_tlb
1509 };
1510