提交 798b045d 编写于 作者: J Jean-Philippe Brucker 提交者: Xie XiuQi

iommu: Introduce Shared Virtual Addressing API

hulk inclusion
category: feature
bugzilla: 14369
CVE: NA
-------------------

Shared Virtual Addressing (SVA) provides a way for device drivers to bind
process address spaces to devices. This requires the IOMMU to support page
table format and features compatible with the CPUs, and usually requires
the system to support I/O Page Faults (IOPF) and Process Address Space ID
(PASID). When all of these are available, DMA can access virtual addresses
of a process. A PASID is allocated for each process, and the device driver
programs it into the device in an implementation-specific way.

Add a new API for sharing process page tables with devices. Introduce two
IOMMU operations, sva_device_init() and sva_device_shutdown(), that
prepare the IOMMU driver for SVA. For example allocate PASID tables and
fault queues. Subsequent patches will implement the bind() and unbind()
operations.

Support for I/O Page Faults will be added in a later patch using a new
feature bit (IOMMU_SVA_FEAT_IOPF). With the current API users must pin
down all shared mappings. Other feature bits that may be added in the
future are IOMMU_SVA_FEAT_PRIVATE, to support private PASID address
spaces, and IOMMU_SVA_FEAT_NO_PASID, to bind the whole device address
space to a process.
Signed-off-by: NJean-Philippe Brucker <jean-philippe.brucker@arm.com>
Signed-off-by: NFang Lijun <fanglijun3@huawei.com>
Reviewed-by: NHanjun Guo <guohanjun@huawei.com>
Reviewed-by: NZhen Lei <thunder.leizhen@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 23ceabf4
......@@ -95,6 +95,10 @@ config IOMMU_DMA
select IOMMU_IOVA
select NEED_SG_DMA_LENGTH
config IOMMU_SVA
bool
select IOMMU_API
config FSL_PAMU
bool "Freescale IOMMU support"
depends on PCI
......
......@@ -4,6 +4,7 @@ obj-$(CONFIG_IOMMU_API) += iommu-traces.o
obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o
obj-$(CONFIG_IOMMU_DEBUGFS) += iommu-debugfs.o
obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o
obj-$(CONFIG_IOMMU_SVA) += iommu-sva.o
obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o
obj-$(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) += io-pgtable-arm-v7s.o
obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Manage PASIDs and bind process address spaces to devices.
*
* Copyright (C) 2018 ARM Ltd.
*/
#include <linux/iommu.h>
#include <linux/slab.h>
/**
* iommu_sva_device_init() - Initialize Shared Virtual Addressing for a device
* @dev: the device
* @features: bitmask of features that need to be initialized
* @max_pasid: max PASID value supported by the device
*
* Users of the bind()/unbind() API must call this function to initialize all
* features required for SVA.
*
* The device must support multiple address spaces (e.g. PCI PASID). By default
* the PASID allocated during bind() is limited by the IOMMU capacity, and by
* the device PASID width defined in the PCI capability or in the firmware
* description. Setting @max_pasid to a non-zero value smaller than this limit
* overrides it.
*
* The device should not be performing any DMA while this function is running,
* otherwise the behavior is undefined.
*
* Return 0 if initialization succeeded, or an error.
*/
int iommu_sva_device_init(struct device *dev, unsigned long features,
unsigned int max_pasid)
{
int ret;
struct iommu_sva_param *param;
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
if (!domain || !domain->ops->sva_device_init)
return -ENODEV;
if (features)
return -EINVAL;
param = kzalloc(sizeof(*param), GFP_KERNEL);
if (!param)
return -ENOMEM;
param->features = features;
param->max_pasid = max_pasid;
/*
* IOMMU driver updates the limits depending on the IOMMU and device
* capabilities.
*/
ret = domain->ops->sva_device_init(dev, param);
if (ret)
goto err_free_param;
mutex_lock(&dev->iommu_param->lock);
if (dev->iommu_param->sva_param)
ret = -EEXIST;
else
dev->iommu_param->sva_param = param;
mutex_unlock(&dev->iommu_param->lock);
if (ret)
goto err_device_shutdown;
return 0;
err_device_shutdown:
if (domain->ops->sva_device_shutdown)
domain->ops->sva_device_shutdown(dev, param);
err_free_param:
kfree(param);
return ret;
}
EXPORT_SYMBOL_GPL(iommu_sva_device_init);
/**
* iommu_sva_device_shutdown() - Shutdown Shared Virtual Addressing for a device
* @dev: the device
*
* Disable SVA. Device driver should ensure that the device isn't performing any
* DMA while this function is running.
*/
int iommu_sva_device_shutdown(struct device *dev)
{
struct iommu_sva_param *param;
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
if (!domain)
return -ENODEV;
mutex_lock(&dev->iommu_param->lock);
param = dev->iommu_param->sva_param;
dev->iommu_param->sva_param = NULL;
mutex_unlock(&dev->iommu_param->lock);
if (!param)
return -ENODEV;
if (domain->ops->sva_device_shutdown)
domain->ops->sva_device_shutdown(dev, param);
kfree(param);
return 0;
}
EXPORT_SYMBOL_GPL(iommu_sva_device_shutdown);
......@@ -212,6 +212,12 @@ struct page_response_msg {
u64 private_data;
};
struct iommu_sva_param {
unsigned long features;
unsigned int min_pasid;
unsigned int max_pasid;
};
/**
* struct iommu_ops - iommu ops and capabilities
* @capable: check capability
......@@ -219,6 +225,8 @@ struct page_response_msg {
* @domain_free: free iommu domain
* @attach_dev: attach device to an iommu domain
* @detach_dev: detach device from an iommu domain
* @sva_device_init: initialize Shared Virtual Adressing for a device
* @sva_device_shutdown: shutdown Shared Virtual Adressing for a device
* @map: map a physically contiguous memory region to an iommu domain
* @unmap: unmap a physically contiguous memory region from an iommu domain
* @flush_tlb_all: Synchronously flush all hardware TLBs for this domain
......@@ -254,6 +262,10 @@ struct iommu_ops {
int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
void (*detach_dev)(struct iommu_domain *domain, struct device *dev);
int (*sva_device_init)(struct device *dev,
struct iommu_sva_param *param);
void (*sva_device_shutdown)(struct device *dev,
struct iommu_sva_param *param);
int (*map)(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot);
size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
......@@ -409,6 +421,7 @@ struct iommu_fault_param {
* struct iommu_param - collection of per-device IOMMU data
*
* @fault_param: IOMMU detected device fault reporting data
* @sva_param: SVA parameters
*
* TODO: migrate other per device data pointers under iommu_dev_data, e.g.
* struct iommu_group *iommu_group;
......@@ -417,6 +430,7 @@ struct iommu_fault_param {
struct iommu_param {
struct mutex lock;
struct iommu_fault_param *fault_param;
struct iommu_sva_param *sva_param;
};
int iommu_device_register(struct iommu_device *iommu);
......@@ -928,6 +942,24 @@ static inline int iommu_sva_invalidate(struct iommu_domain *domain,
#endif /* CONFIG_IOMMU_API */
#ifdef CONFIG_IOMMU_SVA
extern int iommu_sva_device_init(struct device *dev, unsigned long features,
unsigned int max_pasid);
extern int iommu_sva_device_shutdown(struct device *dev);
#else /* CONFIG_IOMMU_SVA */
static inline int iommu_sva_device_init(struct device *dev,
unsigned long features,
unsigned int max_pasid)
{
return -ENODEV;
}
static inline int iommu_sva_device_shutdown(struct device *dev)
{
return -ENODEV;
}
#endif /* CONFIG_IOMMU_SVA */
#ifdef CONFIG_IOMMU_DEBUGFS
extern struct dentry *iommu_debugfs_dir;
void iommu_debugfs_setup(void);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册