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 <linux/kvm_host.h> 15 #include <asm/pci_clp.h> 16 #include <asm/pci_io.h> 17 18 #include <linux/vfio_pci_core.h> 19 20 /* 21 * Add the Base PCI Function information to the device info region. 22 */ 23 static int zpci_base_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 24 { 25 struct vfio_device_info_cap_zpci_base cap = { 26 .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE, 27 .header.version = 2, 28 .start_dma = zdev->start_dma, 29 .end_dma = zdev->end_dma, 30 .pchid = zdev->pchid, 31 .vfn = zdev->vfn, 32 .fmb_length = zdev->fmb_length, 33 .pft = zdev->pft, 34 .gid = zdev->pfgid, 35 .fh = zdev->fh 36 }; 37 38 return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); 39 } 40 41 /* 42 * Add the Base PCI Function Group information to the device info region. 43 */ 44 static int zpci_group_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 45 { 46 struct vfio_device_info_cap_zpci_group cap = { 47 .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP, 48 .header.version = 2, 49 .dasm = zdev->dma_mask, 50 .msi_addr = zdev->msi_addr, 51 .flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH, 52 .mui = zdev->fmb_update, 53 .noi = zdev->max_msi, 54 .maxstbl = ZPCI_MAX_WRITE_SIZE, 55 .version = zdev->version, 56 .reserved = 0, 57 .imaxstbl = zdev->maxstbl 58 }; 59 60 return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); 61 } 62 63 /* 64 * Add the device utility string to the device info region. 65 */ 66 static int zpci_util_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 67 { 68 struct vfio_device_info_cap_zpci_util *cap; 69 int cap_size = sizeof(*cap) + CLP_UTIL_STR_LEN; 70 int ret; 71 72 cap = kmalloc(cap_size, GFP_KERNEL); 73 if (!cap) 74 return -ENOMEM; 75 76 cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_UTIL; 77 cap->header.version = 1; 78 cap->size = CLP_UTIL_STR_LEN; 79 memcpy(cap->util_str, zdev->util_str, cap->size); 80 81 ret = vfio_info_add_capability(caps, &cap->header, cap_size); 82 83 kfree(cap); 84 85 return ret; 86 } 87 88 /* 89 * Add the function path string to the device info region. 90 */ 91 static int zpci_pfip_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 92 { 93 struct vfio_device_info_cap_zpci_pfip *cap; 94 int cap_size = sizeof(*cap) + CLP_PFIP_NR_SEGMENTS; 95 int ret; 96 97 cap = kmalloc(cap_size, GFP_KERNEL); 98 if (!cap) 99 return -ENOMEM; 100 101 cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_PFIP; 102 cap->header.version = 1; 103 cap->size = CLP_PFIP_NR_SEGMENTS; 104 memcpy(cap->pfip, zdev->pfip, cap->size); 105 106 ret = vfio_info_add_capability(caps, &cap->header, cap_size); 107 108 kfree(cap); 109 110 return ret; 111 } 112 113 /* 114 * Add all supported capabilities to the VFIO_DEVICE_GET_INFO capability chain. 115 */ 116 int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, 117 struct vfio_info_cap *caps) 118 { 119 struct zpci_dev *zdev = to_zpci(vdev->pdev); 120 int ret; 121 122 if (!zdev) 123 return -ENODEV; 124 125 ret = zpci_base_cap(zdev, caps); 126 if (ret) 127 return ret; 128 129 ret = zpci_group_cap(zdev, caps); 130 if (ret) 131 return ret; 132 133 if (zdev->util_str_avail) { 134 ret = zpci_util_cap(zdev, caps); 135 if (ret) 136 return ret; 137 } 138 139 ret = zpci_pfip_cap(zdev, caps); 140 141 return ret; 142 } 143 144 int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev) 145 { 146 struct zpci_dev *zdev = to_zpci(vdev->pdev); 147 148 if (!zdev) 149 return -ENODEV; 150 151 if (!vdev->vdev.kvm) 152 return 0; 153 154 return kvm_s390_pci_register_kvm(zdev, vdev->vdev.kvm); 155 } 156 157 void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev) 158 { 159 struct zpci_dev *zdev = to_zpci(vdev->pdev); 160 161 if (!zdev || !vdev->vdev.kvm) 162 return; 163 164 kvm_s390_pci_unregister_kvm(zdev); 165 } 166