162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * VFIO ZPCI devices support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) IBM Corp. 2020. All rights reserved. 662306a36Sopenharmony_ci * Author(s): Pierre Morel <pmorel@linux.ibm.com> 762306a36Sopenharmony_ci * Matthew Rosato <mjrosato@linux.ibm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/pci.h> 1162306a36Sopenharmony_ci#include <linux/uaccess.h> 1262306a36Sopenharmony_ci#include <linux/vfio.h> 1362306a36Sopenharmony_ci#include <linux/vfio_zdev.h> 1462306a36Sopenharmony_ci#include <linux/kvm_host.h> 1562306a36Sopenharmony_ci#include <asm/pci_clp.h> 1662306a36Sopenharmony_ci#include <asm/pci_io.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "vfio_pci_priv.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * Add the Base PCI Function information to the device info region. 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_cistatic int zpci_base_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct vfio_device_info_cap_zpci_base cap = { 2662306a36Sopenharmony_ci .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE, 2762306a36Sopenharmony_ci .header.version = 2, 2862306a36Sopenharmony_ci .start_dma = zdev->start_dma, 2962306a36Sopenharmony_ci .end_dma = zdev->end_dma, 3062306a36Sopenharmony_ci .pchid = zdev->pchid, 3162306a36Sopenharmony_ci .vfn = zdev->vfn, 3262306a36Sopenharmony_ci .fmb_length = zdev->fmb_length, 3362306a36Sopenharmony_ci .pft = zdev->pft, 3462306a36Sopenharmony_ci .gid = zdev->pfgid, 3562306a36Sopenharmony_ci .fh = zdev->fh 3662306a36Sopenharmony_ci }; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * Add the Base PCI Function Group information to the device info region. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_cistatic int zpci_group_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct vfio_device_info_cap_zpci_group cap = { 4762306a36Sopenharmony_ci .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP, 4862306a36Sopenharmony_ci .header.version = 2, 4962306a36Sopenharmony_ci .dasm = zdev->dma_mask, 5062306a36Sopenharmony_ci .msi_addr = zdev->msi_addr, 5162306a36Sopenharmony_ci .flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH, 5262306a36Sopenharmony_ci .mui = zdev->fmb_update, 5362306a36Sopenharmony_ci .noi = zdev->max_msi, 5462306a36Sopenharmony_ci .maxstbl = ZPCI_MAX_WRITE_SIZE, 5562306a36Sopenharmony_ci .version = zdev->version, 5662306a36Sopenharmony_ci .reserved = 0, 5762306a36Sopenharmony_ci .imaxstbl = zdev->maxstbl 5862306a36Sopenharmony_ci }; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* 6462306a36Sopenharmony_ci * Add the device utility string to the device info region. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistatic int zpci_util_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct vfio_device_info_cap_zpci_util *cap; 6962306a36Sopenharmony_ci int cap_size = sizeof(*cap) + CLP_UTIL_STR_LEN; 7062306a36Sopenharmony_ci int ret; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci cap = kmalloc(cap_size, GFP_KERNEL); 7362306a36Sopenharmony_ci if (!cap) 7462306a36Sopenharmony_ci return -ENOMEM; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_UTIL; 7762306a36Sopenharmony_ci cap->header.version = 1; 7862306a36Sopenharmony_ci cap->size = CLP_UTIL_STR_LEN; 7962306a36Sopenharmony_ci memcpy(cap->util_str, zdev->util_str, cap->size); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci ret = vfio_info_add_capability(caps, &cap->header, cap_size); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci kfree(cap); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return ret; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* 8962306a36Sopenharmony_ci * Add the function path string to the device info region. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_cistatic int zpci_pfip_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct vfio_device_info_cap_zpci_pfip *cap; 9462306a36Sopenharmony_ci int cap_size = sizeof(*cap) + CLP_PFIP_NR_SEGMENTS; 9562306a36Sopenharmony_ci int ret; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci cap = kmalloc(cap_size, GFP_KERNEL); 9862306a36Sopenharmony_ci if (!cap) 9962306a36Sopenharmony_ci return -ENOMEM; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_PFIP; 10262306a36Sopenharmony_ci cap->header.version = 1; 10362306a36Sopenharmony_ci cap->size = CLP_PFIP_NR_SEGMENTS; 10462306a36Sopenharmony_ci memcpy(cap->pfip, zdev->pfip, cap->size); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci ret = vfio_info_add_capability(caps, &cap->header, cap_size); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci kfree(cap); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return ret; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * Add all supported capabilities to the VFIO_DEVICE_GET_INFO capability chain. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ciint vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, 11762306a36Sopenharmony_ci struct vfio_info_cap *caps) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct zpci_dev *zdev = to_zpci(vdev->pdev); 12062306a36Sopenharmony_ci int ret; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (!zdev) 12362306a36Sopenharmony_ci return -ENODEV; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci ret = zpci_base_cap(zdev, caps); 12662306a36Sopenharmony_ci if (ret) 12762306a36Sopenharmony_ci return ret; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci ret = zpci_group_cap(zdev, caps); 13062306a36Sopenharmony_ci if (ret) 13162306a36Sopenharmony_ci return ret; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (zdev->util_str_avail) { 13462306a36Sopenharmony_ci ret = zpci_util_cap(zdev, caps); 13562306a36Sopenharmony_ci if (ret) 13662306a36Sopenharmony_ci return ret; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci ret = zpci_pfip_cap(zdev, caps); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return ret; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ciint vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct zpci_dev *zdev = to_zpci(vdev->pdev); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (!zdev) 14962306a36Sopenharmony_ci return -ENODEV; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (!vdev->vdev.kvm) 15262306a36Sopenharmony_ci return 0; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (zpci_kvm_hook.kvm_register) 15562306a36Sopenharmony_ci return zpci_kvm_hook.kvm_register(zdev, vdev->vdev.kvm); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return -ENOENT; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_civoid vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct zpci_dev *zdev = to_zpci(vdev->pdev); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (!zdev || !vdev->vdev.kvm) 16562306a36Sopenharmony_ci return; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (zpci_kvm_hook.kvm_unregister) 16862306a36Sopenharmony_ci zpci_kvm_hook.kvm_unregister(zdev); 16962306a36Sopenharmony_ci} 170