// SPDX-License-Identifier: GPL-2.0-only/* * VFIO: IOMMU DMA mapping support for TCE on POWER * * Copyright (C) 2013 IBM Corp. All rights reserved. * Author: Alexey Kardashevskiy <aik@ozlabs.ru> * * Derived from original vfio_iommu_type1.c: * Copyright (C) 2012 Red Hat, Inc. All rights reserved. * Author: Alex Williamson <alex.williamson@redhat.com> */#include<linux/module.h>#include<linux/pci.h>#include<linux/slab.h>#include<linux/uaccess.h>#include<linux/err.h>#include<linux/vfio.h>#include<linux/vmalloc.h>#include<linux/sched/mm.h>#include<linux/sched/signal.h>#include<linux/mm.h>#include<asm/iommu.h>#include<asm/tce.h>#include<asm/mmu_context.h>#define DRIVER_VERSION "0.1"#define DRIVER_AUTHOR "aik@ozlabs.ru"#define DRIVER_DESC "VFIO IOMMU SPAPR TCE"staticvoidtce_iommu_detach_group(void*iommu_data,structiommu_group*iommu_group);/* * VFIO IOMMU fd for SPAPR_TCE IOMMU implementation * * This code handles mapping and unmapping of user data buffers * into DMA'ble space using the IOMMU */structtce_iommu_group{structlist_headnext;structiommu_group*grp;};/* * A container needs to remember which preregistered region it has * referenced to do proper cleanup at the userspace process exit. */structtce_iommu_prereg{structlist_headnext;structmm_iommu_table_group_mem_t*mem;};/* * The container descriptor supports only a single group per container. * Required by the API as the container is not supplied with the IOMMU group * at the moment of initialization. */structtce_container{structmutexlock;boolenabled;boolv2;booldef_window_pending;unsignedlonglocked_pages;structmm_struct*mm;structiommu_table*tables[IOMMU_TABLE_GROUP_MAX_TABLES];structlist_headgroup_list;structlist_headprereg_list;};staticlongtce_iommu_mm_set(structtce_container*container){if(container->mm){if(container->mm==current->mm)return0;return-EPERM;}BUG_ON(!current->mm);container->mm=current->mm;atomic_inc(&container->mm->mm_count);return0;}staticlongtce_iommu_prereg_free(structtce_container*container,structtce_iommu_prereg*tcemem){longret;ret=mm_iommu_put(container->mm,tcemem->mem);if(ret)returnret;list_del(&tcemem