1 /* 2 * s390 vfio-pci interfaces 3 * 4 * Copyright 2020 IBM Corp. 5 * Author(s): Matthew Rosato <mjrosato@linux.ibm.com> 6 * 7 * This work is licensed under the terms of the GNU GPL, version 2 or (at 8 * your option) any later version. See the COPYING file in the top-level 9 * directory. 10 */ 11 12 #include "qemu/osdep.h" 13 14 #include <sys/ioctl.h> 15 #include <linux/vfio.h> 16 #include <linux/vfio_zdev.h> 17 18 #include "trace.h" 19 #include "hw/s390x/s390-pci-bus.h" 20 #include "hw/s390x/s390-pci-clp.h" 21 #include "hw/s390x/s390-pci-vfio.h" 22 #include "hw/vfio/pci.h" 23 #include "hw/vfio/vfio-common.h" 24 25 /* 26 * Get the current DMA available count from vfio. Returns true if vfio is 27 * limiting DMA requests, false otherwise. The current available count read 28 * from vfio is returned in avail. 29 */ 30 bool s390_pci_update_dma_avail(int fd, unsigned int *avail) 31 { 32 g_autofree struct vfio_iommu_type1_info *info; 33 uint32_t argsz; 34 35 assert(avail); 36 37 argsz = sizeof(struct vfio_iommu_type1_info); 38 info = g_malloc0(argsz); 39 40 /* 41 * If the specified argsz is not large enough to contain all capabilities 42 * it will be updated upon return from the ioctl. Retry until we have 43 * a big enough buffer to hold the entire capability chain. 44 */ 45 retry: 46 info->argsz = argsz; 47 48 if (ioctl(fd, VFIO_IOMMU_GET_INFO, info)) { 49 return false; 50 } 51 52 if (info->argsz > argsz) { 53 argsz = info->argsz; 54 info = g_realloc(info, argsz); 55 goto retry; 56 } 57 58 /* If the capability exists, update with the current value */ 59 return vfio_get_info_dma_avail(info, avail); 60 } 61 62 S390PCIDMACount *s390_pci_start_dma_count(S390pciState *s, 63 S390PCIBusDevice *pbdev) 64 { 65 S390PCIDMACount *cnt; 66 uint32_t avail; 67 VFIOPCIDevice *vpdev = container_of(pbdev->pdev, VFIOPCIDevice, pdev); 68 int id; 69 70 assert(vpdev); 71 72 id = vpdev->vbasedev.group->container->fd; 73 74 if (!s390_pci_update_dma_avail(id, &avail)) { 75 return NULL; 76 } 77 78 QTAILQ_FOREACH(cnt, &s->zpci_dma_limit, link) { 79 if (cnt->id == id) { 80 cnt->users++; 81 return cnt; 82 } 83 } 84 85 cnt = g_new0(S390PCIDMACount, 1); 86 cnt->id = id; 87 cnt->users = 1; 88 cnt->avail = avail; 89 QTAILQ_INSERT_TAIL(&s->zpci_dma_limit, cnt, link); 90 return cnt; 91 } 92 93 void s390_pci_end_dma_count(S390pciState *s, S390PCIDMACount *cnt) 94 { 95 assert(cnt); 96 97 cnt->users--; 98 if (cnt->users == 0) { 99 QTAILQ_REMOVE(&s->zpci_dma_limit, cnt, link); 100 } 101 } 102 103 static void s390_pci_read_base(S390PCIBusDevice *pbdev, 104 struct vfio_device_info *info) 105 { 106 struct vfio_info_cap_header *hdr; 107 struct vfio_device_info_cap_zpci_base *cap; 108 VFIOPCIDevice *vpci = container_of(pbdev->pdev, VFIOPCIDevice, pdev); 109 110 hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_BASE); 111 112 /* If capability not provided, just leave the defaults in place */ 113 if (hdr == NULL) { 114 trace_s390_pci_clp_cap(vpci->vbasedev.name, 115 VFIO_DEVICE_INFO_CAP_ZPCI_BASE); 116 return; 117 } 118 cap = (void *) hdr; 119 120 pbdev->zpci_fn.sdma = cap->start_dma; 121 pbdev->zpci_fn.edma = cap->end_dma; 122 pbdev->zpci_fn.pchid = cap->pchid; 123 pbdev->zpci_fn.vfn = cap->vfn; 124 pbdev->zpci_fn.pfgid = cap->gid; 125 /* The following values remain 0 until we support other FMB formats */ 126 pbdev->zpci_fn.fmbl = 0; 127 pbdev->zpci_fn.pft = 0; 128 } 129 130 static void s390_pci_read_group(S390PCIBusDevice *pbdev, 131 struct vfio_device_info *info) 132 { 133 struct vfio_info_cap_header *hdr; 134 struct vfio_device_info_cap_zpci_group *cap; 135 ClpRspQueryPciGrp *resgrp; 136 VFIOPCIDevice *vpci = container_of(pbdev->pdev, VFIOPCIDevice, pdev); 137 138 hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_GROUP); 139 140 /* If capability not provided, just use the default group */ 141 if (hdr == NULL) { 142 trace_s390_pci_clp_cap(vpci->vbasedev.name, 143 VFIO_DEVICE_INFO_CAP_ZPCI_GROUP); 144 pbdev->zpci_fn.pfgid = ZPCI_DEFAULT_FN_GRP; 145 pbdev->pci_group = s390_group_find(ZPCI_DEFAULT_FN_GRP); 146 return; 147 } 148 cap = (void *) hdr; 149 150 /* See if the PCI group is already defined, create if not */ 151 pbdev->pci_group = s390_group_find(pbdev->zpci_fn.pfgid); 152 153 if (!pbdev->pci_group) { 154 pbdev->pci_group = s390_group_create(pbdev->zpci_fn.pfgid); 155 156 resgrp = &pbdev->pci_group->zpci_group; 157 if (cap->flags & VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH) { 158 resgrp->fr = 1; 159 } 160 resgrp->dasm = cap->dasm; 161 resgrp->msia = cap->msi_addr; 162 resgrp->mui = cap->mui; 163 resgrp->i = cap->noi; 164 resgrp->maxstbl = cap->maxstbl; 165 resgrp->version = cap->version; 166 } 167 } 168 169 static void s390_pci_read_util(S390PCIBusDevice *pbdev, 170 struct vfio_device_info *info) 171 { 172 struct vfio_info_cap_header *hdr; 173 struct vfio_device_info_cap_zpci_util *cap; 174 VFIOPCIDevice *vpci = container_of(pbdev->pdev, VFIOPCIDevice, pdev); 175 176 hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_UTIL); 177 178 /* If capability not provided, just leave the defaults in place */ 179 if (hdr == NULL) { 180 trace_s390_pci_clp_cap(vpci->vbasedev.name, 181 VFIO_DEVICE_INFO_CAP_ZPCI_UTIL); 182 return; 183 } 184 cap = (void *) hdr; 185 186 if (cap->size > CLP_UTIL_STR_LEN) { 187 trace_s390_pci_clp_cap_size(vpci->vbasedev.name, cap->size, 188 VFIO_DEVICE_INFO_CAP_ZPCI_UTIL); 189 return; 190 } 191 192 pbdev->zpci_fn.flags |= CLP_RSP_QPCI_MASK_UTIL; 193 memcpy(pbdev->zpci_fn.util_str, cap->util_str, CLP_UTIL_STR_LEN); 194 } 195 196 static void s390_pci_read_pfip(S390PCIBusDevice *pbdev, 197 struct vfio_device_info *info) 198 { 199 struct vfio_info_cap_header *hdr; 200 struct vfio_device_info_cap_zpci_pfip *cap; 201 VFIOPCIDevice *vpci = container_of(pbdev->pdev, VFIOPCIDevice, pdev); 202 203 hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_PFIP); 204 205 /* If capability not provided, just leave the defaults in place */ 206 if (hdr == NULL) { 207 trace_s390_pci_clp_cap(vpci->vbasedev.name, 208 VFIO_DEVICE_INFO_CAP_ZPCI_PFIP); 209 return; 210 } 211 cap = (void *) hdr; 212 213 if (cap->size > CLP_PFIP_NR_SEGMENTS) { 214 trace_s390_pci_clp_cap_size(vpci->vbasedev.name, cap->size, 215 VFIO_DEVICE_INFO_CAP_ZPCI_PFIP); 216 return; 217 } 218 219 memcpy(pbdev->zpci_fn.pfip, cap->pfip, CLP_PFIP_NR_SEGMENTS); 220 } 221 222 /* 223 * This function will issue the VFIO_DEVICE_GET_INFO ioctl and look for 224 * capabilities that contain information about CLP features provided by the 225 * underlying host. 226 * On entry, defaults have already been placed into the guest CLP response 227 * buffers. On exit, defaults will have been overwritten for any CLP features 228 * found in the capability chain; defaults will remain for any CLP features not 229 * found in the chain. 230 */ 231 void s390_pci_get_clp_info(S390PCIBusDevice *pbdev) 232 { 233 g_autofree struct vfio_device_info *info; 234 VFIOPCIDevice *vfio_pci; 235 uint32_t argsz; 236 int fd; 237 238 argsz = sizeof(*info); 239 info = g_malloc0(argsz); 240 241 vfio_pci = container_of(pbdev->pdev, VFIOPCIDevice, pdev); 242 fd = vfio_pci->vbasedev.fd; 243 244 /* 245 * If the specified argsz is not large enough to contain all capabilities 246 * it will be updated upon return from the ioctl. Retry until we have 247 * a big enough buffer to hold the entire capability chain. On error, 248 * just exit and rely on CLP defaults. 249 */ 250 retry: 251 info->argsz = argsz; 252 253 if (ioctl(fd, VFIO_DEVICE_GET_INFO, info)) { 254 trace_s390_pci_clp_dev_info(vfio_pci->vbasedev.name); 255 return; 256 } 257 258 if (info->argsz > argsz) { 259 argsz = info->argsz; 260 info = g_realloc(info, argsz); 261 goto retry; 262 } 263 264 /* 265 * Find the CLP features provided and fill in the guest CLP responses. 266 * Always call s390_pci_read_base first as information from this could 267 * determine which function group is used in s390_pci_read_group. 268 * For any feature not found, the default values will remain in the CLP 269 * response. 270 */ 271 s390_pci_read_base(pbdev, info); 272 s390_pci_read_group(pbdev, info); 273 s390_pci_read_util(pbdev, info); 274 s390_pci_read_pfip(pbdev, info); 275 276 return; 277 } 278