2021-08-24 08:37:49 +08:00
// SPDX-License-Identifier: GPL-2.0-only
2020-10-07 14:56:23 -04:00
/*
* VFIO ZPCI devices support
*
* Copyright ( C ) IBM Corp . 2020. All rights reserved .
* Author ( s ) : Pierre Morel < pmorel @ linux . ibm . com >
* Matthew Rosato < mjrosato @ linux . ibm . com >
*/
# include <linux/io.h>
# include <linux/pci.h>
# include <linux/uaccess.h>
# include <linux/vfio.h>
# include <linux/vfio_zdev.h>
2022-06-06 16:33:21 -04:00
# include <linux/kvm_host.h>
2020-10-07 14:56:23 -04:00
# include <asm/pci_clp.h>
# include <asm/pci_io.h>
2022-08-26 16:34:01 -03:00
# include "vfio_pci_priv.h"
2020-10-07 14:56:23 -04:00
/*
* Add the Base PCI Function information to the device info region .
*/
2021-02-01 16:28:24 +00:00
static int zpci_base_cap ( struct zpci_dev * zdev , struct vfio_info_cap * caps )
2020-10-07 14:56:23 -04:00
{
struct vfio_device_info_cap_zpci_base cap = {
. header . id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE ,
2022-06-06 16:33:22 -04:00
. header . version = 2 ,
2020-10-07 14:56:23 -04:00
. start_dma = zdev - > start_dma ,
. end_dma = zdev - > end_dma ,
. pchid = zdev - > pchid ,
. vfn = zdev - > vfn ,
. fmb_length = zdev - > fmb_length ,
. pft = zdev - > pft ,
2022-06-06 16:33:22 -04:00
. gid = zdev - > pfgid ,
. fh = zdev - > fh
2020-10-07 14:56:23 -04:00
} ;
return vfio_info_add_capability ( caps , & cap . header , sizeof ( cap ) ) ;
}
/*
* Add the Base PCI Function Group information to the device info region .
*/
2021-02-01 16:28:24 +00:00
static int zpci_group_cap ( struct zpci_dev * zdev , struct vfio_info_cap * caps )
2020-10-07 14:56:23 -04:00
{
struct vfio_device_info_cap_zpci_group cap = {
. header . id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP ,
2022-06-06 16:33:23 -04:00
. header . version = 2 ,
2020-10-07 14:56:23 -04:00
. dasm = zdev - > dma_mask ,
. msi_addr = zdev - > msi_addr ,
. flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH ,
. mui = zdev - > fmb_update ,
. noi = zdev - > max_msi ,
. maxstbl = ZPCI_MAX_WRITE_SIZE ,
2022-06-06 16:33:23 -04:00
. version = zdev - > version ,
. reserved = 0 ,
. imaxstbl = zdev - > maxstbl
2020-10-07 14:56:23 -04:00
} ;
return vfio_info_add_capability ( caps , & cap . header , sizeof ( cap ) ) ;
}
/*
* Add the device utility string to the device info region .
*/
2021-02-01 16:28:24 +00:00
static int zpci_util_cap ( struct zpci_dev * zdev , struct vfio_info_cap * caps )
2020-10-07 14:56:23 -04:00
{
struct vfio_device_info_cap_zpci_util * cap ;
int cap_size = sizeof ( * cap ) + CLP_UTIL_STR_LEN ;
int ret ;
cap = kmalloc ( cap_size , GFP_KERNEL ) ;
2021-02-01 16:28:25 +00:00
if ( ! cap )
return - ENOMEM ;
2020-10-07 14:56:23 -04:00
cap - > header . id = VFIO_DEVICE_INFO_CAP_ZPCI_UTIL ;
cap - > header . version = 1 ;
cap - > size = CLP_UTIL_STR_LEN ;
memcpy ( cap - > util_str , zdev - > util_str , cap - > size ) ;
ret = vfio_info_add_capability ( caps , & cap - > header , cap_size ) ;
kfree ( cap ) ;
return ret ;
}
/*
* Add the function path string to the device info region .
*/
2021-02-01 16:28:24 +00:00
static int zpci_pfip_cap ( struct zpci_dev * zdev , struct vfio_info_cap * caps )
2020-10-07 14:56:23 -04:00
{
struct vfio_device_info_cap_zpci_pfip * cap ;
int cap_size = sizeof ( * cap ) + CLP_PFIP_NR_SEGMENTS ;
int ret ;
cap = kmalloc ( cap_size , GFP_KERNEL ) ;
2021-02-01 16:28:25 +00:00
if ( ! cap )
return - ENOMEM ;
2020-10-07 14:56:23 -04:00
cap - > header . id = VFIO_DEVICE_INFO_CAP_ZPCI_PFIP ;
cap - > header . version = 1 ;
cap - > size = CLP_PFIP_NR_SEGMENTS ;
memcpy ( cap - > pfip , zdev - > pfip , cap - > size ) ;
ret = vfio_info_add_capability ( caps , & cap - > header , cap_size ) ;
kfree ( cap ) ;
return ret ;
}
/*
* Add all supported capabilities to the VFIO_DEVICE_GET_INFO capability chain .
*/
2021-08-26 13:39:02 +03:00
int vfio_pci_info_zdev_add_caps ( struct vfio_pci_core_device * vdev ,
2020-10-07 14:56:23 -04:00
struct vfio_info_cap * caps )
{
struct zpci_dev * zdev = to_zpci ( vdev - > pdev ) ;
int ret ;
if ( ! zdev )
return - ENODEV ;
2021-02-01 16:28:24 +00:00
ret = zpci_base_cap ( zdev , caps ) ;
2020-10-07 14:56:23 -04:00
if ( ret )
return ret ;
2021-02-01 16:28:24 +00:00
ret = zpci_group_cap ( zdev , caps ) ;
2020-10-07 14:56:23 -04:00
if ( ret )
return ret ;
if ( zdev - > util_str_avail ) {
2021-02-01 16:28:24 +00:00
ret = zpci_util_cap ( zdev , caps ) ;
2020-10-07 14:56:23 -04:00
if ( ret )
return ret ;
}
2021-02-01 16:28:24 +00:00
ret = zpci_pfip_cap ( zdev , caps ) ;
2020-10-07 14:56:23 -04:00
return ret ;
}
2022-06-06 16:33:21 -04:00
int vfio_pci_zdev_open_device ( struct vfio_pci_core_device * vdev )
{
struct zpci_dev * zdev = to_zpci ( vdev - > pdev ) ;
if ( ! zdev )
return - ENODEV ;
if ( ! vdev - > vdev . kvm )
return 0 ;
2022-08-19 14:29:45 +02:00
if ( zpci_kvm_hook . kvm_register )
return zpci_kvm_hook . kvm_register ( zdev , vdev - > vdev . kvm ) ;
return - ENOENT ;
2022-06-06 16:33:21 -04:00
}
void vfio_pci_zdev_close_device ( struct vfio_pci_core_device * vdev )
{
struct zpci_dev * zdev = to_zpci ( vdev - > pdev ) ;
if ( ! zdev | | ! vdev - > vdev . kvm )
return ;
2022-08-19 14:29:45 +02:00
if ( zpci_kvm_hook . kvm_unregister )
zpci_kvm_hook . kvm_unregister ( zdev ) ;
2022-06-06 16:33:21 -04:00
}