]>
Commit | Line | Data |
---|---|---|
a8eac943 DJS |
1 | /* |
2 | * s390 CCW Assignment Support | |
3 | * | |
4 | * Copyright 2017 IBM Corp | |
5 | * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> | |
6 | * Xiao Feng Ren <renxiaof@linux.vnet.ibm.com> | |
7 | * Pierre Morel <pmorel@linux.vnet.ibm.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2 | |
10 | * or (at your option) any later version. See the COPYING file in the | |
11 | * top-level directory. | |
12 | */ | |
13 | #include "qemu/osdep.h" | |
14 | #include "qapi/error.h" | |
15 | #include "hw/sysbus.h" | |
16 | #include "libgen.h" | |
17 | #include "hw/s390x/css.h" | |
18 | #include "hw/s390x/css-bridge.h" | |
19 | #include "hw/s390x/s390-ccw.h" | |
20 | ||
21 | static void s390_ccw_get_dev_info(S390CCWDevice *cdev, | |
22 | char *sysfsdev, | |
23 | Error **errp) | |
24 | { | |
25 | unsigned int cssid, ssid, devid; | |
26 | char dev_path[PATH_MAX] = {0}, *tmp; | |
27 | ||
28 | if (!sysfsdev) { | |
29 | error_setg(errp, "No host device provided"); | |
30 | error_append_hint(errp, | |
31 | "Use -device vfio-ccw,sysfsdev=PATH_TO_DEVICE\n"); | |
32 | return; | |
33 | } | |
34 | ||
35 | if (!realpath(sysfsdev, dev_path)) { | |
36 | error_setg_errno(errp, errno, "Host device '%s' not found", sysfsdev); | |
37 | return; | |
38 | } | |
39 | ||
40 | cdev->mdevid = g_strdup(basename(dev_path)); | |
41 | ||
42 | tmp = basename(dirname(dev_path)); | |
43 | if (sscanf(tmp, "%2x.%1x.%4x", &cssid, &ssid, &devid) != 3) { | |
44 | error_setg_errno(errp, errno, "Failed to read %s", tmp); | |
45 | return; | |
46 | } | |
47 | ||
48 | cdev->hostid.cssid = cssid; | |
49 | cdev->hostid.ssid = ssid; | |
50 | cdev->hostid.devid = devid; | |
51 | cdev->hostid.valid = true; | |
52 | } | |
53 | ||
54 | static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp) | |
55 | { | |
56 | CcwDevice *ccw_dev = CCW_DEVICE(cdev); | |
57 | CCWDeviceClass *ck = CCW_DEVICE_GET_CLASS(ccw_dev); | |
58 | DeviceState *parent = DEVICE(ccw_dev); | |
59 | BusState *qbus = qdev_get_parent_bus(parent); | |
60 | VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus); | |
61 | SubchDev *sch; | |
62 | int ret; | |
63 | Error *err = NULL; | |
64 | ||
65 | s390_ccw_get_dev_info(cdev, sysfsdev, &err); | |
66 | if (err) { | |
67 | goto out_err_propagate; | |
68 | } | |
69 | ||
70 | sch = css_create_sch(ccw_dev->devno, false, cbus->squash_mcss, &err); | |
71 | if (!sch) { | |
72 | goto out_mdevid_free; | |
73 | } | |
74 | sch->driver_data = cdev; | |
75 | ||
76 | ccw_dev->sch = sch; | |
77 | ret = css_sch_build_schib(sch, &cdev->hostid); | |
78 | if (ret) { | |
79 | error_setg_errno(&err, -ret, "%s: Failed to build initial schib", | |
80 | __func__); | |
81 | goto out_err; | |
82 | } | |
83 | ||
84 | ck->realize(ccw_dev, &err); | |
85 | if (err) { | |
86 | goto out_err; | |
87 | } | |
88 | ||
89 | css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, | |
90 | parent->hotplugged, 1); | |
91 | return; | |
92 | ||
93 | out_err: | |
94 | css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); | |
95 | ccw_dev->sch = NULL; | |
96 | g_free(sch); | |
97 | out_mdevid_free: | |
98 | g_free(cdev->mdevid); | |
99 | out_err_propagate: | |
100 | error_propagate(errp, err); | |
101 | } | |
102 | ||
103 | static void s390_ccw_unrealize(S390CCWDevice *cdev, Error **errp) | |
104 | { | |
105 | CcwDevice *ccw_dev = CCW_DEVICE(cdev); | |
106 | SubchDev *sch = ccw_dev->sch; | |
107 | ||
108 | if (sch) { | |
109 | css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); | |
110 | g_free(sch); | |
111 | ccw_dev->sch = NULL; | |
112 | } | |
113 | ||
114 | g_free(cdev->mdevid); | |
115 | } | |
116 | ||
117 | static void s390_ccw_class_init(ObjectClass *klass, void *data) | |
118 | { | |
119 | DeviceClass *dc = DEVICE_CLASS(klass); | |
120 | S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass); | |
121 | ||
122 | dc->bus_type = TYPE_VIRTUAL_CSS_BUS; | |
123 | cdc->realize = s390_ccw_realize; | |
124 | cdc->unrealize = s390_ccw_unrealize; | |
125 | } | |
126 | ||
127 | static const TypeInfo s390_ccw_info = { | |
128 | .name = TYPE_S390_CCW, | |
129 | .parent = TYPE_CCW_DEVICE, | |
130 | .instance_size = sizeof(S390CCWDevice), | |
131 | .class_size = sizeof(S390CCWDeviceClass), | |
132 | .class_init = s390_ccw_class_init, | |
133 | .abstract = true, | |
134 | }; | |
135 | ||
136 | static void register_s390_ccw_type(void) | |
137 | { | |
138 | type_register_static(&s390_ccw_info); | |
139 | } | |
140 | ||
141 | type_init(register_s390_ccw_type) |