1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * VFIO ZPCI devices support
4 *
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 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 */
14#include <linux/io.h>
15#include <linux/pci.h>
16#include <linux/uaccess.h>
17#include <linux/vfio.h>
18#include <linux/vfio_zdev.h>
19#include <asm/pci_clp.h>
20#include <asm/pci_io.h>
21
22#include "vfio_pci_private.h"
23
24/*
25 * Add the Base PCI Function information to the device info region.
26 */
27static int zpci_base_cap(struct zpci_dev *zdev, struct vfio_pci_device *vdev,
28			 struct vfio_info_cap *caps)
29{
30	struct vfio_device_info_cap_zpci_base cap = {
31		.header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE,
32		.header.version = 1,
33		.start_dma = zdev->start_dma,
34		.end_dma = zdev->end_dma,
35		.pchid = zdev->pchid,
36		.vfn = zdev->vfn,
37		.fmb_length = zdev->fmb_length,
38		.pft = zdev->pft,
39		.gid = zdev->pfgid
40	};
41
42	return vfio_info_add_capability(caps, &cap.header, sizeof(cap));
43}
44
45/*
46 * Add the Base PCI Function Group information to the device info region.
47 */
48static int zpci_group_cap(struct zpci_dev *zdev, struct vfio_pci_device *vdev,
49			  struct vfio_info_cap *caps)
50{
51	struct vfio_device_info_cap_zpci_group cap = {
52		.header.id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP,
53		.header.version = 1,
54		.dasm = zdev->dma_mask,
55		.msi_addr = zdev->msi_addr,
56		.flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH,
57		.mui = zdev->fmb_update,
58		.noi = zdev->max_msi,
59		.maxstbl = ZPCI_MAX_WRITE_SIZE,
60		.version = zdev->version
61	};
62
63	return vfio_info_add_capability(caps, &cap.header, sizeof(cap));
64}
65
66/*
67 * Add the device utility string to the device info region.
68 */
69static int zpci_util_cap(struct zpci_dev *zdev, struct vfio_pci_device *vdev,
70			 struct vfio_info_cap *caps)
71{
72	struct vfio_device_info_cap_zpci_util *cap;
73	int cap_size = sizeof(*cap) + CLP_UTIL_STR_LEN;
74	int ret;
75
76	cap = kmalloc(cap_size, GFP_KERNEL);
77	if (!cap)
78		return -ENOMEM;
79
80	cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_UTIL;
81	cap->header.version = 1;
82	cap->size = CLP_UTIL_STR_LEN;
83	memcpy(cap->util_str, zdev->util_str, cap->size);
84
85	ret = vfio_info_add_capability(caps, &cap->header, cap_size);
86
87	kfree(cap);
88
89	return ret;
90}
91
92/*
93 * Add the function path string to the device info region.
94 */
95static int zpci_pfip_cap(struct zpci_dev *zdev, struct vfio_pci_device *vdev,
96			 struct vfio_info_cap *caps)
97{
98	struct vfio_device_info_cap_zpci_pfip *cap;
99	int cap_size = sizeof(*cap) + CLP_PFIP_NR_SEGMENTS;
100	int ret;
101
102	cap = kmalloc(cap_size, GFP_KERNEL);
103	if (!cap)
104		return -ENOMEM;
105
106	cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_PFIP;
107	cap->header.version = 1;
108	cap->size = CLP_PFIP_NR_SEGMENTS;
109	memcpy(cap->pfip, zdev->pfip, cap->size);
110
111	ret = vfio_info_add_capability(caps, &cap->header, cap_size);
112
113	kfree(cap);
114
115	return ret;
116}
117
118/*
119 * Add all supported capabilities to the VFIO_DEVICE_GET_INFO capability chain.
120 */
121int vfio_pci_info_zdev_add_caps(struct vfio_pci_device *vdev,
122				struct vfio_info_cap *caps)
123{
124	struct zpci_dev *zdev = to_zpci(vdev->pdev);
125	int ret;
126
127	if (!zdev)
128		return -ENODEV;
129
130	ret = zpci_base_cap(zdev, vdev, caps);
131	if (ret)
132		return ret;
133
134	ret = zpci_group_cap(zdev, vdev, caps);
135	if (ret)
136		return ret;
137
138	if (zdev->util_str_avail) {
139		ret = zpci_util_cap(zdev, vdev, caps);
140		if (ret)
141			return ret;
142	}
143
144	ret = zpci_pfip_cap(zdev, vdev, caps);
145
146	return ret;
147}
148