brintos

brintos / linux-shallow public Read only

0
0
Text · 3.7 KiB · 0990fdb Raw
170 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * VFIO ZPCI devices support4 *5 * Copyright (C) IBM Corp. 2020.  All rights reserved.6 *	Author(s): Pierre Morel <pmorel@linux.ibm.com>7 *                 Matthew Rosato <mjrosato@linux.ibm.com>8 */9#include <linux/io.h>10#include <linux/pci.h>11#include <linux/uaccess.h>12#include <linux/vfio.h>13#include <linux/vfio_zdev.h>14#include <linux/kvm_host.h>15#include <asm/pci_clp.h>16#include <asm/pci_io.h>17 18#include "vfio_pci_priv.h"19 20/*21 * Add the Base PCI Function information to the device info region.22 */23static int zpci_base_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)24{25	struct vfio_device_info_cap_zpci_base cap = {26		.header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE,27		.header.version = 2,28		.start_dma = zdev->start_dma,29		.end_dma = zdev->end_dma,30		.pchid = zdev->pchid,31		.vfn = zdev->vfn,32		.fmb_length = zdev->fmb_length,33		.pft = zdev->pft,34		.gid = zdev->pfgid,35		.fh = zdev->fh36	};37 38	return vfio_info_add_capability(caps, &cap.header, sizeof(cap));39}40 41/*42 * Add the Base PCI Function Group information to the device info region.43 */44static int zpci_group_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)45{46	struct vfio_device_info_cap_zpci_group cap = {47		.header.id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP,48		.header.version = 2,49		.dasm = zdev->dma_mask,50		.msi_addr = zdev->msi_addr,51		.flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH,52		.mui = zdev->fmb_update,53		.noi = zdev->max_msi,54		.maxstbl = ZPCI_MAX_WRITE_SIZE,55		.version = zdev->version,56		.reserved = 0,57		.imaxstbl = zdev->maxstbl58	};59 60	return vfio_info_add_capability(caps, &cap.header, sizeof(cap));61}62 63/*64 * Add the device utility string to the device info region.65 */66static int zpci_util_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)67{68	struct vfio_device_info_cap_zpci_util *cap;69	int cap_size = sizeof(*cap) + CLP_UTIL_STR_LEN;70	int ret;71 72	cap = kmalloc(cap_size, GFP_KERNEL);73	if (!cap)74		return -ENOMEM;75 76	cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_UTIL;77	cap->header.version = 1;78	cap->size = CLP_UTIL_STR_LEN;79	memcpy(cap->util_str, zdev->util_str, cap->size);80 81	ret = vfio_info_add_capability(caps, &cap->header, cap_size);82 83	kfree(cap);84 85	return ret;86}87 88/*89 * Add the function path string to the device info region.90 */91static int zpci_pfip_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)92{93	struct vfio_device_info_cap_zpci_pfip *cap;94	int cap_size = sizeof(*cap) + CLP_PFIP_NR_SEGMENTS;95	int ret;96 97	cap = kmalloc(cap_size, GFP_KERNEL);98	if (!cap)99		return -ENOMEM;100 101	cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_PFIP;102	cap->header.version = 1;103	cap->size = CLP_PFIP_NR_SEGMENTS;104	memcpy(cap->pfip, zdev->pfip, cap->size);105 106	ret = vfio_info_add_capability(caps, &cap->header, cap_size);107 108	kfree(cap);109 110	return ret;111}112 113/*114 * Add all supported capabilities to the VFIO_DEVICE_GET_INFO capability chain.115 */116int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev,117				struct vfio_info_cap *caps)118{119	struct zpci_dev *zdev = to_zpci(vdev->pdev);120	int ret;121 122	if (!zdev)123		return -ENODEV;124 125	ret = zpci_base_cap(zdev, caps);126	if (ret)127		return ret;128 129	ret = zpci_group_cap(zdev, caps);130	if (ret)131		return ret;132 133	if (zdev->util_str_avail) {134		ret = zpci_util_cap(zdev, caps);135		if (ret)136			return ret;137	}138 139	ret = zpci_pfip_cap(zdev, caps);140 141	return ret;142}143 144int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev)145{146	struct zpci_dev *zdev = to_zpci(vdev->pdev);147 148	if (!zdev)149		return -ENODEV;150 151	if (!vdev->vdev.kvm)152		return 0;153 154	if (zpci_kvm_hook.kvm_register)155		return zpci_kvm_hook.kvm_register(zdev, vdev->vdev.kvm);156 157	return -ENOENT;158}159 160void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev)161{162	struct zpci_dev *zdev = to_zpci(vdev->pdev);163 164	if (!zdev || !vdev->vdev.kvm)165		return;166 167	if (zpci_kvm_hook.kvm_unregister)168		zpci_kvm_hook.kvm_unregister(zdev);169}170