svn commit: r366833 - in head/sys: dev/iommu kern sys

Ruslan Bukin br at FreeBSD.org
Mon Oct 19 13:10:23 UTC 2020


Author: br
Date: Mon Oct 19 13:10:21 2020
New Revision: 366833
URL: https://svnweb.freebsd.org/changeset/base/366833

Log:
  Manage MSI iommu pages.
  
  This allows the interrupt controller driver only need a small change to
  create a map for the page the device will write to raise an interrupt.
  
  Submitted by:	andrew
  Reviewed by:	kib
  Sponsored by:	Innovate DSbD
  Differential Revision:	https://reviews.freebsd.org/D26705

Added:
  head/sys/dev/iommu/iommu_msi.h   (contents, props changed)
Modified:
  head/sys/dev/iommu/iommu.h
  head/sys/dev/iommu/iommu_gas.c
  head/sys/kern/msi_if.m
  head/sys/kern/subr_intr.c
  head/sys/sys/intr.h

Modified: head/sys/dev/iommu/iommu.h
==============================================================================
--- head/sys/dev/iommu/iommu.h	Mon Oct 19 12:46:03 2020	(r366832)
+++ head/sys/dev/iommu/iommu.h	Mon Oct 19 13:10:21 2020	(r366833)
@@ -111,6 +111,9 @@ struct iommu_domain {
 	iommu_gaddr_t end;		/* (c) Highest address + 1 in
 					   the guest AS */
 	struct iommu_map_entry *first_place, *last_place; /* (d) */
+	struct iommu_map_entry *msi_entry; /* (d) Arch-specific */
+	iommu_gaddr_t msi_base;		/* (d) Arch-specific */
+	vm_paddr_t msi_phys;		/* (d) Arch-specific */
 	u_int flags;			/* (u) */
 };
 

Modified: head/sys/dev/iommu/iommu_gas.c
==============================================================================
--- head/sys/dev/iommu/iommu_gas.c	Mon Oct 19 12:46:03 2020	(r366832)
+++ head/sys/dev/iommu/iommu_gas.c	Mon Oct 19 13:10:21 2020	(r366833)
@@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/pci/pcivar.h>
 #include <dev/iommu/iommu.h>
 #include <dev/iommu/iommu_gas.h>
+#include <dev/iommu/iommu_msi.h>
 #include <machine/atomic.h>
 #include <machine/bus.h>
 #include <machine/md_var.h>
@@ -722,6 +723,69 @@ iommu_map(struct iommu_domain *domain,
 	    ma, res);
 
 	return (error);
+}
+
+int
+iommu_map_msi(struct iommu_ctx *ctx, iommu_gaddr_t size, int offset,
+    u_int eflags, u_int flags, vm_page_t *ma)
+{
+	struct iommu_domain *domain;
+	struct iommu_map_entry *entry;
+	int error;
+
+	error = 0;
+	domain = ctx->domain;
+
+	/* Check if there is already an MSI page allocated */
+	IOMMU_DOMAIN_LOCK(domain);
+	entry = domain->msi_entry;
+	IOMMU_DOMAIN_UNLOCK(domain);
+
+	if (entry == NULL) {
+		error = iommu_gas_map(domain, &ctx->tag->common, size, offset,
+		    eflags, flags, ma, &entry);
+		IOMMU_DOMAIN_LOCK(domain);
+		if (error == 0) {
+			if (domain->msi_entry == NULL) {
+				MPASS(domain->msi_base == 0);
+				MPASS(domain->msi_phys == 0);
+
+				domain->msi_entry = entry;
+				domain->msi_base = entry->start;
+				domain->msi_phys = VM_PAGE_TO_PHYS(ma[0]);
+			} else {
+				/*
+				 * We lost the race and already have an
+				 * MSI page allocated. Free the unneeded entry.
+				 */
+				iommu_gas_free_entry(domain, entry);
+			}
+		} else if (domain->msi_entry != NULL) {
+			/*
+			 * The allocation failed, but another succeeded.
+			 * Return success as there is a valid MSI page.
+			 */
+			error = 0;
+		}
+		IOMMU_DOMAIN_UNLOCK(domain);
+	}
+
+	return (error);
+}
+
+void
+iommu_translate_msi(struct iommu_domain *domain, uint64_t *addr)
+{
+
+	*addr = (*addr - domain->msi_phys) + domain->msi_base;
+
+	KASSERT(*addr >= domain->msi_entry->start,
+	    ("%s: Address is below the MSI entry start address (%jx < %jx)",
+	    __func__, (uintmax_t)*addr, (uintmax_t)domain->msi_entry->start));
+
+	KASSERT(*addr + sizeof(*addr) <= domain->msi_entry->end,
+	    ("%s: Address is above the MSI entry end address (%jx < %jx)",
+	    __func__, (uintmax_t)*addr, (uintmax_t)domain->msi_entry->end));
 }
 
 int

