Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 18 Apr 2019 14:18:07 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r346352 - head/sys/x86/iommu
Message-ID:  <201904181418.x3IEI7E5057963@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Thu Apr 18 14:18:06 2019
New Revision: 346352
URL: https://svnweb.freebsd.org/changeset/base/346352

Log:
  Correct handling of RMRR during early enumeration stages.
  
  On some machines, DMAR contexts must be created before all devices
  under the scope of the corresponding DMAR unit are enumerated.
  Current code has two problems with that:
  - scope lookup returns NULL device_t, which causes to skip creating a
    context with RMRR, which is fatal for the affected device.
  - calculation of the final pci dbsf address fails if any bridge in the
    scope is not yet enumerated, because code relies on pcib_get_bus().
  
  Make creation of contexts work either with device_t, or with DMAR PCI
  scope paths.  Scope provides enough information to infer context
  address, and it is directly matched against DMAR tables scopes.
  
  When calculating bus addresses for the scope or device, use direct
  pci_cfgregread(PCIR_SECBUS_1) to get the secondary bus number, instead
  of pcib_get_bus().
  
  The issue was observed on HP Gen servers, where iLO PCI devices are
  located behind south bridge switch.  Turning on translation without
  satisfying RMRR requests caused iLO to mostly hang, up to the level of
  being unusable to control the server.
  
  While there, remove hw.dmar.dmar_match_verbose tunable, and make the
  normal logging under bootverbose useful and sufficient to diagnose
  DRHD and RMRR parsing and matching.
  
  Sponsored by:	Mellanox Technologies
  MFC after:	1 week

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_intrmap.c
  head/sys/x86/iommu/intel_utils.c

Modified: head/sys/x86/iommu/busdma_dmar.c
==============================================================================
--- head/sys/x86/iommu/busdma_dmar.c	Thu Apr 18 14:03:59 2019	(r346351)
+++ head/sys/x86/iommu/busdma_dmar.c	Thu Apr 18 14:18:06 2019	(r346352)
@@ -275,7 +275,7 @@ dmar_get_dma_tag(device_t dev, device_t child)
 	struct dmar_ctx *ctx;
 	bus_dma_tag_t res;
 
-	dmar = dmar_find(child);
+	dmar = dmar_find(child, bootverbose);
 	/* Not in scope of any DMAR ? */
 	if (dmar == NULL)
 		return (NULL);

Modified: head/sys/x86/iommu/intel_ctx.c
==============================================================================
--- head/sys/x86/iommu/intel_ctx.c	Thu Apr 18 14:03:59 2019	(r346351)
+++ head/sys/x86/iommu/intel_ctx.c	Thu Apr 18 14:18:06 2019	(r346352)
@@ -62,6 +62,8 @@ __FBSDID("$FreeBSD$");
 #include <machine/bus.h>
 #include <machine/md_var.h>
 #include <machine/specialreg.h>
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
 #include <x86/include/busdma_impl.h>
 #include <x86/iommu/intel_reg.h>
 #include <x86/iommu/busdma_dmar.h>
@@ -203,7 +205,9 @@ dmar_flush_for_ctx_entry(struct dmar_unit *dmar, bool 
 }
 
 static int
