Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 1 Apr 2014 15:48:46 +0000 (UTC)
From:      Ryan Stone <rstone@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r264008 - head/sys/x86/iommu
Message-ID:  <201404011548.s31FmktG048782@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rstone
Date: Tue Apr  1 15:48:46 2014
New Revision: 264008
URL: http://svnweb.freebsd.org/changeset/base/264008

Log:
  Re-implement the DMAR I/O MMU code in terms of PCI RIDs
  
  Under the hood the VT-d spec is really implemented in terms of
  PCI RIDs instead of bus/slot/function, even though the spec makes
  pains to convert back to bus/slot/function in examples.  However
  working with bus/slot/function is not correct when PCI ARI is
  in use, so convert to using RIDs in most cases.  bus/slot/function
  will only be used when reporting errors to a user.
  
  Reviewed by:	kib
  MFC after:	2 months
  Sponsored by:	Sandvine Inc.

Modified:
  head/sys/x86/iommu/busdma_dmar.c
  head/sys/x86/iommu/intel_ctx.c
  head/sys/x86/iommu/intel_dmar.h
  head/sys/x86/iommu/intel_drv.c
  head/sys/x86/iommu/intel_fault.c
  head/sys/x86/iommu/intel_utils.c

Modified: head/sys/x86/iommu/busdma_dmar.c
==============================================================================
--- head/sys/x86/iommu/busdma_dmar.c	Tue Apr  1 15:47:24 2014	(r264007)
+++ head/sys/x86/iommu/busdma_dmar.c	Tue Apr  1 15:48:46 2014	(r264008)
@@ -93,7 +93,7 @@ dmar_bus_dma_is_dev_disabled(int domain,
  * bounce mapping.
  */
 static device_t
-dmar_get_requester(device_t dev, int *bus, int *slot, int *func)
+dmar_get_requester(device_t dev, uint16_t *rid)
 {
 	devclass_t pci_class;
 	device_t pci, pcib, requester;
@@ -102,9 +102,7 @@ dmar_get_requester(device_t dev, int *bu
 	pci_class = devclass_find("pci");
 	requester = dev;
 
-	*bus = pci_get_bus(dev);
-	*slot = pci_get_slot(dev);
-	*func = pci_get_function(dev);
+	*rid = pci_get_rid(dev);
 
 	/*
 	 * Walk the bridge hierarchy from the target device to the
@@ -161,8 +159,7 @@ dmar_get_requester(device_t dev, int *bu
 				 * same page tables for taken and
 				 * non-taken transactions.
 				 */
-				*bus = pci_get_bus(dev);
-				*slot = *func = 0;
+				*rid = PCI_RID(pci_get_bus(dev), 0, 0);
 			} else {
 				/*
 				 * Neither the device nor the bridge
@@ -171,9 +168,7 @@ dmar_get_requester(device_t dev, int *bu
 				 * will use the bridge's BSF as the
 				 * requester ID.
 				 */
-				*bus = pci_get_bus(pcib);
-				*slot = pci_get_slot(pcib);
-				*func = pci_get_function(pcib);
+				*rid = pci_get_rid(pcib);
 			}
 		}
 		/*
@@ -193,9 +188,9 @@ dmar_instantiate_ctx(struct dmar_unit *d
 	device_t requester;
 	struct dmar_ctx *ctx;
 	bool disabled;
-	int bus, slot, func;
+	uint16_t rid;
 
-	requester = dmar_get_requester(dev, &bus, &slot, &func);
+	requester = dmar_get_requester(dev, &rid);
 
 	/*
 	 * If the user requested the IOMMU disabled for the device, we
@@ -204,9 +199,10 @@ dmar_instantiate_ctx(struct dmar_unit *d
 	 * Instead provide the identity mapping for the device
 	 * context.
 	 */
-	disabled = dmar_bus_dma_is_dev_disabled(pci_get_domain(dev), bus,
-	    slot, func);
-	ctx = dmar_get_ctx(dmar, requester, bus, slot, func, disabled, rmrr);
+	disabled = dmar_bus_dma_is_dev_disabled(pci_get_domain(requester), 
+	    pci_get_bus(requester), pci_get_slot(requester), 
+	    pci_get_function(requester));
+	ctx = dmar_get_ctx(dmar, requester, rid, disabled, rmrr);
 	if (ctx == NULL)
 		return (NULL);
 	if (disabled) {

Modified: head/sys/x86/iommu/intel_ctx.c
==============================================================================
--- head/sys/x86/iommu/intel_ctx.c	Tue Apr  1 15:47:24 2014	(r264007)
+++ head/sys/x86/iommu/intel_ctx.c	Tue Apr  1 15:48:46 2014	(r264008)
@@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
 #include <x86/iommu/intel_reg.h>
 #include <x86/iommu/busdma_dmar.h>
 #include <x86/iommu/intel_dmar.h>
+#include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 
 static MALLOC_DEFINE(M_DMAR_CTX, "dmar_ctx", "Intel DMAR Context");
@@ -105,14 +106,14 @@ dmar_map_ctx_entry(struct dmar_ctx *ctx,
 {
 	dmar_ctx_entry_t *ctxp;
 
-	ctxp = dmar_map_pgtbl(ctx->dmar->ctx_obj, 1 + ctx->bus,
+	ctxp = dmar_map_pgtbl(ctx->dmar->ctx_obj, 1 + PCI_RID2BUS(ctx->rid),
 	    DMAR_PGF_NOALLOC | DMAR_PGF_WAITOK, sfp);
-	ctxp += ((ctx->slot & 0x1f) << 3) + (ctx->func & 0x7);
+	ctxp += ctx->rid & 0xff;
 	return (ctxp);
 }
 
 static void
-ctx_tag_init(struct dmar_ctx *ctx)
+ctx_tag_init(struct dmar_ctx *ctx, device_t dev)
 {
 	bus_addr_t maxaddr;
 
@@ -126,6 +127,7 @@ ctx_tag_init(struct dmar_ctx *ctx)
 	ctx->ctx_tag.common.nsegments = BUS_SPACE_UNRESTRICTED;
 	ctx->ctx_tag.common.maxsegsz = maxaddr;
 	ctx->ctx_tag.ctx = ctx;
+	ctx->ctx_tag.owner = dev;
 	/* XXXKIB initialize tag further */
 }
 
@@ -138,7 +140,10 @@ ctx_id_entry_init(struct dmar_ctx *ctx, 
 	unit = ctx->dmar;
 	KASSERT(ctxp->ctx1 == 0 && ctxp->ctx2 == 0,
 	    ("dmar%d: initialized ctx entry %d:%d:%d 0x%jx 0x%jx",
-	    unit->unit, ctx->bus, ctx->slot, ctx->func, ctxp->ctx1,
+	    unit->unit, pci_get_bus(ctx->ctx_tag.owner),
+	    pci_get_slot(ctx->ctx_tag.owner),
+	    pci_get_function(ctx->ctx_tag.owner),
+	    ctxp->ctx1,
 	    ctxp->ctx2));
 	ctxp->ctx2 = DMAR_CTX2_DID(ctx->domain);
 	ctxp->ctx2 |= ctx->awlvl;
@@ -227,7 +232,7 @@ ctx_init_rmrr(struct dmar_ctx *ctx, devi
 }
 
 static struct dmar_ctx *
-dmar_get_ctx_alloc(struct dmar_unit *dmar, int bus, int slot, int func)
+dmar_get_ctx_alloc(struct dmar_unit *dmar, uint16_t rid)
 {
 	struct dmar_ctx *ctx;
 
@@ -237,9 +242,7 @@ dmar_get_ctx_alloc(struct dmar_unit *dma
 	TASK_INIT(&ctx->unload_task, 0, dmar_ctx_unload_task, ctx);
 	mtx_init(&ctx->lock, "dmarctx", NULL, MTX_DEF);
 	ctx->dmar = dmar;
-	ctx->bus = bus;
-	ctx->slot = slot;
-	ctx->func = func;
+	ctx->rid = rid;
 	return (ctx);
 }
 
@@ -262,19 +265,22 @@ dmar_ctx_dtr(struct dmar_ctx *ctx, bool 
 }
 
 struct dmar_ctx *
-dmar_get_ctx(struct dmar_unit *dmar, device_t dev, int bus, int slot, int func,
-    bool id_mapped, bool rmrr_init)
+dmar_get_ctx(struct dmar_unit *dmar, device_t dev, uint16_t rid, bool id_mapped,
+    bool rmrr_init)
 {
 	struct dmar_ctx *ctx, *ctx1;
 	dmar_ctx_entry_t *ctxp;
 	struct sf_buf *sf;
-	int error, mgaw;
+	int bus, slot, func, error, mgaw;
 	bool enable;
 
+	bus = pci_get_bus(dev);
+	slot = pci_get_slot(dev);
+	func = pci_get_function(dev);
 	enable = false;
 	TD_PREP_PINNED_ASSERT;
 	DMAR_LOCK(dmar);
-	ctx = dmar_find_ctx_locked(dmar, bus, slot, func);
+	ctx = dmar_find_ctx_locked(dmar, rid);
 	error = 0;
 	if (ctx == NULL) {
 		/*
@@ -283,7 +289,7 @@ dmar_get_ctx(struct dmar_unit *dmar, dev
 		 */
 		DMAR_UNLOCK(dmar);
 		dmar_ensure_ctx_page(dmar, bus);
-		ctx1 = dmar_get_ctx_alloc(dmar, bus, slot, func);
+		ctx1 = dmar_get_ctx_alloc(dmar, rid);
 
 		if (id_mapped) {
 			/*
@@ -351,7 +357,7 @@ dmar_get_ctx(struct dmar_unit *dmar, dev
 		 * Recheck the contexts, other thread might have
 		 * already allocated needed one.
 		 */
-		ctx = dmar_find_ctx_locked(dmar, bus, slot, func);
+		ctx = dmar_find_ctx_locked(dmar, rid);
 		if (ctx == NULL) {
 			ctx = ctx1;
 			ctx->ctx_tag.owner = dev;
@@ -363,7 +369,7 @@ dmar_get_ctx(struct dmar_unit *dmar, dev
 				TD_PINNED_ASSERT;
 				return (NULL);
 			}
-			ctx_tag_init(ctx);
+			ctx_tag_init(ctx, dev);
 
 			/*
 			 * This is the first activated context for the
@@ -524,14 +530,14 @@ dmar_free_ctx(struct dmar_ctx *ctx)
 }
 
 struct dmar_ctx *
-dmar_find_ctx_locked(struct dmar_unit *dmar, int bus, int slot, int func)
+dmar_find_ctx_locked(struct dmar_unit *dmar, uint16_t rid)
 {
 	struct dmar_ctx *ctx;
 
 	DMAR_ASSERT_LOCKED(dmar);
 
 	LIST_FOREACH(ctx, &dmar->contexts, link) {
-		if (ctx->bus == bus && ctx->slot == slot && ctx->func == func)
+		if (ctx->rid == rid)
 			return (ctx);
 	}
 	return (NULL);

Modified: head/sys/x86/iommu/intel_dmar.h
==============================================================================
--- head/sys/x86/iommu/intel_dmar.h	Tue Apr  1 15:47:24 2014	(r264007)
+++ head/sys/x86/iommu/intel_dmar.h	Tue Apr  1 15:48:46 2014	(r264008)
@@ -74,9 +74,7 @@ RB_PROTOTYPE(dmar_gas_entries_tree, dmar
 #define	DMAR_MAP_ENTRY_TM	0x8000	/* Transient */
 
 struct dmar_ctx {
-	int bus;	/* pci bus/slot/func */
-	int slot;
-	int func;
+	uint16_t rid;	/* pci RID */
 	int domain;	/* DID */
 	int mgaw;	/* Real max address width */
 	int agaw;	/* Adjusted guest address width */
@@ -269,12 +267,11 @@ void ctx_free_pgtbl(struct dmar_ctx *ctx
 
 struct dmar_ctx *dmar_instantiate_ctx(struct dmar_unit *dmar, device_t dev,
     bool rmrr);
-struct dmar_ctx *dmar_get_ctx(struct dmar_unit *dmar, device_t dev,
-    int bus, int slot, int func, bool id_mapped, bool rmrr_init);
+struct dmar_ctx *dmar_get_ctx(struct dmar_unit *dmar, device_t dev, 
+    uint16_t rid, bool id_mapped, bool rmrr_init);
 void dmar_free_ctx_locked(struct dmar_unit *dmar, struct dmar_ctx *ctx);
 void dmar_free_ctx(struct dmar_ctx *ctx);
-struct dmar_ctx *dmar_find_ctx_locked(struct dmar_unit *dmar, int bus,
-    int slot, int func);
+struct dmar_ctx *dmar_find_ctx_locked(struct dmar_unit *dmar, uint16_t rid);
 void dmar_ctx_unload_entry(struct dmar_map_entry *entry, bool free);
 void dmar_ctx_unload(struct dmar_ctx *ctx,
     struct dmar_map_entries_tailq *entries, bool cansleep);

Modified: head/sys/x86/iommu/intel_drv.c
==============================================================================
--- head/sys/x86/iommu/intel_drv.c	Tue Apr  1 15:47:24 2014	(r264007)
+++ head/sys/x86/iommu/intel_drv.c	Tue Apr  1 15:48:46 2014	(r264008)
@@ -1005,7 +1005,9 @@ dmar_print_ctx(struct dmar_ctx *ctx, boo
 	db_printf(
 	    "  @%p pci%d:%d:%d dom %d mgaw %d agaw %d pglvl %d end %jx\n"
 	    "    refs %d flags %x pgobj %p map_ents %u loads %lu unloads %lu\n",
-	    ctx, ctx->bus, ctx->slot, ctx->func, ctx->domain, ctx->mgaw,
+	    ctx, pci_get_bus(ctx->ctx_tag.owner),
+	    pci_get_slot(ctx->ctx_tag.owner),
+	    pci_get_function(ctx->ctx_tag.owner), ctx->domain, ctx->mgaw,
 	    ctx->agaw, ctx->pglvl, (uintmax_t)ctx->end, ctx->refs,
 	    ctx->flags, ctx->pgtbl_obj, ctx->entries_cnt, ctx->loads,
 	    ctx->unloads);
@@ -1078,8 +1080,10 @@ DB_FUNC(dmar_ctx, db_dmar_print_ctx, db_
 	for (i = 0; i < dmar_devcnt; i++) {
 		unit = device_get_softc(dmar_devs[i]);
 		LIST_FOREACH(ctx, &unit->contexts, link) {
-			if (domain == unit->segment && bus == ctx->bus &&
-			    device == ctx->slot && function == ctx->func) {
+			if (domain == unit->segment && 
+			    bus == pci_get_bus(ctx->ctx_tag.owner) &&
+			    device == pci_get_slot(ctx->ctx_tag.owner) && 
+			    function == pci_get_function(ctx->ctx_tag.owner)) {
 				dmar_print_ctx(ctx, show_mappings);
 				goto out;
 			}

Modified: head/sys/x86/iommu/intel_fault.c
==============================================================================
--- head/sys/x86/iommu/intel_fault.c	Tue Apr  1 15:47:24 2014	(r264007)
+++ head/sys/x86/iommu/intel_fault.c	Tue Apr  1 15:48:46 2014	(r264008)
@@ -45,6 +45,8 @@ __FBSDID("$FreeBSD$");
 #include <contrib/dev/acpica/include/acpi.h>
 #include <contrib/dev/acpica/include/accommon.h>
 #include <dev/acpica/acpivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 #include <vm/vm_kern.h>
@@ -203,19 +205,28 @@ dmar_fault_task(void *arg, int pending _
 		DMAR_FAULT_UNLOCK(unit);
 
 		sid = DMAR_FRCD2_SID(fault_rec[1]);
-		bus = (sid >> 8) & 0xf;
-		slot = (sid >> 3) & 0x1f;
-		func = sid & 0x7;
 		printf("DMAR%d: ", unit->unit);
 		DMAR_LOCK(unit);
-		ctx = dmar_find_ctx_locked(unit, bus, slot, func);
+		ctx = dmar_find_ctx_locked(unit, sid);
 		if (ctx == NULL) {
 			printf("<unknown dev>:");
+
+			/*
+			 * Note that the slot and function will not be correct
+			 * if ARI is in use, but without a ctx entry we have
+			 * no way of knowing whether ARI is in use or not.
+			 */
+			bus = PCI_RID2BUS(sid);
+			slot = PCI_RID2SLOT(sid);
+			func = PCI_RID2FUNC(sid);
 		} else {
 			ctx->flags |= DMAR_CTX_FAULTED;
 			ctx->last_fault_rec[0] = fault_rec[0];
 			ctx->last_fault_rec[1] = fault_rec[1];
 			device_print_prettyname(ctx->ctx_tag.owner);
+			bus = pci_get_bus(ctx->ctx_tag.owner);
+			slot = pci_get_slot(ctx->ctx_tag.owner);
+			func = pci_get_function(ctx->ctx_tag.owner);
 		}
 		DMAR_UNLOCK(unit);
 		printf(

Modified: head/sys/x86/iommu/intel_utils.c
==============================================================================
--- head/sys/x86/iommu/intel_utils.c	Tue Apr  1 15:47:24 2014	(r264007)
+++ head/sys/x86/iommu/intel_utils.c	Tue Apr  1 15:48:46 2014	(r264008)
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/systm.h>
 #include <sys/taskqueue.h>
 #include <sys/tree.h>
+#include <dev/pci/pcivar.h>
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 #include <vm/vm_kern.h>
@@ -129,8 +130,10 @@ ctx_set_agaw(struct dmar_ctx *ctx, int m
 	}
 	device_printf(ctx->dmar->dev,
 	    "context request mgaw %d for pci%d:%d:%d:%d, "
-	    "no agaw found, sagaw %x\n", mgaw, ctx->dmar->segment, ctx->bus,
-	     ctx->slot, ctx->func, sagaw);
+	    "no agaw found, sagaw %x\n", mgaw, ctx->dmar->segment, 
+	    pci_get_bus(ctx->ctx_tag.owner),
+	    pci_get_slot(ctx->ctx_tag.owner),
+	    pci_get_function(ctx->ctx_tag.owner), sagaw);
 	return (EINVAL);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201404011548.s31FmktG048782>