xref: /openbmc/qemu/hw/vfio/ccw.c (revision 1dcac3e15263674bb9c84feed6b35bb1f7bc1c6b)
1*1dcac3e1SXiao Feng Ren /*
2*1dcac3e1SXiao Feng Ren  * vfio based subchannel assignment support
3*1dcac3e1SXiao Feng Ren  *
4*1dcac3e1SXiao Feng Ren  * Copyright 2017 IBM Corp.
5*1dcac3e1SXiao Feng Ren  * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com>
6*1dcac3e1SXiao Feng Ren  *            Xiao Feng Ren <renxiaof@linux.vnet.ibm.com>
7*1dcac3e1SXiao Feng Ren  *            Pierre Morel <pmorel@linux.vnet.ibm.com>
8*1dcac3e1SXiao Feng Ren  *
9*1dcac3e1SXiao Feng Ren  * This work is licensed under the terms of the GNU GPL, version 2 or(at
10*1dcac3e1SXiao Feng Ren  * your option) any version. See the COPYING file in the top-level
11*1dcac3e1SXiao Feng Ren  * directory.
12*1dcac3e1SXiao Feng Ren  */
13*1dcac3e1SXiao Feng Ren 
14*1dcac3e1SXiao Feng Ren #include <linux/vfio.h>
15*1dcac3e1SXiao Feng Ren #include <sys/ioctl.h>
16*1dcac3e1SXiao Feng Ren 
17*1dcac3e1SXiao Feng Ren #include "qemu/osdep.h"
18*1dcac3e1SXiao Feng Ren #include "qapi/error.h"
19*1dcac3e1SXiao Feng Ren #include "hw/sysbus.h"
20*1dcac3e1SXiao Feng Ren #include "hw/vfio/vfio.h"
21*1dcac3e1SXiao Feng Ren #include "hw/vfio/vfio-common.h"
22*1dcac3e1SXiao Feng Ren #include "hw/s390x/s390-ccw.h"
23*1dcac3e1SXiao Feng Ren #include "hw/s390x/ccw-device.h"
24*1dcac3e1SXiao Feng Ren 
25*1dcac3e1SXiao Feng Ren #define TYPE_VFIO_CCW "vfio-ccw"
26*1dcac3e1SXiao Feng Ren typedef struct VFIOCCWDevice {
27*1dcac3e1SXiao Feng Ren     S390CCWDevice cdev;
28*1dcac3e1SXiao Feng Ren     VFIODevice vdev;
29*1dcac3e1SXiao Feng Ren } VFIOCCWDevice;
30*1dcac3e1SXiao Feng Ren 
31*1dcac3e1SXiao Feng Ren static void vfio_ccw_compute_needs_reset(VFIODevice *vdev)
32*1dcac3e1SXiao Feng Ren {
33*1dcac3e1SXiao Feng Ren     vdev->needs_reset = false;
34*1dcac3e1SXiao Feng Ren }
35*1dcac3e1SXiao Feng Ren 
36*1dcac3e1SXiao Feng Ren /*
37*1dcac3e1SXiao Feng Ren  * We don't need vfio_hot_reset_multi and vfio_eoi operations for
38*1dcac3e1SXiao Feng Ren  * vfio_ccw device now.
39*1dcac3e1SXiao Feng Ren  */
40*1dcac3e1SXiao Feng Ren struct VFIODeviceOps vfio_ccw_ops = {
41*1dcac3e1SXiao Feng Ren     .vfio_compute_needs_reset = vfio_ccw_compute_needs_reset,
42*1dcac3e1SXiao Feng Ren };
43*1dcac3e1SXiao Feng Ren 
44*1dcac3e1SXiao Feng Ren static void vfio_ccw_reset(DeviceState *dev)
45*1dcac3e1SXiao Feng Ren {
46*1dcac3e1SXiao Feng Ren     CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
47*1dcac3e1SXiao Feng Ren     S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev);
48*1dcac3e1SXiao Feng Ren     VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
49*1dcac3e1SXiao Feng Ren 
50*1dcac3e1SXiao Feng Ren     ioctl(vcdev->vdev.fd, VFIO_DEVICE_RESET);
51*1dcac3e1SXiao Feng Ren }
52*1dcac3e1SXiao Feng Ren 
53*1dcac3e1SXiao Feng Ren static void vfio_put_device(VFIOCCWDevice *vcdev)
54*1dcac3e1SXiao Feng Ren {
55*1dcac3e1SXiao Feng Ren     g_free(vcdev->vdev.name);
56*1dcac3e1SXiao Feng Ren     vfio_put_base_device(&vcdev->vdev);
57*1dcac3e1SXiao Feng Ren }
58*1dcac3e1SXiao Feng Ren 
59*1dcac3e1SXiao Feng Ren static VFIOGroup *vfio_ccw_get_group(S390CCWDevice *cdev, Error **errp)
60*1dcac3e1SXiao Feng Ren {
61*1dcac3e1SXiao Feng Ren     char *tmp, group_path[PATH_MAX];
62*1dcac3e1SXiao Feng Ren     ssize_t len;
63*1dcac3e1SXiao Feng Ren     int groupid;
64*1dcac3e1SXiao Feng Ren 
65*1dcac3e1SXiao Feng Ren     tmp = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/%s/iommu_group",
66*1dcac3e1SXiao Feng Ren                           cdev->hostid.cssid, cdev->hostid.ssid,
67*1dcac3e1SXiao Feng Ren                           cdev->hostid.devid, cdev->mdevid);
68*1dcac3e1SXiao Feng Ren     len = readlink(tmp, group_path, sizeof(group_path));
69*1dcac3e1SXiao Feng Ren     g_free(tmp);
70*1dcac3e1SXiao Feng Ren 
71*1dcac3e1SXiao Feng Ren     if (len <= 0 || len >= sizeof(group_path)) {
72*1dcac3e1SXiao Feng Ren         error_setg(errp, "vfio: no iommu_group found");
73*1dcac3e1SXiao Feng Ren         return NULL;
74*1dcac3e1SXiao Feng Ren     }
75*1dcac3e1SXiao Feng Ren 
76*1dcac3e1SXiao Feng Ren     group_path[len] = 0;
77*1dcac3e1SXiao Feng Ren 
78*1dcac3e1SXiao Feng Ren     if (sscanf(basename(group_path), "%d", &groupid) != 1) {
79*1dcac3e1SXiao Feng Ren         error_setg(errp, "vfio: failed to read %s", group_path);
80*1dcac3e1SXiao Feng Ren         return NULL;
81*1dcac3e1SXiao Feng Ren     }
82*1dcac3e1SXiao Feng Ren 
83*1dcac3e1SXiao Feng Ren     return vfio_get_group(groupid, &address_space_memory, errp);
84*1dcac3e1SXiao Feng Ren }
85*1dcac3e1SXiao Feng Ren 
86*1dcac3e1SXiao Feng Ren static void vfio_ccw_realize(DeviceState *dev, Error **errp)
87*1dcac3e1SXiao Feng Ren {
88*1dcac3e1SXiao Feng Ren     VFIODevice *vbasedev;
89*1dcac3e1SXiao Feng Ren     VFIOGroup *group;
90*1dcac3e1SXiao Feng Ren     CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
91*1dcac3e1SXiao Feng Ren     S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev);
92*1dcac3e1SXiao Feng Ren     VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
93*1dcac3e1SXiao Feng Ren     S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev);
94*1dcac3e1SXiao Feng Ren     Error *err = NULL;
95*1dcac3e1SXiao Feng Ren 
96*1dcac3e1SXiao Feng Ren     /* Call the class init function for subchannel. */
97*1dcac3e1SXiao Feng Ren     if (cdc->realize) {
98*1dcac3e1SXiao Feng Ren         cdc->realize(cdev, vcdev->vdev.sysfsdev, &err);
99*1dcac3e1SXiao Feng Ren         if (err) {
100*1dcac3e1SXiao Feng Ren             goto out_err_propagate;
101*1dcac3e1SXiao Feng Ren         }
102*1dcac3e1SXiao Feng Ren     }
103*1dcac3e1SXiao Feng Ren 
104*1dcac3e1SXiao Feng Ren     group = vfio_ccw_get_group(cdev, &err);
105*1dcac3e1SXiao Feng Ren     if (!group) {
106*1dcac3e1SXiao Feng Ren         goto out_group_err;
107*1dcac3e1SXiao Feng Ren     }
108*1dcac3e1SXiao Feng Ren 
109*1dcac3e1SXiao Feng Ren     vcdev->vdev.ops = &vfio_ccw_ops;
110*1dcac3e1SXiao Feng Ren     vcdev->vdev.type = VFIO_DEVICE_TYPE_CCW;
111*1dcac3e1SXiao Feng Ren     vcdev->vdev.name = g_strdup_printf("%x.%x.%04x", cdev->hostid.cssid,
112*1dcac3e1SXiao Feng Ren                                        cdev->hostid.ssid, cdev->hostid.devid);
113*1dcac3e1SXiao Feng Ren     QLIST_FOREACH(vbasedev, &group->device_list, next) {
114*1dcac3e1SXiao Feng Ren         if (strcmp(vbasedev->name, vcdev->vdev.name) == 0) {
115*1dcac3e1SXiao Feng Ren             error_setg(&err, "vfio: subchannel %s has already been attached",
116*1dcac3e1SXiao Feng Ren                        vcdev->vdev.name);
117*1dcac3e1SXiao Feng Ren             goto out_device_err;
118*1dcac3e1SXiao Feng Ren         }
119*1dcac3e1SXiao Feng Ren     }
120*1dcac3e1SXiao Feng Ren 
121*1dcac3e1SXiao Feng Ren     if (vfio_get_device(group, cdev->mdevid, &vcdev->vdev, &err)) {
122*1dcac3e1SXiao Feng Ren         goto out_device_err;
123*1dcac3e1SXiao Feng Ren     }
124*1dcac3e1SXiao Feng Ren 
125*1dcac3e1SXiao Feng Ren     return;
126*1dcac3e1SXiao Feng Ren 
127*1dcac3e1SXiao Feng Ren out_device_err:
128*1dcac3e1SXiao Feng Ren     vfio_put_group(group);
129*1dcac3e1SXiao Feng Ren out_group_err:
130*1dcac3e1SXiao Feng Ren     if (cdc->unrealize) {
131*1dcac3e1SXiao Feng Ren         cdc->unrealize(cdev, NULL);
132*1dcac3e1SXiao Feng Ren     }
133*1dcac3e1SXiao Feng Ren out_err_propagate:
134*1dcac3e1SXiao Feng Ren     error_propagate(errp, err);
135*1dcac3e1SXiao Feng Ren }
136*1dcac3e1SXiao Feng Ren 
137*1dcac3e1SXiao Feng Ren static void vfio_ccw_unrealize(DeviceState *dev, Error **errp)
138*1dcac3e1SXiao Feng Ren {
139*1dcac3e1SXiao Feng Ren     CcwDevice *ccw_dev = DO_UPCAST(CcwDevice, parent_obj, dev);
140*1dcac3e1SXiao Feng Ren     S390CCWDevice *cdev = DO_UPCAST(S390CCWDevice, parent_obj, ccw_dev);
141*1dcac3e1SXiao Feng Ren     VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev);
142*1dcac3e1SXiao Feng Ren     S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev);
143*1dcac3e1SXiao Feng Ren     VFIOGroup *group = vcdev->vdev.group;
144*1dcac3e1SXiao Feng Ren 
145*1dcac3e1SXiao Feng Ren     vfio_put_device(vcdev);
146*1dcac3e1SXiao Feng Ren     vfio_put_group(group);
147*1dcac3e1SXiao Feng Ren 
148*1dcac3e1SXiao Feng Ren     if (cdc->unrealize) {
149*1dcac3e1SXiao Feng Ren         cdc->unrealize(cdev, errp);
150*1dcac3e1SXiao Feng Ren     }
151*1dcac3e1SXiao Feng Ren }
152*1dcac3e1SXiao Feng Ren 
153*1dcac3e1SXiao Feng Ren static Property vfio_ccw_properties[] = {
154*1dcac3e1SXiao Feng Ren     DEFINE_PROP_STRING("sysfsdev", VFIOCCWDevice, vdev.sysfsdev),
155*1dcac3e1SXiao Feng Ren     DEFINE_PROP_END_OF_LIST(),
156*1dcac3e1SXiao Feng Ren };
157*1dcac3e1SXiao Feng Ren 
158*1dcac3e1SXiao Feng Ren static const VMStateDescription vfio_ccw_vmstate = {
159*1dcac3e1SXiao Feng Ren     .name = TYPE_VFIO_CCW,
160*1dcac3e1SXiao Feng Ren     .unmigratable = 1,
161*1dcac3e1SXiao Feng Ren };
162*1dcac3e1SXiao Feng Ren 
163*1dcac3e1SXiao Feng Ren static void vfio_ccw_class_init(ObjectClass *klass, void *data)
164*1dcac3e1SXiao Feng Ren {
165*1dcac3e1SXiao Feng Ren     DeviceClass *dc = DEVICE_CLASS(klass);
166*1dcac3e1SXiao Feng Ren 
167*1dcac3e1SXiao Feng Ren     dc->props = vfio_ccw_properties;
168*1dcac3e1SXiao Feng Ren     dc->vmsd = &vfio_ccw_vmstate;
169*1dcac3e1SXiao Feng Ren     dc->desc = "VFIO-based subchannel assignment";
170*1dcac3e1SXiao Feng Ren     dc->realize = vfio_ccw_realize;
171*1dcac3e1SXiao Feng Ren     dc->unrealize = vfio_ccw_unrealize;
172*1dcac3e1SXiao Feng Ren     dc->reset = vfio_ccw_reset;
173*1dcac3e1SXiao Feng Ren }
174*1dcac3e1SXiao Feng Ren 
175*1dcac3e1SXiao Feng Ren static const TypeInfo vfio_ccw_info = {
176*1dcac3e1SXiao Feng Ren     .name = TYPE_VFIO_CCW,
177*1dcac3e1SXiao Feng Ren     .parent = TYPE_S390_CCW,
178*1dcac3e1SXiao Feng Ren     .instance_size = sizeof(VFIOCCWDevice),
179*1dcac3e1SXiao Feng Ren     .class_init = vfio_ccw_class_init,
180*1dcac3e1SXiao Feng Ren };
181*1dcac3e1SXiao Feng Ren 
182*1dcac3e1SXiao Feng Ren static void register_vfio_ccw_type(void)
183*1dcac3e1SXiao Feng Ren {
184*1dcac3e1SXiao Feng Ren     type_register_static(&vfio_ccw_info);
185*1dcac3e1SXiao Feng Ren }
186*1dcac3e1SXiao Feng Ren 
187*1dcac3e1SXiao Feng Ren type_init(register_vfio_ccw_type)
188