bus_dma_dmar_load_ident(9): load identity mapping into the map.

Requested, reviewed and tested by:	mav
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D22559
This commit is contained in:
Konstantin Belousov 2019-11-27 19:57:17 +00:00
parent ca293436d1
commit 5c3771d272
6 changed files with 81 additions and 5 deletions

View File

@ -193,6 +193,8 @@ _bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map,
#ifdef _KERNEL
bool bus_dma_dmar_set_buswide(device_t dev);
int bus_dma_dmar_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map,
vm_paddr_t start, vm_size_t length, int flags);
#endif
#endif /* !_X86_BUS_DMA_H_ */

View File

@ -973,3 +973,66 @@ dmar_fini_busdma(struct dmar_unit *unit)
taskqueue_free(unit->delayed_taskqueue);
unit->delayed_taskqueue = NULL;
}
int
bus_dma_dmar_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map1,
vm_paddr_t start, vm_size_t length, int flags)
{
struct bus_dma_tag_common *tc;
struct bus_dma_tag_dmar *tag;
struct bus_dmamap_dmar *map;
struct dmar_ctx *ctx;
struct dmar_domain *domain;
struct dmar_map_entry *entry;
vm_page_t *ma;
vm_size_t i;
int error;
bool waitok;
MPASS((start & PAGE_MASK) == 0);
MPASS((length & PAGE_MASK) == 0);
MPASS(length > 0);
MPASS(start + length >= start);
MPASS((flags & ~(BUS_DMA_NOWAIT | BUS_DMA_NOWRITE)) == 0);
tc = (struct bus_dma_tag_common *)dmat;
if (tc->impl != &bus_dma_dmar_impl)
return (0);
tag = (struct bus_dma_tag_dmar *)dmat;
ctx = tag->ctx;
domain = ctx->domain;
map = (struct bus_dmamap_dmar *)map1;
waitok = (flags & BUS_DMA_NOWAIT) != 0;
entry = dmar_gas_alloc_entry(domain, waitok ? 0 : DMAR_PGF_WAITOK);
if (entry == NULL)
return (ENOMEM);
entry->start = start;
entry->end = start + length;
ma = malloc(sizeof(vm_page_t) * atop(length), M_TEMP, waitok ?
M_WAITOK : M_NOWAIT);
if (ma == NULL) {
dmar_gas_free_entry(domain, entry);
return (ENOMEM);
}
for (i = 0; i < atop(length); i++) {
ma[i] = vm_page_getfake(entry->start + PAGE_SIZE * i,
VM_MEMATTR_DEFAULT);
}
error = dmar_gas_map_region(domain, entry, DMAR_MAP_ENTRY_READ |
((flags & BUS_DMA_NOWRITE) ? 0 : DMAR_MAP_ENTRY_WRITE),
waitok ? DMAR_GM_CANWAIT : 0, ma);
if (error == 0) {
DMAR_DOMAIN_LOCK(domain);
TAILQ_INSERT_TAIL(&map->map_entries, entry, dmamap_link);
entry->flags |= DMAR_MAP_ENTRY_MAP;
DMAR_DOMAIN_UNLOCK(domain);
} else {
dmar_domain_unload_entry(entry, true);
}
for (i = 0; i < atop(length); i++)
vm_page_putfake(ma[i]);
free(ma, M_TEMP);
return (error);
}

View File

@ -279,7 +279,7 @@ domain_init_rmrr(struct dmar_domain *domain, device_t dev, int bus,
}
error1 = dmar_gas_map_region(domain, entry,
DMAR_MAP_ENTRY_READ | DMAR_MAP_ENTRY_WRITE,
DMAR_GM_CANWAIT, ma);
DMAR_GM_CANWAIT | DMAR_GM_RMRR, ma);
/*
* Non-failed RMRR entries are owned by context rb
* tree. Get rid of the failed entry, but do not stop

View File

@ -391,6 +391,7 @@ bool dmar_is_buswide_ctx(struct dmar_unit *unit, u_int busno);
#define DMAR_GM_CANWAIT 0x0001
#define DMAR_GM_CANSPLIT 0x0002
#define DMAR_GM_RMRR 0x0004
#define DMAR_PGF_WAITOK 0x0001
#define DMAR_PGF_ZERO 0x0002

View File

@ -543,13 +543,15 @@ dmar_gas_alloc_region(struct dmar_domain *domain, struct dmar_map_entry *entry,
*/
if (prev != NULL && prev->end > entry->start &&
(prev->flags & DMAR_MAP_ENTRY_PLACE) == 0) {
if ((prev->flags & DMAR_MAP_ENTRY_RMRR) == 0)
if ((flags & DMAR_GM_RMRR) == 0 ||
(prev->flags & DMAR_MAP_ENTRY_RMRR) == 0)
return (EBUSY);
entry->start = prev->end;
}
if (next->start < entry->end &&
(next->flags & DMAR_MAP_ENTRY_PLACE) == 0) {
if ((next->flags & DMAR_MAP_ENTRY_RMRR) == 0)
if ((flags & DMAR_GM_RMRR) == 0 ||
(next->flags & DMAR_MAP_ENTRY_RMRR) == 0)
return (EBUSY);
entry->end = next->start;
}
@ -569,7 +571,8 @@ dmar_gas_alloc_region(struct dmar_domain *domain, struct dmar_map_entry *entry,
found = dmar_gas_rb_insert(domain, entry);
KASSERT(found, ("found RMRR dup %p start %jx end %jx",
domain, (uintmax_t)entry->start, (uintmax_t)entry->end));
entry->flags = DMAR_MAP_ENTRY_RMRR;
if ((flags & DMAR_GM_RMRR) != 0)
entry->flags = DMAR_MAP_ENTRY_RMRR;
#ifdef INVARIANTS
struct dmar_map_entry *ip, *in;
@ -689,7 +692,7 @@ dmar_gas_map_region(struct dmar_domain *domain, struct dmar_map_entry *entry,
KASSERT(entry->flags == 0, ("used RMRR entry %p %p %x", domain,
entry, entry->flags));
KASSERT((flags & ~(DMAR_GM_CANWAIT)) == 0,
KASSERT((flags & ~(DMAR_GM_CANWAIT | DMAR_GM_RMRR)) == 0,
("invalid flags 0x%x", flags));
start = entry->start;

View File

@ -253,4 +253,11 @@ bus_dma_dmar_set_buswide(device_t dev)
{
return (false);
}
int
bus_dma_dmar_load_ident(bus_dma_tag_t dmat, bus_dmamap_t map,
vm_paddr_t start, vm_size_t length, int flags)
{
return (0);
}
#endif