qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

s390-pci-vfio.c (11523B)


      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     uint32_t argsz = sizeof(struct vfio_iommu_type1_info);
     33     g_autofree struct vfio_iommu_type1_info *info = g_malloc0(argsz);
     34 
     35     assert(avail);
     36 
     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 
     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 }
     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 bool get_host_fh(S390PCIBusDevice *pbdev, struct vfio_device_info *info,
    128                         uint32_t *fh)
    129 {
    130     struct vfio_info_cap_header *hdr;
    131     struct vfio_device_info_cap_zpci_base *cap;
    132     VFIOPCIDevice *vpci = container_of(pbdev->pdev, VFIOPCIDevice, pdev);
    133 
    134     hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_BASE);
    135 
    136     /* Can only get the host fh with version 2 or greater */
    137     if (hdr == NULL || hdr->version < 2) {
    138         trace_s390_pci_clp_cap(vpci->vbasedev.name,
    139                                VFIO_DEVICE_INFO_CAP_ZPCI_BASE);
    140         return false;
    141     }
    142     cap = (void *) hdr;
    143 
    144     *fh = cap->fh;
    145     return true;
    146 }
    147 
    148 static void s390_pci_read_group(S390PCIBusDevice *pbdev,
    149                                 struct vfio_device_info *info)
    150 {
    151     struct vfio_info_cap_header *hdr;
    152     struct vfio_device_info_cap_zpci_group *cap;
    153     S390pciState *s = s390_get_phb();
    154     ClpRspQueryPciGrp *resgrp;
    155     VFIOPCIDevice *vpci =  container_of(pbdev->pdev, VFIOPCIDevice, pdev);
    156     uint8_t start_gid = pbdev->zpci_fn.pfgid;
    157 
    158     hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_GROUP);
    159 
    160     /*
    161      * If capability not provided or the underlying hostdev is simulated, just
    162      * use the default group.
    163      */
    164     if (hdr == NULL || pbdev->zpci_fn.pfgid >= ZPCI_SIM_GRP_START) {
    165         trace_s390_pci_clp_cap(vpci->vbasedev.name,
    166                                VFIO_DEVICE_INFO_CAP_ZPCI_GROUP);
    167         pbdev->zpci_fn.pfgid = ZPCI_DEFAULT_FN_GRP;
    168         pbdev->pci_group = s390_group_find(ZPCI_DEFAULT_FN_GRP);
    169         return;
    170     }
    171     cap = (void *) hdr;
    172 
    173     /*
    174      * For an intercept device, let's use an existing simulated group if one
    175      * one was already created for other intercept devices in this group.
    176      * If not, create a new simulated group if any are still available.
    177      * If all else fails, just fall back on the default group.
    178      */
    179     if (!pbdev->interp) {
    180         pbdev->pci_group = s390_group_find_host_sim(pbdev->zpci_fn.pfgid);
    181         if (pbdev->pci_group) {
    182             /* Use existing simulated group */
    183             pbdev->zpci_fn.pfgid = pbdev->pci_group->id;
    184             return;
    185         } else {
    186             if (s->next_sim_grp == ZPCI_DEFAULT_FN_GRP) {
    187                 /* All out of simulated groups, use default */
    188                 trace_s390_pci_clp_cap(vpci->vbasedev.name,
    189                                        VFIO_DEVICE_INFO_CAP_ZPCI_GROUP);
    190                 pbdev->zpci_fn.pfgid = ZPCI_DEFAULT_FN_GRP;
    191                 pbdev->pci_group = s390_group_find(ZPCI_DEFAULT_FN_GRP);
    192                 return;
    193             } else {
    194                 /* We can assign a new simulated group */
    195                 pbdev->zpci_fn.pfgid = s->next_sim_grp;
    196                 s->next_sim_grp++;
    197                 /* Fall through to create the new sim group using CLP info */
    198             }
    199         }
    200     }
    201 
    202     /* See if the PCI group is already defined, create if not */
    203     pbdev->pci_group = s390_group_find(pbdev->zpci_fn.pfgid);
    204 
    205     if (!pbdev->pci_group) {
    206         pbdev->pci_group = s390_group_create(pbdev->zpci_fn.pfgid, start_gid);
    207 
    208         resgrp = &pbdev->pci_group->zpci_group;
    209         if (cap->flags & VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH) {
    210             resgrp->fr = 1;
    211         }
    212         resgrp->dasm = cap->dasm;
    213         resgrp->msia = cap->msi_addr;
    214         resgrp->mui = cap->mui;
    215         resgrp->i = cap->noi;
    216         if (pbdev->interp && hdr->version >= 2) {
    217             resgrp->maxstbl = cap->imaxstbl;
    218         } else {
    219             resgrp->maxstbl = cap->maxstbl;
    220         }
    221         resgrp->version = cap->version;
    222         resgrp->dtsm = ZPCI_DTSM;
    223     }
    224 }
    225 
    226 static void s390_pci_read_util(S390PCIBusDevice *pbdev,
    227                                struct vfio_device_info *info)
    228 {
    229     struct vfio_info_cap_header *hdr;
    230     struct vfio_device_info_cap_zpci_util *cap;
    231     VFIOPCIDevice *vpci =  container_of(pbdev->pdev, VFIOPCIDevice, pdev);
    232 
    233     hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_UTIL);
    234 
    235     /* If capability not provided, just leave the defaults in place */
    236     if (hdr == NULL) {
    237         trace_s390_pci_clp_cap(vpci->vbasedev.name,
    238                                VFIO_DEVICE_INFO_CAP_ZPCI_UTIL);
    239         return;
    240     }
    241     cap = (void *) hdr;
    242 
    243     if (cap->size > CLP_UTIL_STR_LEN) {
    244         trace_s390_pci_clp_cap_size(vpci->vbasedev.name, cap->size,
    245                                     VFIO_DEVICE_INFO_CAP_ZPCI_UTIL);
    246         return;
    247     }
    248 
    249     pbdev->zpci_fn.flags |= CLP_RSP_QPCI_MASK_UTIL;
    250     memcpy(pbdev->zpci_fn.util_str, cap->util_str, CLP_UTIL_STR_LEN);
    251 }
    252 
    253 static void s390_pci_read_pfip(S390PCIBusDevice *pbdev,
    254                                struct vfio_device_info *info)
    255 {
    256     struct vfio_info_cap_header *hdr;
    257     struct vfio_device_info_cap_zpci_pfip *cap;
    258     VFIOPCIDevice *vpci =  container_of(pbdev->pdev, VFIOPCIDevice, pdev);
    259 
    260     hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_PFIP);
    261 
    262     /* If capability not provided, just leave the defaults in place */
    263     if (hdr == NULL) {
    264         trace_s390_pci_clp_cap(vpci->vbasedev.name,
    265                                VFIO_DEVICE_INFO_CAP_ZPCI_PFIP);
    266         return;
    267     }
    268     cap = (void *) hdr;
    269 
    270     if (cap->size > CLP_PFIP_NR_SEGMENTS) {
    271         trace_s390_pci_clp_cap_size(vpci->vbasedev.name, cap->size,
    272                                     VFIO_DEVICE_INFO_CAP_ZPCI_PFIP);
    273         return;
    274     }
    275 
    276     memcpy(pbdev->zpci_fn.pfip, cap->pfip, CLP_PFIP_NR_SEGMENTS);
    277 }
    278 
    279 static struct vfio_device_info *get_device_info(S390PCIBusDevice *pbdev,
    280                                                 uint32_t argsz)
    281 {
    282     struct vfio_device_info *info = g_malloc0(argsz);
    283     VFIOPCIDevice *vfio_pci;
    284     int fd;
    285 
    286     vfio_pci = container_of(pbdev->pdev, VFIOPCIDevice, pdev);
    287     fd = vfio_pci->vbasedev.fd;
    288 
    289     /*
    290      * If the specified argsz is not large enough to contain all capabilities
    291      * it will be updated upon return from the ioctl.  Retry until we have
    292      * a big enough buffer to hold the entire capability chain.  On error,
    293      * just exit and rely on CLP defaults.
    294      */
    295 retry:
    296     info->argsz = argsz;
    297 
    298     if (ioctl(fd, VFIO_DEVICE_GET_INFO, info)) {
    299         trace_s390_pci_clp_dev_info(vfio_pci->vbasedev.name);
    300         g_free(info);
    301         return NULL;
    302     }
    303 
    304     if (info->argsz > argsz) {
    305         argsz = info->argsz;
    306         info = g_realloc(info, argsz);
    307         goto retry;
    308     }
    309 
    310     return info;
    311 }
    312 
    313 /*
    314  * Get the host function handle from the vfio CLP capabilities chain.  Returns
    315  * true if a fh value was placed into the provided buffer.  Returns false
    316  * if a fh could not be obtained (ioctl failed or capability version does
    317  * not include the fh)
    318  */
    319 bool s390_pci_get_host_fh(S390PCIBusDevice *pbdev, uint32_t *fh)
    320 {
    321     g_autofree struct vfio_device_info *info = NULL;
    322 
    323     assert(fh);
    324 
    325     info = get_device_info(pbdev, sizeof(*info));
    326     if (!info) {
    327         return false;
    328     }
    329 
    330     return get_host_fh(pbdev, info, fh);
    331 }
    332 
    333 /*
    334  * This function will issue the VFIO_DEVICE_GET_INFO ioctl and look for
    335  * capabilities that contain information about CLP features provided by the
    336  * underlying host.
    337  * On entry, defaults have already been placed into the guest CLP response
    338  * buffers.  On exit, defaults will have been overwritten for any CLP features
    339  * found in the capability chain; defaults will remain for any CLP features not
    340  * found in the chain.
    341  */
    342 void s390_pci_get_clp_info(S390PCIBusDevice *pbdev)
    343 {
    344     g_autofree struct vfio_device_info *info = NULL;
    345 
    346     info = get_device_info(pbdev, sizeof(*info));
    347     if (!info) {
    348         return;
    349     }
    350 
    351     /*
    352      * Find the CLP features provided and fill in the guest CLP responses.
    353      * Always call s390_pci_read_base first as information from this could
    354      * determine which function group is used in s390_pci_read_group.
    355      * For any feature not found, the default values will remain in the CLP
    356      * response.
    357      */
    358     s390_pci_read_base(pbdev, info);
    359     s390_pci_read_group(pbdev, info);
    360     s390_pci_read_util(pbdev, info);
    361     s390_pci_read_pfip(pbdev, info);
    362 
    363     return;
    364 }