Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8a94ade4 authored by David Woodhouse's avatar David Woodhouse
Browse files

iommu/vt-d: Add initial support for PASID tables



Add CONFIG_INTEL_IOMMU_SVM, and allocate PASID tables on supported hardware.

Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent ae853ddb
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -135,6 +135,14 @@ config INTEL_IOMMU
	  and include PCI device scope covered by these DMA
	  remapping devices.

config INTEL_IOMMU_SVM
	bool "Support for Shared Virtual Memory with Intel IOMMU"
	depends on INTEL_IOMMU && X86
	help
	  Shared Virtual Memory (SVM) provides a facility for devices
	  to access DMA resources through process address space by
	  means of a Process Address Space ID (PASID).

config INTEL_IOMMU_DEFAULT_ON
	def_bool y
	prompt "Enable Intel DMA Remapping Devices by default"
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ obj-$(CONFIG_ARM_SMMU) += arm-smmu.o
obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o
obj-$(CONFIG_DMAR_TABLE) += dmar.o
obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o
obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o
obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o
obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
+14 −0
Original line number Diff line number Diff line
@@ -1680,6 +1680,11 @@ static void free_dmar_iommu(struct intel_iommu *iommu)

	/* free context mapping */
	free_context_table(iommu);

#ifdef CONFIG_INTEL_IOMMU_SVM
	if (pasid_enabled(iommu))
		intel_svm_free_pasid_tables(iommu);
#endif
}

static struct dmar_domain *alloc_domain(int flags)
@@ -3107,6 +3112,10 @@ static int __init init_dmars(void)

		if (!ecap_pass_through(iommu->ecap))
			hw_pass_through = 0;
#ifdef CONFIG_INTEL_IOMMU_SVM
		if (pasid_enabled(iommu))
			intel_svm_alloc_pasid_tables(iommu);
#endif
	}

	if (iommu_pass_through)
@@ -4122,6 +4131,11 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
	if (ret)
		goto out;

#ifdef CONFIG_INTEL_IOMMU_SVM
	if (pasid_enabled(iommu))
		intel_svm_alloc_pasid_tables(iommu);
#endif

	if (dmaru->ignored) {
		/*
		 * we always have to disable PMRs or DMA may fail on this device
+65 −0
Original line number Diff line number Diff line
/*
 * Copyright © 2015 Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * Authors: David Woodhouse <dwmw2@infradead.org>
 */

#include <linux/intel-iommu.h>

int intel_svm_alloc_pasid_tables(struct intel_iommu *iommu)
{
	struct page *pages;
	int order;

	order = ecap_pss(iommu->ecap) + 7 - PAGE_SHIFT;
	if (order < 0)
		order = 0;

	pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
	if (!pages) {
		pr_warn("IOMMU: %s: Failed to allocate PASID table\n",
			iommu->name);
		return -ENOMEM;
	}
	iommu->pasid_table = page_address(pages);
	pr_info("%s: Allocated order %d PASID table.\n", iommu->name, order);

	if (ecap_dis(iommu->ecap)) {
		pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
		if (pages)
			iommu->pasid_state_table = page_address(pages);
		else
			pr_warn("IOMMU: %s: Failed to allocate PASID state table\n",
				iommu->name);
	}

	return 0;
}

int intel_svm_free_pasid_tables(struct intel_iommu *iommu)
{
	int order;

	order = ecap_pss(iommu->ecap) + 7 - PAGE_SHIFT;
	if (order < 0)
		order = 0;

	if (iommu->pasid_table) {
		free_pages((unsigned long)iommu->pasid_table, order);
		iommu->pasid_table = NULL;
	}
	if (iommu->pasid_state_table) {
		free_pages((unsigned long)iommu->pasid_state_table, order);
		iommu->pasid_state_table = NULL;
	}
	return 0;
}
+15 −0
Original line number Diff line number Diff line
@@ -325,6 +325,9 @@ enum {
#define VTD_FLAG_TRANS_PRE_ENABLED	(1 << 0)
#define VTD_FLAG_IRQ_REMAP_PRE_ENABLED	(1 << 1)

struct pasid_entry;
struct pasid_state_entry;

struct intel_iommu {
	void __iomem	*reg; /* Pointer to hardware regs, virtual addr */
	u64 		reg_phys; /* physical address of hw register set */
@@ -347,6 +350,15 @@ struct intel_iommu {
	struct root_entry *root_entry; /* virtual address */

	struct iommu_flush flush;
#endif
#ifdef CONFIG_INTEL_IOMMU_SVM
	/* These are large and need to be contiguous, so we allocate just
	 * one for now. We'll maybe want to rethink that if we truly give
	 * devices away to userspace processes (e.g. for DPDK) and don't
	 * want to trust that userspace will use *only* the PASID it was
	 * told to. But while it's all driver-arbitrated, we're fine. */
	struct pasid_entry *pasid_table;
	struct pasid_state_entry *pasid_state_table;
#endif
	struct q_inval  *qi;            /* Queued invalidation info */
	u32 *iommu_state; /* Store iommu states between suspend and resume.*/
@@ -387,6 +399,9 @@ extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);

extern int dmar_ir_support(void);

extern int intel_svm_alloc_pasid_tables(struct intel_iommu *iommu);
extern int intel_svm_free_pasid_tables(struct intel_iommu *iommu);

extern const struct attribute_group *intel_iommu_groups[];

#endif