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.
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.
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]
22 * Portions Copyright (c) 2010, Oracle and/or its affiliates.
23 * All rights reserved.
26 * Copyright (c) 2009, Intel Corporation.
27 * All rights reserved.
30 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
35 * This file contains Intel IOMMU code that deals with DVMA
39 #include <sys/sysmacros.h>
41 #include <sys/pci_cfgspace.h>
42 #include <vm/hat_i86.h>
43 #include <sys/memlist.h>
44 #include <sys/acpi/acpi.h>
45 #include <sys/acpica.h>
46 #include <sys/modhash.h>
48 #include <sys/x86_archext.h>
49 #include <sys/archsystm.h>
54 * Macros based on PCI spec
56 #define IMMU_PCI_REV2CLASS(r) ((r) >> 8) /* classcode from revid */
57 #define IMMU_PCI_CLASS2BASE(c) ((c) >> 16) /* baseclass from classcode */
58 #define IMMU_PCI_CLASS2SUB(c) (((c) >> 8) & 0xff); /* classcode */
60 #define IMMU_CONTIG_PADDR(d, p) \
61 ((d).dck_paddr && ((d).dck_paddr + IMMU_PAGESIZE) == (p))
63 typedef struct dvma_arg
{
69 immu_flags_t dva_flags
;
74 static domain_t
*domain_create(immu_t
*immu
, dev_info_t
*ddip
,
75 dev_info_t
*rdip
, immu_flags_t immu_flags
);
76 static immu_devi_t
*create_immu_devi(dev_info_t
*rdip
, int bus
,
77 int dev
, int func
, immu_flags_t immu_flags
);
78 static void destroy_immu_devi(immu_devi_t
*immu_devi
);
79 static boolean_t
dvma_map(domain_t
*domain
, uint64_t sdvma
,
80 uint64_t nvpages
, immu_dcookie_t
*dcookies
, int dcount
, dev_info_t
*rdip
,
81 immu_flags_t immu_flags
);
84 extern struct memlist
*phys_install
;
87 * iommulib interface functions.
89 static int immu_probe(iommulib_handle_t unitp
, dev_info_t
*dip
);
90 static int immu_allochdl(iommulib_handle_t handle
,
91 dev_info_t
*dip
, dev_info_t
*rdip
, ddi_dma_attr_t
*attr
,
92 int (*waitfp
)(caddr_t
), caddr_t arg
, ddi_dma_handle_t
*dma_handlep
);
93 static int immu_freehdl(iommulib_handle_t handle
,
94 dev_info_t
*dip
, dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
);
95 static int immu_bindhdl(iommulib_handle_t handle
, dev_info_t
*dip
,
96 dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
, struct ddi_dma_req
*dma_req
,
97 ddi_dma_cookie_t
*cookiep
, uint_t
*ccountp
);
98 static int immu_unbindhdl(iommulib_handle_t handle
,
99 dev_info_t
*dip
, dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
);
100 static int immu_sync(iommulib_handle_t handle
, dev_info_t
*dip
,
101 dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
, off_t off
, size_t len
,
103 static int immu_win(iommulib_handle_t handle
, dev_info_t
*dip
,
104 dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
, uint_t win
,
105 off_t
*offp
, size_t *lenp
, ddi_dma_cookie_t
*cookiep
, uint_t
*ccountp
);
106 static int immu_mapobject(iommulib_handle_t handle
, dev_info_t
*dip
,
107 dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
,
108 struct ddi_dma_req
*dmareq
, ddi_dma_obj_t
*dmao
);
109 static int immu_unmapobject(iommulib_handle_t handle
, dev_info_t
*dip
,
110 dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
, ddi_dma_obj_t
*dmao
);
115 * Used to setup DMA objects (memory regions)
116 * for DMA reads by IOMMU units
118 static ddi_dma_attr_t immu_dma_attr
= {
121 0xffffffffffffffffULL
,
123 MMU_PAGESIZE
, /* MMU page aligned */
127 0xffffffffffffffffULL
,
133 static ddi_device_acc_attr_t immu_acc_attr
= {
139 struct iommulib_ops immulib_ops
= {
156 * Fake physical address range used to set up initial prealloc mappings.
157 * This memory is never actually accessed. It is mapped read-only,
158 * and is overwritten as soon as the first DMA bind operation is
159 * performed. Since 0 is a special case, just start at the 2nd
163 static immu_dcookie_t immu_precookie
= { MMU_PAGESIZE
, IMMU_NPREPTES
};
165 /* globals private to this file */
166 static kmutex_t immu_domain_lock
;
167 static list_t immu_unity_domain_list
;
168 static list_t immu_xlate_domain_list
;
170 /* structure used to store idx into each level of the page tables */
171 typedef struct xlate
{
174 pgtable_t
*xlt_pgtable
;
177 /* 0 is reserved by Vt-d spec. Solaris reserves 1 */
178 #define IMMU_UNITY_DID 1
180 static mod_hash_t
*bdf_domain_hash
;
186 bdf_domain_lookup(immu_devi_t
*immu_devi
)
189 int16_t seg
= immu_devi
->imd_seg
;
190 int16_t bus
= immu_devi
->imd_bus
;
191 int16_t devfunc
= immu_devi
->imd_devfunc
;
192 uintptr_t bdf
= (seg
<< 16 | bus
<< 8 | devfunc
);
194 if (seg
< 0 || bus
< 0 || devfunc
< 0) {
199 if (mod_hash_find(bdf_domain_hash
,
200 (void *)bdf
, (void *)&domain
) == 0) {
202 ASSERT(domain
->dom_did
> 0);
210 bdf_domain_insert(immu_devi_t
*immu_devi
, domain_t
*domain
)
212 int16_t seg
= immu_devi
->imd_seg
;
213 int16_t bus
= immu_devi
->imd_bus
;
214 int16_t devfunc
= immu_devi
->imd_devfunc
;
215 uintptr_t bdf
= (seg
<< 16 | bus
<< 8 | devfunc
);
217 if (seg
< 0 || bus
< 0 || devfunc
< 0) {
221 (void) mod_hash_insert(bdf_domain_hash
, (void *)bdf
, (void *)domain
);
225 match_lpc(dev_info_t
*pdip
, void *arg
)
227 immu_devi_t
*immu_devi
;
228 dvma_arg_t
*dvap
= (dvma_arg_t
*)arg
;
230 if (list_is_empty(dvap
->dva_list
)) {
231 return (DDI_WALK_TERMINATE
);
234 immu_devi
= list_head(dvap
->dva_list
);
235 for (; immu_devi
; immu_devi
= list_next(dvap
->dva_list
,
237 if (immu_devi
->imd_dip
== pdip
) {
238 dvap
->dva_ddip
= pdip
;
239 dvap
->dva_error
= DDI_SUCCESS
;
240 return (DDI_WALK_TERMINATE
);
244 return (DDI_WALK_CONTINUE
);
248 immu_devi_set_spclist(dev_info_t
*dip
, immu_t
*immu
)
250 list_t
*spclist
= NULL
;
251 immu_devi_t
*immu_devi
;
253 immu_devi
= IMMU_DEVI(dip
);
254 if (immu_devi
->imd_display
== B_TRUE
) {
255 spclist
= &(immu
->immu_dvma_gfx_list
);
256 } else if (immu_devi
->imd_lpc
== B_TRUE
) {
257 spclist
= &(immu
->immu_dvma_lpc_list
);
261 mutex_enter(&(immu
->immu_lock
));
262 list_insert_head(spclist
, immu_devi
);
263 mutex_exit(&(immu
->immu_lock
));
268 * Set the immu_devi struct in the immu_devi field of a devinfo node
271 immu_devi_set(dev_info_t
*dip
, immu_flags_t immu_flags
)
274 immu_devi_t
*new_imd
;
275 immu_devi_t
*immu_devi
;
277 immu_devi
= immu_devi_get(dip
);
278 if (immu_devi
!= NULL
) {
279 return (DDI_SUCCESS
);
282 bus
= dev
= func
= -1;
285 * Assume a new immu_devi struct is needed
287 if (!DEVI_IS_PCI(dip
) || acpica_get_bdf(dip
, &bus
, &dev
, &func
) != 0) {
289 * No BDF. Set bus = -1 to indicate this.
290 * We still need to create a immu_devi struct
298 new_imd
= create_immu_devi(dip
, bus
, dev
, func
, immu_flags
);
299 if (new_imd
== NULL
) {
300 ddi_err(DER_WARN
, dip
, "Failed to create immu_devi "
302 return (DDI_FAILURE
);
306 * Check if some other thread allocated a immu_devi while we
307 * didn't own the lock.
309 mutex_enter(&(DEVI(dip
)->devi_lock
));
310 if (IMMU_DEVI(dip
) == NULL
) {
311 IMMU_DEVI_SET(dip
, new_imd
);
313 destroy_immu_devi(new_imd
);
315 mutex_exit(&(DEVI(dip
)->devi_lock
));
317 return (DDI_SUCCESS
);
321 get_lpc_devinfo(immu_t
*immu
, dev_info_t
*rdip
, immu_flags_t immu_flags
)
323 dvma_arg_t dvarg
= {0};
324 dvarg
.dva_list
= &(immu
->immu_dvma_lpc_list
);
325 dvarg
.dva_rdip
= rdip
;
326 dvarg
.dva_error
= DDI_FAILURE
;
328 if (immu_walk_ancestor(rdip
, NULL
, match_lpc
,
329 &dvarg
, NULL
, immu_flags
) != DDI_SUCCESS
) {
330 ddi_err(DER_MODE
, rdip
, "Could not walk ancestors to "
331 "find lpc_devinfo for ISA device");
335 if (dvarg
.dva_error
!= DDI_SUCCESS
|| dvarg
.dva_ddip
== NULL
) {
336 ddi_err(DER_MODE
, rdip
, "Could not find lpc_devinfo for "
341 return (dvarg
.dva_ddip
);
345 get_gfx_devinfo(dev_info_t
*rdip
)
348 immu_devi_t
*immu_devi
;
352 * The GFX device may not be on the same iommu unit as "agpgart"
356 immu
= list_head(&immu_list
);
357 for (; immu
; immu
= list_next(&immu_list
, immu
)) {
358 list_gfx
= &(immu
->immu_dvma_gfx_list
);
359 if (!list_is_empty(list_gfx
)) {
360 immu_devi
= list_head(list_gfx
);
365 if (immu_devi
== NULL
) {
366 ddi_err(DER_WARN
, rdip
, "iommu: No GFX device. "
367 "Cannot redirect agpgart");
371 ddi_err(DER_LOG
, rdip
, "iommu: GFX redirect to %s",
372 ddi_node_name(immu_devi
->imd_dip
));
374 return (immu_devi
->imd_dip
);
378 dma_to_immu_flags(struct ddi_dma_req
*dmareq
)
380 immu_flags_t flags
= 0;
382 if (dmareq
->dmar_fp
== DDI_DMA_SLEEP
) {
383 flags
|= IMMU_FLAGS_SLEEP
;
385 flags
|= IMMU_FLAGS_NOSLEEP
;
390 flags
|= (IMMU_FLAGS_READ
| IMMU_FLAGS_WRITE
);
394 * Read and write flags need to be reversed.
395 * DMA_READ means read from device and write
396 * to memory. So DMA read means DVMA write.
398 if (dmareq
->dmar_flags
& DDI_DMA_READ
)
399 flags
|= IMMU_FLAGS_WRITE
;
401 if (dmareq
->dmar_flags
& DDI_DMA_WRITE
)
402 flags
|= IMMU_FLAGS_READ
;
405 * Some buggy drivers specify neither READ or WRITE
406 * For such drivers set both read and write permissions
408 if ((dmareq
->dmar_flags
& (DDI_DMA_READ
| DDI_DMA_WRITE
)) == 0) {
409 flags
|= (IMMU_FLAGS_READ
| IMMU_FLAGS_WRITE
);
418 pgtable_ctor(void *buf
, void *arg
, int kmflag
)
420 size_t actual_size
= 0;
422 int (*dmafp
)(caddr_t
);
428 pgtable
= (pgtable_t
*)buf
;
430 dmafp
= (kmflag
& KM_NOSLEEP
) ? DDI_DMA_DONTWAIT
: DDI_DMA_SLEEP
;
432 next
= kmem_zalloc(IMMU_PAGESIZE
, kmflag
);
437 if (ddi_dma_alloc_handle(root_devinfo
, &immu_dma_attr
,
438 dmafp
, NULL
, &pgtable
->hwpg_dmahdl
) != DDI_SUCCESS
) {
439 kmem_free(next
, IMMU_PAGESIZE
);
443 flags
= DDI_DMA_CONSISTENT
;
444 if (!immu
->immu_dvma_coherent
)
445 flags
|= IOMEM_DATA_UC_WR_COMBINE
;
447 if (ddi_dma_mem_alloc(pgtable
->hwpg_dmahdl
, IMMU_PAGESIZE
,
448 &immu_acc_attr
, flags
,
449 dmafp
, NULL
, &vaddr
, &actual_size
,
450 &pgtable
->hwpg_memhdl
) != DDI_SUCCESS
) {
451 ddi_dma_free_handle(&pgtable
->hwpg_dmahdl
);
452 kmem_free(next
, IMMU_PAGESIZE
);
457 * Memory allocation failure. Maybe a temporary condition
458 * so return error rather than panic, so we can try again
460 if (actual_size
< IMMU_PAGESIZE
) {
461 ddi_dma_mem_free(&pgtable
->hwpg_memhdl
);
462 ddi_dma_free_handle(&pgtable
->hwpg_dmahdl
);
463 kmem_free(next
, IMMU_PAGESIZE
);
467 pgtable
->hwpg_paddr
= pfn_to_pa(hat_getpfnum(kas
.a_hat
, vaddr
));
468 pgtable
->hwpg_vaddr
= vaddr
;
469 pgtable
->swpg_next_array
= next
;
471 rw_init(&(pgtable
->swpg_rwlock
), NULL
, RW_DEFAULT
, NULL
);
478 pgtable_dtor(void *buf
, void *arg
)
482 pgtable
= (pgtable_t
*)buf
;
484 /* destroy will panic if lock is held. */
485 rw_destroy(&(pgtable
->swpg_rwlock
));
487 ddi_dma_mem_free(&pgtable
->hwpg_memhdl
);
488 ddi_dma_free_handle(&pgtable
->hwpg_dmahdl
);
489 kmem_free(pgtable
->swpg_next_array
, IMMU_PAGESIZE
);
494 * alloc a IOMMU pgtable structure.
495 * This same struct is used for root and context tables as well.
496 * This routine allocs the f/ollowing:
497 * - a pgtable_t struct
498 * - a HW page which holds PTEs/entries which is accesssed by HW
499 * so we set up DMA for this page
500 * - a SW page which is only for our bookeeping
501 * (for example to hold pointers to the next level pgtable).
502 * So a simple kmem_alloc suffices
505 pgtable_alloc(immu_t
*immu
, immu_flags_t immu_flags
)
510 kmflags
= (immu_flags
& IMMU_FLAGS_NOSLEEP
) ? KM_NOSLEEP
: KM_SLEEP
;
512 pgtable
= kmem_cache_alloc(immu
->immu_pgtable_cache
, kmflags
);
513 if (pgtable
== NULL
) {
520 pgtable_zero(pgtable_t
*pgtable
)
522 bzero(pgtable
->hwpg_vaddr
, IMMU_PAGESIZE
);
523 bzero(pgtable
->swpg_next_array
, IMMU_PAGESIZE
);
527 pgtable_free(immu_t
*immu
, pgtable_t
*pgtable
)
529 kmem_cache_free(immu
->immu_pgtable_cache
, pgtable
);
533 * Function to identify a display device from the PCI class code
536 device_is_display(uint_t classcode
)
538 static uint_t disp_classes
[] = {
543 int i
, nclasses
= sizeof (disp_classes
) / sizeof (uint_t
);
545 for (i
= 0; i
< nclasses
; i
++) {
546 if (classcode
== disp_classes
[i
])
553 * Function that determines if device is PCIEX and/or PCIEX bridge
557 uchar_t bus
, uchar_t dev
, uchar_t func
, boolean_t
*is_pcib
)
561 ushort_t cap_count
= PCI_CAP_MAX_PTR
;
563 boolean_t is_pciex
= B_FALSE
;
567 status
= pci_getw_func(bus
, dev
, func
, PCI_CONF_STAT
);
568 if (!(status
& PCI_STAT_CAP
))
571 capsp
= pci_getb_func(bus
, dev
, func
, PCI_CONF_CAP_PTR
);
572 while (cap_count
-- && capsp
>= PCI_CAP_PTR_OFF
) {
573 capsp
&= PCI_CAP_PTR_MASK
;
574 cap
= pci_getb_func(bus
, dev
, func
, capsp
);
576 if (cap
== PCI_CAP_ID_PCI_E
) {
577 status
= pci_getw_func(bus
, dev
, func
, capsp
+ 2);
579 * See section 7.8.2 of PCI-Express Base Spec v1.0a
580 * for Device/Port Type.
581 * PCIE_PCIECAP_DEV_TYPE_PCIE2PCI implies that the
582 * device is a PCIE2PCI bridge
585 ((status
& PCIE_PCIECAP_DEV_TYPE_MASK
) ==
586 PCIE_PCIECAP_DEV_TYPE_PCIE2PCI
) ? B_TRUE
: B_FALSE
;
590 capsp
= (*pci_getb_func
)(bus
, dev
, func
,
591 capsp
+ PCI_CAP_NEXT_PTR
);
598 device_use_premap(uint_t classcode
)
600 if (IMMU_PCI_CLASS2BASE(classcode
) == PCI_CLASS_NET
)
607 * immu_dvma_get_immu()
608 * get the immu unit structure for a dev_info node
611 immu_dvma_get_immu(dev_info_t
*dip
, immu_flags_t immu_flags
)
613 immu_devi_t
*immu_devi
;
617 * check if immu unit was already found earlier.
618 * If yes, then it will be stashed in immu_devi struct.
620 immu_devi
= immu_devi_get(dip
);
621 if (immu_devi
== NULL
) {
622 if (immu_devi_set(dip
, immu_flags
) != DDI_SUCCESS
) {
624 * May fail because of low memory. Return error rather
625 * than panic as we want driver to rey again later
627 ddi_err(DER_PANIC
, dip
, "immu_dvma_get_immu: "
628 "No immu_devi structure");
631 immu_devi
= immu_devi_get(dip
);
634 mutex_enter(&(DEVI(dip
)->devi_lock
));
635 if (immu_devi
->imd_immu
) {
636 immu
= immu_devi
->imd_immu
;
637 mutex_exit(&(DEVI(dip
)->devi_lock
));
640 mutex_exit(&(DEVI(dip
)->devi_lock
));
642 immu
= immu_dmar_get_immu(dip
);
644 ddi_err(DER_PANIC
, dip
, "immu_dvma_get_immu: "
645 "Cannot find immu_t for device");
650 * Check if some other thread found immu
651 * while lock was not held
653 immu_devi
= immu_devi_get(dip
);
654 /* immu_devi should be present as we found it earlier */
655 if (immu_devi
== NULL
) {
656 ddi_err(DER_PANIC
, dip
,
657 "immu_dvma_get_immu: No immu_devi structure");
661 mutex_enter(&(DEVI(dip
)->devi_lock
));
662 if (immu_devi
->imd_immu
== NULL
) {
663 /* nobody else set it, so we should do it */
664 immu_devi
->imd_immu
= immu
;
665 immu_devi_set_spclist(dip
, immu
);
668 * if some other thread got immu before
669 * us, it should get the same results
671 if (immu_devi
->imd_immu
!= immu
) {
672 ddi_err(DER_PANIC
, dip
, "Multiple "
673 "immu units found for device. Expected (%p), "
674 "actual (%p)", (void *)immu
,
675 (void *)immu_devi
->imd_immu
);
676 mutex_exit(&(DEVI(dip
)->devi_lock
));
680 mutex_exit(&(DEVI(dip
)->devi_lock
));
686 /* ############################# IMMU_DEVI code ############################ */
689 * Allocate a immu_devi structure and initialize it
692 create_immu_devi(dev_info_t
*rdip
, int bus
, int dev
, int func
,
693 immu_flags_t immu_flags
)
695 uchar_t baseclass
, subclass
;
696 uint_t classcode
, revclass
;
697 immu_devi_t
*immu_devi
;
698 boolean_t pciex
= B_FALSE
;
700 boolean_t is_pcib
= B_FALSE
;
702 /* bus == -1 indicate non-PCI device (no BDF) */
703 ASSERT(bus
== -1 || bus
>= 0);
707 kmflags
= (immu_flags
& IMMU_FLAGS_NOSLEEP
) ? KM_NOSLEEP
: KM_SLEEP
;
708 immu_devi
= kmem_zalloc(sizeof (immu_devi_t
), kmflags
);
709 if (immu_devi
== NULL
) {
710 ddi_err(DER_WARN
, rdip
, "Failed to allocate memory for "
711 "Intel IOMMU immu_devi structure");
714 immu_devi
->imd_dip
= rdip
;
715 immu_devi
->imd_seg
= 0; /* Currently seg can only be 0 */
716 immu_devi
->imd_bus
= bus
;
717 immu_devi
->imd_pcib_type
= IMMU_PCIB_BAD
;
720 immu_devi
->imd_pcib_type
= IMMU_PCIB_NOBDF
;
724 immu_devi
->imd_devfunc
= IMMU_PCI_DEVFUNC(dev
, func
);
725 immu_devi
->imd_sec
= 0;
726 immu_devi
->imd_sub
= 0;
728 revclass
= pci_getl_func(bus
, dev
, func
, PCI_CONF_REVID
);
730 classcode
= IMMU_PCI_REV2CLASS(revclass
);
731 baseclass
= IMMU_PCI_CLASS2BASE(classcode
);
732 subclass
= IMMU_PCI_CLASS2SUB(classcode
);
734 if (baseclass
== PCI_CLASS_BRIDGE
&& subclass
== PCI_BRIDGE_PCI
) {
736 immu_devi
->imd_sec
= pci_getb_func(bus
, dev
, func
,
738 immu_devi
->imd_sub
= pci_getb_func(bus
, dev
, func
,
741 pciex
= device_is_pciex(bus
, dev
, func
, &is_pcib
);
742 if (pciex
== B_TRUE
&& is_pcib
== B_TRUE
) {
743 immu_devi
->imd_pcib_type
= IMMU_PCIB_PCIE_PCI
;
744 } else if (pciex
== B_TRUE
) {
745 immu_devi
->imd_pcib_type
= IMMU_PCIB_PCIE_PCIE
;
747 immu_devi
->imd_pcib_type
= IMMU_PCIB_PCI_PCI
;
750 immu_devi
->imd_pcib_type
= IMMU_PCIB_ENDPOINT
;
753 /* check for certain special devices */
754 immu_devi
->imd_display
= device_is_display(classcode
);
755 immu_devi
->imd_lpc
= ((baseclass
== PCI_CLASS_BRIDGE
) &&
756 (subclass
== PCI_BRIDGE_ISA
)) ? B_TRUE
: B_FALSE
;
757 immu_devi
->imd_use_premap
= device_use_premap(classcode
);
759 immu_devi
->imd_domain
= NULL
;
761 immu_devi
->imd_dvma_flags
= immu_global_dvma_flags
;
767 destroy_immu_devi(immu_devi_t
*immu_devi
)
769 kmem_free(immu_devi
, sizeof (immu_devi_t
));
773 immu_devi_domain(dev_info_t
*rdip
, dev_info_t
**ddipp
)
775 immu_devi_t
*immu_devi
;
781 immu_devi
= immu_devi_get(rdip
);
782 if (immu_devi
== NULL
) {
786 mutex_enter(&(DEVI(rdip
)->devi_lock
));
787 domain
= immu_devi
->imd_domain
;
788 ddip
= immu_devi
->imd_ddip
;
789 mutex_exit(&(DEVI(rdip
)->devi_lock
));
798 /* ############################# END IMMU_DEVI code ######################## */
799 /* ############################# DOMAIN code ############################### */
802 * This routine always succeeds
805 did_alloc(immu_t
*immu
, dev_info_t
*rdip
,
806 dev_info_t
*ddip
, immu_flags_t immu_flags
)
810 did
= (uintptr_t)vmem_alloc(immu
->immu_did_arena
, 1,
811 (immu_flags
& IMMU_FLAGS_NOSLEEP
) ? VM_NOSLEEP
: VM_SLEEP
);
814 ddi_err(DER_WARN
, rdip
, "device domain-id alloc error"
815 " domain-device: %s%d. immu unit is %s. Using "
816 "unity domain with domain-id (%d)",
817 ddi_driver_name(ddip
), ddi_get_instance(ddip
),
818 immu
->immu_name
, immu
->immu_unity_domain
->dom_did
);
819 did
= immu
->immu_unity_domain
->dom_did
;
826 get_branch_domain(dev_info_t
*pdip
, void *arg
)
828 immu_devi_t
*immu_devi
;
832 dvma_arg_t
*dvp
= (dvma_arg_t
*)arg
;
835 * The field dvp->dva_rdip is a work-in-progress
836 * and gets updated as we walk up the ancestor
837 * tree. The final ddip is set only when we reach
838 * the top of the tree. So the dvp->dva_ddip field cannot
839 * be relied on until we reach the top of the field.
842 /* immu_devi may not be set. */
843 immu_devi
= immu_devi_get(pdip
);
844 if (immu_devi
== NULL
) {
845 if (immu_devi_set(pdip
, dvp
->dva_flags
) != DDI_SUCCESS
) {
846 dvp
->dva_error
= DDI_FAILURE
;
847 return (DDI_WALK_TERMINATE
);
851 immu_devi
= immu_devi_get(pdip
);
852 immu
= immu_devi
->imd_immu
;
854 immu
= immu_dvma_get_immu(pdip
, dvp
->dva_flags
);
857 * If we encounter a PCIE_PCIE bridge *ANCESTOR* we need to
858 * terminate the walk (since the device under the PCIE bridge
859 * is a PCIE device and has an independent entry in the
860 * root/context table)
862 if (dvp
->dva_rdip
!= pdip
&&
863 immu_devi
->imd_pcib_type
== IMMU_PCIB_PCIE_PCIE
) {
864 return (DDI_WALK_TERMINATE
);
868 * In order to be a domain-dim, it must be a PCI device i.e.
869 * must have valid BDF. This also eliminates the root complex.
871 if (immu_devi
->imd_pcib_type
!= IMMU_PCIB_BAD
&&
872 immu_devi
->imd_pcib_type
!= IMMU_PCIB_NOBDF
) {
873 ASSERT(immu_devi
->imd_bus
>= 0);
874 ASSERT(immu_devi
->imd_devfunc
>= 0);
875 dvp
->dva_ddip
= pdip
;
878 if (immu_devi
->imd_display
== B_TRUE
||
879 (dvp
->dva_flags
& IMMU_FLAGS_UNITY
)) {
880 dvp
->dva_domain
= immu
->immu_unity_domain
;
881 /* continue walking to find ddip */
882 return (DDI_WALK_CONTINUE
);
885 mutex_enter(&(DEVI(pdip
)->devi_lock
));
886 domain
= immu_devi
->imd_domain
;
887 ddip
= immu_devi
->imd_ddip
;
888 mutex_exit(&(DEVI(pdip
)->devi_lock
));
890 if (domain
&& ddip
) {
891 /* if domain is set, it must be the same */
892 if (dvp
->dva_domain
) {
893 ASSERT(domain
== dvp
->dva_domain
);
895 dvp
->dva_domain
= domain
;
896 dvp
->dva_ddip
= ddip
;
897 return (DDI_WALK_TERMINATE
);
900 /* Domain may already be set, continue walking so that ddip gets set */
901 if (dvp
->dva_domain
) {
902 return (DDI_WALK_CONTINUE
);
905 /* domain is not set in either immu_devi or dvp */
906 domain
= bdf_domain_lookup(immu_devi
);
907 if (domain
== NULL
) {
908 return (DDI_WALK_CONTINUE
);
911 /* ok, the BDF hash had a domain for this BDF. */
913 /* Grab lock again to check if something else set immu_devi fields */
914 mutex_enter(&(DEVI(pdip
)->devi_lock
));
915 if (immu_devi
->imd_domain
!= NULL
) {
916 dvp
->dva_domain
= domain
;
918 dvp
->dva_domain
= domain
;
920 mutex_exit(&(DEVI(pdip
)->devi_lock
));
923 * walk upwards until the topmost PCI bridge is found
925 return (DDI_WALK_CONTINUE
);
930 map_unity_domain(domain_t
*domain
)
935 immu_dcookie_t dcookies
[1] = {0};
939 * UNITY arenas are a mirror of the physical memory
940 * installed on the system.
945 * Dont skip page0. Some broken HW/FW access it.
947 dcookies
[0].dck_paddr
= 0;
948 dcookies
[0].dck_npages
= 1;
950 (void) dvma_map(domain
, 0, 1, dcookies
, dcount
, NULL
,
951 IMMU_FLAGS_READ
| IMMU_FLAGS_WRITE
| IMMU_FLAGS_PAGE1
);
958 if (mp
->ml_address
== 0) {
959 /* since we already mapped page1 above */
960 start
= IMMU_PAGESIZE
;
962 start
= mp
->ml_address
;
964 npages
= mp
->ml_size
/IMMU_PAGESIZE
+ 1;
966 dcookies
[0].dck_paddr
= start
;
967 dcookies
[0].dck_npages
= npages
;
969 (void) dvma_map(domain
, start
, npages
, dcookies
,
970 dcount
, NULL
, IMMU_FLAGS_READ
| IMMU_FLAGS_WRITE
);
972 ddi_err(DER_LOG
, domain
->dom_dip
, "iommu: mapping PHYS span [0x%" PRIx64
973 " - 0x%" PRIx64
"]", start
, start
+ mp
->ml_size
);
977 ddi_err(DER_LOG
, domain
->dom_dip
,
978 "iommu: mapping PHYS span [0x%" PRIx64
" - 0x%" PRIx64
"]",
979 mp
->ml_address
, mp
->ml_address
+ mp
->ml_size
);
981 start
= mp
->ml_address
;
982 npages
= mp
->ml_size
/IMMU_PAGESIZE
+ 1;
984 dcookies
[0].dck_paddr
= start
;
985 dcookies
[0].dck_npages
= npages
;
987 (void) dvma_map(domain
, start
, npages
,
988 dcookies
, dcount
, NULL
, IMMU_FLAGS_READ
| IMMU_FLAGS_WRITE
);
994 ddi_err(DER_LOG
, domain
->dom_dip
,
995 "iommu: mapping PHYS span [0x%" PRIx64
" - 0x%" PRIx64
"]",
996 mp
->ml_address
, mp
->ml_address
+ mp
->ml_size
);
998 start
= mp
->ml_address
;
999 npages
= mp
->ml_size
/IMMU_PAGESIZE
+ 1;
1001 dcookies
[0].dck_paddr
= start
;
1002 dcookies
[0].dck_npages
= npages
;
1004 (void) dvma_map(domain
, start
, npages
,
1005 dcookies
, dcount
, NULL
, IMMU_FLAGS_READ
| IMMU_FLAGS_WRITE
);
1010 memlist_read_unlock();
1014 * create_xlate_arena()
1015 * Create the dvma arena for a domain with translation
1019 create_xlate_arena(immu_t
*immu
, domain_t
*domain
,
1020 dev_info_t
*rdip
, immu_flags_t immu_flags
)
1031 arena_name
= domain
->dom_dvma_arena_name
;
1033 /* Note, don't do sizeof (arena_name) - it is just a pointer */
1034 (void) snprintf(arena_name
,
1035 sizeof (domain
->dom_dvma_arena_name
),
1036 "%s-domain-%d-xlate-DVMA-arena", immu
->immu_name
,
1039 vmem_flags
= (immu_flags
& IMMU_FLAGS_NOSLEEP
) ? VM_NOSLEEP
: VM_SLEEP
;
1041 /* Restrict mgaddr (max guest addr) to MGAW */
1042 mgaw
= IMMU_CAP_MGAW(immu
->immu_regs_cap
);
1045 * To ensure we avoid ioapic and PCI MMIO ranges we just
1046 * use the physical memory address range of the system as the
1049 maxaddr
= ((uint64_t)1 << mgaw
);
1051 memlist_read_lock();
1055 if (mp
->ml_address
== 0)
1056 start
= MMU_PAGESIZE
;
1058 start
= mp
->ml_address
;
1060 if (start
+ mp
->ml_size
> maxaddr
)
1061 size
= maxaddr
- start
;
1065 ddi_err(DER_VERB
, rdip
,
1066 "iommu: %s: Creating dvma vmem arena [0x%" PRIx64
1067 " - 0x%" PRIx64
"]", arena_name
, start
, start
+ size
);
1070 * We always allocate in quanta of IMMU_PAGESIZE
1072 domain
->dom_dvma_arena
= vmem_create(arena_name
,
1073 (void *)(uintptr_t)start
, /* start addr */
1075 IMMU_PAGESIZE
, /* quantum */
1082 if (domain
->dom_dvma_arena
== NULL
) {
1083 ddi_err(DER_PANIC
, rdip
,
1084 "Failed to allocate DVMA arena(%s) "
1085 "for domain ID (%d)", arena_name
, domain
->dom_did
);
1092 if (mp
->ml_address
== 0)
1093 start
= MMU_PAGESIZE
;
1095 start
= mp
->ml_address
;
1097 if (start
+ mp
->ml_size
> maxaddr
)
1098 size
= maxaddr
- start
;
1102 ddi_err(DER_VERB
, rdip
,
1103 "iommu: %s: Adding dvma vmem span [0x%" PRIx64
1104 " - 0x%" PRIx64
"]", arena_name
, start
,
1107 vmem_ret
= vmem_add(domain
->dom_dvma_arena
,
1108 (void *)(uintptr_t)start
, size
, vmem_flags
);
1110 if (vmem_ret
== NULL
) {
1111 ddi_err(DER_PANIC
, rdip
,
1112 "Failed to allocate DVMA arena(%s) "
1113 "for domain ID (%d)",
1114 arena_name
, domain
->dom_did
);
1119 memlist_read_unlock();
1122 /* ################################### DOMAIN CODE ######################### */
1125 * Set the domain and domain-dip for a dip
1133 immu_devi_t
*immu_devi
;
1137 immu_devi
= immu_devi_get(dip
);
1139 mutex_enter(&(DEVI(dip
)->devi_lock
));
1140 fddip
= immu_devi
->imd_ddip
;
1141 fdomain
= immu_devi
->imd_domain
;
1144 ASSERT(fddip
== ddip
);
1146 immu_devi
->imd_ddip
= ddip
;
1150 ASSERT(fdomain
== domain
);
1152 immu_devi
->imd_domain
= domain
;
1154 mutex_exit(&(DEVI(dip
)->devi_lock
));
1159 * Get domain for a device. The domain may be global in which case it
1160 * is shared between all IOMMU units. Due to potential AGAW differences
1161 * between IOMMU units, such global domains *have to be* UNITY mapping
1162 * domains. Alternatively, the domain may be local to a IOMMU unit.
1163 * Local domains may be shared or immu_devi, although the
1165 * is restricted to devices controlled by the IOMMU unit to
1167 * belongs. If shared, they (currently) have to be UNITY domains. If
1168 * immu_devi a domain may be either UNITY or translation (XLATE) domain.
1171 device_domain(dev_info_t
*rdip
, dev_info_t
**ddipp
, immu_flags_t immu_flags
)
1173 dev_info_t
*ddip
; /* topmost dip in domain i.e. domain owner */
1176 dvma_arg_t dvarg
= {0};
1182 * Check if the domain is already set. This is usually true
1183 * if this is not the first DVMA transaction.
1186 domain
= immu_devi_domain(rdip
, &ddip
);
1192 immu
= immu_dvma_get_immu(rdip
, immu_flags
);
1195 * possible that there is no IOMMU unit for this device
1196 * - BIOS bugs are one example.
1198 ddi_err(DER_WARN
, rdip
, "No iommu unit found for device");
1202 immu_flags
|= immu_devi_get(rdip
)->imd_dvma_flags
;
1204 dvarg
.dva_rdip
= rdip
;
1205 dvarg
.dva_ddip
= NULL
;
1206 dvarg
.dva_domain
= NULL
;
1207 dvarg
.dva_flags
= immu_flags
;
1209 if (immu_walk_ancestor(rdip
, NULL
, get_branch_domain
,
1210 &dvarg
, &level
, immu_flags
) != DDI_SUCCESS
) {
1212 * maybe low memory. return error,
1213 * so driver tries again later
1218 /* should have walked at least 1 dip (i.e. edip) */
1221 ddip
= dvarg
.dva_ddip
; /* must be present */
1222 domain
= dvarg
.dva_domain
; /* may be NULL */
1225 * We may find the domain during our ancestor walk on any one of our
1226 * ancestor dips, If the domain is found then the domain-dip
1227 * (i.e. ddip) will also be found in the same immu_devi struct.
1228 * The domain-dip is the highest ancestor dip which shares the
1229 * same domain with edip.
1230 * The domain may or may not be found, but the domain dip must
1234 ddi_err(DER_MODE
, rdip
, "Cannot find domain dip for device.");
1239 * Did we find a domain ?
1245 /* nope, so allocate */
1246 domain
= domain_create(immu
, ddip
, rdip
, immu_flags
);
1247 if (domain
== NULL
) {
1254 * We know *domain *is* the right domain, so panic if
1255 * another domain is set for either the request-dip or
1258 set_domain(ddip
, ddip
, domain
);
1259 set_domain(rdip
, ddip
, domain
);
1266 create_unity_domain(immu_t
*immu
)
1270 /* domain created during boot and always use sleep flag */
1271 domain
= kmem_zalloc(sizeof (domain_t
), KM_SLEEP
);
1273 rw_init(&(domain
->dom_pgtable_rwlock
), NULL
, RW_DEFAULT
, NULL
);
1275 domain
->dom_did
= IMMU_UNITY_DID
;
1276 domain
->dom_maptype
= IMMU_MAPTYPE_UNITY
;
1278 domain
->dom_immu
= immu
;
1279 immu
->immu_unity_domain
= domain
;
1282 * Setup the domain's initial page table
1283 * should never fail.
1285 domain
->dom_pgtable_root
= pgtable_alloc(immu
, IMMU_FLAGS_SLEEP
);
1286 pgtable_zero(domain
->dom_pgtable_root
);
1289 * Only map all physical memory in to the unity domain
1290 * if passthrough is not supported. If it is supported,
1291 * passthrough is set in the context entry instead.
1293 if (!IMMU_ECAP_GET_PT(immu
->immu_regs_excap
))
1294 map_unity_domain(domain
);
1298 * put it on the system-wide UNITY domain list
1300 mutex_enter(&(immu_domain_lock
));
1301 list_insert_tail(&immu_unity_domain_list
, domain
);
1302 mutex_exit(&(immu_domain_lock
));
1306 * ddip is the domain-dip - the topmost dip in a domain
1307 * rdip is the requesting-dip - the device which is
1308 * requesting DVMA setup
1309 * if domain is a non-shared domain rdip == ddip
1312 domain_create(immu_t
*immu
, dev_info_t
*ddip
, dev_info_t
*rdip
,
1313 immu_flags_t immu_flags
)
1317 char mod_hash_name
[128];
1318 immu_devi_t
*immu_devi
;
1320 immu_dcookie_t dcookies
[1] = {0};
1323 immu_devi
= immu_devi_get(rdip
);
1326 * First allocate a domainid.
1327 * This routine will never fail, since if we run out
1328 * of domains the unity domain will be allocated.
1330 did
= did_alloc(immu
, rdip
, ddip
, immu_flags
);
1331 if (did
== IMMU_UNITY_DID
) {
1332 /* domain overflow */
1333 ASSERT(immu
->immu_unity_domain
);
1334 return (immu
->immu_unity_domain
);
1337 kmflags
= (immu_flags
& IMMU_FLAGS_NOSLEEP
) ? KM_NOSLEEP
: KM_SLEEP
;
1338 domain
= kmem_zalloc(sizeof (domain_t
), kmflags
);
1339 if (domain
== NULL
) {
1340 ddi_err(DER_PANIC
, rdip
, "Failed to alloc DVMA domain "
1341 "structure for device. IOMMU unit: %s", immu
->immu_name
);
1345 rw_init(&(domain
->dom_pgtable_rwlock
), NULL
, RW_DEFAULT
, NULL
);
1347 (void) snprintf(mod_hash_name
, sizeof (mod_hash_name
),
1348 "immu%s-domain%d-pava-hash", immu
->immu_name
, did
);
1350 domain
->dom_did
= did
;
1351 domain
->dom_immu
= immu
;
1352 domain
->dom_maptype
= IMMU_MAPTYPE_XLATE
;
1353 domain
->dom_dip
= ddip
;
1356 * Create xlate DVMA arena for this domain.
1358 create_xlate_arena(immu
, domain
, rdip
, immu_flags
);
1361 * Setup the domain's initial page table
1363 domain
->dom_pgtable_root
= pgtable_alloc(immu
, immu_flags
);
1364 if (domain
->dom_pgtable_root
== NULL
) {
1365 ddi_err(DER_PANIC
, rdip
, "Failed to alloc root "
1366 "pgtable for domain (%d). IOMMU unit: %s",
1367 domain
->dom_did
, immu
->immu_name
);
1370 pgtable_zero(domain
->dom_pgtable_root
);
1373 * Since this is a immu unit-specific domain, put it on
1374 * the per-immu domain list.
1376 mutex_enter(&(immu
->immu_lock
));
1377 list_insert_head(&immu
->immu_domain_list
, domain
);
1378 mutex_exit(&(immu
->immu_lock
));
1381 * Also put it on the system-wide xlate domain list
1383 mutex_enter(&(immu_domain_lock
));
1384 list_insert_head(&immu_xlate_domain_list
, domain
);
1385 mutex_exit(&(immu_domain_lock
));
1387 bdf_domain_insert(immu_devi
, domain
);
1389 #ifdef BUGGY_DRIVERS
1391 * Map page0. Some broken HW/FW access it.
1393 dcookies
[0].dck_paddr
= 0;
1394 dcookies
[0].dck_npages
= 1;
1396 (void) dvma_map(domain
, 0, 1, dcookies
, dcount
, NULL
,
1397 IMMU_FLAGS_READ
| IMMU_FLAGS_WRITE
| IMMU_FLAGS_PAGE1
);
1403 * Create domainid arena.
1404 * Domainid 0 is reserved by Vt-d spec and cannot be used by
1406 * Domainid 1 is reserved by solaris and used for *all* of the following:
1407 * as the "uninitialized" domain - For devices not yet controlled
1409 * as the "unity" domain - For devices that will always belong
1410 * to the unity domain
1411 * as the "overflow" domain - Used for any new device after we
1412 * run out of domains
1413 * All of the above domains map into a single domain with
1414 * domainid 1 and UNITY DVMA mapping
1415 * Each IMMU unity has its own unity/uninit/overflow domain
1418 did_init(immu_t
*immu
)
1420 (void) snprintf(immu
->immu_did_arena_name
,
1421 sizeof (immu
->immu_did_arena_name
),
1422 "%s_domainid_arena", immu
->immu_name
);
1424 ddi_err(DER_VERB
, immu
->immu_dip
, "creating domainid arena %s",
1425 immu
->immu_did_arena_name
);
1427 immu
->immu_did_arena
= vmem_create(
1428 immu
->immu_did_arena_name
,
1429 (void *)(uintptr_t)(IMMU_UNITY_DID
+ 1), /* start addr */
1430 immu
->immu_max_domains
- IMMU_UNITY_DID
,
1438 /* Even with SLEEP flag, vmem_create() can fail */
1439 if (immu
->immu_did_arena
== NULL
) {
1440 ddi_err(DER_PANIC
, NULL
, "%s: Failed to create Intel "
1441 "IOMMU domainid allocator: %s", immu
->immu_name
,
1442 immu
->immu_did_arena_name
);
1446 /* ######################### CONTEXT CODE ################################# */
1449 context_set(immu_t
*immu
, domain_t
*domain
, pgtable_t
*root_table
,
1450 int bus
, int devfunc
)
1453 pgtable_t
*pgtable_root
;
1459 boolean_t fill_root
;
1462 pgtable_root
= domain
->dom_pgtable_root
;
1464 ctxp
= (hw_rce_t
*)(root_table
->swpg_next_array
);
1465 context
= *(pgtable_t
**)(ctxp
+ bus
);
1466 hw_rent
= (hw_rce_t
*)(root_table
->hwpg_vaddr
) + bus
;
1468 fill_root
= B_FALSE
;
1471 /* Check the most common case first with reader lock */
1472 rw_enter(&(immu
->immu_ctx_rwlock
), RW_READER
);
1475 if (ROOT_GET_P(hw_rent
)) {
1476 hw_cent
= (hw_rce_t
*)(context
->hwpg_vaddr
) + devfunc
;
1477 if (CONT_GET_AVAIL(hw_cent
) == IMMU_CONT_INITED
) {
1478 rw_exit(&(immu
->immu_ctx_rwlock
));
1488 if (rwtype
== RW_READER
&&
1489 rw_tryupgrade(&(immu
->immu_ctx_rwlock
)) == 0) {
1490 rw_exit(&(immu
->immu_ctx_rwlock
));
1491 rw_enter(&(immu
->immu_ctx_rwlock
), RW_WRITER
);
1497 if (fill_root
== B_TRUE
) {
1498 ROOT_SET_CONT(hw_rent
, context
->hwpg_paddr
);
1499 ROOT_SET_P(hw_rent
);
1500 immu_regs_cpu_flush(immu
, (caddr_t
)hw_rent
, sizeof (hw_rce_t
));
1503 if (fill_ctx
== B_TRUE
) {
1504 hw_cent
= (hw_rce_t
*)(context
->hwpg_vaddr
) + devfunc
;
1505 /* need to disable context entry before reprogramming it */
1506 bzero(hw_cent
, sizeof (hw_rce_t
));
1509 immu_regs_cpu_flush(immu
, (caddr_t
)hw_cent
, sizeof (hw_rce_t
));
1511 sid
= ((bus
<< 8) | devfunc
);
1512 immu_flush_context_fsi(immu
, 0, sid
, domain
->dom_did
,
1513 &immu
->immu_ctx_inv_wait
);
1515 CONT_SET_AVAIL(hw_cent
, IMMU_CONT_INITED
);
1516 CONT_SET_DID(hw_cent
, domain
->dom_did
);
1517 CONT_SET_AW(hw_cent
, immu
->immu_dvma_agaw
);
1518 CONT_SET_ASR(hw_cent
, pgtable_root
->hwpg_paddr
);
1519 if (domain
->dom_did
== IMMU_UNITY_DID
&&
1520 IMMU_ECAP_GET_PT(immu
->immu_regs_excap
))
1521 CONT_SET_TTYPE(hw_cent
, TTYPE_PASSTHRU
);
1524 CONT_SET_TTYPE(hw_cent
, TTYPE_XLATE_ONLY
);
1525 CONT_SET_P(hw_cent
);
1526 if (IMMU_ECAP_GET_CH(immu
->immu_regs_excap
)) {
1527 CONT_SET_EH(hw_cent
);
1529 CONT_SET_ALH(hw_cent
);
1531 immu_regs_cpu_flush(immu
, (caddr_t
)hw_cent
, sizeof (hw_rce_t
));
1533 rw_exit(&(immu
->immu_ctx_rwlock
));
1537 context_create(immu_t
*immu
)
1541 pgtable_t
*root_table
;
1543 pgtable_t
*pgtable_root
;
1548 /* Allocate a zeroed root table (4K 256b entries) */
1549 root_table
= pgtable_alloc(immu
, IMMU_FLAGS_SLEEP
);
1550 pgtable_zero(root_table
);
1553 * Setup context tables for all possible root table entries.
1554 * Start out with unity domains for all entries.
1556 ctxp
= (hw_rce_t
*)(root_table
->swpg_next_array
);
1557 hw_rent
= (hw_rce_t
*)(root_table
->hwpg_vaddr
);
1558 for (bus
= 0; bus
< IMMU_ROOT_NUM
; bus
++, ctxp
++, hw_rent
++) {
1559 context
= pgtable_alloc(immu
, IMMU_FLAGS_SLEEP
);
1560 pgtable_zero(context
);
1561 ROOT_SET_P(hw_rent
);
1562 ROOT_SET_CONT(hw_rent
, context
->hwpg_paddr
);
1563 hw_cent
= (hw_rce_t
*)(context
->hwpg_vaddr
);
1564 for (devfunc
= 0; devfunc
< IMMU_CONT_NUM
;
1565 devfunc
++, hw_cent
++) {
1567 immu
->immu_unity_domain
->dom_pgtable_root
;
1568 CONT_SET_DID(hw_cent
,
1569 immu
->immu_unity_domain
->dom_did
);
1570 CONT_SET_AW(hw_cent
, immu
->immu_dvma_agaw
);
1571 CONT_SET_ASR(hw_cent
, pgtable_root
->hwpg_paddr
);
1572 if (IMMU_ECAP_GET_PT(immu
->immu_regs_excap
))
1573 CONT_SET_TTYPE(hw_cent
, TTYPE_PASSTHRU
);
1576 CONT_SET_TTYPE(hw_cent
, TTYPE_XLATE_ONLY
);
1577 CONT_SET_AVAIL(hw_cent
, IMMU_CONT_UNINITED
);
1578 CONT_SET_P(hw_cent
);
1580 immu_regs_cpu_flush(immu
, context
->hwpg_vaddr
, IMMU_PAGESIZE
);
1581 *((pgtable_t
**)ctxp
) = context
;
1584 return (root_table
);
1588 * Called during rootnex attach, so no locks needed
1591 context_init(immu_t
*immu
)
1593 rw_init(&(immu
->immu_ctx_rwlock
), NULL
, RW_DEFAULT
, NULL
);
1595 immu_init_inv_wait(&immu
->immu_ctx_inv_wait
, "ctxglobal", B_TRUE
);
1597 immu_regs_wbf_flush(immu
);
1599 immu
->immu_ctx_root
= context_create(immu
);
1601 immu_regs_set_root_table(immu
);
1603 rw_enter(&(immu
->immu_ctx_rwlock
), RW_WRITER
);
1604 immu_flush_context_gbl(immu
, &immu
->immu_ctx_inv_wait
);
1605 immu_flush_iotlb_gbl(immu
, &immu
->immu_ctx_inv_wait
);
1606 rw_exit(&(immu
->immu_ctx_rwlock
));
1614 find_top_pcib(dev_info_t
*dip
, void *arg
)
1616 immu_devi_t
*immu_devi
;
1617 dev_info_t
**pcibdipp
= (dev_info_t
**)arg
;
1619 immu_devi
= immu_devi_get(dip
);
1621 if (immu_devi
->imd_pcib_type
== IMMU_PCIB_PCI_PCI
) {
1625 return (DDI_WALK_CONTINUE
);
1629 immu_context_update(immu_t
*immu
, domain_t
*domain
, dev_info_t
*ddip
,
1630 dev_info_t
*rdip
, immu_flags_t immu_flags
)
1632 immu_devi_t
*r_immu_devi
;
1633 immu_devi_t
*d_immu_devi
;
1638 immu_pcib_t d_pcib_type
;
1639 dev_info_t
*pcibdip
;
1641 if (ddip
== NULL
|| rdip
== NULL
||
1642 ddip
== root_devinfo
|| rdip
== root_devinfo
) {
1643 ddi_err(DER_MODE
, rdip
, "immu_contexts_update: domain-dip or "
1644 "request-dip are NULL or are root devinfo");
1645 return (DDI_FAILURE
);
1649 * We need to set the context fields
1650 * based on what type of device rdip and ddip are.
1651 * To do that we need the immu_devi field.
1652 * Set the immu_devi field (if not already set)
1654 if (immu_devi_set(ddip
, immu_flags
) == DDI_FAILURE
) {
1655 ddi_err(DER_MODE
, rdip
,
1656 "immu_context_update: failed to set immu_devi for ddip");
1657 return (DDI_FAILURE
);
1660 if (immu_devi_set(rdip
, immu_flags
) == DDI_FAILURE
) {
1661 ddi_err(DER_MODE
, rdip
,
1662 "immu_context_update: failed to set immu_devi for rdip");
1663 return (DDI_FAILURE
);
1666 d_immu_devi
= immu_devi_get(ddip
);
1667 r_immu_devi
= immu_devi_get(rdip
);
1669 d_bus
= d_immu_devi
->imd_bus
;
1670 d_devfunc
= d_immu_devi
->imd_devfunc
;
1671 d_pcib_type
= d_immu_devi
->imd_pcib_type
;
1672 r_bus
= r_immu_devi
->imd_bus
;
1673 r_devfunc
= r_immu_devi
->imd_devfunc
;
1676 /* rdip is a PCIE device. set context for it only */
1677 context_set(immu
, domain
, immu
->immu_ctx_root
, r_bus
,
1679 #ifdef BUGGY_DRIVERS
1680 } else if (r_immu_devi
== d_immu_devi
) {
1682 ddi_err(DER_WARN
, rdip
, "Driver bug: Devices 0x%lx and "
1683 "0x%lx are identical", rdip
, ddip
);
1685 /* rdip is a PCIE device. set context for it only */
1686 context_set(immu
, domain
, immu
->immu_ctx_root
, r_bus
,
1689 } else if (d_pcib_type
== IMMU_PCIB_PCIE_PCI
) {
1691 * ddip is a PCIE_PCI bridge. Set context for ddip's
1692 * secondary bus. If rdip is on ddip's secondary
1693 * bus, set context for rdip. Else, set context
1694 * for rdip's PCI bridge on ddip's secondary bus.
1696 context_set(immu
, domain
, immu
->immu_ctx_root
,
1697 d_immu_devi
->imd_sec
, 0);
1698 if (d_immu_devi
->imd_sec
== r_bus
) {
1699 context_set(immu
, domain
, immu
->immu_ctx_root
,
1703 if (immu_walk_ancestor(rdip
, ddip
, find_top_pcib
,
1704 &pcibdip
, NULL
, immu_flags
) == DDI_SUCCESS
&&
1706 r_immu_devi
= immu_devi_get(pcibdip
);
1707 r_bus
= r_immu_devi
->imd_bus
;
1708 r_devfunc
= r_immu_devi
->imd_devfunc
;
1709 context_set(immu
, domain
, immu
->immu_ctx_root
,
1712 ddi_err(DER_PANIC
, rdip
, "Failed to find PCI "
1713 " bridge for PCI device");
1717 } else if (d_pcib_type
== IMMU_PCIB_PCI_PCI
) {
1718 context_set(immu
, domain
, immu
->immu_ctx_root
, d_bus
,
1720 } else if (d_pcib_type
== IMMU_PCIB_ENDPOINT
) {
1722 * ddip is a PCIE device which has a non-PCI device under it
1723 * i.e. it is a PCI-nonPCI bridge. Example: pciicde-ata
1725 context_set(immu
, domain
, immu
->immu_ctx_root
, d_bus
,
1728 ddi_err(DER_PANIC
, rdip
, "unknown device type. Cannot "
1729 "set iommu context.");
1733 /* XXX do we need a membar_producer() here */
1734 return (DDI_SUCCESS
);
1737 /* ##################### END CONTEXT CODE ################################## */
1738 /* ##################### MAPPING CODE ################################## */
1743 PDTE_check(immu_t
*immu
, hw_pdte_t pdte
, pgtable_t
*next
, paddr_t paddr
,
1744 dev_info_t
*rdip
, immu_flags_t immu_flags
)
1746 /* The PDTE must be set i.e. present bit is set */
1747 if (!PDTE_P(pdte
)) {
1748 ddi_err(DER_MODE
, rdip
, "No present flag");
1753 * Just assert to check most significant system software field
1754 * (PDTE_SW4) as it is same as present bit and we
1755 * checked that above
1757 ASSERT(PDTE_SW4(pdte
));
1760 * TM field should be clear if not reserved.
1761 * non-leaf is always reserved
1763 if (next
== NULL
&& immu
->immu_TM_reserved
== B_FALSE
) {
1764 if (PDTE_TM(pdte
)) {
1765 ddi_err(DER_MODE
, rdip
, "TM flag set");
1771 * The SW3 field is not used and must be clear
1773 if (PDTE_SW3(pdte
)) {
1774 ddi_err(DER_MODE
, rdip
, "SW3 set");
1779 * PFN (for PTE) or next level pgtable-paddr (for PDE) must be set
1782 ASSERT(paddr
% IMMU_PAGESIZE
== 0);
1783 if (PDTE_PADDR(pdte
) != paddr
) {
1784 ddi_err(DER_MODE
, rdip
,
1785 "PTE paddr mismatch: %lx != %lx",
1786 PDTE_PADDR(pdte
), paddr
);
1790 if (PDTE_PADDR(pdte
) != next
->hwpg_paddr
) {
1791 ddi_err(DER_MODE
, rdip
,
1792 "PDE paddr mismatch: %lx != %lx",
1793 PDTE_PADDR(pdte
), next
->hwpg_paddr
);
1799 * SNP field should be clear if not reserved.
1800 * non-leaf is always reserved
1802 if (next
== NULL
&& immu
->immu_SNP_reserved
== B_FALSE
) {
1803 if (PDTE_SNP(pdte
)) {
1804 ddi_err(DER_MODE
, rdip
, "SNP set");
1809 /* second field available for system software should be clear */
1810 if (PDTE_SW2(pdte
)) {
1811 ddi_err(DER_MODE
, rdip
, "SW2 set");
1815 /* Super pages field should be clear */
1816 if (PDTE_SP(pdte
)) {
1817 ddi_err(DER_MODE
, rdip
, "SP set");
1822 * least significant field available for
1823 * system software should be clear
1825 if (PDTE_SW1(pdte
)) {
1826 ddi_err(DER_MODE
, rdip
, "SW1 set");
1830 if ((immu_flags
& IMMU_FLAGS_READ
) && !PDTE_READ(pdte
)) {
1831 ddi_err(DER_MODE
, rdip
, "READ not set");
1835 if ((immu_flags
& IMMU_FLAGS_WRITE
) && !PDTE_WRITE(pdte
)) {
1836 ddi_err(DER_MODE
, rdip
, "WRITE not set");
1846 PTE_clear_all(immu_t
*immu
, domain_t
*domain
, xlate_t
*xlate
,
1847 uint64_t *dvma_ptr
, uint64_t *npages_ptr
, dev_info_t
*rdip
)
1856 pgtable
= xlate
->xlt_pgtable
;
1857 idx
= xlate
->xlt_idx
;
1860 npages
= *npages_ptr
;
1863 * since a caller gets a unique dvma for a physical address,
1864 * no other concurrent thread will be writing to the same
1865 * PTE even if it has the same paddr. So no locks needed.
1867 shwp
= (hw_pdte_t
*)(pgtable
->hwpg_vaddr
) + idx
;
1870 for (; npages
> 0 && idx
<= IMMU_PGTABLE_MAXIDX
; idx
++, hwp
++) {
1872 dvma
+= IMMU_PAGESIZE
;
1877 *npages_ptr
= npages
;
1879 xlate
->xlt_idx
= idx
;
1883 xlate_setup(uint64_t dvma
, xlate_t
*xlate
, int nlevels
)
1889 * Skip the first 12 bits which is the offset into
1890 * 4K PFN (phys page frame based on IMMU_PAGESIZE)
1892 offbits
= dvma
>> IMMU_PAGESHIFT
;
1894 /* skip to level 1 i.e. leaf PTE */
1895 for (level
= 1, xlate
++; level
<= nlevels
; level
++, xlate
++) {
1896 xlate
->xlt_level
= level
;
1897 xlate
->xlt_idx
= (offbits
& IMMU_PGTABLE_LEVEL_MASK
);
1898 ASSERT(xlate
->xlt_idx
<= IMMU_PGTABLE_MAXIDX
);
1899 xlate
->xlt_pgtable
= NULL
;
1900 offbits
>>= IMMU_PGTABLE_LEVEL_STRIDE
;
1908 PDE_lookup(domain_t
*domain
, xlate_t
*xlate
, int nlevels
)
1914 /* start with highest level pgtable i.e. root */
1917 if (xlate
->xlt_pgtable
== NULL
) {
1918 xlate
->xlt_pgtable
= domain
->dom_pgtable_root
;
1921 for (; xlate
->xlt_level
> 1; xlate
--) {
1922 idx
= xlate
->xlt_idx
;
1923 pgtable
= xlate
->xlt_pgtable
;
1925 if ((xlate
- 1)->xlt_pgtable
) {
1929 /* Lock the pgtable in read mode */
1930 rw_enter(&(pgtable
->swpg_rwlock
), RW_READER
);
1933 * since we are unmapping, the pgtable should
1934 * already point to a leafier pgtable.
1936 next
= *(pgtable
->swpg_next_array
+ idx
);
1937 (xlate
- 1)->xlt_pgtable
= next
;
1938 rw_exit(&(pgtable
->swpg_rwlock
));
1947 immu_fault_walk(void *arg
, void *base
, size_t len
)
1949 uint64_t dvma
, start
;
1951 dvma
= *(uint64_t *)arg
;
1952 start
= (uint64_t)(uintptr_t)base
;
1954 if (dvma
>= start
&& dvma
< (start
+ len
)) {
1955 ddi_err(DER_WARN
, NULL
,
1956 "faulting DVMA address is in vmem arena "
1957 "(%" PRIx64
"-%" PRIx64
")",
1958 start
, start
+ len
);
1959 *(uint64_t *)arg
= ~0ULL;
1964 immu_print_fault_info(uint_t sid
, uint64_t dvma
)
1967 xlate_t xlate
[IMMU_PGTABLE_MAX_LEVELS
+ 1] = {0};
1974 if (mod_hash_find(bdf_domain_hash
,
1975 (void *)(uintptr_t)sid
, (void *)&domain
) != 0) {
1976 ddi_err(DER_WARN
, NULL
,
1977 "no domain for faulting SID %08x", sid
);
1981 immu
= domain
->dom_immu
;
1984 vmem_walk(domain
->dom_dvma_arena
, VMEM_ALLOC
, immu_fault_walk
,
1986 if (dvma_arg
!= ~0ULL)
1987 ddi_err(DER_WARN
, domain
->dom_dip
,
1988 "faulting DVMA address is not in vmem arena");
1990 nlevels
= immu
->immu_dvma_nlevels
;
1991 xlate_setup(dvma
, xlate
, nlevels
);
1993 if (!PDE_lookup(domain
, xlate
, nlevels
)) {
1994 ddi_err(DER_WARN
, domain
->dom_dip
,
1995 "pte not found in domid %d for faulting addr %" PRIx64
,
1996 domain
->dom_did
, dvma
);
2001 pte
= *((hw_pdte_t
*)
2002 (xlatep
->xlt_pgtable
->hwpg_vaddr
) + xlatep
->xlt_idx
);
2004 ddi_err(DER_WARN
, domain
->dom_dip
,
2005 "domid %d pte: %" PRIx64
"(paddr %" PRIx64
")", domain
->dom_did
,
2006 (unsigned long long)pte
, (unsigned long long)PDTE_PADDR(pte
));
2011 PTE_set_one(immu_t
*immu
, hw_pdte_t
*hwp
, paddr_t paddr
,
2012 dev_info_t
*rdip
, immu_flags_t immu_flags
)
2017 pte
= immu
->immu_ptemask
;
2018 PDTE_SET_PADDR(pte
, paddr
);
2023 if (PDTE_PADDR(pte
) != paddr
) {
2024 ddi_err(DER_MODE
, rdip
, "PTE paddr %lx != paddr %lx",
2025 PDTE_PADDR(pte
), paddr
);
2027 #ifdef BUGGY_DRIVERS
2034 /* clear TM field if not reserved */
2035 if (immu
->immu_TM_reserved
== B_FALSE
) {
2039 /* Clear 3rd field for system software - not used */
2040 PDTE_CLEAR_SW3(pte
);
2043 ASSERT(paddr
% IMMU_PAGESIZE
== 0);
2044 PDTE_CLEAR_PADDR(pte
);
2045 PDTE_SET_PADDR(pte
, paddr
);
2047 /* clear SNP field if not reserved. */
2048 if (immu
->immu_SNP_reserved
== B_FALSE
) {
2049 PDTE_CLEAR_SNP(pte
);
2052 /* Clear SW2 field available for software */
2053 PDTE_CLEAR_SW2(pte
);
2056 /* SP is don't care for PTEs. Clear it for cleanliness */
2059 /* Clear SW1 field available for software */
2060 PDTE_CLEAR_SW1(pte
);
2063 * Now that we are done writing the PTE
2064 * set the "present" flag. Note this present
2065 * flag is a bit in the PDE/PTE that the
2066 * spec says is available for system software.
2067 * This is an implementation detail of Solaris
2068 * bare-metal Intel IOMMU.
2069 * The present field in a PDE/PTE is not defined
2075 pte
|= immu
->immu_ptemask
;
2079 #ifdef BUGGY_DRIVERS
2081 PDTE_SET_WRITE(pte
);
2083 if (immu_flags
& IMMU_FLAGS_READ
)
2085 if (immu_flags
& IMMU_FLAGS_WRITE
)
2086 PDTE_SET_WRITE(pte
);
2087 #endif /* BUGGY_DRIVERS */
2094 PTE_set_all(immu_t
*immu
, domain_t
*domain
, xlate_t
*xlate
,
2095 uint64_t *dvma_ptr
, uint64_t *nvpages_ptr
, immu_dcookie_t
*dcookies
,
2096 int dcount
, dev_info_t
*rdip
, immu_flags_t immu_flags
)
2108 pgtable
= xlate
->xlt_pgtable
;
2109 idx
= xlate
->xlt_idx
;
2112 nvpages
= *nvpages_ptr
;
2115 * since a caller gets a unique dvma for a physical address,
2116 * no other concurrent thread will be writing to the same
2117 * PTE even if it has the same paddr. So no locks needed.
2119 shwp
= (hw_pdte_t
*)(pgtable
->hwpg_vaddr
) + idx
;
2122 for (j
= dcount
- 1; j
>= 0; j
--) {
2123 if (nvpages
<= dcookies
[j
].dck_npages
)
2125 nvpages
-= dcookies
[j
].dck_npages
;
2129 paddr
= dcookies
[j
].dck_paddr
+
2130 (dcookies
[j
].dck_npages
- nppages
) * IMMU_PAGESIZE
;
2132 nvpages
= *nvpages_ptr
;
2134 for (; nvpages
> 0 && idx
<= IMMU_PGTABLE_MAXIDX
; idx
++, hwp
++) {
2135 PTE_set_one(immu
, hwp
, paddr
, rdip
, immu_flags
);
2138 ASSERT(PDTE_check(immu
, *hwp
, NULL
, paddr
, rdip
, immu_flags
)
2142 paddr
+= IMMU_PAGESIZE
;
2143 dvma
+= IMMU_PAGESIZE
;
2153 nppages
= dcookies
[j
].dck_npages
;
2154 paddr
= dcookies
[j
].dck_paddr
;
2160 *nvpages_ptr
= nvpages
;
2166 xlate
->xlt_idx
= idx
;
2171 PDE_set_one(immu_t
*immu
, hw_pdte_t
*hwp
, pgtable_t
*next
,
2172 dev_info_t
*rdip
, immu_flags_t immu_flags
)
2178 /* if PDE is already set, make sure it is correct */
2180 ASSERT(PDTE_PADDR(pde
) == next
->hwpg_paddr
);
2181 #ifdef BUGGY_DRIVERS
2188 /* Dont touch SW4, it is the present bit */
2190 /* don't touch TM field it is reserved for PDEs */
2192 /* 3rd field available for system software is not used */
2193 PDTE_CLEAR_SW3(pde
);
2195 /* Set next level pgtable-paddr for PDE */
2196 PDTE_CLEAR_PADDR(pde
);
2197 PDTE_SET_PADDR(pde
, next
->hwpg_paddr
);
2199 /* don't touch SNP field it is reserved for PDEs */
2201 /* Clear second field available for system software */
2202 PDTE_CLEAR_SW2(pde
);
2204 /* No super pages for PDEs */
2207 /* Clear SW1 for software */
2208 PDTE_CLEAR_SW1(pde
);
2211 * Now that we are done writing the PDE
2212 * set the "present" flag. Note this present
2213 * flag is a bit in the PDE/PTE that the
2214 * spec says is available for system software.
2215 * This is an implementation detail of Solaris
2216 * base-metal Intel IOMMU.
2217 * The present field in a PDE/PTE is not defined
2222 #ifdef BUGGY_DRIVERS
2224 PDTE_SET_WRITE(pde
);
2226 if (immu_flags
& IMMU_FLAGS_READ
)
2228 if (immu_flags
& IMMU_FLAGS_WRITE
)
2229 PDTE_SET_WRITE(pde
);
2241 PDE_set_all(immu_t
*immu
, domain_t
*domain
, xlate_t
*xlate
, int nlevels
,
2242 dev_info_t
*rdip
, immu_flags_t immu_flags
)
2251 boolean_t set
= B_FALSE
;
2253 /* start with highest level pgtable i.e. root */
2257 xlate
->xlt_pgtable
= domain
->dom_pgtable_root
;
2258 for (level
= nlevels
; level
> 1; level
--, xlate
--) {
2259 idx
= xlate
->xlt_idx
;
2260 pgtable
= xlate
->xlt_pgtable
;
2262 /* Lock the pgtable in READ mode first */
2263 rw_enter(&(pgtable
->swpg_rwlock
), RW_READER
);
2266 hwp
= (hw_pdte_t
*)(pgtable
->hwpg_vaddr
) + idx
;
2267 next
= (pgtable
->swpg_next_array
)[idx
];
2270 * check if leafier level already has a pgtable
2276 IMMU_DPROBE2(immu__pdp__alloc
, dev_info_t
*,
2279 new = pgtable_alloc(immu
, immu_flags
);
2281 ddi_err(DER_PANIC
, rdip
,
2282 "pgtable alloc err");
2287 /* Change to a write lock */
2288 if (rwtype
== RW_READER
&&
2289 rw_tryupgrade(&(pgtable
->swpg_rwlock
)) == 0) {
2290 rw_exit(&(pgtable
->swpg_rwlock
));
2291 rw_enter(&(pgtable
->swpg_rwlock
), RW_WRITER
);
2297 (pgtable
->swpg_next_array
)[idx
] = next
;
2299 PDE_set_one(immu
, hwp
, next
, rdip
, immu_flags
);
2301 rw_downgrade(&(pgtable
->swpg_rwlock
));
2304 #ifndef BUGGY_DRIVERS
2306 hw_pdte_t pde
= *hwp
;
2309 * If buggy driver we already set permission
2310 * READ+WRITE so nothing to do for that case
2311 * XXX Check that read writer perms change before
2312 * actually setting perms. Also need to hold lock
2314 if (immu_flags
& IMMU_FLAGS_READ
)
2316 if (immu_flags
& IMMU_FLAGS_WRITE
)
2317 PDTE_SET_WRITE(pde
);
2323 ASSERT(PDTE_check(immu
, *hwp
, next
, 0, rdip
, immu_flags
)
2326 (xlate
- 1)->xlt_pgtable
= next
;
2327 rw_exit(&(pgtable
->swpg_rwlock
));
2331 pgtable_free(immu
, new);
2339 * map a contiguous range of DVMA pages
2341 * immu: IOMMU unit for which we are generating DVMA cookies
2343 * sdvma: Starting dvma
2344 * spaddr: Starting paddr
2345 * npages: Number of pages
2346 * rdip: requesting device
2350 dvma_map(domain_t
*domain
, uint64_t sdvma
, uint64_t snvpages
,
2351 immu_dcookie_t
*dcookies
, int dcount
, dev_info_t
*rdip
,
2352 immu_flags_t immu_flags
)
2356 immu_t
*immu
= domain
->dom_immu
;
2357 int nlevels
= immu
->immu_dvma_nlevels
;
2358 xlate_t xlate
[IMMU_PGTABLE_MAX_LEVELS
+ 1] = {0};
2359 boolean_t pde_set
= B_FALSE
;
2365 xlate_setup(dvma
, xlate
, nlevels
);
2367 /* Lookup or allocate PGDIRs and PGTABLEs if necessary */
2368 if (PDE_set_all(immu
, domain
, xlate
, nlevels
, rdip
, immu_flags
)
2373 /* set all matching ptes that fit into this leaf pgtable */
2374 PTE_set_all(immu
, domain
, &xlate
[1], &dvma
, &n
, dcookies
,
2375 dcount
, rdip
, immu_flags
);
2383 * unmap a range of DVMAs
2385 * immu: IOMMU unit state
2386 * domain: domain for requesting device
2388 * dvma: starting DVMA
2389 * npages: Number of IMMU pages to be unmapped
2390 * rdip: requesting device
2393 dvma_unmap(domain_t
*domain
, uint64_t sdvma
, uint64_t snpages
,
2396 immu_t
*immu
= domain
->dom_immu
;
2397 int nlevels
= immu
->immu_dvma_nlevels
;
2398 xlate_t xlate
[IMMU_PGTABLE_MAX_LEVELS
+ 1] = {0};
2406 /* setup the xlate array */
2407 xlate_setup(dvma
, xlate
, nlevels
);
2409 /* just lookup existing pgtables. Should never fail */
2410 if (!PDE_lookup(domain
, xlate
, nlevels
))
2411 ddi_err(DER_PANIC
, rdip
,
2412 "PTE not found for addr %" PRIx64
,
2413 (unsigned long long)dvma
);
2415 /* clear all matching ptes that fit into this leaf pgtable */
2416 PTE_clear_all(immu
, domain
, &xlate
[1], &dvma
, &n
, rdip
);
2419 /* No need to flush IOTLB after unmap */
2423 dvma_alloc(domain_t
*domain
, ddi_dma_attr_t
*dma_attr
, uint_t npages
, int kmf
)
2426 size_t xsize
, align
;
2427 uint64_t minaddr
, maxaddr
;
2430 xsize
= npages
* IMMU_PAGESIZE
;
2431 align
= MAX((size_t)(dma_attr
->dma_attr_align
), IMMU_PAGESIZE
);
2432 minaddr
= dma_attr
->dma_attr_addr_lo
;
2433 maxaddr
= dma_attr
->dma_attr_addr_hi
+ 1;
2435 /* handle the rollover cases */
2436 if (maxaddr
< dma_attr
->dma_attr_addr_hi
) {
2437 maxaddr
= dma_attr
->dma_attr_addr_hi
;
2441 * allocate from vmem arena.
2443 dvma
= (uint64_t)(uintptr_t)vmem_xalloc(domain
->dom_dvma_arena
,
2444 xsize
, align
, 0, 0, (void *)(uintptr_t)minaddr
,
2445 (void *)(uintptr_t)maxaddr
, kmf
);
2451 dvma_prealloc(dev_info_t
*rdip
, immu_hdl_priv_t
*ihp
, ddi_dma_attr_t
*dma_attr
)
2454 xlate_t xlate
[IMMU_PGTABLE_MAX_LEVELS
+ 1] = {0}, *xlp
;
2456 size_t xsize
, align
;
2457 uint64_t minaddr
, maxaddr
, dmamax
;
2458 int on
, npte
, pindex
;
2464 domain
= IMMU_DEVI(rdip
)->imd_domain
;
2465 immu
= domain
->dom_immu
;
2466 nlevels
= immu
->immu_dvma_nlevels
;
2467 xsize
= IMMU_NPREPTES
* IMMU_PAGESIZE
;
2468 align
= MAX((size_t)(dma_attr
->dma_attr_align
), IMMU_PAGESIZE
);
2469 minaddr
= dma_attr
->dma_attr_addr_lo
;
2470 if (dma_attr
->dma_attr_flags
& _DDI_DMA_BOUNCE_ON_SEG
)
2471 dmamax
= dma_attr
->dma_attr_seg
;
2473 dmamax
= dma_attr
->dma_attr_addr_hi
;
2474 maxaddr
= dmamax
+ 1;
2476 if (maxaddr
< dmamax
)
2479 dvma
= (uint64_t)(uintptr_t)vmem_xalloc(domain
->dom_dvma_arena
,
2480 xsize
, align
, 0, dma_attr
->dma_attr_seg
+ 1,
2481 (void *)(uintptr_t)minaddr
, (void *)(uintptr_t)maxaddr
, VM_NOSLEEP
);
2483 ihp
->ihp_predvma
= dvma
;
2484 ihp
->ihp_npremapped
= 0;
2492 * Set up a mapping at address 0, just so that all PDPs get allocated
2493 * now. Although this initial mapping should never be used,
2494 * explicitly set it to read-only, just to be safe.
2497 xlate_setup(dvma
, xlate
, nlevels
);
2499 (void) PDE_set_all(immu
, domain
, xlate
, nlevels
, rdip
,
2500 IMMU_FLAGS_READ
| IMMU_FLAGS_WRITE
);
2503 shwp
= (hw_pdte_t
*)(xlp
->xlt_pgtable
->hwpg_vaddr
)
2507 PTE_set_all(immu
, domain
, xlp
, &dvma
, &n
, &immu_precookie
,
2508 1, rdip
, IMMU_FLAGS_READ
);
2513 ihp
->ihp_preptes
[pindex
++] = shwp
;
2514 #ifdef BUGGY_DRIVERS
2515 PDTE_CLEAR_WRITE(*shwp
);
2524 dvma_prefree(dev_info_t
*rdip
, immu_hdl_priv_t
*ihp
)
2528 domain
= IMMU_DEVI(rdip
)->imd_domain
;
2530 if (ihp
->ihp_predvma
!= 0) {
2531 dvma_unmap(domain
, ihp
->ihp_predvma
, IMMU_NPREPTES
, rdip
);
2532 vmem_free(domain
->dom_dvma_arena
,
2533 (void *)(uintptr_t)ihp
->ihp_predvma
,
2534 IMMU_NPREPTES
* IMMU_PAGESIZE
);
2539 dvma_free(domain_t
*domain
, uint64_t dvma
, uint64_t npages
)
2541 uint64_t size
= npages
* IMMU_PAGESIZE
;
2543 if (domain
->dom_maptype
!= IMMU_MAPTYPE_XLATE
)
2546 vmem_free(domain
->dom_dvma_arena
, (void *)(uintptr_t)dvma
, size
);
2550 immu_map_dvmaseg(dev_info_t
*rdip
, ddi_dma_handle_t handle
,
2551 immu_hdl_priv_t
*ihp
, struct ddi_dma_req
*dmareq
,
2552 ddi_dma_obj_t
*dma_out
)
2556 immu_flags_t immu_flags
;
2557 ddi_dma_atyp_t buftype
;
2558 ddi_dma_obj_t
*dmar_object
;
2559 ddi_dma_attr_t
*attrp
;
2560 uint64_t offset
, paddr
, dvma
, sdvma
, rwmask
;
2561 size_t npages
, npgalloc
;
2562 uint_t psize
, size
, pcnt
, dmax
;
2567 immu_dcookie_t
*dcookies
;
2570 domain
= IMMU_DEVI(rdip
)->imd_domain
;
2571 immu
= domain
->dom_immu
;
2572 immu_flags
= dma_to_immu_flags(dmareq
);
2574 attrp
= &((ddi_dma_impl_t
*)handle
)->dmai_attr
;
2576 dmar_object
= &dmareq
->dmar_object
;
2577 pparray
= dmar_object
->dmao_obj
.virt_obj
.v_priv
;
2578 vaddr
= dmar_object
->dmao_obj
.virt_obj
.v_addr
;
2579 buftype
= dmar_object
->dmao_type
;
2580 size
= dmar_object
->dmao_size
;
2582 IMMU_DPROBE3(immu__map__dvma
, dev_info_t
*, rdip
, ddi_dma_atyp_t
,
2583 buftype
, uint_t
, size
);
2585 dcookies
= &ihp
->ihp_dcookies
[0];
2589 /* retrieve paddr, psize, offset from dmareq */
2590 if (buftype
== DMA_OTYP_PAGES
) {
2591 page
= dmar_object
->dmao_obj
.pp_obj
.pp_pp
;
2592 offset
= dmar_object
->dmao_obj
.pp_obj
.pp_offset
&
2594 paddr
= pfn_to_pa(page
->p_pagenum
) + offset
;
2595 psize
= MIN((MMU_PAGESIZE
- offset
), size
);
2596 page
= page
->p_next
;
2597 vas
= dmar_object
->dmao_obj
.virt_obj
.v_as
;
2602 offset
= (uintptr_t)vaddr
& MMU_PAGEOFFSET
;
2603 if (pparray
!= NULL
) {
2604 paddr
= pfn_to_pa(pparray
[pcnt
]->p_pagenum
) + offset
;
2605 psize
= MIN((MMU_PAGESIZE
- offset
), size
);
2608 paddr
= pfn_to_pa(hat_getpfnum(vas
->a_hat
,
2610 psize
= MIN(size
, (MMU_PAGESIZE
- offset
));
2615 npgalloc
= IMMU_BTOPR(size
+ offset
);
2617 if (npgalloc
<= IMMU_NPREPTES
&& ihp
->ihp_predvma
!= 0) {
2618 #ifdef BUGGY_DRIVERS
2619 rwmask
= PDTE_MASK_R
| PDTE_MASK_W
| immu
->immu_ptemask
;
2621 rwmask
= immu
->immu_ptemask
;
2622 if (immu_flags
& IMMU_FLAGS_READ
)
2623 rwmask
|= PDTE_MASK_R
;
2624 if (immu_flags
& IMMU_FLAGS_WRITE
)
2625 rwmask
|= PDTE_MASK_W
;
2628 rwmask
|= PDTE_MASK_P
;
2630 sdvma
= ihp
->ihp_predvma
;
2631 ihp
->ihp_npremapped
= npgalloc
;
2632 *ihp
->ihp_preptes
[0] =
2633 PDTE_PADDR(paddr
& ~MMU_PAGEOFFSET
) | rwmask
;
2635 ihp
->ihp_npremapped
= 0;
2636 sdvma
= dvma_alloc(domain
, attrp
, npgalloc
,
2637 dmareq
->dmar_fp
== DDI_DMA_SLEEP
? VM_SLEEP
: VM_NOSLEEP
);
2639 return (DDI_DMA_NORESOURCES
);
2641 dcookies
[0].dck_paddr
= (paddr
& ~MMU_PAGEOFFSET
);
2642 dcookies
[0].dck_npages
= 1;
2645 IMMU_DPROBE3(immu__dvma__alloc
, dev_info_t
*, rdip
, uint64_t, npgalloc
,
2653 /* get the size for this page (i.e. partial or full page) */
2654 psize
= MIN(size
, MMU_PAGESIZE
);
2655 if (buftype
== DMA_OTYP_PAGES
) {
2656 /* get the paddr from the page_t */
2657 paddr
= pfn_to_pa(page
->p_pagenum
);
2658 page
= page
->p_next
;
2659 } else if (pparray
!= NULL
) {
2660 /* index into the array of page_t's to get the paddr */
2661 paddr
= pfn_to_pa(pparray
[pcnt
]->p_pagenum
);
2664 /* call into the VM to get the paddr */
2665 paddr
= pfn_to_pa(hat_getpfnum(vas
->a_hat
, vaddr
));
2671 if (ihp
->ihp_npremapped
> 0) {
2672 *ihp
->ihp_preptes
[npages
- 1] =
2673 PDTE_PADDR(paddr
) | rwmask
;
2674 } else if (IMMU_CONTIG_PADDR(dcookies
[dmax
], paddr
)) {
2675 dcookies
[dmax
].dck_npages
++;
2677 /* No, we need a new dcookie */
2678 if (dmax
== (IMMU_NDCK
- 1)) {
2680 * Ran out of dcookies. Map them now.
2682 if (dvma_map(domain
, dvma
,
2683 npages
, dcookies
, dmax
+ 1, rdip
,
2687 IMMU_DPROBE4(immu__dvmamap__early
,
2688 dev_info_t
*, rdip
, uint64_t, dvma
,
2689 uint_t
, npages
, uint_t
, dmax
+1);
2691 dvma
+= (npages
<< IMMU_PAGESHIFT
);
2696 dcookies
[dmax
].dck_paddr
= paddr
;
2697 dcookies
[dmax
].dck_npages
= 1;
2703 * Finish up, mapping all, or all of the remaining,
2704 * physical memory ranges.
2706 if (ihp
->ihp_npremapped
== 0 && npages
> 0) {
2707 IMMU_DPROBE4(immu__dvmamap__late
, dev_info_t
*, rdip
, \
2708 uint64_t, dvma
, uint_t
, npages
, uint_t
, dmax
+1);
2710 if (dvma_map(domain
, dvma
, npages
, dcookies
,
2711 dmax
+ 1, rdip
, immu_flags
))
2715 /* Invalidate the IOTLB */
2716 immu_flush_iotlb_psi(immu
, domain
->dom_did
, sdvma
, npgalloc
,
2717 pde_set
> 0 ? TLB_IVA_WHOLE
: TLB_IVA_LEAF
,
2718 &ihp
->ihp_inv_wait
);
2720 ihp
->ihp_ndvseg
= 1;
2721 ihp
->ihp_dvseg
[0].dvs_start
= sdvma
;
2722 ihp
->ihp_dvseg
[0].dvs_len
= dmar_object
->dmao_size
;
2724 dma_out
->dmao_size
= dmar_object
->dmao_size
;
2725 dma_out
->dmao_obj
.dvma_obj
.dv_off
= offset
& IMMU_PAGEOFFSET
;
2726 dma_out
->dmao_obj
.dvma_obj
.dv_nseg
= 1;
2727 dma_out
->dmao_obj
.dvma_obj
.dv_seg
= &ihp
->ihp_dvseg
[0];
2728 dma_out
->dmao_type
= DMA_OTYP_DVADDR
;
2730 return (DDI_DMA_MAPPED
);
2734 immu_unmap_dvmaseg(dev_info_t
*rdip
, ddi_dma_obj_t
*dmao
)
2736 uint64_t dvma
, npages
;
2738 struct dvmaseg
*dvs
;
2740 domain
= IMMU_DEVI(rdip
)->imd_domain
;
2741 dvs
= dmao
->dmao_obj
.dvma_obj
.dv_seg
;
2743 dvma
= dvs
[0].dvs_start
;
2744 npages
= IMMU_BTOPR(dvs
[0].dvs_len
+ dmao
->dmao_obj
.dvma_obj
.dv_off
);
2747 /* Unmap only in DEBUG mode */
2748 dvma_unmap(domain
, dvma
, npages
, rdip
);
2750 dvma_free(domain
, dvma
, npages
);
2752 IMMU_DPROBE3(immu__dvma__free
, dev_info_t
*, rdip
, uint_t
, npages
,
2757 * In the DEBUG case, the unmap was actually done,
2758 * but an IOTLB flush was not done. So, an explicit
2759 * write back flush is needed.
2761 immu_regs_wbf_flush(domain
->dom_immu
);
2764 return (DDI_SUCCESS
);
2767 /* ############################# Functions exported ######################## */
2770 * setup the DVMA subsystem
2771 * this code runs only for the first IOMMU unit
2774 immu_dvma_setup(list_t
*listp
)
2781 mutex_init(&immu_domain_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
2784 list_create(&immu_unity_domain_list
, sizeof (domain_t
),
2785 offsetof(domain_t
, dom_maptype_node
));
2786 list_create(&immu_xlate_domain_list
, sizeof (domain_t
),
2787 offsetof(domain_t
, dom_maptype_node
));
2789 /* Setup BDF domain hash */
2791 kval
= mod_hash_iddata_gen(nchains
);
2793 bdf_domain_hash
= mod_hash_create_extended("BDF-DOMAIN_HASH",
2794 nchains
, mod_hash_null_keydtor
, mod_hash_null_valdtor
,
2795 mod_hash_byid
, (void *)(uintptr_t)kval
, mod_hash_idkey_cmp
,
2798 immu
= list_head(listp
);
2799 for (; immu
; immu
= list_next(listp
, immu
)) {
2800 create_unity_domain(immu
);
2803 immu
->immu_dvma_setup
= B_TRUE
;
2808 * Startup up one DVMA unit
2811 immu_dvma_startup(immu_t
*immu
)
2813 if (immu_gfxdvma_enable
== B_FALSE
&&
2814 immu
->immu_dvma_gfx_only
== B_TRUE
) {
2819 * DVMA will start once IOMMU is "running"
2821 immu
->immu_dvma_running
= B_TRUE
;
2825 * immu_dvma_physmem_update()
2826 * called when the installed memory on a
2827 * system increases, to expand domain DVMA
2828 * for domains with UNITY mapping
2831 immu_dvma_physmem_update(uint64_t addr
, uint64_t size
)
2836 immu_dcookie_t dcookies
[1] = {0};
2840 * Just walk the system-wide list of domains with
2841 * UNITY mapping. Both the list of *all* domains
2842 * and *UNITY* domains is protected by the same
2845 mutex_enter(&immu_domain_lock
);
2846 domain
= list_head(&immu_unity_domain_list
);
2847 for (; domain
; domain
= list_next(&immu_unity_domain_list
, domain
)) {
2849 * Nothing to do if the IOMMU supports passthrough.
2851 if (IMMU_ECAP_GET_PT(domain
->dom_immu
->immu_regs_excap
))
2854 /* There is no vmem_arena for unity domains. Just map it */
2855 ddi_err(DER_LOG
, domain
->dom_dip
,
2856 "iommu: unity-domain: Adding map "
2857 "[0x%" PRIx64
" - 0x%" PRIx64
"]", addr
, addr
+ size
);
2859 start
= IMMU_ROUNDOWN(addr
);
2860 npages
= (IMMU_ROUNDUP(size
) / IMMU_PAGESIZE
) + 1;
2862 dcookies
[0].dck_paddr
= start
;
2863 dcookies
[0].dck_npages
= npages
;
2865 (void) dvma_map(domain
, start
, npages
,
2866 dcookies
, dcount
, NULL
, IMMU_FLAGS_READ
| IMMU_FLAGS_WRITE
);
2869 mutex_exit(&immu_domain_lock
);
2873 immu_dvma_device_setup(dev_info_t
*rdip
, immu_flags_t immu_flags
)
2875 dev_info_t
*ddip
, *odip
;
2881 immu
= immu_dvma_get_immu(rdip
, immu_flags
);
2884 * possible that there is no IOMMU unit for this device
2885 * - BIOS bugs are one example.
2887 ddi_err(DER_WARN
, rdip
, "No iommu unit found for device");
2888 return (DDI_DMA_NORESOURCES
);
2892 * redirect isa devices attached under lpc to lpc dip
2894 if (strcmp(ddi_node_name(ddi_get_parent(rdip
)), "isa") == 0) {
2895 rdip
= get_lpc_devinfo(immu
, rdip
, immu_flags
);
2897 ddi_err(DER_PANIC
, rdip
, "iommu redirect failed");
2902 /* Reset immu, as redirection can change IMMU */
2906 * for gart, redirect to the real graphic devinfo
2908 if (strcmp(ddi_node_name(rdip
), "agpgart") == 0) {
2909 rdip
= get_gfx_devinfo(rdip
);
2911 ddi_err(DER_PANIC
, rdip
, "iommu redirect failed");
2917 * Setup DVMA domain for the device. This does
2918 * work only the first time we do DVMA for a
2922 domain
= device_domain(rdip
, &ddip
, immu_flags
);
2923 if (domain
== NULL
) {
2924 ddi_err(DER_MODE
, rdip
, "Intel IOMMU setup failed for device");
2925 return (DDI_DMA_NORESOURCES
);
2928 immu
= domain
->dom_immu
;
2931 * If a domain is found, we must also have a domain dip
2932 * which is the topmost ancestor dip of rdip that shares
2933 * the same domain with rdip.
2935 if (domain
->dom_did
== 0 || ddip
== NULL
) {
2936 ddi_err(DER_MODE
, rdip
, "domain did 0(%d) or ddip NULL(%p)",
2937 domain
->dom_did
, ddip
);
2938 return (DDI_DMA_NORESOURCES
);
2942 set_domain(odip
, ddip
, domain
);
2945 * Update the root and context entries
2947 if (immu_context_update(immu
, domain
, ddip
, rdip
, immu_flags
)
2949 ddi_err(DER_MODE
, rdip
, "DVMA map: context update failed");
2950 return (DDI_DMA_NORESOURCES
);
2953 return (DDI_SUCCESS
);
2957 immu_map_memrange(dev_info_t
*rdip
, memrng_t
*mrng
)
2959 immu_dcookie_t dcookies
[1] = {0};
2965 dcookies
[0].dck_paddr
= mrng
->mrng_start
;
2966 dcookies
[0].dck_npages
= mrng
->mrng_npages
;
2968 domain
= IMMU_DEVI(rdip
)->imd_domain
;
2969 immu
= domain
->dom_immu
;
2971 pde_set
= dvma_map(domain
, mrng
->mrng_start
,
2972 mrng
->mrng_npages
, dcookies
, 1, rdip
,
2973 IMMU_FLAGS_READ
| IMMU_FLAGS_WRITE
);
2975 immu_init_inv_wait(&iw
, "memrange", B_TRUE
);
2977 immu_flush_iotlb_psi(immu
, domain
->dom_did
, mrng
->mrng_start
,
2978 mrng
->mrng_npages
, pde_set
== B_TRUE
?
2979 TLB_IVA_WHOLE
: TLB_IVA_LEAF
, &iw
);
2981 return (DDI_SUCCESS
);
2985 immu_devi_get(dev_info_t
*rdip
)
2987 immu_devi_t
*immu_devi
;
2988 volatile uintptr_t *vptr
= (uintptr_t *)&(DEVI(rdip
)->devi_iommu
);
2990 /* Just want atomic reads. No need for lock */
2991 immu_devi
= (immu_devi_t
*)(uintptr_t)atomic_or_64_nv((uint64_t *)vptr
,
2998 immu_hdl_priv_ctor(void *buf
, void *arg
, int kmf
)
3000 immu_hdl_priv_t
*ihp
;
3003 immu_init_inv_wait(&ihp
->ihp_inv_wait
, "dmahandle", B_FALSE
);
3009 * iommulib interface functions
3012 immu_probe(iommulib_handle_t handle
, dev_info_t
*dip
)
3014 immu_devi_t
*immu_devi
;
3018 return (DDI_FAILURE
);
3021 * Make sure the device has all the IOMMU structures
3022 * initialized. If this device goes through an IOMMU
3023 * unit (e.g. this probe function returns success),
3024 * this will be called at most N times, with N being
3025 * the number of IOMMUs in the system.
3027 * After that, when iommulib_nex_open succeeds,
3028 * we can always assume that this device has all
3029 * the structures initialized. IOMMU_USED(dip) will
3030 * be true. There is no need to find the controlling
3031 * IOMMU/domain again.
3033 ret
= immu_dvma_device_setup(dip
, IMMU_FLAGS_NOSLEEP
);
3034 if (ret
!= DDI_SUCCESS
)
3037 immu_devi
= IMMU_DEVI(dip
);
3040 * For unity domains, there is no need to call in to
3043 if (immu_devi
->imd_domain
->dom_did
== IMMU_UNITY_DID
)
3044 return (DDI_FAILURE
);
3046 if (immu_devi
->imd_immu
->immu_dip
== iommulib_iommu_getdip(handle
))
3047 return (DDI_SUCCESS
);
3049 return (DDI_FAILURE
);
3054 immu_allochdl(iommulib_handle_t handle
,
3055 dev_info_t
*dip
, dev_info_t
*rdip
, ddi_dma_attr_t
*attr
,
3056 int (*waitfp
)(caddr_t
), caddr_t arg
, ddi_dma_handle_t
*dma_handlep
)
3059 immu_hdl_priv_t
*ihp
;
3062 ret
= iommulib_iommu_dma_allochdl(dip
, rdip
, attr
, waitfp
,
3064 if (ret
== DDI_SUCCESS
) {
3065 immu
= IMMU_DEVI(rdip
)->imd_immu
;
3067 ihp
= kmem_cache_alloc(immu
->immu_hdl_cache
,
3068 waitfp
== DDI_DMA_SLEEP
? KM_SLEEP
: KM_NOSLEEP
);
3070 (void) iommulib_iommu_dma_freehdl(dip
, rdip
,
3072 return (DDI_DMA_NORESOURCES
);
3075 if (IMMU_DEVI(rdip
)->imd_use_premap
)
3076 dvma_prealloc(rdip
, ihp
, attr
);
3078 ihp
->ihp_npremapped
= 0;
3079 ihp
->ihp_predvma
= 0;
3081 ret
= iommulib_iommu_dmahdl_setprivate(dip
, rdip
, *dma_handlep
,
3089 immu_freehdl(iommulib_handle_t handle
,
3090 dev_info_t
*dip
, dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
)
3092 immu_hdl_priv_t
*ihp
;
3094 ihp
= iommulib_iommu_dmahdl_getprivate(dip
, rdip
, dma_handle
);
3096 if (IMMU_DEVI(rdip
)->imd_use_premap
)
3097 dvma_prefree(rdip
, ihp
);
3098 kmem_cache_free(IMMU_DEVI(rdip
)->imd_immu
->immu_hdl_cache
, ihp
);
3101 return (iommulib_iommu_dma_freehdl(dip
, rdip
, dma_handle
));
3107 immu_bindhdl(iommulib_handle_t handle
, dev_info_t
*dip
,
3108 dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
,
3109 struct ddi_dma_req
*dma_req
, ddi_dma_cookie_t
*cookiep
,
3113 immu_hdl_priv_t
*ihp
;
3115 ret
= iommulib_iommu_dma_bindhdl(dip
, rdip
, dma_handle
,
3116 dma_req
, cookiep
, ccountp
);
3118 if (ret
== DDI_DMA_MAPPED
) {
3119 ihp
= iommulib_iommu_dmahdl_getprivate(dip
, rdip
, dma_handle
);
3120 immu_flush_wait(IMMU_DEVI(rdip
)->imd_immu
, &ihp
->ihp_inv_wait
);
3128 immu_unbindhdl(iommulib_handle_t handle
,
3129 dev_info_t
*dip
, dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
)
3131 return (iommulib_iommu_dma_unbindhdl(dip
, rdip
, dma_handle
));
3136 immu_sync(iommulib_handle_t handle
, dev_info_t
*dip
,
3137 dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
, off_t off
,
3138 size_t len
, uint_t cachefl
)
3140 return (iommulib_iommu_dma_sync(dip
, rdip
, dma_handle
, off
, len
,
3146 immu_win(iommulib_handle_t handle
, dev_info_t
*dip
,
3147 dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
, uint_t win
,
3148 off_t
*offp
, size_t *lenp
, ddi_dma_cookie_t
*cookiep
,
3151 return (iommulib_iommu_dma_win(dip
, rdip
, dma_handle
, win
, offp
,
3152 lenp
, cookiep
, ccountp
));
3157 immu_mapobject(iommulib_handle_t handle
, dev_info_t
*dip
,
3158 dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
,
3159 struct ddi_dma_req
*dmareq
, ddi_dma_obj_t
*dmao
)
3161 immu_hdl_priv_t
*ihp
;
3163 ihp
= iommulib_iommu_dmahdl_getprivate(dip
, rdip
, dma_handle
);
3165 return (immu_map_dvmaseg(rdip
, dma_handle
, ihp
, dmareq
, dmao
));
3170 immu_unmapobject(iommulib_handle_t handle
, dev_info_t
*dip
,
3171 dev_info_t
*rdip
, ddi_dma_handle_t dma_handle
, ddi_dma_obj_t
*dmao
)
3173 immu_hdl_priv_t
*ihp
;
3175 ihp
= iommulib_iommu_dmahdl_getprivate(dip
, rdip
, dma_handle
);
3176 if (ihp
->ihp_npremapped
> 0)
3177 return (DDI_SUCCESS
);
3178 return (immu_unmap_dvmaseg(rdip
, dmao
));