Added: head/sys/dev/iommu/iommu_msi.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/iommu/iommu_msi.h	Mon Oct 19 13:10:21 2020	(r366833)
@@ -0,0 +1,46 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Andrew Turner
+ *
+ * This work was supported by Innovate UK project 105694, "Digital Security
+ * by Design (DSbD) Technology Platform Prototype".
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_IOMMU_IOMMU_MSI_H_
+#define _DEV_IOMMU_IOMMU_MSI_H_
+
+#include <dev/iommu/iommu_types.h>
+
+struct iommu_unit;
+struct iommu_domain;
+struct iommu_ctx;
+
+void iommu_translate_msi(struct iommu_domain *domain, uint64_t *addr);
+int iommu_map_msi(struct iommu_ctx *ctx, iommu_gaddr_t size, int offset,
+    u_int eflags, u_int flags, vm_page_t *ma);
+
+#endif /* !_DEV_IOMMU_IOMMU_MSI_H_ */

Modified: head/sys/kern/msi_if.m
==============================================================================
--- head/sys/kern/msi_if.m	Mon Oct 19 12:46:03 2020	(r366832)
+++ head/sys/kern/msi_if.m	Mon Oct 19 13:10:21 2020	(r366833)
@@ -32,6 +32,9 @@
 INTERFACE msi;
 
 HEADER {
+	#include <machine/bus.h>
+	#include <dev/iommu/iommu_msi.h>
+
 	struct intr_irqsrc;
 };
 
@@ -72,3 +75,8 @@ METHOD int map_msi {
 	uint32_t	*data;
 };
 
+METHOD int iommu_init {
+	device_t	dev;
+	device_t	child;
+	struct iommu_domain **domain;
+};

Modified: head/sys/kern/subr_intr.c
==============================================================================
--- head/sys/kern/subr_intr.c	Mon Oct 19 12:46:03 2020	(r366832)
+++ head/sys/kern/subr_intr.c	Mon Oct 19 13:10:21 2020	(r366833)
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
 
 #include "opt_ddb.h"
 #include "opt_hwpmc_hooks.h"
+#include "opt_iommu.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -50,6 +51,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/queue.h>
 #include <sys/bus.h>
 #include <sys/interrupt.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
 #include <sys/conf.h>
 #include <sys/cpuset.h>
 #include <sys/rman.h>
@@ -70,6 +73,10 @@ __FBSDID("$FreeBSD$");
 #include <ddb/ddb.h>
 #endif
 
+#ifdef IOMMU
+#include <dev/iommu/iommu_msi.h>
+#endif
+
 #include "pic_if.h"
 #include "msi_if.h"
 
