diff options
Diffstat (limited to 'drivers/iommu/intel')
| -rw-r--r-- | drivers/iommu/intel/dmar.c | 7 | ||||
| -rw-r--r-- | drivers/iommu/intel/iommu.c | 225 | ||||
| -rw-r--r-- | drivers/iommu/intel/iommu.h | 33 | ||||
| -rw-r--r-- | drivers/iommu/intel/irq_remapping.c | 13 | ||||
| -rw-r--r-- | drivers/iommu/intel/pasid.c | 6 | ||||
| -rw-r--r-- | drivers/iommu/intel/svm.c | 145 | 
6 files changed, 215 insertions, 214 deletions
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c index bc94059a5b87..b00a0ceb2d13 100644 --- a/drivers/iommu/intel/dmar.c +++ b/drivers/iommu/intel/dmar.c @@ -1106,6 +1106,13 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)  	raw_spin_lock_init(&iommu->register_lock);  	/* +	 * A value of N in PSS field of eCap register indicates hardware +	 * supports PASID field of N+1 bits. +	 */ +	if (pasid_supported(iommu)) +		iommu->iommu.max_pasids = 2UL << ecap_pss(iommu->ecap); + +	/*  	 * This is only for hotplug; at boot time intel_iommu_enabled won't  	 * be set yet. When intel_iommu_init() runs, it registers the units  	 * present at boot time, then sets intel_iommu_enabled. diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index 644ca49e8cf8..59df7e42fd53 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -27,7 +27,7 @@  #include "iommu.h"  #include "../dma-iommu.h"  #include "../irq_remapping.h" -#include "../iommu-sva-lib.h" +#include "../iommu-sva.h"  #include "pasid.h"  #include "cap_audit.h" @@ -277,7 +277,8 @@ static LIST_HEAD(dmar_satc_units);  #define for_each_rmrr_units(rmrr) \  	list_for_each_entry(rmrr, &dmar_rmrr_units, list) -static void dmar_remove_one_dev_info(struct device *dev); +static void device_block_translation(struct device *dev); +static void intel_iommu_domain_free(struct iommu_domain *domain);  int dmar_disabled = !IS_ENABLED(CONFIG_INTEL_IOMMU_DEFAULT_ON);  int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON); @@ -382,11 +383,6 @@ static inline int domain_type_is_si(struct dmar_domain *domain)  	return domain->domain.type == IOMMU_DOMAIN_IDENTITY;  } -static inline bool domain_use_first_level(struct dmar_domain *domain) -{ -	return domain->flags & DOMAIN_FLAG_USE_FIRST_LEVEL; -} -  static inline int domain_pfn_supported(struct dmar_domain *domain,  				       unsigned long pfn)  { @@ -500,7 +496,7 @@ static int domain_update_iommu_superpage(struct dmar_domain *domain,  	rcu_read_lock();  	for_each_active_iommu(iommu, drhd) {  		if (iommu != skip) { -			if (domain && domain_use_first_level(domain)) { +			if (domain && domain->use_first_level) {  				if (!cap_fl1gp_support(iommu->cap))  					mask = 0x1;  			} else { @@ -578,7 +574,7 @@ static void domain_update_iommu_cap(struct dmar_domain *domain)  	 * paging and 57-bits with 5-level paging). Hence, skip bit  	 * [N-1].  	 */ -	if (domain_use_first_level(domain)) +	if (domain->use_first_level)  		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw - 1);  	else  		domain->domain.geometry.aperture_end = __DOMAIN_MAX_ADDR(domain->gaw); @@ -779,19 +775,6 @@ static void domain_flush_cache(struct dmar_domain *domain,  		clflush_cache_range(addr, size);  } -static int device_context_mapped(struct intel_iommu *iommu, u8 bus, u8 devfn) -{ -	struct context_entry *context; -	int ret = 0; - -	spin_lock(&iommu->lock); -	context = iommu_context_addr(iommu, bus, devfn, 0); -	if (context) -		ret = context_present(context); -	spin_unlock(&iommu->lock); -	return ret; -} -  static void free_context_table(struct intel_iommu *iommu)  {  	struct context_entry *context; @@ -959,7 +942,7 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,  			domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);  			pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE; -			if (domain_use_first_level(domain)) +			if (domain->use_first_level)  				pteval |= DMA_FL_PTE_XD | DMA_FL_PTE_US | DMA_FL_PTE_ACCESS;  			if (cmpxchg64(&pte->val, 0ULL, pteval)) @@ -1418,7 +1401,7 @@ static void iommu_enable_pci_caps(struct device_domain_info *info)  {  	struct pci_dev *pdev; -	if (!info || !dev_is_pci(info->dev)) +	if (!dev_is_pci(info->dev))  		return;  	pdev = to_pci_dev(info->dev); @@ -1458,7 +1441,7 @@ static void iommu_enable_pci_caps(struct device_domain_info *info)  	}  } -static void iommu_disable_dev_iotlb(struct device_domain_info *info) +static void iommu_disable_pci_caps(struct device_domain_info *info)  {  	struct pci_dev *pdev; @@ -1529,7 +1512,7 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu,  	if (ih)  		ih = 1 << 6; -	if (domain_use_first_level(domain)) { +	if (domain->use_first_level) {  		qi_flush_piotlb(iommu, did, PASID_RID2PASID, addr, pages, ih);  	} else {  		unsigned long bitmask = aligned_pages - 1; @@ -1583,7 +1566,7 @@ static inline void __mapping_notify_one(struct intel_iommu *iommu,  	 * It's a non-present to present mapping. Only flush if caching mode  	 * and second level.  	 */ -	if (cap_caching_mode(iommu->cap) && !domain_use_first_level(domain)) +	if (cap_caching_mode(iommu->cap) && !domain->use_first_level)  		iommu_flush_iotlb_psi(iommu, domain, pfn, pages, 0, 1);  	else  		iommu_flush_write_buffer(iommu); @@ -1599,7 +1582,7 @@ static void intel_flush_iotlb_all(struct iommu_domain *domain)  		struct intel_iommu *iommu = info->iommu;  		u16 did = domain_id_iommu(dmar_domain, iommu); -		if (domain_use_first_level(dmar_domain)) +		if (dmar_domain->use_first_level)  			qi_flush_piotlb(iommu, did, PASID_RID2PASID, 0, -1, 0);  		else  			iommu->flush.flush_iotlb(iommu, did, 0, 0, @@ -1772,7 +1755,7 @@ static struct dmar_domain *alloc_domain(unsigned int type)  	domain->nid = NUMA_NO_NODE;  	if (first_level_by_default(type)) -		domain->flags |= DOMAIN_FLAG_USE_FIRST_LEVEL; +		domain->use_first_level = true;  	domain->has_iotlb_device = false;  	INIT_LIST_HEAD(&domain->devices);  	spin_lock_init(&domain->lock); @@ -2064,7 +2047,6 @@ static int domain_context_mapping_one(struct dmar_domain *domain,  	} else {  		iommu_flush_write_buffer(iommu);  	} -	iommu_enable_pci_caps(info);  	ret = 0; @@ -2116,30 +2098,6 @@ domain_context_mapping(struct dmar_domain *domain, struct device *dev)  				      &domain_context_mapping_cb, &data);  } -static int domain_context_mapped_cb(struct pci_dev *pdev, -				    u16 alias, void *opaque) -{ -	struct intel_iommu *iommu = opaque; - -	return !device_context_mapped(iommu, PCI_BUS_NUM(alias), alias & 0xff); -} - -static int domain_context_mapped(struct device *dev) -{ -	struct intel_iommu *iommu; -	u8 bus, devfn; - -	iommu = device_to_iommu(dev, &bus, &devfn); -	if (!iommu) -		return -ENODEV; - -	if (!dev_is_pci(dev)) -		return device_context_mapped(iommu, bus, devfn); - -	return !pci_for_each_dma_alias(to_pci_dev(dev), -				       domain_context_mapped_cb, iommu); -} -  /* Returns a number of VTD pages, but aligned to MM page size */  static inline unsigned long aligned_nrpages(unsigned long host_addr,  					    size_t size) @@ -2229,7 +2187,7 @@ __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,  	attr = prot & (DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP);  	attr |= DMA_FL_PTE_PRESENT; -	if (domain_use_first_level(domain)) { +	if (domain->use_first_level) {  		attr |= DMA_FL_PTE_XD | DMA_FL_PTE_US | DMA_FL_PTE_ACCESS;  		if (prot & DMA_PTE_WRITE)  			attr |= DMA_FL_PTE_DIRTY; @@ -2472,7 +2430,8 @@ static int __init si_domain_init(int hw)  	return 0;  } -static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev) +static int dmar_domain_attach_device(struct dmar_domain *domain, +				     struct device *dev)  {  	struct device_domain_info *info = dev_iommu_priv_get(dev);  	struct intel_iommu *iommu; @@ -2494,18 +2453,11 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)  	/* PASID table is mandatory for a PCI device in scalable mode. */  	if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) { -		ret = intel_pasid_alloc_table(dev); -		if (ret) { -			dev_err(dev, "PASID table allocation failed\n"); -			dmar_remove_one_dev_info(dev); -			return ret; -		} -  		/* Setup the PASID entry for requests without PASID: */  		if (hw_pass_through && domain_type_is_si(domain))  			ret = intel_pasid_setup_pass_through(iommu, domain,  					dev, PASID_RID2PASID); -		else if (domain_use_first_level(domain)) +		else if (domain->use_first_level)  			ret = domain_setup_first_level(iommu, domain, dev,  					PASID_RID2PASID);  		else @@ -2513,7 +2465,7 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)  					dev, PASID_RID2PASID);  		if (ret) {  			dev_err(dev, "Setup RID2PASID failed\n"); -			dmar_remove_one_dev_info(dev); +			device_block_translation(dev);  			return ret;  		}  	} @@ -2521,10 +2473,12 @@ static int domain_add_dev_info(struct dmar_domain *domain, struct device *dev)  	ret = domain_context_mapping(domain, dev);  	if (ret) {  		dev_err(dev, "Domain context map failed\n"); -		dmar_remove_one_dev_info(dev); +		device_block_translation(dev);  		return ret;  	} +	iommu_enable_pci_caps(info); +  	return 0;  } @@ -4125,9 +4079,8 @@ static void dmar_remove_one_dev_info(struct device *dev)  			intel_pasid_tear_down_entry(iommu, info->dev,  					PASID_RID2PASID, false); -		iommu_disable_dev_iotlb(info); +		iommu_disable_pci_caps(info);  		domain_context_clear(info); -		intel_pasid_free_table(info->dev);  	}  	spin_lock_irqsave(&domain->lock, flags); @@ -4138,6 +4091,37 @@ static void dmar_remove_one_dev_info(struct device *dev)  	info->domain = NULL;  } +/* + * Clear the page table pointer in context or pasid table entries so that + * all DMA requests without PASID from the device are blocked. If the page + * table has been set, clean up the data structures. + */ +static void device_block_translation(struct device *dev) +{ +	struct device_domain_info *info = dev_iommu_priv_get(dev); +	struct intel_iommu *iommu = info->iommu; +	unsigned long flags; + +	iommu_disable_pci_caps(info); +	if (!dev_is_real_dma_subdevice(dev)) { +		if (sm_supported(iommu)) +			intel_pasid_tear_down_entry(iommu, dev, +						    PASID_RID2PASID, false); +		else +			domain_context_clear(info); +	} + +	if (!info->domain) +		return; + +	spin_lock_irqsave(&info->domain->lock, flags); +	list_del(&info->link); +	spin_unlock_irqrestore(&info->domain->lock, flags); + +	domain_detach_iommu(info->domain, iommu); +	info->domain = NULL; +} +  static int md_domain_init(struct dmar_domain *domain, int guest_width)  {  	int adjust_width; @@ -4159,12 +4143,28 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)  	return 0;  } +static int blocking_domain_attach_dev(struct iommu_domain *domain, +				      struct device *dev) +{ +	device_block_translation(dev); +	return 0; +} + +static struct iommu_domain blocking_domain = { +	.ops = &(const struct iommu_domain_ops) { +		.attach_dev	= blocking_domain_attach_dev, +		.free		= intel_iommu_domain_free +	} +}; +  static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)  {  	struct dmar_domain *dmar_domain;  	struct iommu_domain *domain;  	switch (type) { +	case IOMMU_DOMAIN_BLOCKED: +		return &blocking_domain;  	case IOMMU_DOMAIN_DMA:  	case IOMMU_DOMAIN_DMA_FQ:  	case IOMMU_DOMAIN_UNMANAGED: @@ -4188,6 +4188,8 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)  		return domain;  	case IOMMU_DOMAIN_IDENTITY:  		return &si_domain->domain; +	case IOMMU_DOMAIN_SVA: +		return intel_svm_domain_alloc();  	default:  		return NULL;  	} @@ -4197,7 +4199,7 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)  static void intel_iommu_domain_free(struct iommu_domain *domain)  { -	if (domain != &si_domain->domain) +	if (domain != &si_domain->domain && domain != &blocking_domain)  		domain_exit(to_dmar_domain(domain));  } @@ -4213,19 +4215,15 @@ static int prepare_domain_attach_device(struct iommu_domain *domain,  		return -ENODEV;  	if (dmar_domain->force_snooping && !ecap_sc_support(iommu->ecap)) -		return -EOPNOTSUPP; +		return -EINVAL;  	/* check if this iommu agaw is sufficient for max mapped address */  	addr_width = agaw_to_width(iommu->agaw);  	if (addr_width > cap_mgaw(iommu->cap))  		addr_width = cap_mgaw(iommu->cap); -	if (dmar_domain->max_addr > (1LL << addr_width)) { -		dev_err(dev, "%s: iommu width (%d) is not " -		        "sufficient for the mapped address (%llx)\n", -		        __func__, addr_width, dmar_domain->max_addr); -		return -EFAULT; -	} +	if (dmar_domain->max_addr > (1LL << addr_width)) +		return -EINVAL;  	dmar_domain->gaw = addr_width;  	/* @@ -4248,6 +4246,7 @@ static int prepare_domain_attach_device(struct iommu_domain *domain,  static int intel_iommu_attach_device(struct iommu_domain *domain,  				     struct device *dev)  { +	struct device_domain_info *info = dev_iommu_priv_get(dev);  	int ret;  	if (domain->type == IOMMU_DOMAIN_UNMANAGED && @@ -4256,25 +4255,14 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,  		return -EPERM;  	} -	/* normally dev is not mapped */ -	if (unlikely(domain_context_mapped(dev))) { -		struct device_domain_info *info = dev_iommu_priv_get(dev); - -		if (info->domain) -			dmar_remove_one_dev_info(dev); -	} +	if (info->domain) +		device_block_translation(dev);  	ret = prepare_domain_attach_device(domain, dev);  	if (ret)  		return ret; -	return domain_add_dev_info(to_dmar_domain(domain), dev); -} - -static void intel_iommu_detach_device(struct iommu_domain *domain, -				      struct device *dev) -{ -	dmar_remove_one_dev_info(dev); +	return dmar_domain_attach_device(to_dmar_domain(domain), dev);  }  static int intel_iommu_map(struct iommu_domain *domain, @@ -4438,7 +4426,7 @@ static void domain_set_force_snooping(struct dmar_domain *domain)  	 * Second level page table supports per-PTE snoop control. The  	 * iommu_map() interface will handle this by setting SNP bit.  	 */ -	if (!domain_use_first_level(domain)) { +	if (!domain->use_first_level) {  		domain->set_pte_snp = true;  		return;  	} @@ -4471,14 +4459,20 @@ static bool intel_iommu_enforce_cache_coherency(struct iommu_domain *domain)  static bool intel_iommu_capable(struct device *dev, enum iommu_cap cap)  { -	if (cap == IOMMU_CAP_CACHE_COHERENCY) +	struct device_domain_info *info = dev_iommu_priv_get(dev); + +	switch (cap) { +	case IOMMU_CAP_CACHE_COHERENCY:  		return true; -	if (cap == IOMMU_CAP_INTR_REMAP) +	case IOMMU_CAP_INTR_REMAP:  		return irq_remapping_enabled == 1; -	if (cap == IOMMU_CAP_PRE_BOOT_PROTECTION) +	case IOMMU_CAP_PRE_BOOT_PROTECTION:  		return dmar_platform_optin(); - -	return false; +	case IOMMU_CAP_ENFORCE_CACHE_COHERENCY: +		return ecap_sc_support(info->iommu->ecap); +	default: +		return false; +	}  }  static struct iommu_device *intel_iommu_probe_device(struct device *dev) @@ -4487,6 +4481,7 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)  	struct device_domain_info *info;  	struct intel_iommu *iommu;  	u8 bus, devfn; +	int ret;  	iommu = device_to_iommu(dev, &bus, &devfn);  	if (!iommu || !iommu->iommu.ops) @@ -4531,6 +4526,16 @@ static struct iommu_device *intel_iommu_probe_device(struct device *dev)  	dev_iommu_priv_set(dev, info); +	if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) { +		ret = intel_pasid_alloc_table(dev); +		if (ret) { +			dev_err(dev, "PASID table allocation failed\n"); +			dev_iommu_priv_set(dev, NULL); +			kfree(info); +			return ERR_PTR(ret); +		} +	} +  	return &iommu->iommu;  } @@ -4539,6 +4544,7 @@ static void intel_iommu_release_device(struct device *dev)  	struct device_domain_info *info = dev_iommu_priv_get(dev);  	dmar_remove_one_dev_info(dev); +	intel_pasid_free_table(dev);  	dev_iommu_priv_set(dev, NULL);  	kfree(info);  	set_dma_ops(dev, NULL); @@ -4732,6 +4738,28 @@ static void intel_iommu_iotlb_sync_map(struct iommu_domain *domain,  		__mapping_notify_one(info->iommu, dmar_domain, pfn, pages);  } +static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) +{ +	struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL); +	struct iommu_domain *domain; + +	/* Domain type specific cleanup: */ +	domain = iommu_get_domain_for_dev_pasid(dev, pasid, 0); +	if (domain) { +		switch (domain->type) { +		case IOMMU_DOMAIN_SVA: +			intel_svm_remove_dev_pasid(dev, pasid); +			break; +		default: +			/* should never reach here */ +			WARN_ON(1); +			break; +		} +	} + +	intel_pasid_tear_down_entry(iommu, dev, pasid, false); +} +  const struct iommu_ops intel_iommu_ops = {  	.capable		= intel_iommu_capable,  	.domain_alloc		= intel_iommu_domain_alloc, @@ -4744,16 +4772,13 @@ const struct iommu_ops intel_iommu_ops = {  	.dev_disable_feat	= intel_iommu_dev_disable_feat,  	.is_attach_deferred	= intel_iommu_is_attach_deferred,  	.def_domain_type	= device_def_domain_type, +	.remove_dev_pasid	= intel_iommu_remove_dev_pasid,  	.pgsize_bitmap		= SZ_4K,  #ifdef CONFIG_INTEL_IOMMU_SVM -	.sva_bind		= intel_svm_bind, -	.sva_unbind		= intel_svm_unbind, -	.sva_get_pasid		= intel_svm_get_pasid,  	.page_response		= intel_svm_page_response,  #endif  	.default_domain_ops = &(const struct iommu_domain_ops) {  		.attach_dev		= intel_iommu_attach_device, -		.detach_dev		= intel_iommu_detach_device,  		.map_pages		= intel_iommu_map_pages,  		.unmap_pages		= intel_iommu_unmap_pages,  		.iotlb_sync_map		= intel_iommu_iotlb_sync_map, diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h index b3d82d7093e6..06e61e474856 100644 --- a/drivers/iommu/intel/iommu.h +++ b/drivers/iommu/intel/iommu.h @@ -480,8 +480,6 @@ enum {  #define VTD_FLAG_IRQ_REMAP_PRE_ENABLED	(1 << 1)  #define VTD_FLAG_SVM_CAPABLE		(1 << 2) -extern int intel_iommu_sm; -  #define sm_supported(iommu)	(intel_iommu_sm && ecap_smts((iommu)->ecap))  #define pasid_supported(iommu)	(sm_supported(iommu) &&			\  				 ecap_pasid((iommu)->ecap)) @@ -517,14 +515,6 @@ struct context_entry {  	u64 hi;  }; -/* - * When VT-d works in the scalable mode, it allows DMA translation to - * happen through either first level or second level page table. This - * bit marks that the DMA translation for the domain goes through the - * first level page table, otherwise, it goes through the second level. - */ -#define DOMAIN_FLAG_USE_FIRST_LEVEL		BIT(1) -  struct iommu_domain_info {  	struct intel_iommu *iommu;  	unsigned int refcnt;		/* Refcount of devices per iommu */ @@ -541,6 +531,11 @@ struct dmar_domain {  	u8 iommu_coherency: 1;		/* indicate coherency of iommu access */  	u8 force_snooping : 1;		/* Create IOPTEs with snoop control */  	u8 set_pte_snp:1; +	u8 use_first_level:1;		/* DMA translation for the domain goes +					 * through the first level page table, +					 * otherwise, goes through the second +					 * level. +					 */  	spinlock_t lock;		/* Protect device tracking lists */  	struct list_head devices;	/* all devices' list */ @@ -550,8 +545,6 @@ struct dmar_domain {  	/* adjusted guest address width, 0 is level 2 30-bit */  	int		agaw; - -	int		flags;		/* flags to find out type of domain */  	int		iommu_superpage;/* Level of superpages supported:  					   0 == 4KiB (no superpages), 1 == 2MiB,  					   2 == 1GiB, 3 == 512GiB, 4 == 1TiB */ @@ -753,12 +746,10 @@ struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn);  extern void intel_svm_check(struct intel_iommu *iommu);  extern int intel_svm_enable_prq(struct intel_iommu *iommu);  extern int intel_svm_finish_prq(struct intel_iommu *iommu); -struct iommu_sva *intel_svm_bind(struct device *dev, struct mm_struct *mm, -				 void *drvdata); -void intel_svm_unbind(struct iommu_sva *handle); -u32 intel_svm_get_pasid(struct iommu_sva *handle);  int intel_svm_page_response(struct device *dev, struct iommu_fault_event *evt,  			    struct iommu_page_response *msg); +struct iommu_domain *intel_svm_domain_alloc(void); +void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid);  struct intel_svm_dev {  	struct list_head list; @@ -783,6 +774,14 @@ struct intel_svm {  };  #else  static inline void intel_svm_check(struct intel_iommu *iommu) {} +static inline struct iommu_domain *intel_svm_domain_alloc(void) +{ +	return NULL; +} + +static inline void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid) +{ +}  #endif  #ifdef CONFIG_INTEL_IOMMU_DEBUGFS @@ -798,6 +797,7 @@ struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,  extern const struct iommu_ops intel_iommu_ops;  #ifdef CONFIG_INTEL_IOMMU +extern int intel_iommu_sm;  extern int iommu_calculate_agaw(struct intel_iommu *iommu);  extern int iommu_calculate_max_sagaw(struct intel_iommu *iommu);  extern int dmar_disabled; @@ -813,6 +813,7 @@ static inline int iommu_calculate_max_sagaw(struct intel_iommu *iommu)  }  #define dmar_disabled	(1)  #define intel_iommu_enabled (0) +#define intel_iommu_sm (0)  #endif  static inline const char *decode_prq_descriptor(char *str, size_t size, diff --git a/drivers/iommu/intel/irq_remapping.c b/drivers/iommu/intel/irq_remapping.c index a723f53ba472..f58f5f57af78 100644 --- a/drivers/iommu/intel/irq_remapping.c +++ b/drivers/iommu/intel/irq_remapping.c @@ -174,7 +174,6 @@ static int modify_irte(struct irq_2_iommu *irq_iommu,  	index = irq_iommu->irte_index + irq_iommu->sub_handle;  	irte = &iommu->ir_table->base[index]; -#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE)  	if ((irte->pst == 1) || (irte_modified->pst == 1)) {  		bool ret; @@ -188,11 +187,9 @@ static int modify_irte(struct irq_2_iommu *irq_iommu,  		 * same as the old value.  		 */  		WARN_ON(!ret); -	} else -#endif -	{ -		set_64bit(&irte->low, irte_modified->low); -		set_64bit(&irte->high, irte_modified->high); +	} else { +		WRITE_ONCE(irte->low, irte_modified->low); +		WRITE_ONCE(irte->high, irte_modified->high);  	}  	__iommu_flush_cache(iommu, irte, sizeof(*irte)); @@ -250,8 +247,8 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)  	end = start + (1 << irq_iommu->irte_mask);  	for (entry = start; entry < end; entry++) { -		set_64bit(&entry->low, 0); -		set_64bit(&entry->high, 0); +		WRITE_ONCE(entry->low, 0); +		WRITE_ONCE(entry->high, 0);  	}  	bitmap_release_region(iommu->ir_table->bitmap, index,  			      irq_iommu->irte_mask); diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c index e13d7e5273e1..fb3c7020028d 100644 --- a/drivers/iommu/intel/pasid.c +++ b/drivers/iommu/intel/pasid.c @@ -101,8 +101,10 @@ int intel_pasid_alloc_table(struct device *dev)  	might_sleep();  	info = dev_iommu_priv_get(dev); -	if (WARN_ON(!info || !dev_is_pci(dev) || info->pasid_table)) -		return -EINVAL; +	if (WARN_ON(!info || !dev_is_pci(dev))) +		return -ENODEV; +	if (WARN_ON(info->pasid_table)) +		return -EEXIST;  	pasid_table = kzalloc(sizeof(*pasid_table), GFP_KERNEL);  	if (!pasid_table) diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index 03b25358946c..c76b66263467 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -24,7 +24,7 @@  #include "iommu.h"  #include "pasid.h"  #include "perf.h" -#include "../iommu-sva-lib.h" +#include "../iommu-sva.h"  #include "trace.h"  static irqreturn_t prq_event_thread(int irq, void *d); @@ -299,19 +299,9 @@ out:  	return 0;  } -static int intel_svm_alloc_pasid(struct device *dev, struct mm_struct *mm, -				 unsigned int flags) -{ -	ioasid_t max_pasid = dev_is_pci(dev) ? -			pci_max_pasids(to_pci_dev(dev)) : intel_pasid_max_id; - -	return iommu_sva_alloc_pasid(mm, PASID_MIN, max_pasid - 1); -} -  static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,  					   struct device *dev, -					   struct mm_struct *mm, -					   unsigned int flags) +					   struct mm_struct *mm)  {  	struct device_domain_info *info = dev_iommu_priv_get(dev);  	struct intel_svm_dev *sdev; @@ -327,22 +317,18 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,  		svm->pasid = mm->pasid;  		svm->mm = mm; -		svm->flags = flags;  		INIT_LIST_HEAD_RCU(&svm->devs); -		if (!(flags & SVM_FLAG_SUPERVISOR_MODE)) { -			svm->notifier.ops = &intel_mmuops; -			ret = mmu_notifier_register(&svm->notifier, mm); -			if (ret) { -				kfree(svm); -				return ERR_PTR(ret); -			} +		svm->notifier.ops = &intel_mmuops; +		ret = mmu_notifier_register(&svm->notifier, mm); +		if (ret) { +			kfree(svm); +			return ERR_PTR(ret);  		}  		ret = pasid_private_add(svm->pasid, svm);  		if (ret) { -			if (svm->notifier.ops) -				mmu_notifier_unregister(&svm->notifier, mm); +			mmu_notifier_unregister(&svm->notifier, mm);  			kfree(svm);  			return ERR_PTR(ret);  		} @@ -377,9 +363,7 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,  	}  	/* Setup the pasid table: */ -	sflags = (flags & SVM_FLAG_SUPERVISOR_MODE) ? -			PASID_FLAG_SUPERVISOR_MODE : 0; -	sflags |= cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0; +	sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;  	ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, mm->pasid,  					    FLPT_DEFAULT_DID, sflags);  	if (ret) @@ -393,8 +377,7 @@ free_sdev:  	kfree(sdev);  free_svm:  	if (list_empty(&svm->devs)) { -		if (svm->notifier.ops) -			mmu_notifier_unregister(&svm->notifier, mm); +		mmu_notifier_unregister(&svm->notifier, mm);  		pasid_private_remove(mm->pasid);  		kfree(svm);  	} @@ -787,67 +770,6 @@ prq_advance:  	return IRQ_RETVAL(handled);  } -struct iommu_sva *intel_svm_bind(struct device *dev, struct mm_struct *mm, void *drvdata) -{ -	struct intel_iommu *iommu = device_to_iommu(dev, NULL, NULL); -	unsigned int flags = 0; -	struct iommu_sva *sva; -	int ret; - -	if (drvdata) -		flags = *(unsigned int *)drvdata; - -	if (flags & SVM_FLAG_SUPERVISOR_MODE) { -		if (!ecap_srs(iommu->ecap)) { -			dev_err(dev, "%s: Supervisor PASID not supported\n", -				iommu->name); -			return ERR_PTR(-EOPNOTSUPP); -		} - -		if (mm) { -			dev_err(dev, "%s: Supervisor PASID with user provided mm\n", -				iommu->name); -			return ERR_PTR(-EINVAL); -		} - -		mm = &init_mm; -	} - -	mutex_lock(&pasid_mutex); -	ret = intel_svm_alloc_pasid(dev, mm, flags); -	if (ret) { -		mutex_unlock(&pasid_mutex); -		return ERR_PTR(ret); -	} - -	sva = intel_svm_bind_mm(iommu, dev, mm, flags); -	mutex_unlock(&pasid_mutex); - -	return sva; -} - -void intel_svm_unbind(struct iommu_sva *sva) -{ -	struct intel_svm_dev *sdev = to_intel_svm_dev(sva); - -	mutex_lock(&pasid_mutex); -	intel_svm_unbind_mm(sdev->dev, sdev->pasid); -	mutex_unlock(&pasid_mutex); -} - -u32 intel_svm_get_pasid(struct iommu_sva *sva) -{ -	struct intel_svm_dev *sdev; -	u32 pasid; - -	mutex_lock(&pasid_mutex); -	sdev = to_intel_svm_dev(sva); -	pasid = sdev->pasid; -	mutex_unlock(&pasid_mutex); - -	return pasid; -} -  int intel_svm_page_response(struct device *dev,  			    struct iommu_fault_event *evt,  			    struct iommu_page_response *msg) @@ -918,3 +840,50 @@ int intel_svm_page_response(struct device *dev,  out:  	return ret;  } + +void intel_svm_remove_dev_pasid(struct device *dev, ioasid_t pasid) +{ +	mutex_lock(&pasid_mutex); +	intel_svm_unbind_mm(dev, pasid); +	mutex_unlock(&pasid_mutex); +} + +static int intel_svm_set_dev_pasid(struct iommu_domain *domain, +				   struct device *dev, ioasid_t pasid) +{ +	struct device_domain_info *info = dev_iommu_priv_get(dev); +	struct intel_iommu *iommu = info->iommu; +	struct mm_struct *mm = domain->mm; +	struct iommu_sva *sva; +	int ret = 0; + +	mutex_lock(&pasid_mutex); +	sva = intel_svm_bind_mm(iommu, dev, mm); +	if (IS_ERR(sva)) +		ret = PTR_ERR(sva); +	mutex_unlock(&pasid_mutex); + +	return ret; +} + +static void intel_svm_domain_free(struct iommu_domain *domain) +{ +	kfree(to_dmar_domain(domain)); +} + +static const struct iommu_domain_ops intel_svm_domain_ops = { +	.set_dev_pasid		= intel_svm_set_dev_pasid, +	.free			= intel_svm_domain_free +}; + +struct iommu_domain *intel_svm_domain_alloc(void) +{ +	struct dmar_domain *domain; + +	domain = kzalloc(sizeof(*domain), GFP_KERNEL); +	if (!domain) +		return NULL; +	domain->domain.ops = &intel_svm_domain_ops; + +	return &domain->domain; +}  | 
