123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * VFIO ZPCI devices support
- *
- * Copyright (C) IBM Corp. 2020. All rights reserved.
- * Author(s): Pierre Morel <[email protected]>
- * Matthew Rosato <[email protected]>
- */
- #include <linux/io.h>
- #include <linux/pci.h>
- #include <linux/uaccess.h>
- #include <linux/vfio.h>
- #include <linux/vfio_zdev.h>
- #include <linux/kvm_host.h>
- #include <asm/pci_clp.h>
- #include <asm/pci_io.h>
- #include "vfio_pci_priv.h"
- /*
- * Add the Base PCI Function information to the device info region.
- */
- static int zpci_base_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)
- {
- struct vfio_device_info_cap_zpci_base cap = {
- .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE,
- .header.version = 2,
- .start_dma = zdev->start_dma,
- .end_dma = zdev->end_dma,
- .pchid = zdev->pchid,
- .vfn = zdev->vfn,
- .fmb_length = zdev->fmb_length,
- .pft = zdev->pft,
- .gid = zdev->pfgid,
- .fh = zdev->fh
- };
- return vfio_info_add_capability(caps, &cap.header, sizeof(cap));
- }
- /*
- * Add the Base PCI Function Group information to the device info region.
- */
- static int zpci_group_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)
- {
- struct vfio_device_info_cap_zpci_group cap = {
- .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP,
- .header.version = 2,
- .dasm = zdev->dma_mask,
- .msi_addr = zdev->msi_addr,
- .flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH,
- .mui = zdev->fmb_update,
- .noi = zdev->max_msi,
- .maxstbl = ZPCI_MAX_WRITE_SIZE,
- .version = zdev->version,
- .reserved = 0,
- .imaxstbl = zdev->maxstbl
- };
- return vfio_info_add_capability(caps, &cap.header, sizeof(cap));
- }
- /*
- * Add the device utility string to the device info region.
- */
- static int zpci_util_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)
- {
- struct vfio_device_info_cap_zpci_util *cap;
- int cap_size = sizeof(*cap) + CLP_UTIL_STR_LEN;
- int ret;
- cap = kmalloc(cap_size, GFP_KERNEL);
- if (!cap)
- return -ENOMEM;
- cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_UTIL;
- cap->header.version = 1;
- cap->size = CLP_UTIL_STR_LEN;
- memcpy(cap->util_str, zdev->util_str, cap->size);
- ret = vfio_info_add_capability(caps, &cap->header, cap_size);
- kfree(cap);
- return ret;
- }
- /*
- * Add the function path string to the device info region.
- */
- static int zpci_pfip_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)
- {
- struct vfio_device_info_cap_zpci_pfip *cap;
- int cap_size = sizeof(*cap) + CLP_PFIP_NR_SEGMENTS;
- int ret;
- cap = kmalloc(cap_size, GFP_KERNEL);
- if (!cap)
- return -ENOMEM;
- cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_PFIP;
- cap->header.version = 1;
- cap->size = CLP_PFIP_NR_SEGMENTS;
- memcpy(cap->pfip, zdev->pfip, cap->size);
- ret = vfio_info_add_capability(caps, &cap->header, cap_size);
- kfree(cap);
- return ret;
- }
- /*
- * Add all supported capabilities to the VFIO_DEVICE_GET_INFO capability chain.
- */
- int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev,
- struct vfio_info_cap *caps)
- {
- struct zpci_dev *zdev = to_zpci(vdev->pdev);
- int ret;
- if (!zdev)
- return -ENODEV;
- ret = zpci_base_cap(zdev, caps);
- if (ret)
- return ret;
- ret = zpci_group_cap(zdev, caps);
- if (ret)
- return ret;
- if (zdev->util_str_avail) {
- ret = zpci_util_cap(zdev, caps);
- if (ret)
- return ret;
- }
- ret = zpci_pfip_cap(zdev, caps);
- return ret;
- }
- int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev)
- {
- struct zpci_dev *zdev = to_zpci(vdev->pdev);
- if (!zdev)
- return -ENODEV;
- if (!vdev->vdev.kvm)
- return 0;
- if (zpci_kvm_hook.kvm_register)
- return zpci_kvm_hook.kvm_register(zdev, vdev->vdev.kvm);
- return -ENOENT;
- }
- void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev)
- {
- struct zpci_dev *zdev = to_zpci(vdev->pdev);
- if (!zdev || !vdev->vdev.kvm)
- return;
- if (zpci_kvm_hook.kvm_unregister)
- zpci_kvm_hook.kvm_unregister(zdev);
- }
|