-domain_init_rmrr(struct dmar_domain *domain, device_t dev)
+domain_init_rmrr(struct dmar_domain *domain, device_t dev, int bus,
+    int slot, int func, int dev_domain, int dev_busno,
+    const void *dev_path, int dev_path_len)
 {
 	struct dmar_map_entries_tailq rmrr_entries;
 	struct dmar_map_entry *entry, *entry1;
@@ -214,7 +218,8 @@ domain_init_rmrr(struct dmar_domain *domain, device_t 
 
 	error = 0;
 	TAILQ_INIT(&rmrr_entries);
-	dmar_dev_parse_rmrr(domain, dev, &rmrr_entries);
+	dmar_dev_parse_rmrr(domain, dev_domain, dev_busno, dev_path,
+	    dev_path_len, &rmrr_entries);
 	TAILQ_FOREACH_SAFE(entry, &rmrr_entries, unroll_link, entry1) {
 		/*
 		 * VT-d specification requires that the start of an
@@ -227,12 +232,19 @@ domain_init_rmrr(struct dmar_domain *domain, device_t 
 		 */
 		start = entry->start;
 		end = entry->end;
+		if (bootverbose)
+			printf("dmar%d ctx pci%d:%d:%d RMRR [%#jx, %#jx]\n",
+			    domain->dmar->unit, bus, slot, func,
+			    (uintmax_t)start, (uintmax_t)end);
 		entry->start = trunc_page(start);
 		entry->end = round_page(end);
 		if (entry->start == entry->end) {
 			/* Workaround for some AMI (?) BIOSes */
 			if (bootverbose) {
-				device_printf(dev, "BIOS bug: dmar%d RMRR "
+				if (dev != NULL)
+					device_printf(dev, "");
+				printf("pci%d:%d:%d ", bus, slot, func);
+				printf("BIOS bug: dmar%d RMRR "
 				    "region (%jx, %jx) corrected\n",
 				    domain->dmar->unit, start, end);
 			}
@@ -260,9 +272,13 @@ domain_init_rmrr(struct dmar_domain *domain, device_t 
 			DMAR_UNLOCK(domain->dmar);
 		} else {
 			if (error1 != 0) {
-				device_printf(dev,
+				if (dev != NULL)
+					device_printf(dev, "");
+				printf("pci%d:%d:%d ", bus, slot, func);
+				printf(
 			    "dmar%d failed to map RMRR region (%jx, %jx) %d\n",
-				    domain->dmar->unit, start, end, error1);
+				    domain->dmar->unit, start, end,
+				    error1);
 				error = error1;
 			}
 			TAILQ_REMOVE(&rmrr_entries, entry, unroll_link);
@@ -404,8 +420,9 @@ dmar_domain_destroy(struct dmar_domain *domain)
 	free(domain, M_DMAR_DOMAIN);
 }
 
-struct dmar_ctx *
-dmar_get_ctx_for_dev(struct dmar_unit *dmar, device_t dev, uint16_t rid,
+static struct dmar_ctx *
+dmar_get_ctx_for_dev1(struct dmar_unit *dmar, device_t dev, uint16_t rid,
+    int dev_domain, int dev_busno, const void *dev_path, int dev_path_len,
     bool id_mapped, bool rmrr_init)
 {
 	struct dmar_domain *domain, *domain1;
@@ -415,9 +432,15 @@ dmar_get_ctx_for_dev(struct dmar_unit *dmar, device_t 
 	int bus, slot, func, error;
 	bool enable;
 
-	bus = pci_get_bus(dev);
-	slot = pci_get_slot(dev);
-	func = pci_get_function(dev);
+	if (dev != NULL) {
+		bus = pci_get_bus(dev);
+		slot = pci_get_slot(dev);
+		func = pci_get_function(dev);
+	} else {
+		bus = PCI_RID2BUS(rid);
+		slot = PCI_RID2SLOT(rid);
+		func = PCI_RID2FUNC(rid);
+	}
 	enable = false;
 	TD_PREP_PINNED_ASSERT;
 	DMAR_LOCK(dmar);
@@ -436,7 +459,9 @@ dmar_get_ctx_for_dev(struct dmar_unit *dmar, device_t 
 			return (NULL);
 		}
 		if (!id_mapped) {
-			error = domain_init_rmrr(domain1, dev);
+			error = domain_init_rmrr(domain1, dev, bus,
+			    slot, func, dev_domain, dev_busno, dev_path,
+			    dev_path_len);
 			if (error != 0) {
 				dmar_domain_destroy(domain1);
 				TD_PINNED_ASSERT;
@@ -468,12 +493,14 @@ dmar_get_ctx_for_dev(struct dmar_unit *dmar, device_t 
 				enable = true;
 			LIST_INSERT_HEAD(&dmar->domains, domain, link);
 			ctx_id_entry_init(ctx, ctxp, false);
-			device_printf(dev,
+			if (dev != NULL) {
+				device_printf(dev,
 			    "dmar%d pci%d:%d:%d:%d rid %x domain %d mgaw %d "
-			    "agaw %d %s-mapped\n",
-			    dmar->unit, dmar->segment, bus, slot,
-			    func, rid, domain->domain, domain->mgaw,
-			    domain->agaw, id_mapped ? "id" : "re");
+				    "agaw %d %s-mapped\n",
+				    dmar->unit, dmar->segment, bus, slot,
+				    func, rid, domain->domain, domain->mgaw,
+				    domain->agaw, id_mapped ? "id" : "re");
+			}
 			dmar_unmap_pgtbl(sf);
 		} else {
 			dmar_unmap_pgtbl(sf);
@@ -485,6 +512,8 @@ dmar_get_ctx_for_dev(struct dmar_unit *dmar, device_t 
 		}
 	} else {
 		domain = ctx->domain;
+		if (ctx->ctx_tag.owner == NULL)
+			ctx->ctx_tag.owner = dev;
 		ctx->refs++; /* tag referenced us */
 	}
 
@@ -502,7 +531,14 @@ dmar_get_ctx_for_dev(struct dmar_unit *dmar, device_t 
 	 */
 	if (enable && !rmrr_init && (dmar->hw_gcmd & DMAR_GCMD_TE) == 0) {
 		error = dmar_enable_translation(dmar);
-		if (error != 0) {
+		if (error == 0) {
+			if (bootverbose) {
+				printf("dmar%d: enabled translation\n",
+				    dmar->unit);
+			}
+		} else {
+			printf("dmar%d: enabling translation failed, "
+			    "error %d\n", dmar->unit, error);
 			dmar_free_ctx_locked(dmar, ctx);
 			TD_PINNED_ASSERT;
 			return (NULL);
@@ -511,6 +547,31 @@ dmar_get_ctx_for_dev(struct dmar_unit *dmar, device_t 
 	DMAR_UNLOCK(dmar);
 	TD_PINNED_ASSERT;
 	return (ctx);
+}
+
+struct dmar_ctx *
+dmar_get_ctx_for_dev(struct dmar_unit *dmar, device_t dev, uint16_t rid,
+    bool id_mapped, bool rmrr_init)
+{
+	int dev_domain, dev_path_len, dev_busno;
+
+	dev_domain = pci_get_domain(dev);
+	dev_path_len = dmar_dev_depth(dev);
+	ACPI_DMAR_PCI_PATH dev_path[dev_path_len];
+	dmar_dev_path(dev, &dev_busno, dev_path, dev_path_len);
+	return (dmar_get_ctx_for_dev1(dmar, dev, rid, dev_domain, dev_busno,
+	    dev_path, dev_path_len, id_mapped, rmrr_init));
+}
+
+struct dmar_ctx *
+dmar_get_ctx_for_devpath(struct dmar_unit *dmar, uint16_t rid,
+    int dev_domain, int dev_busno,
+    const void *dev_path, int dev_path_len,
+    bool id_mapped, bool rmrr_init)
+{
+
+	return (dmar_get_ctx_for_dev1(dmar, NULL, rid, dev_domain, dev_busno,
+	    dev_path, dev_path_len, id_mapped, rmrr_init));
 }
 
 int

Modified: head/sys/x86/iommu/intel_dmar.h
==============================================================================
--- head/sys/x86/iommu/intel_dmar.h	Thu Apr 18 14:03:59 2019	(r346351)
+++ head/sys/x86/iommu/intel_dmar.h	Thu Apr 18 14:18:06 2019	(r346352)
@@ -258,7 +258,7 @@ struct dmar_unit {
 #define	DMAR_BARRIER_RMRR	0
 #define	DMAR_BARRIER_USEQ	1
 
-struct dmar_unit *dmar_find(device_t dev);
+struct dmar_unit *dmar_find(device_t dev, bool verbose);
 struct dmar_unit *dmar_find_hpet(device_t dev, uint16_t *rid);
 struct dmar_unit *dmar_find_ioapic(u_int apic_id, uint16_t *rid);
 
@@ -325,10 +325,16 @@ void domain_flush_iotlb_sync(struct dmar_domain *domai
 int domain_alloc_pgtbl(struct dmar_domain *domain);
 void domain_free_pgtbl(struct dmar_domain *domain);
 
+int dmar_dev_depth(device_t child);
+void dmar_dev_path(device_t child, int *busno, void *path1, int depth);
+
 struct dmar_ctx *dmar_instantiate_ctx(struct dmar_unit *dmar, device_t dev,
     bool rmrr);
 struct dmar_ctx *dmar_get_ctx_for_dev(struct dmar_unit *dmar, device_t dev,
     uint16_t rid, bool id_mapped, bool rmrr_init);
+struct dmar_ctx *dmar_get_ctx_for_devpath(struct dmar_unit *dmar, uint16_t rid,
+    int dev_domain, int dev_busno, const void *dev_path, int dev_path_len,
+    bool id_mapped, bool rmrr_init);
 int dmar_move_ctx_to_domain(struct dmar_domain *domain, struct dmar_ctx *ctx);
 void dmar_free_ctx_locked(struct dmar_unit *dmar, struct dmar_ctx *ctx);
 void dmar_free_ctx(struct dmar_ctx *ctx);
@@ -360,7 +366,8 @@ int dmar_gas_map_region(struct dmar_domain *domain,
 int dmar_gas_reserve_region(struct dmar_domain *domain, dmar_gaddr_t start,
     dmar_gaddr_t end);
 
-void dmar_dev_parse_rmrr(struct dmar_domain *domain, device_t dev,
+void dmar_dev_parse_rmrr(struct dmar_domain *domain, int dev_domain,
+    int dev_busno, const void *dev_path, int dev_path_len,
     struct dmar_map_entries_tailq *rmrr_entries);
 int dmar_instantiate_rmrr_ctxs(struct dmar_unit *dmar);
 
@@ -382,7 +389,6 @@ void dmar_fini_irt(struct dmar_unit *unit);
 extern dmar_haddr_t dmar_high;
 extern int haw;
 extern int dmar_tbl_pagecnt;
-extern int dmar_match_verbose;
 extern int dmar_batch_coalesce;
 extern int dmar_check_free;
 

Modified: head/sys/x86/iommu/intel_drv.c
==============================================================================
--- head/sys/x86/iommu/intel_drv.c	Thu Apr 18 14:03:59 2019	(r346351)
+++ head/sys/x86/iommu/intel_drv.c	Thu Apr 18 14:18:06 2019	(r346352)
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/tree.h>
 #include <sys/vmem.h>
 #include <machine/bus.h>
+#include <machine/pci_cfgreg.h>
 #include <contrib/dev/acpica/include/acpi.h>
 #include <contrib/dev/acpica/include/accommon.h>
 #include <dev/acpica/acpivar.h>
@@ -176,7 +177,6 @@ dmar_identify(driver_t *driver, device_t parent)
 #ifdef INVARIANTS
 	TUNABLE_INT_FETCH("hw.dmar.check_free", &dmar_check_free);
 #endif
-	TUNABLE_INT_FETCH("hw.dmar.match_verbose", &dmar_match_verbose);
 	status = AcpiGetTable(ACPI_SIG_DMAR, 1, (ACPI_TABLE_HEADER **)&dmartbl);
 	if (ACPI_FAILURE(status))
 		return;
@@ -595,21 +595,20 @@ DRIVER_MODULE(dmar, acpi, dmar_driver, dmar_devclass, 
 MODULE_DEPEND(dmar, acpi, 1, 1, 1);
 
 static void
-dmar_print_path(device_t dev, const char *banner, int busno, int depth,
-    const ACPI_DMAR_PCI_PATH *path)
+dmar_print_path(int busno, int depth, const ACPI_DMAR_PCI_PATH *path)
 {
 	int i;
 
-	device_printf(dev, "%s [%d, ", banner, busno);
+	printf("[%d, ", busno);
 	for (i = 0; i < depth; i++) {
 		if (i != 0)
 			printf(", ");
 		printf("(%d, %d)", path[i].Device, path[i].Function);
 	}
-	printf("]\n");
+	printf("]");
 }
 
-static int
+int
 dmar_dev_depth(device_t child)
 {
 	devclass_t pci_class;
@@ -627,13 +626,15 @@ dmar_dev_depth(device_t child)
 	}
 }
 
-static void
-dmar_dev_path(device_t child, int *busno, ACPI_DMAR_PCI_PATH *path, int depth)
+void
+dmar_dev_path(device_t child, int *busno, void *path1, int depth)
 {
 	devclass_t pci_class;
 	device_t bus, pcib;
+	ACPI_DMAR_PCI_PATH *path;
 
 	pci_class = devclass_find("pci");
+	path = path1;
 	for (depth--; depth != -1; depth--) {
 		path[depth].Device = pci_get_slot(child);
 		path[depth].Function = pci_get_function(child);
@@ -673,14 +674,14 @@ dmar_match_pathes(int busno1, const ACPI_DMAR_PCI_PATH
 }
 
 static int
-dmar_match_devscope(ACPI_DMAR_DEVICE_SCOPE *devscope, device_t dev,
-    int dev_busno, const ACPI_DMAR_PCI_PATH *dev_path, int dev_path_len)
+dmar_match_devscope(ACPI_DMAR_DEVICE_SCOPE *devscope, int dev_busno,
+    const ACPI_DMAR_PCI_PATH *dev_path, int dev_path_len)
 {
 	ACPI_DMAR_PCI_PATH *path;
 	int path_len;
 
 	if (devscope->Length < sizeof(*devscope)) {
-		printf("dmar_find: corrupted DMAR table, dl %d\n",
+		printf("dmar_match_devscope: corrupted DMAR table, dl %d\n",
 		    devscope->Length);
 		return (-1);
 	}
@@ -689,99 +690,112 @@ dmar_match_devscope(ACPI_DMAR_DEVICE_SCOPE *devscope, 
 		return (0);
 	path_len = devscope->Length - sizeof(*devscope);
 	if (path_len % 2 != 0) {
-		printf("dmar_find_bsf: corrupted DMAR table, dl %d\n",
+		printf("dmar_match_devscope: corrupted DMAR table, dl %d\n",
 		    devscope->Length);
 		return (-1);
 	}
 	path_len /= 2;
 	path = (ACPI_DMAR_PCI_PATH *)(devscope + 1);
 	if (path_len == 0) {
-		printf("dmar_find: corrupted DMAR table, dl %d\n",
+		printf("dmar_match_devscope: corrupted DMAR table, dl %d\n",
 		    devscope->Length);
 		return (-1);
 	}
-	if (dmar_match_verbose)
-		dmar_print_path(dev, "DMAR", devscope->Bus, path_len, path);
 
 	return (dmar_match_pathes(devscope->Bus, path, path_len, dev_busno,
 	    dev_path, dev_path_len, devscope->EntryType));
 }
 
-struct dmar_unit *
-dmar_find(device_t dev)
+static bool
+dmar_match_by_path(struct dmar_unit *unit, int dev_domain, int dev_busno,
+    const ACPI_DMAR_PCI_PATH *dev_path, int dev_path_len, const char **banner)
 {
-	device_t dmar_dev;
 	ACPI_DMAR_HARDWARE_UNIT *dmarh;
 	ACPI_DMAR_DEVICE_SCOPE *devscope;
 	char *ptr, *ptrend;
-	int i, match, dev_domain, dev_busno, dev_path_len;
+	int match;
 
+	dmarh = dmar_find_by_index(unit->unit);
+	if (dmarh == NULL)
+		return (false);
+	if (dmarh->Segment != dev_domain)
+		return (false);
+	if ((dmarh->Flags & ACPI_DMAR_INCLUDE_ALL) != 0) {
+		if (banner != NULL)
+			*banner = "INCLUDE_ALL";
+		return (true);
+	}
+	ptr = (char *)dmarh + sizeof(*dmarh);
+	ptrend = (char *)dmarh + dmarh->Header.Length;
+	while (ptr < ptrend) {
+		devscope = (ACPI_DMAR_DEVICE_SCOPE *)ptr;
+		ptr += devscope->Length;
+		match = dmar_match_devscope(devscope, dev_busno, dev_path,
+		    dev_path_len);
+		if (match == -1)
+			return (false);
+		if (match == 1) {
+			if (banner != NULL)
+				*banner = "specific match";
+			return (true);
+		}
+	}
+	return (false);
+}
+
+static struct dmar_unit *
+dmar_find_by_scope(int dev_domain, int dev_busno,
+    const ACPI_DMAR_PCI_PATH *dev_path, int dev_path_len)
+{
+	struct dmar_unit *unit;
+	int i;
+
+	for (i = 0; i < dmar_devcnt; i++) {
+		if (dmar_devs[i] == NULL)
+			continue;
+		unit = device_get_softc(dmar_devs[i]);
+		if (dmar_match_by_path(unit, dev_domain, dev_busno, dev_path,
+		    dev_path_len, NULL))
+			return (unit);
+	}
+	return (NULL);
+}
+
+struct dmar_unit *
+dmar_find(device_t dev, bool verbose)
+{
+	device_t dmar_dev;
+	struct dmar_unit *unit;
+	const char *banner;
+	int i, dev_domain, dev_busno, dev_path_len;
+
 	dmar_dev = NULL;
 	dev_domain = pci_get_domain(dev);
 	dev_path_len = dmar_dev_depth(dev);
 	ACPI_DMAR_PCI_PATH dev_path[dev_path_len];
 	dmar_dev_path(dev, &dev_busno, dev_path, dev_path_len);
-	if (dmar_match_verbose)
-		dmar_print_path(dev, "PCI", dev_busno, dev_path_len, dev_path);
+	banner = "";
 
 	for (i = 0; i < dmar_devcnt; i++) {
 		if (dmar_devs[i] == NULL)
 			continue;
-		dmarh = dmar_find_by_index(i);
-		if (dmarh == NULL)
-			continue;
-		if (dmarh->Segment != dev_domain)
-			continue;
-		if ((dmarh->Flags & ACPI_DMAR_INCLUDE_ALL) != 0) {
-			dmar_dev = dmar_devs[i];
-			if (dmar_match_verbose) {
-				device_printf(dev,
-				    "pci%d:%d:%d:%d matched dmar%d INCLUDE_ALL\n",
-				    dev_domain, pci_get_bus(dev),
-				    pci_get_slot(dev),
-				    pci_get_function(dev),
-				    ((struct dmar_unit *)device_get_softc(
-				    dmar_dev))->unit);
-			}
-			goto found;
-		}
-		ptr = (char *)dmarh + sizeof(*dmarh);
-		ptrend = (char *)dmarh + dmarh->Header.Length;
-		for (;;) {
-			if (ptr >= ptrend)
-				break;
-			devscope = (ACPI_DMAR_DEVICE_SCOPE *)ptr;
-			ptr += devscope->Length;
-			if (dmar_match_verbose) {
-				device_printf(dev,
-				    "pci%d:%d:%d:%d matching dmar%d\n",
-				    dev_domain, pci_get_bus(dev),
-				    pci_get_slot(dev),
-				    pci_get_function(dev),
-				    ((struct dmar_unit *)device_get_softc(
-				    dmar_devs[i]))->unit);
-			}
-			match = dmar_match_devscope(devscope, dev, dev_busno,
-			    dev_path, dev_path_len);
-			if (dmar_match_verbose) {
-				if (match == -1)
-					printf("table error\n");
-				else if (match == 0)
-					printf("not matched\n");
-				else
-					printf("matched\n");
-			}
-			if (match == -1)
-				return (NULL);
-			else if (match == 1) {
-				dmar_dev = dmar_devs[i];
-				goto found;
-			}
-		}
+		unit = device_get_softc(dmar_devs[i]);
+		if (dmar_match_by_path(unit, dev_domain, dev_busno,
+		    dev_path, dev_path_len, &banner))
+			break;
 	}
-	return (NULL);
-found:
-	return (device_get_softc(dmar_dev));
+	if (i == dmar_devcnt)
+		return (NULL);
+
+	if (verbose) {
+		device_printf(dev, "pci%d:%d:%d:%d matched dmar%d by %s",
+		    dev_domain, pci_get_bus(dev), pci_get_slot(dev),
+		    pci_get_function(dev), unit->unit, banner);
+		printf(" scope path ");
+		dmar_print_path(dev_busno, dev_path_len, dev_path);
+		printf("\n");
+	}
+	return (unit);
 }
 
 static struct dmar_unit *
@@ -865,10 +879,9 @@ dmar_find_ioapic(u_int apic_id, uint16_t *rid)
 
 struct rmrr_iter_args {
 	struct dmar_domain *domain;
-	device_t dev;
 	int dev_domain;
 	int dev_busno;
-	ACPI_DMAR_PCI_PATH *dev_path;
+	const ACPI_DMAR_PCI_PATH *dev_path;
 	int dev_path_len;
 	struct dmar_map_entries_tailq *rmrr_entries;
 };
@@ -888,12 +901,6 @@ dmar_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
 
 	ria = arg;
 	resmem = (ACPI_DMAR_RESERVED_MEMORY *)dmarh;
-	if (dmar_match_verbose) {
-		printf("RMRR [%jx,%jx] segment %d\n",
-		    (uintmax_t)resmem->BaseAddress,
-		    (uintmax_t)resmem->EndAddress,
-		    resmem->Segment);
-	}
 	if (resmem->Segment != ria->dev_domain)
 		return (1);
 
@@ -904,11 +911,9 @@ dmar_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
 			break;
 		devscope = (ACPI_DMAR_DEVICE_SCOPE *)ptr;
 		ptr += devscope->Length;
-		match = dmar_match_devscope(devscope, ria->dev, ria->dev_busno,
+		match = dmar_match_devscope(devscope, ria->dev_busno,
 		    ria->dev_path, ria->dev_path_len);
 		if (match == 1) {
-			if (dmar_match_verbose)
-				printf("matched\n");
 			entry = dmar_gas_alloc_entry(ria->domain,
 			    DMAR_PGF_WAITOK);
 			entry->start = resmem->BaseAddress;
@@ -916,8 +921,6 @@ dmar_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
 			entry->end = resmem->EndAddress;
 			TAILQ_INSERT_TAIL(ria->rmrr_entries, entry,
 			    unroll_link);
-		} else if (dmar_match_verbose) {
-			printf("not matched, err %d\n", match);
 		}
 	}
 
@@ -925,25 +928,17 @@ dmar_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg)
 }
 
 void
-dmar_dev_parse_rmrr(struct dmar_domain *domain, device_t dev,
+dmar_dev_parse_rmrr(struct dmar_domain *domain, int dev_domain, int dev_busno,
+    const void *dev_path, int dev_path_len,
     struct dmar_map_entries_tailq *rmrr_entries)
 {
 	struct rmrr_iter_args ria;
 
-	ria.dev_domain = pci_get_domain(dev);
-	ria.dev_path_len = dmar_dev_depth(dev);
-	ACPI_DMAR_PCI_PATH dev_path[ria.dev_path_len];
-	dmar_dev_path(dev, &ria.dev_busno, dev_path, ria.dev_path_len);
-
-	if (dmar_match_verbose) {
-		device_printf(dev, "parsing RMRR entries for ");
-		dmar_print_path(dev, "PCI", ria.dev_busno, ria.dev_path_len,
-		    dev_path);
-	}
-
 	ria.domain = domain;
-	ria.dev = dev;
-	ria.dev_path = dev_path;
+	ria.dev_domain = dev_domain;
+	ria.dev_busno = dev_busno;
+	ria.dev_path = (const ACPI_DMAR_PCI_PATH *)dev_path;
+	ria.dev_path_len = dev_path_len;
 	ria.rmrr_entries = rmrr_entries;
 	dmar_iterate_tbl(dmar_rmrr_iter, &ria);
 }
@@ -954,28 +949,22 @@ struct inst_rmrr_iter_args {
 
 static device_t
 dmar_path_dev(int segment, int path_len, int busno,
-    const ACPI_DMAR_PCI_PATH *path)
+    const ACPI_DMAR_PCI_PATH *path, uint16_t *rid)
 {
-	devclass_t pci_class;
-	device_t bus, pcib, dev;
+	device_t dev;
 	int i;
 
-	pci_class = devclass_find("pci");
 	dev = NULL;
-	for (i = 0; i < path_len; i++, path++) {
+	for (i = 0; i < path_len; i++) {
 		dev = pci_find_dbsf(segment, busno, path->Device,
 		    path->Function);
-		if (dev == NULL)
-			break;
 		if (i != path_len - 1) {
-			bus = device_get_parent(dev);
-			pcib = device_get_parent(bus);
-			if (device_get_devclass(device_get_parent(pcib)) !=
-			    pci_class)
-				return (NULL);
+			busno = pci_cfgregread(busno, path->Device,
+			    path->Function, PCIR_SECBUS_1, 1);
+			path++;
 		}
-		busno = pcib_get_bus(dev);
 	}
+	*rid = PCI_RID(busno, path->Device, path->Function);
 	return (dev);
 }
 
@@ -986,21 +975,19 @@ dmar_inst_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg
 	const ACPI_DMAR_DEVICE_SCOPE *devscope;
 	struct inst_rmrr_iter_args *iria;
 	const char *ptr, *ptrend;
-	struct dmar_unit *dev_dmar;
 	device_t dev;
+	struct dmar_unit *unit;
+	int dev_path_len;
+	uint16_t rid;
 
+	iria = arg;
+
 	if (dmarh->Type != ACPI_DMAR_TYPE_RESERVED_MEMORY)
 		return (1);
 
-	iria = arg;
 	resmem = (ACPI_DMAR_RESERVED_MEMORY *)dmarh;
 	if (resmem->Segment != iria->dmar->segment)
 		return (1);
-	if (dmar_match_verbose) {
-		printf("dmar%d: RMRR [%jx,%jx]\n", iria->dmar->unit,
-		    (uintmax_t)resmem->BaseAddress,
-		    (uintmax_t)resmem->EndAddress);
-	}
 
 	ptr = (const char *)resmem + sizeof(*resmem);
 	ptrend = (const char *)resmem + resmem->Header.Length;
@@ -1012,31 +999,40 @@ dmar_inst_rmrr_iter(ACPI_DMAR_HEADER *dmarh, void *arg
 		/* XXXKIB bridge */
 		if (devscope->EntryType != ACPI_DMAR_SCOPE_TYPE_ENDPOINT)
 			continue;
-		if (dmar_match_verbose) {
-			dmar_print_path(iria->dmar->dev, "RMRR scope",
-			    devscope->Bus, (devscope->Length -
-			    sizeof(ACPI_DMAR_DEVICE_SCOPE)) / 2,
-			    (const ACPI_DMAR_PCI_PATH *)(devscope + 1));
-		}
-		dev = dmar_path_dev(resmem->Segment, (devscope->Length -
-		    sizeof(ACPI_DMAR_DEVICE_SCOPE)) / 2, devscope->Bus,
-		    (const ACPI_DMAR_PCI_PATH *)(devscope + 1));
+		rid = 0;
+		dev_path_len = (devscope->Length -
+		    sizeof(ACPI_DMAR_DEVICE_SCOPE)) / 2;
+		dev = dmar_path_dev(resmem->Segment, dev_path_len,
+		    devscope->Bus,
+		    (const ACPI_DMAR_PCI_PATH *)(devscope + 1), &rid);
 		if (dev == NULL) {
-			if (dmar_match_verbose)
-				printf("null dev\n");
-			continue;
-		}
-		dev_dmar = dmar_find(dev);
-		if (dev_dmar != iria->dmar) {
-			if (dmar_match_verbose) {
-				printf("dmar%d matched, skipping\n",
-				    dev_dmar->unit);
+			if (bootverbose) {
+				printf("dmar%d no dev found for RMRR "
+				    "[%#jx, %#jx] rid %#x scope path ",
+				     iria->dmar->unit,
+				     (uintptr_t)resmem->BaseAddress,
+				     (uintptr_t)resmem->EndAddress,
+				     rid);
+				dmar_print_path(devscope->Bus, dev_path_len,
+				    (const ACPI_DMAR_PCI_PATH *)(devscope + 1));
+				printf("\n");
 			}
-			continue;
+			unit = dmar_find_by_scope(resmem->Segment,
+			    devscope->Bus,
+			    (const ACPI_DMAR_PCI_PATH *)(devscope + 1),
+			    dev_path_len);
+			if (iria->dmar != unit)
+				continue;
+			dmar_get_ctx_for_devpath(iria->dmar, rid,
+			    resmem->Segment, devscope->Bus, 
+			    (const ACPI_DMAR_PCI_PATH *)(devscope + 1),
+			    dev_path_len, false, true);
+		} else {
+			unit = dmar_find(dev, false);
+			if (iria->dmar != unit)
+				continue;
+			dmar_instantiate_ctx(iria->dmar, dev, true);
 		}
-		if (dmar_match_verbose)
-			printf("matched, instantiating RMRR context\n");
-		dmar_instantiate_ctx(iria->dmar, dev, true);
 	}
 
 	return (1);
@@ -1057,8 +1053,6 @@ dmar_instantiate_rmrr_ctxs(struct dmar_unit *dmar)
 
 	error = 0;
 	iria.dmar = dmar;
-	if (dmar_match_verbose)
-		printf("dmar%d: instantiating RMRR contexts\n", dmar->unit);
 	dmar_iterate_tbl(dmar_inst_rmrr_iter, &iria);
 	DMAR_LOCK(dmar);
 	if (!LIST_EMPTY(&dmar->domains)) {
@@ -1066,6 +1060,15 @@ dmar_instantiate_rmrr_ctxs(struct dmar_unit *dmar)
 	    ("dmar%d: RMRR not handled but translation is already enabled",
 		    dmar->unit));
 		error = dmar_enable_translation(dmar);
+		if (bootverbose) {
+			if (error == 0) {
+				printf("dmar%d: enabled translation\n",
+				    dmar->unit);
+			} else {
+				printf("dmar%d: enabling translation failed, "
+				    "error %d\n", dmar->unit, error);
+			}
+		}
 	}
 	dmar_barrier_exit(dmar, DMAR_BARRIER_RMRR);
 	return (error);

Modified: head/sys/x86/iommu/intel_intrmap.c
==============================================================================
--- head/sys/x86/iommu/intel_intrmap.c	Thu Apr 18 14:03:59 2019	(r346351)
+++ head/sys/x86/iommu/intel_intrmap.c	Thu Apr 18 14:18:06 2019	(r346352)
@@ -251,7 +251,7 @@ dmar_ir_find(device_t src, uint16_t *rid, int *is_dmar
 	} else if (src_class == devclass_find("hpet")) {
 		unit = dmar_find_hpet(src, rid);
 	} else {
-		unit = dmar_find(src);
+		unit = dmar_find(src, bootverbose);
 		if (unit != NULL && rid != NULL)
 			dmar_get_requester(src, rid);
 	}

Modified: head/sys/x86/iommu/intel_utils.c
==============================================================================
--- head/sys/x86/iommu/intel_utils.c	Thu Apr 18 14:03:59 2019	(r346351)
+++ head/sys/x86/iommu/intel_utils.c	Thu Apr 18 14:18:06 2019	(r346352)
@@ -614,7 +614,6 @@ dmar_barrier_exit(struct dmar_unit *dmar, u_int barrie
 	DMAR_UNLOCK(dmar);
 }
 
-int dmar_match_verbose;
 int dmar_batch_coalesce = 100;
 struct timespec dmar_hw_timeout = {
 	.tv_sec = 0,
@@ -658,9 +657,6 @@ static SYSCTL_NODE(_hw, OID_AUTO, dmar, CTLFLAG_RD, NU
 SYSCTL_INT(_hw_dmar, OID_AUTO, tbl_pagecnt, CTLFLAG_RD,
     &dmar_tbl_pagecnt, 0,
     "Count of pages used for DMAR pagetables");
-SYSCTL_INT(_hw_dmar, OID_AUTO, match_verbose, CTLFLAG_RWTUN,
-    &dmar_match_verbose, 0,
-    "Verbose matching of the PCI devices to DMAR paths");
 SYSCTL_INT(_hw_dmar, OID_AUTO, batch_coalesce, CTLFLAG_RWTUN,
     &dmar_batch_coalesce, 0,
     "Number of qi batches between interrupt");



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