diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 4f4132d0fca40de669e30147b8e4627ff34bcbb6..80aeff486e0c5a014aeb9176e97fe4e413eda494 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -112,6 +112,17 @@ config IOMMU_DMA select IOMMU_IOVA 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 bool select IOMMU_API diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index a6f94cc89f92444a1e72efb7013c426409fe06b7..1533a9ff47770a1b5664e1b04893222d070ab47a 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_IOMMU_API) += iommu.o obj-$(CONFIG_IOMMU_API) += iommu-traces.o obj-$(CONFIG_IOMMU_API) += iommu-sysfs.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_SVA) += iommu-sva.o obj-$(CONFIG_IOMMU_PAGE_FAULT) += io-pgfault.o diff --git a/drivers/iommu/iommu-process.c b/drivers/iommu/iommu-process.c new file mode 100644 index 0000000000000000000000000000000000000000..66ee91c140940c0ae831946ae0378bb91742c1cc --- /dev/null +++ b/drivers/iommu/iommu-process.c @@ -0,0 +1,68 @@ +// 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 + */ + +#include +#include +#include +#include + +/* 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); diff --git a/include/linux/iommu.h b/include/linux/iommu.h index e6ffd426e267792405a93be7efc2e22741e99d7f..8bec6a66e0656ec7115ff66ad610616a1e54596f 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -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_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) struct iommu_domain_geometry { @@ -101,12 +106,27 @@ struct iommu_domain { unsigned long pgsize_bitmap; /* Bitmap of page sizes in use */ iommu_fault_handler_t handler; void *handler_token; + iommu_process_exit_handler_t process_exit; + void *process_exit_token; struct iommu_domain_geometry geometry; void *iova_cookie; + unsigned int min_pasid, max_pasid; + struct list_head processes; + 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 { int pasid; /* IOMMU_SVA_FEAT_* */ @@ -1125,4 +1145,16 @@ void iommu_debugfs_setup(void); static inline void iommu_debugfs_setup(void) {} #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 */