1
0
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:
Konstantin Belousov 2024-10-12 22:56:14 +03:00
parent 7896b03fff
commit e9d948cfe0
6 changed files with 78 additions and 71 deletions

View File

@ -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) */

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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