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