Add iommu_domain_map_ops virtual table with map/unmap methods
so x86 can support Intel DMAR and AMD IOMMU simultaneously. Reviewed by: kib Sponsored by: DARPA/AFRL Differential Revision: https://reviews.freebsd.org/D25894
This commit is contained in:
parent
5904f93598
commit
66204be4b4
sys
@ -100,6 +100,13 @@ struct iommu_unit {
|
|||||||
uint32_t buswide_ctxs[(PCI_BUSMAX + 1) / NBBY / sizeof(uint32_t)];
|
uint32_t buswide_ctxs[(PCI_BUSMAX + 1) / NBBY / sizeof(uint32_t)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct iommu_domain_map_ops {
|
||||||
|
int (*map)(struct iommu_domain *domain, iommu_gaddr_t base,
|
||||||
|
iommu_gaddr_t size, vm_page_t *ma, uint64_t pflags, int flags);
|
||||||
|
int (*unmap)(struct iommu_domain *domain, iommu_gaddr_t base,
|
||||||
|
iommu_gaddr_t size, int flags);
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Locking annotations:
|
* Locking annotations:
|
||||||
* (u) - Protected by iommu unit lock
|
* (u) - Protected by iommu unit lock
|
||||||
@ -109,6 +116,7 @@ struct iommu_unit {
|
|||||||
|
|
||||||
struct iommu_domain {
|
struct iommu_domain {
|
||||||
struct iommu_unit *iommu; /* (c) */
|
struct iommu_unit *iommu; /* (c) */
|
||||||
|
const struct iommu_domain_map_ops *ops;
|
||||||
struct mtx lock; /* (c) */
|
struct mtx lock; /* (c) */
|
||||||
struct task unload_task; /* (c) */
|
struct task unload_task; /* (c) */
|
||||||
u_int entries_cnt; /* (d) */
|
u_int entries_cnt; /* (d) */
|
||||||
|
@ -66,10 +66,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <machine/bus.h>
|
#include <machine/bus.h>
|
||||||
#include <machine/md_var.h>
|
#include <machine/md_var.h>
|
||||||
#if defined(__amd64__) || defined(__i386__)
|
#if defined(__amd64__) || defined(__i386__)
|
||||||
#include <machine/specialreg.h>
|
|
||||||
#include <x86/include/busdma_impl.h>
|
|
||||||
#include <x86/iommu/intel_reg.h>
|
#include <x86/iommu/intel_reg.h>
|
||||||
#include <x86/iommu/intel_dmar.h>
|
|
||||||
#endif
|
#endif
|
||||||
#include <dev/iommu/busdma_iommu.h>
|
#include <dev/iommu/busdma_iommu.h>
|
||||||
|
|
||||||
@ -620,9 +617,9 @@ iommu_gas_map(struct iommu_domain *domain,
|
|||||||
entry->flags |= eflags;
|
entry->flags |= eflags;
|
||||||
IOMMU_DOMAIN_UNLOCK(domain);
|
IOMMU_DOMAIN_UNLOCK(domain);
|
||||||
|
|
||||||
error = domain_map_buf(domain, entry->start, entry->end - entry->start,
|
error = domain->ops->map(domain, entry->start,
|
||||||
ma, eflags,
|
entry->end - entry->start, ma, eflags,
|
||||||
((flags & IOMMU_MF_CANWAIT) != 0 ? IOMMU_PGF_WAITOK : 0));
|
((flags & IOMMU_MF_CANWAIT) != 0 ? IOMMU_PGF_WAITOK : 0));
|
||||||
if (error == ENOMEM) {
|
if (error == ENOMEM) {
|
||||||
iommu_domain_unload_entry(entry, true);
|
iommu_domain_unload_entry(entry, true);
|
||||||
return (error);
|
return (error);
|
||||||
@ -658,9 +655,9 @@ iommu_gas_map_region(struct iommu_domain *domain, struct iommu_map_entry *entry,
|
|||||||
if (entry->end == entry->start)
|
if (entry->end == entry->start)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
error = domain_map_buf(domain, entry->start, entry->end - entry->start,
|
error = domain->ops->map(domain, entry->start,
|
||||||
ma + OFF_TO_IDX(start - entry->start), eflags,
|
entry->end - entry->start, ma + OFF_TO_IDX(start - entry->start),
|
||||||
((flags & IOMMU_MF_CANWAIT) != 0 ? IOMMU_PGF_WAITOK : 0));
|
eflags, ((flags & IOMMU_MF_CANWAIT) != 0 ? IOMMU_PGF_WAITOK : 0));
|
||||||
if (error == ENOMEM) {
|
if (error == ENOMEM) {
|
||||||
iommu_domain_unload_entry(entry, false);
|
iommu_domain_unload_entry(entry, false);
|
||||||
return (error);
|
return (error);
|
||||||
|
@ -341,6 +341,7 @@ dmar_domain_alloc(struct dmar_unit *dmar, bool id_mapped)
|
|||||||
mtx_init(&domain->iodom.lock, "dmardom", NULL, MTX_DEF);
|
mtx_init(&domain->iodom.lock, "dmardom", NULL, MTX_DEF);
|
||||||
domain->dmar = dmar;
|
domain->dmar = dmar;
|
||||||
domain->iodom.iommu = &dmar->iommu;
|
domain->iodom.iommu = &dmar->iommu;
|
||||||
|
domain_pgtbl_init(domain);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For now, use the maximal usable physical address of the
|
* For now, use the maximal usable physical address of the
|
||||||
@ -842,15 +843,17 @@ dmar_domain_unload(struct dmar_domain *domain,
|
|||||||
struct iommu_map_entries_tailq *entries, bool cansleep)
|
struct iommu_map_entries_tailq *entries, bool cansleep)
|
||||||
{
|
{
|
||||||
struct dmar_unit *unit;
|
struct dmar_unit *unit;
|
||||||
|
struct iommu_domain *iodom;
|
||||||
struct iommu_map_entry *entry, *entry1;
|
struct iommu_map_entry *entry, *entry1;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
iodom = (struct iommu_domain *)domain;
|
||||||
unit = (struct dmar_unit *)domain->iodom.iommu;
|
unit = (struct dmar_unit *)domain->iodom.iommu;
|
||||||
|
|
||||||
TAILQ_FOREACH_SAFE(entry, entries, dmamap_link, entry1) {
|
TAILQ_FOREACH_SAFE(entry, entries, dmamap_link, entry1) {
|
||||||
KASSERT((entry->flags & IOMMU_MAP_ENTRY_MAP) != 0,
|
KASSERT((entry->flags & IOMMU_MAP_ENTRY_MAP) != 0,
|
||||||
("not mapped entry %p %p", domain, entry));
|
("not mapped entry %p %p", domain, entry));
|
||||||
error = domain_unmap_buf(domain, entry->start, entry->end -
|
error = iodom->ops->unmap(iodom, entry->start, entry->end -
|
||||||
entry->start, cansleep ? IOMMU_PGF_WAITOK : 0);
|
entry->start, cansleep ? IOMMU_PGF_WAITOK : 0);
|
||||||
KASSERT(error == 0, ("unmap %p error %d", domain, error));
|
KASSERT(error == 0, ("unmap %p error %d", domain, error));
|
||||||
if (!unit->qi_enabled) {
|
if (!unit->qi_enabled) {
|
||||||
|
@ -244,14 +244,11 @@ void dmar_qi_invalidate_iec(struct dmar_unit *unit, u_int start, u_int cnt);
|
|||||||
vm_object_t domain_get_idmap_pgtbl(struct dmar_domain *domain,
|
vm_object_t domain_get_idmap_pgtbl(struct dmar_domain *domain,
|
||||||
iommu_gaddr_t maxaddr);
|
iommu_gaddr_t maxaddr);
|
||||||
void put_idmap_pgtbl(vm_object_t obj);
|
void put_idmap_pgtbl(vm_object_t obj);
|
||||||
int domain_map_buf(struct iommu_domain *domain, iommu_gaddr_t base,
|
|
||||||
iommu_gaddr_t size, vm_page_t *ma, uint64_t pflags, int flags);
|
|
||||||
int domain_unmap_buf(struct dmar_domain *domain, iommu_gaddr_t base,
|
|
||||||
iommu_gaddr_t size, int flags);
|
|
||||||
void domain_flush_iotlb_sync(struct dmar_domain *domain, iommu_gaddr_t base,
|
void domain_flush_iotlb_sync(struct dmar_domain *domain, iommu_gaddr_t base,
|
||||||
iommu_gaddr_t size);
|
iommu_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);
|
||||||
|
void domain_pgtbl_init(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);
|
||||||
|
@ -498,7 +498,7 @@ domain_map_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base,
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
domain_map_buf(struct iommu_domain *iodom, iommu_gaddr_t base,
|
domain_map_buf(struct iommu_domain *iodom, iommu_gaddr_t base,
|
||||||
iommu_gaddr_t size, vm_page_t *ma, uint64_t eflags, int flags)
|
iommu_gaddr_t size, vm_page_t *ma, uint64_t eflags, int flags)
|
||||||
{
|
{
|
||||||
@ -684,12 +684,15 @@ domain_unmap_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base,
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
domain_unmap_buf(struct dmar_domain *domain, iommu_gaddr_t base,
|
domain_unmap_buf(struct iommu_domain *iodom, iommu_gaddr_t base,
|
||||||
iommu_gaddr_t size, int flags)
|
iommu_gaddr_t size, int flags)
|
||||||
{
|
{
|
||||||
|
struct dmar_domain *domain;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
domain = (struct dmar_domain *)iodom;
|
||||||
|
|
||||||
DMAR_DOMAIN_PGLOCK(domain);
|
DMAR_DOMAIN_PGLOCK(domain);
|
||||||
error = domain_unmap_buf_locked(domain, base, size, flags);
|
error = domain_unmap_buf_locked(domain, base, size, flags);
|
||||||
DMAR_DOMAIN_PGUNLOCK(domain);
|
DMAR_DOMAIN_PGUNLOCK(domain);
|
||||||
@ -809,3 +812,17 @@ domain_flush_iotlb_sync(struct dmar_domain *domain, iommu_gaddr_t base,
|
|||||||
}
|
}
|
||||||
DMAR_UNLOCK(unit);
|
DMAR_UNLOCK(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct iommu_domain_map_ops dmar_domain_map_ops = {
|
||||||
|
.map = domain_map_buf,
|
||||||
|
.unmap = domain_unmap_buf,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
domain_pgtbl_init(struct dmar_domain *domain)
|
||||||
|
{
|
||||||
|
struct iommu_domain *iodom;
|
||||||
|
|
||||||
|
iodom = (struct iommu_domain *)domain;
|
||||||
|
iodom->ops = &dmar_domain_map_ops;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user