o Move iommu_test_boundary() to sys/iommu.h
o Rename DMAR -> IOMMU in comments o Add IOMMU_PAGE_SIZE / IOMMU_PAGE_MASK macroses o x86 only: dmar_quirks_pre_use() / dmar_instantiate_rmrr_ctxs() Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25665
This commit is contained in:
parent
5682c291e7
commit
643d9657a2
@ -35,6 +35,7 @@
|
||||
#define _SYS_IOMMU_H_
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <sys/taskqueue.h>
|
||||
#include <sys/tree.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
@ -43,6 +44,7 @@ typedef uint64_t iommu_haddr_t;
|
||||
/* Guest or bus address, before translation. */
|
||||
typedef uint64_t iommu_gaddr_t;
|
||||
|
||||
struct bus_dma_tag_common;
|
||||
struct iommu_map_entry;
|
||||
TAILQ_HEAD(iommu_map_entries_tailq, iommu_map_entry);
|
||||
|
||||
@ -102,6 +104,7 @@ struct iommu_domain {
|
||||
struct iommu_unit *iommu; /* (c) */
|
||||
struct mtx lock; /* (c) */
|
||||
struct task unload_task; /* (c) */
|
||||
u_int entries_cnt; /* (d) */
|
||||
struct iommu_map_entries_tailq unload_entries; /* (d) Entries to
|
||||
unload */
|
||||
};
|
||||
@ -129,6 +132,16 @@ struct iommu_ctx {
|
||||
#define IOMMU_DOMAIN_UNLOCK(dom) mtx_unlock(&(dom)->lock)
|
||||
#define IOMMU_DOMAIN_ASSERT_LOCKED(dom) mtx_assert(&(dom)->lock, MA_OWNED)
|
||||
|
||||
static inline bool
|
||||
iommu_test_boundary(iommu_gaddr_t start, iommu_gaddr_t size,
|
||||
iommu_gaddr_t boundary)
|
||||
{
|
||||
|
||||
if (boundary == 0)
|
||||
return (true);
|
||||
return (start + size <= ((start + boundary) & ~(boundary - 1)));
|
||||
}
|
||||
|
||||
void iommu_free_ctx(struct iommu_ctx *ctx);
|
||||
void iommu_free_ctx_locked(struct iommu_unit *iommu, struct iommu_ctx *ctx);
|
||||
struct iommu_ctx *iommu_get_ctx(struct iommu_unit *, device_t dev,
|
||||
|
@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/interrupt.h>
|
||||
#include <sys/iommu.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/ktr.h>
|
||||
#include <sys/lock.h>
|
||||
@ -62,11 +63,13 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/atomic.h>
|
||||
#include <machine/bus.h>
|
||||
#include <machine/md_var.h>
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
#include <machine/specialreg.h>
|
||||
#include <x86/include/busdma_impl.h>
|
||||
#include <x86/iommu/intel_reg.h>
|
||||
#include <x86/iommu/busdma_dmar.h>
|
||||
#include <x86/iommu/intel_dmar.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* busdma_dmar.c, the implementation of the busdma(9) interface using
|
||||
@ -112,11 +115,11 @@ iommu_bus_dma_is_dev_disabled(int domain, int bus, int slot, int func)
|
||||
|
||||
/*
|
||||
* Given original device, find the requester ID that will be seen by
|
||||
* the DMAR unit and used for page table lookup. PCI bridges may take
|
||||
* the IOMMU unit and used for page table lookup. PCI bridges may take
|
||||
* ownership of transactions from downstream devices, so it may not be
|
||||
* the same as the BSF of the target device. In those cases, all
|
||||
* devices downstream of the bridge must share a single mapping
|
||||
* domain, and must collectively be assigned to use either DMAR or
|
||||
* domain, and must collectively be assigned to use either IOMMU or
|
||||
* bounce mapping.
|
||||
*/
|
||||
device_t
|
||||
@ -135,7 +138,7 @@ iommu_get_requester(device_t dev, uint16_t *rid)
|
||||
|
||||
/*
|
||||
* Walk the bridge hierarchy from the target device to the
|
||||
* host port to find the translating bridge nearest the DMAR
|
||||
* host port to find the translating bridge nearest the IOMMU
|
||||
* unit.
|
||||
*/
|
||||
for (;;) {
|
||||
@ -173,7 +176,7 @@ iommu_get_requester(device_t dev, uint16_t *rid)
|
||||
} else {
|
||||
/*
|
||||
* Device is not PCIe, it cannot be seen as a
|
||||
* requester by DMAR unit. Check whether the
|
||||
* requester by IOMMU unit. Check whether the
|
||||
* bridge is PCIe.
|
||||
*/
|
||||
bridge_is_pcie = pci_find_cap(pcib, PCIY_EXPRESS,
|
||||
@ -243,8 +246,8 @@ iommu_instantiate_ctx(struct iommu_unit *unit, device_t dev, bool rmrr)
|
||||
|
||||
/*
|
||||
* If the user requested the IOMMU disabled for the device, we
|
||||
* cannot disable the DMAR, due to possibility of other
|
||||
* devices on the same DMAR still requiring translation.
|
||||
* cannot disable the IOMMU unit, due to possibility of other
|
||||
* devices on the same IOMMU unit still requiring translation.
|
||||
* Instead provide the identity mapping for the device
|
||||
* context.
|
||||
*/
|
||||
@ -279,13 +282,16 @@ acpi_iommu_get_dma_tag(device_t dev, device_t child)
|
||||
bus_dma_tag_t res;
|
||||
|
||||
unit = iommu_find(child, bootverbose);
|
||||
/* Not in scope of any DMAR ? */
|
||||
/* Not in scope of any IOMMU ? */
|
||||
if (unit == NULL)
|
||||
return (NULL);
|
||||
if (!unit->dma_enabled)
|
||||
return (NULL);
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
dmar_quirks_pre_use(unit);
|
||||
dmar_instantiate_rmrr_ctxs(unit);
|
||||
#endif
|
||||
|
||||
ctx = iommu_instantiate_ctx(unit, child, false);
|
||||
res = ctx == NULL ? NULL : (bus_dma_tag_t)ctx->tag;
|
||||
@ -536,7 +542,7 @@ iommu_bus_dmamap_load_something1(struct bus_dma_tag_iommu *tag,
|
||||
bus_size_t buflen1;
|
||||
int error, idx, gas_flags, seg;
|
||||
|
||||
KASSERT(offset < DMAR_PAGE_SIZE, ("offset %d", offset));
|
||||
KASSERT(offset < IOMMU_PAGE_SIZE, ("offset %d", offset));
|
||||
if (segs == NULL)
|
||||
segs = tag->segments;
|
||||
ctx = tag->ctx;
|
||||
@ -621,7 +627,7 @@ iommu_bus_dmamap_load_something1(struct bus_dma_tag_iommu *tag,
|
||||
|
||||
idx += OFF_TO_IDX(trunc_page(offset + buflen1));
|
||||
offset += buflen1;
|
||||
offset &= DMAR_PAGE_MASK;
|
||||
offset &= IOMMU_PAGE_MASK;
|
||||
buflen -= buflen1;
|
||||
}
|
||||
if (error == 0)
|
||||
@ -841,7 +847,7 @@ iommu_bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map1,
|
||||
}
|
||||
|
||||
/*
|
||||
* The limitations of busdma KPI forces the dmar to perform the actual
|
||||
* The limitations of busdma KPI forces the iommu to perform the actual
|
||||
* unload, consisting of the unmapping of the map entries page tables,
|
||||
* from the delayed context on i386, since page table page mapping
|
||||
* might require a sleep to be successfull. The unfortunate
|
||||
|
@ -77,7 +77,6 @@ struct dmar_domain {
|
||||
LIST_HEAD(, dmar_ctx) contexts; /* (u) */
|
||||
vm_object_t pgtbl_obj; /* (c) Page table pages */
|
||||
u_int flags; /* (u) */
|
||||
u_int entries_cnt; /* (d) */
|
||||
struct dmar_gas_entries_tree rb_root; /* (d) */
|
||||
struct iommu_map_entry *first_place, *last_place; /* (d) */
|
||||
u_int batch_no;
|
||||
@ -460,16 +459,6 @@ dmar_pte_clear(volatile uint64_t *dst)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool
|
||||
iommu_test_boundary(iommu_gaddr_t start, iommu_gaddr_t size,
|
||||
iommu_gaddr_t boundary)
|
||||
{
|
||||
|
||||
if (boundary == 0)
|
||||
return (true);
|
||||
return (start + size <= ((start + boundary) & ~(boundary - 1)));
|
||||
}
|
||||
|
||||
extern struct timespec dmar_hw_timeout;
|
||||
|
||||
#define DMAR_WAIT_UNTIL(cond) \
|
||||
|
@ -1160,7 +1160,7 @@ dmar_print_domain(struct dmar_domain *domain, bool show_mappings)
|
||||
" ctx_cnt %d flags %x pgobj %p map_ents %u\n",
|
||||
domain, domain->domain, domain->mgaw, domain->agaw, domain->pglvl,
|
||||
(uintmax_t)domain->end, domain->refs, domain->ctx_cnt,
|
||||
domain->flags, domain->pgtbl_obj, domain->entries_cnt);
|
||||
domain->flags, domain->pgtbl_obj, domain->iodom.entries_cnt);
|
||||
if (!LIST_EMPTY(&domain->contexts)) {
|
||||
db_printf(" Contexts:\n");
|
||||
LIST_FOREACH(ctx, &domain->contexts, link)
|
||||
|
@ -98,7 +98,7 @@ dmar_gas_alloc_entry(struct dmar_domain *domain, u_int flags)
|
||||
0 ? M_WAITOK : M_NOWAIT) | M_ZERO);
|
||||
if (res != NULL) {
|
||||
res->domain = (struct iommu_domain *)domain;
|
||||
atomic_add_int(&domain->entries_cnt, 1);
|
||||
atomic_add_int(&domain->iodom.entries_cnt, 1);
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
@ -110,7 +110,7 @@ dmar_gas_free_entry(struct dmar_domain *domain, struct iommu_map_entry *entry)
|
||||
KASSERT(domain == (struct dmar_domain *)entry->domain,
|
||||
("mismatched free domain %p entry %p entry->domain %p", domain,
|
||||
entry, entry->domain));
|
||||
atomic_subtract_int(&domain->entries_cnt, 1);
|
||||
atomic_subtract_int(&domain->iodom.entries_cnt, 1);
|
||||
uma_zfree(iommu_map_entry_zone, entry);
|
||||
}
|
||||
|
||||
@ -214,7 +214,7 @@ dmar_gas_init_domain(struct dmar_domain *domain)
|
||||
end = dmar_gas_alloc_entry(domain, DMAR_PGF_WAITOK);
|
||||
|
||||
DMAR_DOMAIN_LOCK(domain);
|
||||
KASSERT(domain->entries_cnt == 2, ("dirty domain %p", domain));
|
||||
KASSERT(domain->iodom.entries_cnt == 2, ("dirty domain %p", domain));
|
||||
KASSERT(RB_EMPTY(&domain->rb_root), ("non-empty entries %p", domain));
|
||||
|
||||
begin->start = 0;
|
||||
@ -239,7 +239,8 @@ dmar_gas_fini_domain(struct dmar_domain *domain)
|
||||
struct iommu_map_entry *entry, *entry1;
|
||||
|
||||
DMAR_DOMAIN_ASSERT_LOCKED(domain);
|
||||
KASSERT(domain->entries_cnt == 2, ("domain still in use %p", domain));
|
||||
KASSERT(domain->iodom.entries_cnt == 2,
|
||||
("domain still in use %p", domain));
|
||||
|
||||
entry = RB_MIN(dmar_gas_entries_tree, &domain->rb_root);
|
||||
KASSERT(entry->start == 0, ("start entry start %p", domain));
|
||||
|
@ -41,6 +41,9 @@
|
||||
#define DMAR_NPTEPGSHIFT 9
|
||||
#define DMAR_PTEMASK (DMAR_NPTEPG - 1)
|
||||
|
||||
#define IOMMU_PAGE_SIZE DMAR_PAGE_SIZE
|
||||
#define IOMMU_PAGE_MASK DMAR_PAGE_MASK
|
||||
|
||||
typedef struct dmar_root_entry {
|
||||
uint64_t r1;
|
||||
uint64_t r2;
|
||||
|
Loading…
x
Reference in New Issue
Block a user