2014-06-10 05:41:57 +04:00
/*
* EEH functionality support for VFIO devices . The feature is only
* available on sPAPR compatible platforms .
*
* Copyright Gavin Shan , IBM Corporation 2014.
*
* 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 .
*/
2014-08-08 20:37:51 +04:00
# include <linux/module.h>
2014-06-10 05:41:57 +04:00
# include <linux/uaccess.h>
# include <linux/vfio.h>
# include <asm/eeh.h>
2014-08-08 20:37:51 +04:00
# define DRIVER_VERSION "0.1"
# define DRIVER_AUTHOR "Gavin Shan, IBM Corporation"
# define DRIVER_DESC "VFIO IOMMU SPAPR EEH"
2014-06-10 05:41:57 +04:00
/* We might build address mapping here for "fast" path later */
2014-08-08 20:39:16 +04:00
void vfio_spapr_pci_eeh_open ( struct pci_dev * pdev )
2014-06-10 05:41:57 +04:00
{
2014-08-08 20:39:16 +04:00
eeh_dev_open ( pdev ) ;
2014-06-10 05:41:57 +04:00
}
2014-08-08 20:36:20 +04:00
EXPORT_SYMBOL_GPL ( vfio_spapr_pci_eeh_open ) ;
2014-06-10 05:41:57 +04:00
void vfio_spapr_pci_eeh_release ( struct pci_dev * pdev )
{
eeh_dev_release ( pdev ) ;
}
2014-08-08 20:36:20 +04:00
EXPORT_SYMBOL_GPL ( vfio_spapr_pci_eeh_release ) ;
2014-06-10 05:41:57 +04:00
long vfio_spapr_iommu_eeh_ioctl ( struct iommu_group * group ,
unsigned int cmd , unsigned long arg )
{
struct eeh_pe * pe ;
struct vfio_eeh_pe_op op ;
unsigned long minsz ;
long ret = - EINVAL ;
switch ( cmd ) {
case VFIO_CHECK_EXTENSION :
if ( arg = = VFIO_EEH )
ret = eeh_enabled ( ) ? 1 : 0 ;
else
ret = 0 ;
break ;
case VFIO_EEH_PE_OP :
pe = eeh_iommu_group_to_pe ( group ) ;
if ( ! pe )
return - ENODEV ;
minsz = offsetofend ( struct vfio_eeh_pe_op , op ) ;
if ( copy_from_user ( & op , ( void __user * ) arg , minsz ) )
return - EFAULT ;
if ( op . argsz < minsz | | op . flags )
return - EINVAL ;
switch ( op . op ) {
case VFIO_EEH_PE_DISABLE :
ret = eeh_pe_set_option ( pe , EEH_OPT_DISABLE ) ;
break ;
case VFIO_EEH_PE_ENABLE :
ret = eeh_pe_set_option ( pe , EEH_OPT_ENABLE ) ;
break ;
case VFIO_EEH_PE_UNFREEZE_IO :
ret = eeh_pe_set_option ( pe , EEH_OPT_THAW_MMIO ) ;
break ;
case VFIO_EEH_PE_UNFREEZE_DMA :
ret = eeh_pe_set_option ( pe , EEH_OPT_THAW_DMA ) ;
break ;
case VFIO_EEH_PE_GET_STATE :
ret = eeh_pe_get_state ( pe ) ;
break ;
case VFIO_EEH_PE_RESET_DEACTIVATE :
2018-11-29 06:16:41 +03:00
ret = eeh_pe_reset ( pe , EEH_RESET_DEACTIVATE , true ) ;
2014-06-10 05:41:57 +04:00
break ;
case VFIO_EEH_PE_RESET_HOT :
2018-11-29 06:16:41 +03:00
ret = eeh_pe_reset ( pe , EEH_RESET_HOT , true ) ;
2014-06-10 05:41:57 +04:00
break ;
case VFIO_EEH_PE_RESET_FUNDAMENTAL :
2018-11-29 06:16:41 +03:00
ret = eeh_pe_reset ( pe , EEH_RESET_FUNDAMENTAL , true ) ;
2014-06-10 05:41:57 +04:00
break ;
case VFIO_EEH_PE_CONFIGURE :
ret = eeh_pe_configure ( pe ) ;
break ;
2015-03-26 08:42:09 +03:00
case VFIO_EEH_PE_INJECT_ERR :
minsz = offsetofend ( struct vfio_eeh_pe_op , err . mask ) ;
if ( op . argsz < minsz )
return - EINVAL ;
if ( copy_from_user ( & op , ( void __user * ) arg , minsz ) )
return - EFAULT ;
ret = eeh_pe_inject_err ( pe , op . err . type , op . err . func ,
op . err . addr , op . err . mask ) ;
break ;
2014-06-10 05:41:57 +04:00
default :
ret = - EINVAL ;
}
}
return ret ;
}
2014-09-29 20:31:51 +04:00
EXPORT_SYMBOL_GPL ( vfio_spapr_iommu_eeh_ioctl ) ;
2014-08-08 20:37:51 +04:00
MODULE_VERSION ( DRIVER_VERSION ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( DRIVER_AUTHOR ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;