mirror of
https://git.FreeBSD.org/src.git
synced 2024-10-18 02:19:39 +00:00
iommu: move context link and ref count into device-independent parts
This also allows to move some bits of ddb print routines into iommu_utils.c common for x86 iommu drivers. Sponsored by: Advanced Micro Devices (AMD) Sponsored by: The FreeBSD Foundation MFC after: 1 week
This commit is contained in:
parent
7896b03fff
commit
e9d948cfe0
@ -121,11 +121,14 @@ struct iommu_domain {
|
||||
iommu_gaddr_t msi_base; /* (d) Arch-specific */
|
||||
vm_paddr_t msi_phys; /* (d) Arch-specific */
|
||||
u_int flags; /* (u) */
|
||||
LIST_HEAD(, iommu_ctx) contexts;/* (u) */
|
||||
};
|
||||
|
||||
struct iommu_ctx {
|
||||
struct iommu_domain *domain; /* (c) */
|
||||
struct bus_dma_tag_iommu *tag; /* (c) Root tag */
|
||||
LIST_ENTRY(iommu_ctx) link; /* (u) Member in the domain list */
|
||||
u_int refs; /* (u) References from tags */
|
||||
u_long loads; /* atomic updates, for stat only */
|
||||
u_long unloads; /* same */
|
||||
u_int flags; /* (u) */
|
||||
|
@ -375,7 +375,7 @@ dmar_domain_alloc(struct dmar_unit *dmar, bool id_mapped)
|
||||
iodom = DOM2IODOM(domain);
|
||||
unit = DMAR2IOMMU(dmar);
|
||||
domain->domain = id;
|
||||
LIST_INIT(&domain->contexts);
|
||||
LIST_INIT(&iodom->contexts);
|
||||
iommu_domain_init(unit, iodom, &dmar_domain_map_ops);
|
||||
|
||||
domain->dmar = dmar;
|
||||
@ -430,7 +430,7 @@ dmar_ctx_alloc(struct dmar_domain *domain, uint16_t rid)
|
||||
ctx->context.tag = malloc(sizeof(struct bus_dma_tag_iommu),
|
||||
M_DMAR_CTX, M_WAITOK | M_ZERO);
|
||||
ctx->context.rid = rid;
|
||||
ctx->refs = 1;
|
||||
ctx->context.refs = 1;
|
||||
return (ctx);
|
||||
}
|
||||
|
||||
@ -446,7 +446,7 @@ dmar_ctx_link(struct dmar_ctx *ctx)
|
||||
domain->ctx_cnt));
|
||||
domain->refs++;
|
||||
domain->ctx_cnt++;
|
||||
LIST_INSERT_HEAD(&domain->contexts, ctx, link);
|
||||
LIST_INSERT_HEAD(&domain->iodom.contexts, &ctx->context, link);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -463,7 +463,7 @@ dmar_ctx_unlink(struct dmar_ctx *ctx)
|
||||
domain->refs, domain->ctx_cnt));
|
||||
domain->refs--;
|
||||
domain->ctx_cnt--;
|
||||
LIST_REMOVE(ctx, link);
|
||||
LIST_REMOVE(&ctx->context, link);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -476,7 +476,7 @@ dmar_domain_destroy(struct dmar_domain *domain)
|
||||
|
||||
KASSERT(TAILQ_EMPTY(&domain->iodom.unload_entries),
|
||||
("unfinished unloads %p", domain));
|
||||
KASSERT(LIST_EMPTY(&domain->contexts),
|
||||
KASSERT(LIST_EMPTY(&iodom->contexts),
|
||||
("destroying dom %p with contexts", domain));
|
||||
KASSERT(domain->ctx_cnt == 0,
|
||||
("destroying dom %p with ctx_cnt %d", domain, domain->ctx_cnt));
|
||||
@ -593,13 +593,13 @@ dmar_get_ctx_for_dev1(struct dmar_unit *dmar, device_t dev, uint16_t rid,
|
||||
/* Nothing needs to be done to destroy ctx1. */
|
||||
free(ctx1, M_DMAR_CTX);
|
||||
domain = CTX2DOM(ctx);
|
||||
ctx->refs++; /* tag referenced us */
|
||||
ctx->context.refs++; /* tag referenced us */
|
||||
}
|
||||
} else {
|
||||
domain = CTX2DOM(ctx);
|
||||
if (ctx->context.tag->owner == NULL)
|
||||
ctx->context.tag->owner = dev;
|
||||
ctx->refs++; /* tag referenced us */
|
||||
ctx->context.refs++; /* tag referenced us */
|
||||
}
|
||||
|
||||
error = dmar_flush_for_ctx_entry(dmar, enable);
|
||||
@ -737,15 +737,15 @@ dmar_free_ctx_locked(struct dmar_unit *dmar, struct dmar_ctx *ctx)
|
||||
struct dmar_domain *domain;
|
||||
|
||||
DMAR_ASSERT_LOCKED(dmar);
|
||||
KASSERT(ctx->refs >= 1,
|
||||
("dmar %p ctx %p refs %u", dmar, ctx, ctx->refs));
|
||||
KASSERT(ctx->context.refs >= 1,
|
||||
("dmar %p ctx %p refs %u", dmar, ctx, ctx->context.refs));
|
||||
|
||||
/*
|
||||
* If our reference is not last, only the dereference should
|
||||
* be performed.
|
||||
*/
|
||||
if (ctx->refs > 1) {
|
||||
ctx->refs--;
|
||||
if (ctx->context.refs > 1) {
|
||||
ctx->context.refs--;
|
||||
DMAR_UNLOCK(dmar);
|
||||
return;
|
||||
}
|
||||
@ -762,15 +762,15 @@ dmar_free_ctx_locked(struct dmar_unit *dmar, struct dmar_ctx *ctx)
|
||||
TD_PREP_PINNED_ASSERT;
|
||||
ctxp = dmar_map_ctx_entry(ctx, &sf);
|
||||
DMAR_LOCK(dmar);
|
||||
KASSERT(ctx->refs >= 1,
|
||||
("dmar %p ctx %p refs %u", dmar, ctx, ctx->refs));
|
||||
KASSERT(ctx->context.refs >= 1,
|
||||
("dmar %p ctx %p refs %u", dmar, ctx, ctx->context.refs));
|
||||
|
||||
/*
|
||||
* Other thread might have referenced the context, in which
|
||||
* case again only the dereference should be performed.
|
||||
*/
|
||||
if (ctx->refs > 1) {
|
||||
ctx->refs--;
|
||||
if (ctx->context.refs > 1) {
|
||||
ctx->context.refs--;
|
||||
DMAR_UNLOCK(dmar);
|
||||
iommu_unmap_pgtbl(sf);
|
||||
TD_PINNED_ASSERT;
|
||||
@ -820,14 +820,14 @@ struct dmar_ctx *
|
||||
dmar_find_ctx_locked(struct dmar_unit *dmar, uint16_t rid)
|
||||
{
|
||||
struct dmar_domain *domain;
|
||||
struct dmar_ctx *ctx;
|
||||
struct iommu_ctx *ctx;
|
||||
|
||||
DMAR_ASSERT_LOCKED(dmar);
|
||||
|
||||
LIST_FOREACH(domain, &dmar->domains, link) {
|
||||
LIST_FOREACH(ctx, &domain->contexts, link) {
|
||||
if (ctx->context.rid == rid)
|
||||
return (ctx);
|
||||
LIST_FOREACH(ctx, &domain->iodom.contexts, link) {
|
||||
if (ctx->rid == rid)
|
||||
return (IOCTX2CTX(ctx));
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
|
@ -65,7 +65,6 @@ struct dmar_domain {
|
||||
u_int refs; /* (u) Refs, including ctx */
|
||||
struct dmar_unit *dmar; /* (c) */
|
||||
LIST_ENTRY(dmar_domain) link; /* (u) Member in the dmar list */
|
||||
LIST_HEAD(, dmar_ctx) contexts; /* (u) */
|
||||
vm_object_t pgtbl_obj; /* (c) Page table pages */
|
||||
u_int batch_no;
|
||||
};
|
||||
@ -73,8 +72,6 @@ struct dmar_domain {
|
||||
struct dmar_ctx {
|
||||
struct iommu_ctx context;
|
||||
uint64_t last_fault_rec[2]; /* Last fault reported */
|
||||
LIST_ENTRY(dmar_ctx) link; /* (u) Member in the domain list */
|
||||
u_int refs; /* (u) References from tags */
|
||||
};
|
||||
|
||||
#define DMAR_DOMAIN_PGLOCK(dom) VM_OBJECT_WLOCK((dom)->pgtbl_obj)
|
||||
|
@ -1053,48 +1053,12 @@ dmar_instantiate_rmrr_ctxs(struct iommu_unit *unit)
|
||||
#include <ddb/ddb.h>
|
||||
#include <ddb/db_lex.h>
|
||||
|
||||
static void
|
||||
dmar_print_domain_entry(const struct iommu_map_entry *entry)
|
||||
{
|
||||
struct iommu_map_entry *l, *r;
|
||||
|
||||
db_printf(
|
||||
" start %jx end %jx first %jx last %jx free_down %jx flags %x ",
|
||||
entry->start, entry->end, entry->first, entry->last,
|
||||
entry->free_down, entry->flags);
|
||||
db_printf("left ");
|
||||
l = RB_LEFT(entry, rb_entry);
|
||||
if (l == NULL)
|
||||
db_printf("NULL ");
|
||||
else
|
||||
db_printf("%jx ", l->start);
|
||||
db_printf("right ");
|
||||
r = RB_RIGHT(entry, rb_entry);
|
||||
if (r == NULL)
|
||||
db_printf("NULL");
|
||||
else
|
||||
db_printf("%jx", r->start);
|
||||
db_printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
dmar_print_ctx(struct dmar_ctx *ctx)
|
||||
{
|
||||
|
||||
db_printf(
|
||||
" @%p pci%d:%d:%d refs %d flags %x loads %lu unloads %lu\n",
|
||||
ctx, pci_get_bus(ctx->context.tag->owner),
|
||||
pci_get_slot(ctx->context.tag->owner),
|
||||
pci_get_function(ctx->context.tag->owner), ctx->refs,
|
||||
ctx->context.flags, ctx->context.loads, ctx->context.unloads);
|
||||
}
|
||||
|
||||
static void
|
||||
dmar_print_domain(struct dmar_domain *domain, bool show_mappings)
|
||||
{
|
||||
struct iommu_domain *iodom;
|
||||
struct iommu_map_entry *entry;
|
||||
struct dmar_ctx *ctx;
|
||||
struct iommu_ctx *ctx;
|
||||
|
||||
iodom = DOM2IODOM(domain);
|
||||
|
||||
@ -1104,16 +1068,16 @@ dmar_print_domain(struct dmar_domain *domain, bool show_mappings)
|
||||
domain, domain->domain, domain->mgaw, domain->agaw, domain->pglvl,
|
||||
(uintmax_t)domain->iodom.end, domain->refs, domain->ctx_cnt,
|
||||
domain->iodom.flags, domain->pgtbl_obj, domain->iodom.entries_cnt);
|
||||
if (!LIST_EMPTY(&domain->contexts)) {
|
||||
if (!LIST_EMPTY(&iodom->contexts)) {
|
||||
db_printf(" Contexts:\n");
|
||||
LIST_FOREACH(ctx, &domain->contexts, link)
|
||||
dmar_print_ctx(ctx);
|
||||
LIST_FOREACH(ctx, &iodom->contexts, link)
|
||||
iommu_db_print_ctx(ctx);
|
||||
}
|
||||
if (!show_mappings)
|
||||
return;
|
||||
db_printf(" mapped:\n");
|
||||
RB_FOREACH(entry, iommu_gas_entries_tree, &iodom->rb_root) {
|
||||
dmar_print_domain_entry(entry);
|
||||
iommu_db_print_domain_entry(entry);
|
||||
if (db_pager_quit)
|
||||
break;
|
||||
}
|
||||
@ -1121,7 +1085,7 @@ dmar_print_domain(struct dmar_domain *domain, bool show_mappings)
|
||||
return;
|
||||
db_printf(" unloading:\n");
|
||||
TAILQ_FOREACH(entry, &domain->iodom.unload_entries, dmamap_link) {
|
||||
dmar_print_domain_entry(entry);
|
||||
iommu_db_print_domain_entry(entry);
|
||||
if (db_pager_quit)
|
||||
break;
|
||||
}
|
||||
@ -1131,7 +1095,7 @@ DB_SHOW_COMMAND_FLAGS(dmar_domain, db_dmar_print_domain, CS_OWN)
|
||||
{
|
||||
struct dmar_unit *unit;
|
||||
struct dmar_domain *domain;
|
||||
struct dmar_ctx *ctx;
|
||||
struct iommu_ctx *ctx;
|
||||
bool show_mappings, valid;
|
||||
int pci_domain, bus, device, function, i, t;
|
||||
db_expr_t radix;
|
||||
@ -1179,13 +1143,12 @@ DB_SHOW_COMMAND_FLAGS(dmar_domain, db_dmar_print_domain, CS_OWN)
|
||||
for (i = 0; i < dmar_devcnt; i++) {
|
||||
unit = device_get_softc(dmar_devs[i]);
|
||||
LIST_FOREACH(domain, &unit->domains, link) {
|
||||
LIST_FOREACH(ctx, &domain->contexts, link) {
|
||||
LIST_FOREACH(ctx, &domain->iodom.contexts, link) {
|
||||
if (pci_domain == unit->segment &&
|
||||
bus == pci_get_bus(ctx->context.tag->owner) &&
|
||||
device ==
|
||||
pci_get_slot(ctx->context.tag->owner) &&
|
||||
function ==
|
||||
pci_get_function(ctx->context.tag->owner)) {
|
||||
bus == pci_get_bus(ctx->tag->owner) &&
|
||||
device == pci_get_slot(ctx->tag->owner) &&
|
||||
function == pci_get_function(ctx->tag->
|
||||
owner)) {
|
||||
dmar_print_domain(domain,
|
||||
show_mappings);
|
||||
goto out;
|
||||
|
@ -34,6 +34,7 @@
|
||||
#else
|
||||
#include "opt_apic.h"
|
||||
#endif
|
||||
#include "opt_ddb.h"
|
||||
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
@ -756,3 +757,43 @@ pglvl_page_size(int total_pglvl, int lvl)
|
||||
KASSERT(rlvl < nitems(pg_sz), ("sizeof pg_sz lvl %d", lvl));
|
||||
return (pg_sz[rlvl]);
|
||||
}
|
||||
|
||||
#ifdef DDB
|
||||
#include <ddb/ddb.h>
|
||||
#include <ddb/db_lex.h>
|
||||
|
||||
void
|
||||
iommu_db_print_domain_entry(const struct iommu_map_entry *entry)
|
||||
{
|
||||
struct iommu_map_entry *l, *r;
|
||||
|
||||
db_printf(
|
||||
" start %jx end %jx first %jx last %jx free_down %jx flags %x ",
|
||||
entry->start, entry->end, entry->first, entry->last,
|
||||
entry->free_down, entry->flags);
|
||||
db_printf("left ");
|
||||
l = RB_LEFT(entry, rb_entry);
|
||||
if (l == NULL)
|
||||
db_printf("NULL ");
|
||||
else
|
||||
db_printf("%jx ", l->start);
|
||||
db_printf("right ");
|
||||
r = RB_RIGHT(entry, rb_entry);
|
||||
if (r == NULL)
|
||||
db_printf("NULL");
|
||||
else
|
||||
db_printf("%jx", r->start);
|
||||
db_printf("\n");
|
||||
}
|
||||
|
||||
void
|
||||
iommu_db_print_ctx(struct iommu_ctx *ctx)
|
||||
{
|
||||
db_printf(
|
||||
" @%p pci%d:%d:%d refs %d flags %#x loads %lu unloads %lu\n",
|
||||
ctx, pci_get_bus(ctx->tag->owner),
|
||||
pci_get_slot(ctx->tag->owner),
|
||||
pci_get_function(ctx->tag->owner), ctx->refs,
|
||||
ctx->flags, ctx->loads, ctx->unloads);
|
||||
}
|
||||
#endif
|
||||
|
@ -194,4 +194,7 @@ vm_pindex_t pglvl_pgtbl_get_pindex(int pglvl, iommu_gaddr_t base, int lvl);
|
||||
vm_pindex_t pglvl_max_pages(int pglvl);
|
||||
iommu_gaddr_t pglvl_page_size(int total_pglvl, int lvl);
|
||||
|
||||
void iommu_db_print_domain_entry(const struct iommu_map_entry *entry);
|
||||
void iommu_db_print_ctx(struct iommu_ctx *ctx);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user