提交 ad9f5b52 编写于 作者: J Jean-Philippe Brucker 提交者: Yang Yingliang

iommu: Add a process_exit callback for device drivers

ascend inclusion
category: feature
bugzilla: 14369
CVE: NA

--------------

IOMMU drivers need a way to bind Linux processes to devices. This is used
for Shared Virtual Memory (SVM), where devices support paging. In that
mode, DMA can directly target virtual addresses of a process.

Introduce boilerplate code for allocating process structures and binding
them to devices. Four operations are added to IOMMU drivers:

When a process exits, we need to ensure that devices attached to it stop
issuing transactions with its PASID. Let device drivers register a
callback to be notified on process exit.

At the moment the callback is set on the domain like the fault handler,
because we don't have a structure available for IOMMU masters. This can
become problematic if different devices in a domain are managed by
distinct device drivers (for example multiple devices in the same group).
The problem is the same for the fault handler, so we'll probably fix them
all at once.
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>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 a6cbc521
...@@ -112,6 +112,17 @@ config IOMMU_DMA ...@@ -112,6 +112,17 @@ config IOMMU_DMA
select IOMMU_IOVA select IOMMU_IOVA
select NEED_SG_DMA_LENGTH select NEED_SG_DMA_LENGTH
config IOMMU_PROCESS
bool "Process management API for the IOMMU"
depends on MMU_NOTIFIER
select IOMMU_API
help
Enable process management for the IOMMU API. In systems that support
it, device drivers can bind processes to devices and share their page
tables using this API.
If unsure, say N here.
config IOMMU_SVA config IOMMU_SVA
bool bool
select IOMMU_API select IOMMU_API
......
...@@ -3,6 +3,7 @@ obj-$(CONFIG_IOMMU_API) += iommu.o ...@@ -3,6 +3,7 @@ obj-$(CONFIG_IOMMU_API) += iommu.o
obj-$(CONFIG_IOMMU_API) += iommu-traces.o obj-$(CONFIG_IOMMU_API) += iommu-traces.o
obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o
obj-$(CONFIG_IOMMU_DEBUGFS) += iommu-debugfs.o obj-$(CONFIG_IOMMU_DEBUGFS) += iommu-debugfs.o
obj-$(CONFIG_IOMMU_PROCESS) += iommu-process.o
obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o
obj-$(CONFIG_IOMMU_SVA) += iommu-sva.o obj-$(CONFIG_IOMMU_SVA) += iommu-sva.o
obj-$(CONFIG_IOMMU_PAGE_FAULT) += io-pgfault.o obj-$(CONFIG_IOMMU_PAGE_FAULT) += io-pgfault.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Track processes bound to devices
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that 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.
*
* You should have received a copy of the GNU General Public License
* along with this program.
*
* Copyright (C) 2017 ARM Ltd.
*
* Author: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
*/
#include <linux/idr.h>
#include <linux/iommu.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
/* Link between a domain and a process */
struct iommu_context {
struct iommu_process *process;
struct iommu_domain *domain;
struct list_head process_head;
struct list_head domain_head;
/* Number of devices that use this context */
refcount_t ref;
};
/**
* iommu_set_process_exit_handler() - set a callback for stopping the use of
* PASID in a device.
* @dev: the device
* @handler: exit handler
* @token: user data, will be passed back to the exit handler
*
* Users of the bind/unbind API should call this function to set a
* device-specific callback telling them when a process is exiting.
*
* After the callback returns, the device must not issue any more transaction
* with the PASIDs given as argument to the handler. It can be a single PASID
* value or the special IOMMU_PROCESS_EXIT_ALL.
*
* The handler itself should return 0 on success, and an appropriate error code
* otherwise.
*/
void iommu_set_process_exit_handler(struct device *dev,
iommu_process_exit_handler_t handler,
void *token)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
if (WARN_ON(!domain))
return;
domain->process_exit = handler;
domain->process_exit_token = token;
}
EXPORT_SYMBOL_GPL(iommu_set_process_exit_handler);
...@@ -63,6 +63,11 @@ typedef int (*iommu_fault_handler_t)(struct iommu_domain *, ...@@ -63,6 +63,11 @@ typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault_event *, void *); typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault_event *, void *);
typedef int (*iommu_mm_exit_handler_t)(struct device *dev, int pasid, void *); typedef int (*iommu_mm_exit_handler_t)(struct device *dev, int pasid, void *);
/* All process are being detached from this device */
#define IOMMU_PROCESS_EXIT_ALL (-1)
typedef int (*iommu_process_exit_handler_t)(struct iommu_domain *, struct device *dev,
int pasid, void *);
#define IOMMU_SVA_FEAT_IOPF (1 << 0) #define IOMMU_SVA_FEAT_IOPF (1 << 0)
struct iommu_domain_geometry { struct iommu_domain_geometry {
...@@ -101,12 +106,27 @@ struct iommu_domain { ...@@ -101,12 +106,27 @@ struct iommu_domain {
unsigned long pgsize_bitmap; /* Bitmap of page sizes in use */ unsigned long pgsize_bitmap; /* Bitmap of page sizes in use */
iommu_fault_handler_t handler; iommu_fault_handler_t handler;
void *handler_token; void *handler_token;
iommu_process_exit_handler_t process_exit;
void *process_exit_token;
struct iommu_domain_geometry geometry; struct iommu_domain_geometry geometry;
void *iova_cookie; void *iova_cookie;
unsigned int min_pasid, max_pasid;
struct list_head processes;
struct list_head mm_list; struct list_head mm_list;
}; };
struct iommu_process {
struct pid *pid;
int pasid;
struct list_head domains;
struct kref kref;
/* Release callback for this process */
void (*release)(struct iommu_process *process);
};
struct io_mm { struct io_mm {
int pasid; int pasid;
/* IOMMU_SVA_FEAT_* */ /* IOMMU_SVA_FEAT_* */
...@@ -1125,4 +1145,16 @@ void iommu_debugfs_setup(void); ...@@ -1125,4 +1145,16 @@ void iommu_debugfs_setup(void);
static inline void iommu_debugfs_setup(void) {} static inline void iommu_debugfs_setup(void) {}
#endif #endif
#ifdef CONFIG_IOMMU_PROCESS
extern void iommu_set_process_exit_handler(struct device *dev,
iommu_process_exit_handler_t cb,
void *token);
#else /* CONFIG_IOMMU_PROCESS */
static inline void iommu_set_process_exit_handler(struct device *dev,
iommu_process_exit_handler_t cb,
void *token)
{
}
#endif /* CONFIG_IOMMU_PROCESS */
#endif /* __LINUX_IOMMU_H */ #endif /* __LINUX_IOMMU_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册