18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * VFIO ZPCI devices support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) IBM Corp. 2020. All rights reserved. 68c2ecf20Sopenharmony_ci * Author(s): Pierre Morel <pmorel@linux.ibm.com> 78c2ecf20Sopenharmony_ci * Matthew Rosato <mjrosato@linux.ibm.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 118c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/pci.h> 168c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 178c2ecf20Sopenharmony_ci#include <linux/vfio.h> 188c2ecf20Sopenharmony_ci#include <linux/vfio_zdev.h> 198c2ecf20Sopenharmony_ci#include <asm/pci_clp.h> 208c2ecf20Sopenharmony_ci#include <asm/pci_io.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "vfio_pci_private.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * Add the Base PCI Function information to the device info region. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_cistatic int zpci_base_cap(struct zpci_dev *zdev, struct vfio_pci_device *vdev, 288c2ecf20Sopenharmony_ci struct vfio_info_cap *caps) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct vfio_device_info_cap_zpci_base cap = { 318c2ecf20Sopenharmony_ci .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE, 328c2ecf20Sopenharmony_ci .header.version = 1, 338c2ecf20Sopenharmony_ci .start_dma = zdev->start_dma, 348c2ecf20Sopenharmony_ci .end_dma = zdev->end_dma, 358c2ecf20Sopenharmony_ci .pchid = zdev->pchid, 368c2ecf20Sopenharmony_ci .vfn = zdev->vfn, 378c2ecf20Sopenharmony_ci .fmb_length = zdev->fmb_length, 388c2ecf20Sopenharmony_ci .pft = zdev->pft, 398c2ecf20Sopenharmony_ci .gid = zdev->pfgid 408c2ecf20Sopenharmony_ci }; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * Add the Base PCI Function Group information to the device info region. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_cistatic int zpci_group_cap(struct zpci_dev *zdev, struct vfio_pci_device *vdev, 498c2ecf20Sopenharmony_ci struct vfio_info_cap *caps) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct vfio_device_info_cap_zpci_group cap = { 528c2ecf20Sopenharmony_ci .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP, 538c2ecf20Sopenharmony_ci .header.version = 1, 548c2ecf20Sopenharmony_ci .dasm = zdev->dma_mask, 558c2ecf20Sopenharmony_ci .msi_addr = zdev->msi_addr, 568c2ecf20Sopenharmony_ci .flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH, 578c2ecf20Sopenharmony_ci .mui = zdev->fmb_update, 588c2ecf20Sopenharmony_ci .noi = zdev->max_msi, 598c2ecf20Sopenharmony_ci .maxstbl = ZPCI_MAX_WRITE_SIZE, 608c2ecf20Sopenharmony_ci .version = zdev->version 618c2ecf20Sopenharmony_ci }; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* 678c2ecf20Sopenharmony_ci * Add the device utility string to the device info region. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_cistatic int zpci_util_cap(struct zpci_dev *zdev, struct vfio_pci_device *vdev, 708c2ecf20Sopenharmony_ci struct vfio_info_cap *caps) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct vfio_device_info_cap_zpci_util *cap; 738c2ecf20Sopenharmony_ci int cap_size = sizeof(*cap) + CLP_UTIL_STR_LEN; 748c2ecf20Sopenharmony_ci int ret; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci cap = kmalloc(cap_size, GFP_KERNEL); 778c2ecf20Sopenharmony_ci if (!cap) 788c2ecf20Sopenharmony_ci return -ENOMEM; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_UTIL; 818c2ecf20Sopenharmony_ci cap->header.version = 1; 828c2ecf20Sopenharmony_ci cap->size = CLP_UTIL_STR_LEN; 838c2ecf20Sopenharmony_ci memcpy(cap->util_str, zdev->util_str, cap->size); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci ret = vfio_info_add_capability(caps, &cap->header, cap_size); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci kfree(cap); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return ret; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* 938c2ecf20Sopenharmony_ci * Add the function path string to the device info region. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_cistatic int zpci_pfip_cap(struct zpci_dev *zdev, struct vfio_pci_device *vdev, 968c2ecf20Sopenharmony_ci struct vfio_info_cap *caps) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct vfio_device_info_cap_zpci_pfip *cap; 998c2ecf20Sopenharmony_ci int cap_size = sizeof(*cap) + CLP_PFIP_NR_SEGMENTS; 1008c2ecf20Sopenharmony_ci int ret; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci cap = kmalloc(cap_size, GFP_KERNEL); 1038c2ecf20Sopenharmony_ci if (!cap) 1048c2ecf20Sopenharmony_ci return -ENOMEM; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_PFIP; 1078c2ecf20Sopenharmony_ci cap->header.version = 1; 1088c2ecf20Sopenharmony_ci cap->size = CLP_PFIP_NR_SEGMENTS; 1098c2ecf20Sopenharmony_ci memcpy(cap->pfip, zdev->pfip, cap->size); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci ret = vfio_info_add_capability(caps, &cap->header, cap_size); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci kfree(cap); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return ret; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* 1198c2ecf20Sopenharmony_ci * Add all supported capabilities to the VFIO_DEVICE_GET_INFO capability chain. 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ciint vfio_pci_info_zdev_add_caps(struct vfio_pci_device *vdev, 1228c2ecf20Sopenharmony_ci struct vfio_info_cap *caps) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct zpci_dev *zdev = to_zpci(vdev->pdev); 1258c2ecf20Sopenharmony_ci int ret; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (!zdev) 1288c2ecf20Sopenharmony_ci return -ENODEV; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci ret = zpci_base_cap(zdev, vdev, caps); 1318c2ecf20Sopenharmony_ci if (ret) 1328c2ecf20Sopenharmony_ci return ret; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci ret = zpci_group_cap(zdev, vdev, caps); 1358c2ecf20Sopenharmony_ci if (ret) 1368c2ecf20Sopenharmony_ci return ret; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (zdev->util_str_avail) { 1398c2ecf20Sopenharmony_ci ret = zpci_util_cap(zdev, vdev, caps); 1408c2ecf20Sopenharmony_ci if (ret) 1418c2ecf20Sopenharmony_ci return ret; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ret = zpci_pfip_cap(zdev, vdev, caps); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return ret; 1478c2ecf20Sopenharmony_ci} 148