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