Changeset View
Standalone View
sys/x86/iommu/intel_dmar.h
Show All 33 Lines | |||||
#ifndef __X86_IOMMU_INTEL_DMAR_H | #ifndef __X86_IOMMU_INTEL_DMAR_H | ||||
#define __X86_IOMMU_INTEL_DMAR_H | #define __X86_IOMMU_INTEL_DMAR_H | ||||
/* Host or physical memory address, after translation. */ | /* Host or physical memory address, after translation. */ | ||||
typedef uint64_t dmar_haddr_t; | typedef uint64_t dmar_haddr_t; | ||||
/* Guest or bus address, before translation. */ | /* Guest or bus address, before translation. */ | ||||
typedef uint64_t dmar_gaddr_t; | typedef uint64_t dmar_gaddr_t; | ||||
struct dmar_unit; | |||||
struct dmar_qi_genseq { | struct dmar_qi_genseq { | ||||
u_int gen; | u_int gen; | ||||
uint32_t seq; | uint32_t seq; | ||||
}; | }; | ||||
struct dmar_map_entry { | struct iommu_map_entry { | ||||
kib: iommu_map_entry is a good candidate to move together with iommu_unit etc. Together with flags… | |||||
brAuthorUnsubmitted Done Inline ActionsAgree, moved! br: Agree, moved! | |||||
dmar_gaddr_t start; | dmar_gaddr_t start; | ||||
dmar_gaddr_t end; | dmar_gaddr_t end; | ||||
dmar_gaddr_t first; /* Least start in subtree */ | dmar_gaddr_t first; /* Least start in subtree */ | ||||
dmar_gaddr_t last; /* Greatest end in subtree */ | dmar_gaddr_t last; /* Greatest end in subtree */ | ||||
dmar_gaddr_t free_down; /* Max free space below the | dmar_gaddr_t free_down; /* Max free space below the | ||||
current R/B tree node */ | current R/B tree node */ | ||||
u_int flags; | u_int flags; | ||||
TAILQ_ENTRY(dmar_map_entry) dmamap_link; /* Link for dmamap entries */ | TAILQ_ENTRY(iommu_map_entry) dmamap_link; /* Link for dmamap entries */ | ||||
RB_ENTRY(dmar_map_entry) rb_entry; /* Links for domain entries */ | RB_ENTRY(iommu_map_entry) rb_entry; /* Links for domain entries */ | ||||
TAILQ_ENTRY(dmar_map_entry) unroll_link; /* Link for unroll after | TAILQ_ENTRY(iommu_map_entry) unroll_link; /* Link for unroll after | ||||
dmamap_load failure */ | dmamap_load failure */ | ||||
struct dmar_domain *domain; | struct dmar_domain *domain; | ||||
struct dmar_qi_genseq gseq; | struct dmar_qi_genseq gseq; | ||||
}; | }; | ||||
RB_HEAD(dmar_gas_entries_tree, dmar_map_entry); | RB_HEAD(dmar_gas_entries_tree, iommu_map_entry); | ||||
RB_PROTOTYPE(dmar_gas_entries_tree, dmar_map_entry, rb_entry, | RB_PROTOTYPE(dmar_gas_entries_tree, iommu_map_entry, rb_entry, | ||||
dmar_gas_cmp_entries); | dmar_gas_cmp_entries); | ||||
#define DMAR_MAP_ENTRY_PLACE 0x0001 /* Fake entry */ | #define IOMMU_MAP_ENTRY_PLACE 0x0001 /* Fake entry */ | ||||
#define DMAR_MAP_ENTRY_RMRR 0x0002 /* Permanent, not linked by | #define IOMMU_MAP_ENTRY_RMRR 0x0002 /* Permanent, not linked by | ||||
dmamap_link */ | dmamap_link */ | ||||
#define DMAR_MAP_ENTRY_MAP 0x0004 /* Busdma created, linked by | #define IOMMU_MAP_ENTRY_MAP 0x0004 /* Busdma created, linked by | ||||
dmamap_link */ | dmamap_link */ | ||||
#define DMAR_MAP_ENTRY_UNMAPPED 0x0010 /* No backing pages */ | #define IOMMU_MAP_ENTRY_UNMAPPED 0x0010 /* No backing pages */ | ||||
#define DMAR_MAP_ENTRY_QI_NF 0x0020 /* qi task, do not free entry */ | #define IOMMU_MAP_ENTRY_QI_NF 0x0020 /* qi task, do not free entry */ | ||||
#define DMAR_MAP_ENTRY_READ 0x1000 /* Read permitted */ | #define IOMMU_MAP_ENTRY_READ 0x1000 /* Read permitted */ | ||||
#define DMAR_MAP_ENTRY_WRITE 0x2000 /* Write permitted */ | #define IOMMU_MAP_ENTRY_WRITE 0x2000 /* Write permitted */ | ||||
#define DMAR_MAP_ENTRY_SNOOP 0x4000 /* Snoop */ | #define IOMMU_MAP_ENTRY_SNOOP 0x4000 /* Snoop */ | ||||
#define DMAR_MAP_ENTRY_TM 0x8000 /* Transient */ | #define IOMMU_MAP_ENTRY_TM 0x8000 /* Transient */ | ||||
/* | /* | ||||
* Locking annotations: | * Locking annotations: | ||||
kibUnsubmitted Done Inline ActionsThis is the locking annotations I mentioned earlier. kib: This is the locking annotations I mentioned earlier. | |||||
* (u) - Protected by dmar unit lock | * (u) - Protected by dmar unit lock | ||||
* (d) - Protected by domain lock | * (d) - Protected by domain lock | ||||
* (c) - Immutable after initialization | * (c) - Immutable after initialization | ||||
*/ | */ | ||||
/* | /* | ||||
* The domain abstraction. Most non-constant members of the domain | * The domain abstraction. Most non-constant members of the domain | ||||
* are protected by owning dmar unit lock, not by the domain lock. | * are protected by owning dmar unit lock, not by the domain lock. | ||||
* Most important, the dmar lock protects the contexts list. | * Most important, the dmar lock protects the contexts list. | ||||
* | * | ||||
* The domain lock protects the address map for the domain, and list | * The domain lock protects the address map for the domain, and list | ||||
* of unload entries delayed. | * of unload entries delayed. | ||||
* | * | ||||
* Page tables pages and pages content is protected by the vm object | * Page tables pages and pages content is protected by the vm object | ||||
* lock pgtbl_obj, which contains the page tables pages. | * lock pgtbl_obj, which contains the page tables pages. | ||||
*/ | */ | ||||
struct dmar_domain { | struct dmar_domain { | ||||
struct iommu_domain iodom; | |||||
Not Done Inline ActionsI do not think that the whole content of dmar_domain is relevant to other hw. For instance, mgaw/agaw/pglvl/awlvl are definitely dmar-specific. kib: I do not think that the whole content of dmar_domain is relevant to other hw. For instance… | |||||
int domain; /* (c) DID, written in context entry */ | int domain; /* (c) DID, written in context entry */ | ||||
int mgaw; /* (c) Real max address width */ | int mgaw; /* (c) Real max address width */ | ||||
int agaw; /* (c) Adjusted guest address width */ | int agaw; /* (c) Adjusted guest address width */ | ||||
int pglvl; /* (c) The pagelevel */ | int pglvl; /* (c) The pagelevel */ | ||||
int awlvl; /* (c) The pagelevel as the bitmask, | int awlvl; /* (c) The pagelevel as the bitmask, | ||||
to set in context entry */ | to set in context entry */ | ||||
dmar_gaddr_t end; /* (c) Highest address + 1 in | dmar_gaddr_t end; /* (c) Highest address + 1 in | ||||
the guest AS */ | the guest AS */ | ||||
u_int ctx_cnt; /* (u) Number of contexts owned */ | u_int ctx_cnt; /* (u) Number of contexts owned */ | ||||
u_int refs; /* (u) Refs, including ctx */ | u_int refs; /* (u) Refs, including ctx */ | ||||
struct dmar_unit *dmar; /* (c) */ | |||||
struct mtx lock; /* (c) */ | |||||
LIST_ENTRY(dmar_domain) link; /* (u) Member in the dmar list */ | LIST_ENTRY(dmar_domain) link; /* (u) Member in the dmar list */ | ||||
LIST_HEAD(, dmar_ctx) contexts; /* (u) */ | LIST_HEAD(, dmar_ctx) contexts; /* (u) */ | ||||
vm_object_t pgtbl_obj; /* (c) Page table pages */ | vm_object_t pgtbl_obj; /* (c) Page table pages */ | ||||
u_int flags; /* (u) */ | u_int flags; /* (u) */ | ||||
u_int entries_cnt; /* (d) */ | u_int entries_cnt; /* (d) */ | ||||
struct dmar_gas_entries_tree rb_root; /* (d) */ | struct dmar_gas_entries_tree rb_root; /* (d) */ | ||||
struct dmar_map_entries_tailq unload_entries; /* (d) Entries to | struct iommu_map_entry *first_place, *last_place; /* (d) */ | ||||
unload */ | |||||
struct dmar_map_entry *first_place, *last_place; /* (d) */ | |||||
struct task unload_task; /* (c) */ | |||||
u_int batch_no; | u_int batch_no; | ||||
}; | }; | ||||
struct dmar_ctx { | struct dmar_ctx { | ||||
struct bus_dma_tag_dmar ctx_tag; /* (c) Root tag */ | struct iommu_device device; | ||||
Not Done Inline ActionsWhy this rename ? It is very strange. I would never call dmar context (this is hw-defined term) an iommu_device. In fact context is dmar-specific thing, it is some laziness on my part that currently it maps 1:1 to requestor, but I have unpublished patches that make context multi-device, which allows to use dmar driver from x86/iommu in bhyve. kib: Why this rename ? It is very strange. I would never call dmar context (this is hw-defined… | |||||
Done Inline ActionsI can try to do similar change with dmar_ctx and dmar_domain as we did with dmar_unit. br: I can try to do similar change with dmar_ctx and dmar_domain as we did with dmar_unit.
(I.e. | |||||
uint16_t rid; /* (c) pci RID */ | uint16_t rid; /* (c) pci RID */ | ||||
uint64_t last_fault_rec[2]; /* Last fault reported */ | uint64_t last_fault_rec[2]; /* Last fault reported */ | ||||
struct dmar_domain *domain; /* (c) */ | |||||
LIST_ENTRY(dmar_ctx) link; /* (u) Member in the domain list */ | LIST_ENTRY(dmar_ctx) link; /* (u) Member in the domain list */ | ||||
u_int refs; /* (u) References from tags */ | u_int refs; /* (u) References from tags */ | ||||
u_int flags; /* (u) */ | |||||
u_long loads; /* atomic updates, for stat only */ | |||||
u_long unloads; /* same */ | |||||
}; | }; | ||||
#define DMAR_DOMAIN_GAS_INITED 0x0001 | #define IOMMU_DOMAIN_GAS_INITED 0x0001 | ||||
#define DMAR_DOMAIN_PGTBL_INITED 0x0002 | #define IOMMU_DOMAIN_PGTBL_INITED 0x0002 | ||||
#define DMAR_DOMAIN_IDMAP 0x0010 /* Domain uses identity | #define IOMMU_DOMAIN_IDMAP 0x0010 /* Domain uses identity | ||||
page table */ | page table */ | ||||
#define DMAR_DOMAIN_RMRR 0x0020 /* Domain contains RMRR entry, | #define IOMMU_DOMAIN_RMRR 0x0020 /* Domain contains RMRR entry, | ||||
cannot be turned off */ | cannot be turned off */ | ||||
/* struct dmar_ctx flags */ | /* struct dmar_ctx flags */ | ||||
#define DMAR_CTX_FAULTED 0x0001 /* Fault was reported, | #define DMAR_CTX_FAULTED 0x0001 /* Fault was reported, | ||||
last_fault_rec is valid */ | last_fault_rec is valid */ | ||||
#define DMAR_CTX_DISABLED 0x0002 /* Device is disabled, the | #define DMAR_CTX_DISABLED 0x0002 /* Device is disabled, the | ||||
ephemeral reference is kept | ephemeral reference is kept | ||||
to prevent context destruction */ | to prevent context destruction */ | ||||
#define DMAR_DOMAIN_PGLOCK(dom) VM_OBJECT_WLOCK((dom)->pgtbl_obj) | #define IOMMU_DOMAIN_PGLOCK(dom) VM_OBJECT_WLOCK((dom)->pgtbl_obj) | ||||
#define DMAR_DOMAIN_PGTRYLOCK(dom) VM_OBJECT_TRYWLOCK((dom)->pgtbl_obj) | #define IOMMU_DOMAIN_PGTRYLOCK(dom) VM_OBJECT_TRYWLOCK((dom)->pgtbl_obj) | ||||
#define DMAR_DOMAIN_PGUNLOCK(dom) VM_OBJECT_WUNLOCK((dom)->pgtbl_obj) | #define IOMMU_DOMAIN_PGUNLOCK(dom) VM_OBJECT_WUNLOCK((dom)->pgtbl_obj) | ||||
#define DMAR_DOMAIN_ASSERT_PGLOCKED(dom) \ | #define IOMMU_DOMAIN_ASSERT_PGLOCKED(dom) \ | ||||
VM_OBJECT_ASSERT_WLOCKED((dom)->pgtbl_obj) | VM_OBJECT_ASSERT_WLOCKED((dom)->pgtbl_obj) | ||||
#define DMAR_DOMAIN_LOCK(dom) mtx_lock(&(dom)->lock) | #define IOMMU_DOMAIN_LOCK(dom) mtx_lock(&(dom)->lock) | ||||
#define DMAR_DOMAIN_UNLOCK(dom) mtx_unlock(&(dom)->lock) | #define IOMMU_DOMAIN_UNLOCK(dom) mtx_unlock(&(dom)->lock) | ||||
#define DMAR_DOMAIN_ASSERT_LOCKED(dom) mtx_assert(&(dom)->lock, MA_OWNED) | #define IOMMU_DOMAIN_ASSERT_LOCKED(dom) mtx_assert(&(dom)->lock, MA_OWNED) | ||||
#define DMAR_DOMAIN_LOCK(dom) mtx_lock(&(dom)->iodom.lock) | |||||
#define DMAR_DOMAIN_UNLOCK(dom) mtx_unlock(&(dom)->iodom.lock) | |||||
#define DMAR_DOMAIN_ASSERT_LOCKED(dom) mtx_assert(&(dom)->iodom.lock, MA_OWNED) | |||||
struct dmar_msi_data { | struct dmar_msi_data { | ||||
int irq; | int irq; | ||||
int irq_rid; | int irq_rid; | ||||
struct resource *irq_res; | struct resource *irq_res; | ||||
void *intr_handle; | void *intr_handle; | ||||
int (*handler)(void *); | int (*handler)(void *); | ||||
int msi_data_reg; | int msi_data_reg; | ||||
int msi_addr_reg; | int msi_addr_reg; | ||||
int msi_uaddr_reg; | int msi_uaddr_reg; | ||||
void (*enable_intr)(struct dmar_unit *); | void (*enable_intr)(struct dmar_unit *); | ||||
void (*disable_intr)(struct dmar_unit *); | void (*disable_intr)(struct dmar_unit *); | ||||
const char *name; | const char *name; | ||||
}; | }; | ||||
#define DMAR_INTR_FAULT 0 | #define DMAR_INTR_FAULT 0 | ||||
#define DMAR_INTR_QI 1 | #define DMAR_INTR_QI 1 | ||||
#define DMAR_INTR_TOTAL 2 | #define DMAR_INTR_TOTAL 2 | ||||
struct dmar_unit { | struct dmar_unit { | ||||
struct iommu_unit iommu; | |||||
Not Done Inline ActionsI am not sure this would work out. You intent is to provide the arch-specific iommu_unit on armv8, right ? I do not request you to do this, just discuss. IMO iommu_unit should be MI, and this x86 structure still being called dmar_unit. dmar_unit would embed iommu_unit as the first member, so you can trivially convert iommu_unit to dmar_unit. iommu_unit would contain something common to all implementations, perhaps lock, unit number, might be device. Significant number of chunks in this patch then would be not needed, when passing dmar_unit to x86 DMAR code. This is actually useful on x86 too, since there is AMD with its IOMMU which is not DMAR, but currently not supported. kib: I am not sure this would work out. You intent is to provide the arch-specific iommu_unit on… | |||||
Done Inline ActionsYes, the intent is to provide the arch-specific iommu_unit, iommu_domain and iommu_device. There is a small iommu framework/interface in arm64/iommu/ that defines struct iommu_unit, struct iommu_domain and struct iommu_device. The framework has no idea about SMMU. That allows us to keep SMMU driver small and simple, and to not overload if with unnecessary matters like busdma, etc. We already do the similar way that you proposed with smmu_domain. So smmu_domain embeds iommu_domain as a first member (see 'struct smmu_domain {' in https://reviews.freebsd.org/D24618). So I think the idea you described does not fit well arm64 because of the framework, i.e. we already have another layer of abstraction on arm64 that keeps MMU drivers small. So renaming iommu_unit to smmu_unit may not be possible, unless we remove the framework. For x86 it could be possible, let me check br: Yes, the intent is to provide the arch-specific iommu_unit, iommu_domain and iommu_device. | |||||
Done Inline ActionsSo here is an updated patch with struct iommu_unit as the first member of dmar_unit. br: So here is an updated patch with struct iommu_unit as the first member of dmar_unit.
I moved a… | |||||
device_t dev; | device_t dev; | ||||
int unit; | |||||
uint16_t segment; | uint16_t segment; | ||||
uint64_t base; | uint64_t base; | ||||
/* Resources */ | /* Resources */ | ||||
int reg_rid; | int reg_rid; | ||||
struct resource *regs; | struct resource *regs; | ||||
struct dmar_msi_data intrs[DMAR_INTR_TOTAL]; | struct dmar_msi_data intrs[DMAR_INTR_TOTAL]; | ||||
/* Hardware registers cache */ | /* Hardware registers cache */ | ||||
uint32_t hw_ver; | uint32_t hw_ver; | ||||
uint64_t hw_cap; | uint64_t hw_cap; | ||||
uint64_t hw_ecap; | uint64_t hw_ecap; | ||||
uint32_t hw_gcmd; | uint32_t hw_gcmd; | ||||
/* Data for being a dmar */ | /* Data for being a dmar */ | ||||
struct mtx lock; | |||||
LIST_HEAD(, dmar_domain) domains; | LIST_HEAD(, dmar_domain) domains; | ||||
struct unrhdr *domids; | struct unrhdr *domids; | ||||
vm_object_t ctx_obj; | vm_object_t ctx_obj; | ||||
u_int barrier_flags; | u_int barrier_flags; | ||||
/* Fault handler data */ | /* Fault handler data */ | ||||
struct mtx fault_lock; | struct mtx fault_lock; | ||||
uint64_t *fault_log; | uint64_t *fault_log; | ||||
Show All 20 Lines | struct dmar_unit { | ||||
/* IR */ | /* IR */ | ||||
int ir_enabled; | int ir_enabled; | ||||
vm_paddr_t irt_phys; | vm_paddr_t irt_phys; | ||||
dmar_irte_t *irt; | dmar_irte_t *irt; | ||||
u_int irte_cnt; | u_int irte_cnt; | ||||
vmem_t *irtids; | vmem_t *irtids; | ||||
/* Delayed freeing of map entries queue processing */ | /* Delayed freeing of map entries queue processing */ | ||||
struct dmar_map_entries_tailq tlb_flush_entries; | struct iommu_map_entries_tailq tlb_flush_entries; | ||||
struct task qi_task; | struct task qi_task; | ||||
struct taskqueue *qi_taskqueue; | struct taskqueue *qi_taskqueue; | ||||
/* Busdma delayed map load */ | |||||
struct task dmamap_load_task; | |||||
TAILQ_HEAD(, bus_dmamap_dmar) delayed_maps; | |||||
struct taskqueue *delayed_taskqueue; | |||||
int dma_enabled; | |||||
/* | /* | ||||
* Bitmap of buses for which context must ignore slot:func, | * Bitmap of buses for which context must ignore slot:func, | ||||
* duplicating the page table pointer into all context table | * duplicating the page table pointer into all context table | ||||
* entries. This is a client-controlled quirk to support some | * entries. This is a client-controlled quirk to support some | ||||
* NTBs. | * NTBs. | ||||
*/ | */ | ||||
uint32_t buswide_ctxs[(PCI_BUSMAX + 1) / NBBY / sizeof(uint32_t)]; | uint32_t buswide_ctxs[(PCI_BUSMAX + 1) / NBBY / sizeof(uint32_t)]; | ||||
}; | }; | ||||
#define DMAR_LOCK(dmar) mtx_lock(&(dmar)->lock) | #define DMAR_LOCK(dmar) mtx_lock(&(dmar)->iommu.lock) | ||||
#define DMAR_UNLOCK(dmar) mtx_unlock(&(dmar)->lock) | #define DMAR_UNLOCK(dmar) mtx_unlock(&(dmar)->iommu.lock) | ||||
#define DMAR_ASSERT_LOCKED(dmar) mtx_assert(&(dmar)->lock, MA_OWNED) | #define DMAR_ASSERT_LOCKED(dmar) mtx_assert(&(dmar)->iommu.lock, MA_OWNED) | ||||
#define DMAR_FAULT_LOCK(dmar) mtx_lock_spin(&(dmar)->fault_lock) | #define DMAR_FAULT_LOCK(dmar) mtx_lock_spin(&(dmar)->fault_lock) | ||||
#define DMAR_FAULT_UNLOCK(dmar) mtx_unlock_spin(&(dmar)->fault_lock) | #define DMAR_FAULT_UNLOCK(dmar) mtx_unlock_spin(&(dmar)->fault_lock) | ||||
#define DMAR_FAULT_ASSERT_LOCKED(dmar) mtx_assert(&(dmar)->fault_lock, MA_OWNED) | #define DMAR_FAULT_ASSERT_LOCKED(dmar) mtx_assert(&(dmar)->fault_lock, MA_OWNED) | ||||
#define DMAR_IS_COHERENT(dmar) (((dmar)->hw_ecap & DMAR_ECAP_C) != 0) | #define DMAR_IS_COHERENT(dmar) (((dmar)->hw_ecap & DMAR_ECAP_C) != 0) | ||||
#define DMAR_HAS_QI(dmar) (((dmar)->hw_ecap & DMAR_ECAP_QI) != 0) | #define DMAR_HAS_QI(dmar) (((dmar)->hw_ecap & DMAR_ECAP_QI) != 0) | ||||
#define DMAR_X2APIC(dmar) \ | #define DMAR_X2APIC(dmar) \ | ||||
(x2apic_mode && ((dmar)->hw_ecap & DMAR_ECAP_EIM) != 0) | (x2apic_mode && ((dmar)->hw_ecap & DMAR_ECAP_EIM) != 0) | ||||
/* Barrier ids */ | /* Barrier ids */ | ||||
#define DMAR_BARRIER_RMRR 0 | #define DMAR_BARRIER_RMRR 0 | ||||
#define DMAR_BARRIER_USEQ 1 | #define DMAR_BARRIER_USEQ 1 | ||||
struct dmar_unit *dmar_find(device_t dev, bool verbose); | struct dmar_unit *dmar_find(device_t dev, bool verbose); | ||||
struct dmar_unit *dmar_find_hpet(device_t dev, uint16_t *rid); | struct dmar_unit *dmar_find_hpet(device_t dev, uint16_t *rid); | ||||
struct dmar_unit *dmar_find_ioapic(u_int apic_id, uint16_t *rid); | struct dmar_unit *dmar_find_ioapic(u_int apic_id, uint16_t *rid); | ||||
u_int dmar_nd2mask(u_int nd); | u_int dmar_nd2mask(u_int nd); | ||||
bool dmar_pglvl_supported(struct dmar_unit *unit, int pglvl); | bool dmar_pglvl_supported(struct iommu_unit *unit, int pglvl); | ||||
int domain_set_agaw(struct dmar_domain *domain, int mgaw); | int domain_set_agaw(struct dmar_domain *domain, int mgaw); | ||||
int dmar_maxaddr2mgaw(struct dmar_unit *unit, dmar_gaddr_t maxaddr, | int dmar_maxaddr2mgaw(struct dmar_unit *unit, dmar_gaddr_t maxaddr, | ||||
bool allow_less); | bool allow_less); | ||||
vm_pindex_t pglvl_max_pages(int pglvl); | vm_pindex_t pglvl_max_pages(int pglvl); | ||||
int domain_is_sp_lvl(struct dmar_domain *domain, int lvl); | int domain_is_sp_lvl(struct dmar_domain *domain, int lvl); | ||||
dmar_gaddr_t pglvl_page_size(int total_pglvl, int lvl); | dmar_gaddr_t pglvl_page_size(int total_pglvl, int lvl); | ||||
dmar_gaddr_t domain_page_size(struct dmar_domain *domain, int lvl); | dmar_gaddr_t domain_page_size(struct dmar_domain *domain, int lvl); | ||||
int calc_am(struct dmar_unit *unit, dmar_gaddr_t base, dmar_gaddr_t size, | int calc_am(struct dmar_unit *unit, dmar_gaddr_t base, dmar_gaddr_t size, | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
void domain_flush_iotlb_sync(struct dmar_domain *domain, dmar_gaddr_t base, | void domain_flush_iotlb_sync(struct dmar_domain *domain, dmar_gaddr_t base, | ||||
dmar_gaddr_t size); | dmar_gaddr_t size); | ||||
int domain_alloc_pgtbl(struct dmar_domain *domain); | int domain_alloc_pgtbl(struct dmar_domain *domain); | ||||
void domain_free_pgtbl(struct dmar_domain *domain); | void domain_free_pgtbl(struct dmar_domain *domain); | ||||
int dmar_dev_depth(device_t child); | int dmar_dev_depth(device_t child); | ||||
void dmar_dev_path(device_t child, int *busno, void *path1, int depth); | void dmar_dev_path(device_t child, int *busno, void *path1, int depth); | ||||
struct dmar_ctx *dmar_instantiate_ctx(struct dmar_unit *dmar, device_t dev, | struct iommu_device *iommu_instantiate_device(struct iommu_unit *dmar, | ||||
bool rmrr); | device_t dev, bool rmrr); | ||||
struct dmar_ctx *dmar_get_ctx_for_dev(struct dmar_unit *dmar, device_t dev, | struct dmar_ctx *dmar_get_ctx_for_dev(struct dmar_unit *dmar, device_t dev, | ||||
uint16_t rid, bool id_mapped, bool rmrr_init); | uint16_t rid, bool id_mapped, bool rmrr_init); | ||||
struct dmar_ctx *dmar_get_ctx_for_devpath(struct dmar_unit *dmar, uint16_t rid, | struct dmar_ctx *dmar_get_ctx_for_devpath(struct dmar_unit *dmar, uint16_t rid, | ||||
int dev_domain, int dev_busno, const void *dev_path, int dev_path_len, | int dev_domain, int dev_busno, const void *dev_path, int dev_path_len, | ||||
bool id_mapped, bool rmrr_init); | bool id_mapped, bool rmrr_init); | ||||
int dmar_move_ctx_to_domain(struct dmar_domain *domain, struct dmar_ctx *ctx); | int dmar_move_ctx_to_domain(struct dmar_domain *domain, struct dmar_ctx *ctx); | ||||
void dmar_free_ctx_locked(struct dmar_unit *dmar, struct dmar_ctx *ctx); | void dmar_free_ctx_locked(struct iommu_unit *dmar, struct iommu_device *ctx); | ||||
void dmar_free_ctx(struct dmar_ctx *ctx); | void dmar_free_ctx(struct iommu_device *ctx); | ||||
struct dmar_ctx *dmar_find_ctx_locked(struct dmar_unit *dmar, uint16_t rid); | struct dmar_ctx *dmar_find_ctx_locked(struct dmar_unit *dmar, uint16_t rid); | ||||
void dmar_domain_unload_entry(struct dmar_map_entry *entry, bool free); | void dmar_domain_unload_entry(struct iommu_map_entry *entry, bool free); | ||||
void dmar_domain_unload(struct dmar_domain *domain, | void dmar_domain_unload(struct dmar_domain *domain, | ||||
struct dmar_map_entries_tailq *entries, bool cansleep); | struct iommu_map_entries_tailq *entries, bool cansleep); | ||||
void dmar_domain_free_entry(struct dmar_map_entry *entry, bool free); | void dmar_domain_free_entry(struct iommu_map_entry *entry, bool free); | ||||
int dmar_init_busdma(struct dmar_unit *unit); | int iommu_init_busdma(struct iommu_unit *unit); | ||||
void dmar_fini_busdma(struct dmar_unit *unit); | void iommu_fini_busdma(struct iommu_unit *unit); | ||||
device_t dmar_get_requester(device_t dev, uint16_t *rid); | device_t iommu_get_requester(device_t dev, uint16_t *rid); | ||||
void dmar_gas_init_domain(struct dmar_domain *domain); | void dmar_gas_init_domain(struct dmar_domain *domain); | ||||
void dmar_gas_fini_domain(struct dmar_domain *domain); | void dmar_gas_fini_domain(struct dmar_domain *domain); | ||||
struct dmar_map_entry *dmar_gas_alloc_entry(struct dmar_domain *domain, | struct iommu_map_entry *dmar_gas_alloc_entry(struct iommu_domain *domain, | ||||
u_int flags); | u_int flags); | ||||
void dmar_gas_free_entry(struct dmar_domain *domain, | void dmar_gas_free_entry(struct iommu_domain *domain, | ||||
struct dmar_map_entry *entry); | struct iommu_map_entry *entry); | ||||
void dmar_gas_free_space(struct dmar_domain *domain, | void dmar_gas_free_space(struct dmar_domain *domain, | ||||
struct dmar_map_entry *entry); | struct iommu_map_entry *entry); | ||||
int dmar_gas_map(struct dmar_domain *domain, | int dmar_gas_map(struct iommu_domain *domain, | ||||
const struct bus_dma_tag_common *common, dmar_gaddr_t size, int offset, | const struct bus_dma_tag_common *common, dmar_gaddr_t size, int offset, | ||||
u_int eflags, u_int flags, vm_page_t *ma, struct dmar_map_entry **res); | u_int eflags, u_int flags, vm_page_t *ma, struct iommu_map_entry **res); | ||||
void dmar_gas_free_region(struct dmar_domain *domain, | void dmar_gas_free_region(struct dmar_domain *domain, | ||||
struct dmar_map_entry *entry); | struct iommu_map_entry *entry); | ||||
int dmar_gas_map_region(struct dmar_domain *domain, | int dmar_gas_map_region(struct iommu_domain *domain, | ||||
struct dmar_map_entry *entry, u_int eflags, u_int flags, vm_page_t *ma); | struct iommu_map_entry *entry, u_int eflags, u_int flags, vm_page_t *ma); | ||||
int dmar_gas_reserve_region(struct dmar_domain *domain, dmar_gaddr_t start, | int dmar_gas_reserve_region(struct dmar_domain *domain, dmar_gaddr_t start, | ||||
dmar_gaddr_t end); | dmar_gaddr_t end); | ||||
void dmar_dev_parse_rmrr(struct dmar_domain *domain, int dev_domain, | void dmar_dev_parse_rmrr(struct dmar_domain *domain, int dev_domain, | ||||
int dev_busno, const void *dev_path, int dev_path_len, | int dev_busno, const void *dev_path, int dev_path_len, | ||||
struct dmar_map_entries_tailq *rmrr_entries); | struct iommu_map_entries_tailq *rmrr_entries); | ||||
int dmar_instantiate_rmrr_ctxs(struct dmar_unit *dmar); | int dmar_instantiate_rmrr_ctxs(struct iommu_unit *dmar); | ||||
void dmar_quirks_post_ident(struct dmar_unit *dmar); | void dmar_quirks_post_ident(struct dmar_unit *dmar); | ||||
void dmar_quirks_pre_use(struct dmar_unit *dmar); | void dmar_quirks_pre_use(struct iommu_unit *dmar); | ||||
int dmar_init_irt(struct dmar_unit *unit); | int dmar_init_irt(struct dmar_unit *unit); | ||||
void dmar_fini_irt(struct dmar_unit *unit); | void dmar_fini_irt(struct dmar_unit *unit); | ||||
void dmar_set_buswide_ctx(struct dmar_unit *unit, u_int busno); | void dmar_set_buswide_ctx(struct iommu_unit *unit, u_int busno); | ||||
bool dmar_is_buswide_ctx(struct dmar_unit *unit, u_int busno); | bool dmar_is_buswide_ctx(struct dmar_unit *unit, u_int busno); | ||||
#define DMAR_GM_CANWAIT 0x0001 | /* Map flags */ | ||||
#define DMAR_GM_CANSPLIT 0x0002 | #define IOMMU_MF_CANWAIT 0x0001 | ||||
#define DMAR_GM_RMRR 0x0004 | #define IOMMU_MF_CANSPLIT 0x0002 | ||||
#define IOMMU_MF_RMRR 0x0004 | |||||
#define DMAR_PGF_WAITOK 0x0001 | #define DMAR_PGF_WAITOK 0x0001 | ||||
#define DMAR_PGF_ZERO 0x0002 | #define DMAR_PGF_ZERO 0x0002 | ||||
#define DMAR_PGF_ALLOC 0x0004 | #define DMAR_PGF_ALLOC 0x0004 | ||||
#define DMAR_PGF_NOALLOC 0x0008 | #define DMAR_PGF_NOALLOC 0x0008 | ||||
#define DMAR_PGF_OBJL 0x0010 | #define DMAR_PGF_OBJL 0x0010 | ||||
extern dmar_haddr_t dmar_high; | extern dmar_haddr_t dmar_high; | ||||
Show All 24 Lines | |||||
} | } | ||||
static inline void | static inline void | ||||
dmar_write4(const struct dmar_unit *unit, int reg, uint32_t val) | dmar_write4(const struct dmar_unit *unit, int reg, uint32_t val) | ||||
{ | { | ||||
KASSERT(reg != DMAR_GCMD_REG || (val & DMAR_GCMD_TE) == | KASSERT(reg != DMAR_GCMD_REG || (val & DMAR_GCMD_TE) == | ||||
(unit->hw_gcmd & DMAR_GCMD_TE), | (unit->hw_gcmd & DMAR_GCMD_TE), | ||||
("dmar%d clearing TE 0x%08x 0x%08x", unit->unit, | ("dmar%d clearing TE 0x%08x 0x%08x", unit->iommu.unit, | ||||
unit->hw_gcmd, val)); | unit->hw_gcmd, val)); | ||||
bus_write_4(unit->regs, reg, val); | bus_write_4(unit->regs, reg, val); | ||||
} | } | ||||
static inline void | static inline void | ||||
dmar_write8(const struct dmar_unit *unit, int reg, uint64_t val) | dmar_write8(const struct dmar_unit *unit, int reg, uint64_t val) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | #ifdef __i386__ | ||||
*p = 0; | *p = 0; | ||||
*(p + 1) = 0; | *(p + 1) = 0; | ||||
#else | #else | ||||
*dst = 0; | *dst = 0; | ||||
#endif | #endif | ||||
} | } | ||||
static inline bool | static inline bool | ||||
dmar_test_boundary(dmar_gaddr_t start, dmar_gaddr_t size, | iommu_test_boundary(dmar_gaddr_t start, dmar_gaddr_t size, | ||||
dmar_gaddr_t boundary) | dmar_gaddr_t boundary) | ||||
{ | { | ||||
if (boundary == 0) | if (boundary == 0) | ||||
return (true); | return (true); | ||||
return (start + size <= ((start + boundary) & ~(boundary - 1))); | return (start + size <= ((start + boundary) & ~(boundary - 1))); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 43 Lines • Show Last 20 Lines |
iommu_map_entry is a good candidate to move together with iommu_unit etc. Together with flags definitions.