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>
# include <asm/pci_clp.h>
# include <asm/pci_io.h>
2021-08-26 13:39:12 +03:00
# include <linux/vfio_pci_core.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 ,
. header . version = 1 ,
. start_dma = zdev - > start_dma ,
. end_dma = zdev - > end_dma ,
. pchid = zdev - > pchid ,
. vfn = zdev - > vfn ,
. fmb_length = zdev - > fmb_length ,
. pft = zdev - > pft ,
. gid = zdev - > pfgid
} ;
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 ,
. header . version = 1 ,
. 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 ,
. version = zdev - > version
} ;
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 ;
}