vfio_spapr_eeh.c (2681B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * EEH functionality support for VFIO devices. The feature is only 4 * available on sPAPR compatible platforms. 5 * 6 * Copyright Gavin Shan, IBM Corporation 2014. 7 */ 8 9#include <linux/module.h> 10#include <linux/uaccess.h> 11#include <linux/vfio.h> 12#include <asm/eeh.h> 13 14#define DRIVER_VERSION "0.1" 15#define DRIVER_AUTHOR "Gavin Shan, IBM Corporation" 16#define DRIVER_DESC "VFIO IOMMU SPAPR EEH" 17 18/* We might build address mapping here for "fast" path later */ 19void vfio_spapr_pci_eeh_open(struct pci_dev *pdev) 20{ 21 eeh_dev_open(pdev); 22} 23EXPORT_SYMBOL_GPL(vfio_spapr_pci_eeh_open); 24 25void vfio_spapr_pci_eeh_release(struct pci_dev *pdev) 26{ 27 eeh_dev_release(pdev); 28} 29EXPORT_SYMBOL_GPL(vfio_spapr_pci_eeh_release); 30 31long vfio_spapr_iommu_eeh_ioctl(struct iommu_group *group, 32 unsigned int cmd, unsigned long arg) 33{ 34 struct eeh_pe *pe; 35 struct vfio_eeh_pe_op op; 36 unsigned long minsz; 37 long ret = -EINVAL; 38 39 switch (cmd) { 40 case VFIO_CHECK_EXTENSION: 41 if (arg == VFIO_EEH) 42 ret = eeh_enabled() ? 1 : 0; 43 else 44 ret = 0; 45 break; 46 case VFIO_EEH_PE_OP: 47 pe = eeh_iommu_group_to_pe(group); 48 if (!pe) 49 return -ENODEV; 50 51 minsz = offsetofend(struct vfio_eeh_pe_op, op); 52 if (copy_from_user(&op, (void __user *)arg, minsz)) 53 return -EFAULT; 54 if (op.argsz < minsz || op.flags) 55 return -EINVAL; 56 57 switch (op.op) { 58 case VFIO_EEH_PE_DISABLE: 59 ret = eeh_pe_set_option(pe, EEH_OPT_DISABLE); 60 break; 61 case VFIO_EEH_PE_ENABLE: 62 ret = eeh_pe_set_option(pe, EEH_OPT_ENABLE); 63 break; 64 case VFIO_EEH_PE_UNFREEZE_IO: 65 ret = eeh_pe_set_option(pe, EEH_OPT_THAW_MMIO); 66 break; 67 case VFIO_EEH_PE_UNFREEZE_DMA: 68 ret = eeh_pe_set_option(pe, EEH_OPT_THAW_DMA); 69 break; 70 case VFIO_EEH_PE_GET_STATE: 71 ret = eeh_pe_get_state(pe); 72 break; 73 case VFIO_EEH_PE_RESET_DEACTIVATE: 74 ret = eeh_pe_reset(pe, EEH_RESET_DEACTIVATE, true); 75 break; 76 case VFIO_EEH_PE_RESET_HOT: 77 ret = eeh_pe_reset(pe, EEH_RESET_HOT, true); 78 break; 79 case VFIO_EEH_PE_RESET_FUNDAMENTAL: 80 ret = eeh_pe_reset(pe, EEH_RESET_FUNDAMENTAL, true); 81 break; 82 case VFIO_EEH_PE_CONFIGURE: 83 ret = eeh_pe_configure(pe); 84 break; 85 case VFIO_EEH_PE_INJECT_ERR: 86 minsz = offsetofend(struct vfio_eeh_pe_op, err.mask); 87 if (op.argsz < minsz) 88 return -EINVAL; 89 if (copy_from_user(&op, (void __user *)arg, minsz)) 90 return -EFAULT; 91 92 ret = eeh_pe_inject_err(pe, op.err.type, op.err.func, 93 op.err.addr, op.err.mask); 94 break; 95 default: 96 ret = -EINVAL; 97 } 98 } 99 100 return ret; 101} 102EXPORT_SYMBOL_GPL(vfio_spapr_iommu_eeh_ioctl); 103 104MODULE_VERSION(DRIVER_VERSION); 105MODULE_LICENSE("GPL v2"); 106MODULE_AUTHOR(DRIVER_AUTHOR); 107MODULE_DESCRIPTION(DRIVER_DESC);