xref: /openbmc/linux/drivers/vfio/pci/vfio_pci_zdev.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
129848a03SCai Huoqing // SPDX-License-Identifier: GPL-2.0-only
2e6b817d4SMatthew Rosato /*
3e6b817d4SMatthew Rosato  * VFIO ZPCI devices support
4e6b817d4SMatthew Rosato  *
5e6b817d4SMatthew Rosato  * Copyright (C) IBM Corp. 2020.  All rights reserved.
6e6b817d4SMatthew Rosato  *	Author(s): Pierre Morel <pmorel@linux.ibm.com>
7e6b817d4SMatthew Rosato  *                 Matthew Rosato <mjrosato@linux.ibm.com>
8e6b817d4SMatthew Rosato  */
9e6b817d4SMatthew Rosato #include <linux/io.h>
10e6b817d4SMatthew Rosato #include <linux/pci.h>
11e6b817d4SMatthew Rosato #include <linux/uaccess.h>
12e6b817d4SMatthew Rosato #include <linux/vfio.h>
13e6b817d4SMatthew Rosato #include <linux/vfio_zdev.h>
148061d1c3SMatthew Rosato #include <linux/kvm_host.h>
15e6b817d4SMatthew Rosato #include <asm/pci_clp.h>
16e6b817d4SMatthew Rosato #include <asm/pci_io.h>
17e6b817d4SMatthew Rosato 
18*e34a0425SJason Gunthorpe #include "vfio_pci_priv.h"
19e6b817d4SMatthew Rosato 
20e6b817d4SMatthew Rosato /*
21e6b817d4SMatthew Rosato  * Add the Base PCI Function information to the device info region.
22e6b817d4SMatthew Rosato  */
zpci_base_cap(struct zpci_dev * zdev,struct vfio_info_cap * caps)2346c47466SMax Gurtovoy static int zpci_base_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)
24e6b817d4SMatthew Rosato {
25e6b817d4SMatthew Rosato 	struct vfio_device_info_cap_zpci_base cap = {
26e6b817d4SMatthew Rosato 		.header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE,
27faf3bfcbSMatthew Rosato 		.header.version = 2,
28e6b817d4SMatthew Rosato 		.start_dma = zdev->start_dma,
29e6b817d4SMatthew Rosato 		.end_dma = zdev->end_dma,
30e6b817d4SMatthew Rosato 		.pchid = zdev->pchid,
31e6b817d4SMatthew Rosato 		.vfn = zdev->vfn,
32e6b817d4SMatthew Rosato 		.fmb_length = zdev->fmb_length,
33e6b817d4SMatthew Rosato 		.pft = zdev->pft,
34faf3bfcbSMatthew Rosato 		.gid = zdev->pfgid,
35faf3bfcbSMatthew Rosato 		.fh = zdev->fh
36e6b817d4SMatthew Rosato 	};
37e6b817d4SMatthew Rosato 
38e6b817d4SMatthew Rosato 	return vfio_info_add_capability(caps, &cap.header, sizeof(cap));
39e6b817d4SMatthew Rosato }
40e6b817d4SMatthew Rosato 
41e6b817d4SMatthew Rosato /*
42e6b817d4SMatthew Rosato  * Add the Base PCI Function Group information to the device info region.
43e6b817d4SMatthew Rosato  */
zpci_group_cap(struct zpci_dev * zdev,struct vfio_info_cap * caps)4446c47466SMax Gurtovoy static int zpci_group_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)
45e6b817d4SMatthew Rosato {
46e6b817d4SMatthew Rosato 	struct vfio_device_info_cap_zpci_group cap = {
47e6b817d4SMatthew Rosato 		.header.id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP,
48ba6090ffSMatthew Rosato 		.header.version = 2,
49e6b817d4SMatthew Rosato 		.dasm = zdev->dma_mask,
50e6b817d4SMatthew Rosato 		.msi_addr = zdev->msi_addr,
51e6b817d4SMatthew Rosato 		.flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH,
52e6b817d4SMatthew Rosato 		.mui = zdev->fmb_update,
53e6b817d4SMatthew Rosato 		.noi = zdev->max_msi,
54e6b817d4SMatthew Rosato 		.maxstbl = ZPCI_MAX_WRITE_SIZE,
55ba6090ffSMatthew Rosato 		.version = zdev->version,
56ba6090ffSMatthew Rosato 		.reserved = 0,
57ba6090ffSMatthew Rosato 		.imaxstbl = zdev->maxstbl
58e6b817d4SMatthew Rosato 	};
59e6b817d4SMatthew Rosato 
60e6b817d4SMatthew Rosato 	return vfio_info_add_capability(caps, &cap.header, sizeof(cap));
61e6b817d4SMatthew Rosato }
62e6b817d4SMatthew Rosato 
63e6b817d4SMatthew Rosato /*
64e6b817d4SMatthew Rosato  * Add the device utility string to the device info region.
65e6b817d4SMatthew Rosato  */
zpci_util_cap(struct zpci_dev * zdev,struct vfio_info_cap * caps)6646c47466SMax Gurtovoy static int zpci_util_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)
67e6b817d4SMatthew Rosato {
68e6b817d4SMatthew Rosato 	struct vfio_device_info_cap_zpci_util *cap;
69e6b817d4SMatthew Rosato 	int cap_size = sizeof(*cap) + CLP_UTIL_STR_LEN;
70e6b817d4SMatthew Rosato 	int ret;
71e6b817d4SMatthew Rosato 
72e6b817d4SMatthew Rosato 	cap = kmalloc(cap_size, GFP_KERNEL);
737e31d6dcSMax Gurtovoy 	if (!cap)
747e31d6dcSMax Gurtovoy 		return -ENOMEM;
75e6b817d4SMatthew Rosato 
76e6b817d4SMatthew Rosato 	cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_UTIL;
77e6b817d4SMatthew Rosato 	cap->header.version = 1;
78e6b817d4SMatthew Rosato 	cap->size = CLP_UTIL_STR_LEN;
79e6b817d4SMatthew Rosato 	memcpy(cap->util_str, zdev->util_str, cap->size);
80e6b817d4SMatthew Rosato 
81e6b817d4SMatthew Rosato 	ret = vfio_info_add_capability(caps, &cap->header, cap_size);
82e6b817d4SMatthew Rosato 
83e6b817d4SMatthew Rosato 	kfree(cap);
84e6b817d4SMatthew Rosato 
85e6b817d4SMatthew Rosato 	return ret;
86e6b817d4SMatthew Rosato }
87e6b817d4SMatthew Rosato 
88e6b817d4SMatthew Rosato /*
89e6b817d4SMatthew Rosato  * Add the function path string to the device info region.
90e6b817d4SMatthew Rosato  */
zpci_pfip_cap(struct zpci_dev * zdev,struct vfio_info_cap * caps)9146c47466SMax Gurtovoy static int zpci_pfip_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps)
92e6b817d4SMatthew Rosato {
93e6b817d4SMatthew Rosato 	struct vfio_device_info_cap_zpci_pfip *cap;
94e6b817d4SMatthew Rosato 	int cap_size = sizeof(*cap) + CLP_PFIP_NR_SEGMENTS;
95e6b817d4SMatthew Rosato 	int ret;
96e6b817d4SMatthew Rosato 
97e6b817d4SMatthew Rosato 	cap = kmalloc(cap_size, GFP_KERNEL);
987e31d6dcSMax Gurtovoy 	if (!cap)
997e31d6dcSMax Gurtovoy 		return -ENOMEM;
100e6b817d4SMatthew Rosato 
101e6b817d4SMatthew Rosato 	cap->header.id = VFIO_DEVICE_INFO_CAP_ZPCI_PFIP;
102e6b817d4SMatthew Rosato 	cap->header.version = 1;
103e6b817d4SMatthew Rosato 	cap->size = CLP_PFIP_NR_SEGMENTS;
104e6b817d4SMatthew Rosato 	memcpy(cap->pfip, zdev->pfip, cap->size);
105e6b817d4SMatthew Rosato 
106e6b817d4SMatthew Rosato 	ret = vfio_info_add_capability(caps, &cap->header, cap_size);
107e6b817d4SMatthew Rosato 
108e6b817d4SMatthew Rosato 	kfree(cap);
109e6b817d4SMatthew Rosato 
110e6b817d4SMatthew Rosato 	return ret;
111e6b817d4SMatthew Rosato }
112e6b817d4SMatthew Rosato 
113e6b817d4SMatthew Rosato /*
114e6b817d4SMatthew Rosato  * Add all supported capabilities to the VFIO_DEVICE_GET_INFO capability chain.
115e6b817d4SMatthew Rosato  */
vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device * vdev,struct vfio_info_cap * caps)11653647510SMax Gurtovoy int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev,
117e6b817d4SMatthew Rosato 				struct vfio_info_cap *caps)
118e6b817d4SMatthew Rosato {
119e6b817d4SMatthew Rosato 	struct zpci_dev *zdev = to_zpci(vdev->pdev);
120e6b817d4SMatthew Rosato 	int ret;
121e6b817d4SMatthew Rosato 
122e6b817d4SMatthew Rosato 	if (!zdev)
123e6b817d4SMatthew Rosato 		return -ENODEV;
124e6b817d4SMatthew Rosato 
12546c47466SMax Gurtovoy 	ret = zpci_base_cap(zdev, caps);
126e6b817d4SMatthew Rosato 	if (ret)
127e6b817d4SMatthew Rosato 		return ret;
128e6b817d4SMatthew Rosato 
12946c47466SMax Gurtovoy 	ret = zpci_group_cap(zdev, caps);
130e6b817d4SMatthew Rosato 	if (ret)
131e6b817d4SMatthew Rosato 		return ret;
132e6b817d4SMatthew Rosato 
133e6b817d4SMatthew Rosato 	if (zdev->util_str_avail) {
13446c47466SMax Gurtovoy 		ret = zpci_util_cap(zdev, caps);
135e6b817d4SMatthew Rosato 		if (ret)
136e6b817d4SMatthew Rosato 			return ret;
137e6b817d4SMatthew Rosato 	}
138e6b817d4SMatthew Rosato 
13946c47466SMax Gurtovoy 	ret = zpci_pfip_cap(zdev, caps);
140e6b817d4SMatthew Rosato 
141e6b817d4SMatthew Rosato 	return ret;
142e6b817d4SMatthew Rosato }
1438061d1c3SMatthew Rosato 
vfio_pci_zdev_open_device(struct vfio_pci_core_device * vdev)1448061d1c3SMatthew Rosato int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev)
1458061d1c3SMatthew Rosato {
1468061d1c3SMatthew Rosato 	struct zpci_dev *zdev = to_zpci(vdev->pdev);
1478061d1c3SMatthew Rosato 
1488061d1c3SMatthew Rosato 	if (!zdev)
1498061d1c3SMatthew Rosato 		return -ENODEV;
1508061d1c3SMatthew Rosato 
1518061d1c3SMatthew Rosato 	if (!vdev->vdev.kvm)
1528061d1c3SMatthew Rosato 		return 0;
1538061d1c3SMatthew Rosato 
154ca922fecSPierre Morel 	if (zpci_kvm_hook.kvm_register)
155ca922fecSPierre Morel 		return zpci_kvm_hook.kvm_register(zdev, vdev->vdev.kvm);
156ca922fecSPierre Morel 
157ca922fecSPierre Morel 	return -ENOENT;
1588061d1c3SMatthew Rosato }
1598061d1c3SMatthew Rosato 
vfio_pci_zdev_close_device(struct vfio_pci_core_device * vdev)1608061d1c3SMatthew Rosato void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev)
1618061d1c3SMatthew Rosato {
1628061d1c3SMatthew Rosato 	struct zpci_dev *zdev = to_zpci(vdev->pdev);
1638061d1c3SMatthew Rosato 
1648061d1c3SMatthew Rosato 	if (!zdev || !vdev->vdev.kvm)
1658061d1c3SMatthew Rosato 		return;
1668061d1c3SMatthew Rosato 
167ca922fecSPierre Morel 	if (zpci_kvm_hook.kvm_unregister)
168ca922fecSPierre Morel 		zpci_kvm_hook.kvm_unregister(zdev);
1698061d1c3SMatthew Rosato }
170