1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * VFIO ZPCI devices support 4 * 5 * Copyright (C) IBM Corp. 2020. All rights reserved. 6 * Author(s): Pierre Morel <pmorel@linux.ibm.com> 7 * Matthew Rosato <mjrosato@linux.ibm.com> 8 */ 9 #include <linux/io.h> 10 #include <linux/pci.h> 11 #include <linux/uaccess.h> 12 #include <linux/vfio.h> 13 #include <linux/vfio_zdev.h> 14 #include <asm/pci_clp.h> 15 #include <asm/pci_io.h> 16 17 #include <linux/vfio_pci_core.h> 18 19 /* 20 * Add the Base PCI Function information to the device info region. 21 */ 22 static int zpci_base_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 23 { 24 struct vfio_device_info_cap_zpci_base cap = { 25 .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE, 26 .header.version = 1, 27 .start_dma = zdev->start_dma, 28 .end_dma = zdev->end_dma, 29 .pchid = zdev->pchid, 30 .vfn = zdev->vfn, 31 .fmb_length = zdev->fmb_length, 32 .pft = zdev->pft, 33 .gid = zdev->pfgid 34 }; 35 36 return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); 37 } 38 39 /* 40 * Add the Base PCI Function Group information to the device info region. 41 */ 42 static int zpci_group_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 43 { 44 struct vfio_device_info_cap_zpci_group cap = { 45 .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP, 46 .header.version = 1, 47 .dasm = zdev->dma_mask, 48 .msi_addr = zdev->msi_addr, 49 .flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH, 50 .mui = zdev->fmb_update, 51 .noi = zdev->max_msi, 52 .maxstbl = ZPCI_MAX_WRITE_SIZE, 53 .version = zdev->version 54 }; 55 56 return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); 57 } 58 59 /* 60 * Add the device utility string to the device info region. 61 */ 62 static int zpci_util_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 63 { 64 struct vfio_device_info_cap_zpci_util *cap; 65 int cap_size = sizeof(*cap) + CLP_UTIL_STR_LEN; 66 int ret; 67 68 cap = kmalloc(cap_size, GFP_KERNEL); 69 if (!cap) 70 return -ENOMEM; 71 72 cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_UTIL; 73 cap->header.version = 1; 74 cap->size = CLP_UTIL_STR_LEN; 75 memcpy(cap->util_str, zdev->util_str, cap->size); 76 77 ret = vfio_info_add_capability(caps, &cap->header, cap_size); 78 79 kfree(cap); 80 81 return ret; 82 } 83 84 /* 85 * Add the function path string to the device info region. 86 */ 87 static int zpci_pfip_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 88 { 89 struct vfio_device_info_cap_zpci_pfip *cap; 90 int cap_size = sizeof(*cap) + CLP_PFIP_NR_SEGMENTS; 91 int ret; 92 93 cap = kmalloc(cap_size, GFP_KERNEL); 94 if (!cap) 95 return -ENOMEM; 96 97 cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_PFIP; 98 cap->header.version = 1; 99 cap->size = CLP_PFIP_NR_SEGMENTS; 100 memcpy(cap->pfip, zdev->pfip, cap->size); 101 102 ret = vfio_info_add_capability(caps, &cap->header, cap_size); 103 104 kfree(cap); 105 106 return ret; 107 } 108 109 /* 110 * Add all supported capabilities to the VFIO_DEVICE_GET_INFO capability chain. 111 */ 112 int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, 113 struct vfio_info_cap *caps) 114 { 115 struct zpci_dev *zdev = to_zpci(vdev->pdev); 116 int ret; 117 118 if (!zdev) 119 return -ENODEV; 120 121 ret = zpci_base_cap(zdev, caps); 122 if (ret) 123 return ret; 124 125 ret = zpci_group_cap(zdev, caps); 126 if (ret) 127 return ret; 128 129 if (zdev->util_str_avail) { 130 ret = zpci_util_cap(zdev, caps); 131 if (ret) 132 return ret; 133 } 134 135 ret = zpci_pfip_cap(zdev, caps); 136 137 return ret; 138 } 139