@@ -1290,6 +1297,9 @@ int
 intr_alloc_msi(device_t pci, device_t child, intptr_t xref, int count,
     int maxcount, int *irqs)
 {
+#ifdef IOMMU
+	struct iommu_domain *domain;
+#endif
 	struct intr_irqsrc **isrc;
 	struct intr_pic *pic;
 	device_t pdev;
@@ -1304,6 +1314,16 @@ intr_alloc_msi(device_t pci, device_t child, intptr_t 
 	    ("%s: Found a non-MSI controller: %s", __func__,
 	     device_get_name(pic->pic_dev)));
 
+#ifdef IOMMU
+	/*
+	 * If this is the first time we have used this context ask the
+	 * interrupt controller to map memory the msi source will need.
+	 */
+	err = MSI_IOMMU_INIT(pic->pic_dev, child, &domain);
+	if (err != 0)
+		return (err);
+#endif
+
 	isrc = malloc(sizeof(*isrc) * count, M_INTRNG, M_WAITOK);
 	err = MSI_ALLOC_MSI(pic->pic_dev, child, count, maxcount, &pdev, isrc);
 	if (err != 0) {
@@ -1312,9 +1332,13 @@ intr_alloc_msi(device_t pci, device_t child, intptr_t 
 	}
 
 	for (i = 0; i < count; i++) {
+#ifdef IOMMU
+		isrc[i]->isrc_iommu = domain;
+#endif
 		msi = (struct intr_map_data_msi *)intr_alloc_map_data(
 		    INTR_MAP_DATA_MSI, sizeof(*msi), M_WAITOK | M_ZERO);
 		msi-> isrc = isrc[i];
+
 		irqs[i] = intr_map_irq(pic->pic_dev, xref,
 		    (struct intr_map_data *)msi);
 	}
@@ -1365,6 +1389,9 @@ intr_release_msi(device_t pci, device_t child, intptr_
 int
 intr_alloc_msix(device_t pci, device_t child, intptr_t xref, int *irq)
 {
+#ifdef IOMMU
+	struct iommu_domain *domain;
+#endif
 	struct intr_irqsrc *isrc;
 	struct intr_pic *pic;
 	device_t pdev;
@@ -1379,10 +1406,23 @@ intr_alloc_msix(device_t pci, device_t child, intptr_t
 	    ("%s: Found a non-MSI controller: %s", __func__,
 	     device_get_name(pic->pic_dev)));
 
+#ifdef IOMMU
+	/*
+	 * If this is the first time we have used this context ask the
+	 * interrupt controller to map memory the msi source will need.
+	 */
+	err = MSI_IOMMU_INIT(pic->pic_dev, child, &domain);
+	if (err != 0)
+		return (err);
+#endif
+
 	err = MSI_ALLOC_MSIX(pic->pic_dev, child, &pdev, &isrc);
 	if (err != 0)
 		return (err);
 
+#ifdef IOMMU
+	isrc->isrc_iommu = domain;
+#endif
 	msi = (struct intr_map_data_msi *)intr_alloc_map_data(
 		    INTR_MAP_DATA_MSI, sizeof(*msi), M_WAITOK | M_ZERO);
 	msi->isrc = isrc;
@@ -1444,6 +1484,12 @@ intr_map_msi(device_t pci, device_t child, intptr_t xr
 		return (EINVAL);
 
 	err = MSI_MAP_MSI(pic->pic_dev, child, isrc, addr, data);
+
+#ifdef IOMMU
+	if (isrc->isrc_iommu != NULL)
+		iommu_translate_msi(isrc->isrc_iommu, addr);
+#endif
+
 	return (err);
 }
 

Modified: head/sys/sys/intr.h
==============================================================================
--- head/sys/sys/intr.h	Mon Oct 19 12:46:03 2020	(r366832)
+++ head/sys/sys/intr.h	Mon Oct 19 13:10:21 2020	(r366833)
@@ -94,6 +94,8 @@ struct intr_irqsrc {
 	intr_irq_filter_t *	isrc_filter;
 	void *			isrc_arg;
 #endif
+	/* Used by MSI interrupts to store the iommu details */
+	void *			isrc_iommu;
 };
 
 /* Intr interface for PIC. */


More information about the svn-src-all mailing list