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