]>
Commit | Line | Data |
---|---|---|
dd70bd0d JL |
1 | /* |
2 | * css bridge implementation | |
3 | * | |
4 | * Copyright 2012,2016 IBM Corp. | |
5 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> | |
6 | * Pierre Morel <pmorel@linux.vnet.ibm.com> | |
7 | * | |
8 | * This work is licensed under the terms of the GNU GPL, version 2 or (at | |
9 | * your option) any later version. See the COPYING file in the top-level | |
10 | * directory. | |
11 | */ | |
0b8fa32f | 12 | |
dd70bd0d JL |
13 | #include "qemu/osdep.h" |
14 | #include "qapi/error.h" | |
dd70bd0d | 15 | #include "hw/hotplug.h" |
a27bd6c7 | 16 | #include "hw/qdev-properties.h" |
dd70bd0d JL |
17 | #include "hw/sysbus.h" |
18 | #include "qemu/bitops.h" | |
0b8fa32f | 19 | #include "qemu/module.h" |
dd70bd0d | 20 | #include "hw/s390x/css.h" |
b804e8a6 | 21 | #include "ccw-device.h" |
dd70bd0d | 22 | #include "hw/s390x/css-bridge.h" |
817d4a6b | 23 | #include "cpu.h" |
dd70bd0d | 24 | |
b804e8a6 JL |
25 | /* |
26 | * Invoke device-specific unplug handler, disable the subchannel | |
27 | * (including sending a channel report to the guest) and remove the | |
28 | * device from the virtual css bus. | |
29 | */ | |
30 | static void ccw_device_unplug(HotplugHandler *hotplug_dev, | |
31 | DeviceState *dev, Error **errp) | |
32 | { | |
33 | CcwDevice *ccw_dev = CCW_DEVICE(dev); | |
34 | CCWDeviceClass *k = CCW_DEVICE_GET_CLASS(ccw_dev); | |
35 | SubchDev *sch = ccw_dev->sch; | |
36 | Error *err = NULL; | |
37 | ||
38 | if (k->unplug) { | |
39 | k->unplug(hotplug_dev, dev, &err); | |
40 | if (err) { | |
41 | error_propagate(errp, err); | |
42 | return; | |
43 | } | |
44 | } | |
45 | ||
46 | /* | |
47 | * We should arrive here only for device_del, since we don't support | |
48 | * direct hot(un)plug of channels. | |
49 | */ | |
50 | assert(sch != NULL); | |
51 | /* Subchannel is now disabled and no longer valid. */ | |
52 | sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA | | |
53 | PMCW_FLAGS_MASK_DNV); | |
54 | ||
55 | css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); | |
56 | ||
07578b0a | 57 | object_property_set_bool(OBJECT(dev), false, "realized", NULL); |
b804e8a6 JL |
58 | } |
59 | ||
dd70bd0d JL |
60 | static void virtual_css_bus_reset(BusState *qbus) |
61 | { | |
62 | /* This should actually be modelled via the generic css */ | |
63 | css_reset(); | |
64 | } | |
65 | ||
2a79eb1a CH |
66 | static char *virtual_css_bus_get_dev_path(DeviceState *dev) |
67 | { | |
68 | CcwDevice *ccw_dev = CCW_DEVICE(dev); | |
69 | SubchDev *sch = ccw_dev->sch; | |
70 | VirtualCssBridge *bridge = | |
71 | VIRTUAL_CSS_BRIDGE(qdev_get_parent_bus(dev)->parent); | |
72 | ||
73 | /* | |
74 | * We can't provide a dev path for backward compatibility on | |
75 | * older machines, as it is visible in the migration stream. | |
76 | */ | |
77 | return bridge->css_dev_path ? | |
78 | g_strdup_printf("/%02x.%1x.%04x", sch->cssid, sch->ssid, sch->devno) : | |
79 | NULL; | |
80 | } | |
81 | ||
dd70bd0d JL |
82 | static void virtual_css_bus_class_init(ObjectClass *klass, void *data) |
83 | { | |
84 | BusClass *k = BUS_CLASS(klass); | |
85 | ||
86 | k->reset = virtual_css_bus_reset; | |
2a79eb1a | 87 | k->get_dev_path = virtual_css_bus_get_dev_path; |
dd70bd0d JL |
88 | } |
89 | ||
90 | static const TypeInfo virtual_css_bus_info = { | |
91 | .name = TYPE_VIRTUAL_CSS_BUS, | |
92 | .parent = TYPE_BUS, | |
93 | .instance_size = sizeof(VirtualCssBus), | |
94 | .class_init = virtual_css_bus_class_init, | |
95 | }; | |
96 | ||
97 | VirtualCssBus *virtual_css_bus_init(void) | |
98 | { | |
99 | VirtualCssBus *cbus; | |
100 | BusState *bus; | |
101 | DeviceState *dev; | |
102 | ||
103 | /* Create bridge device */ | |
104 | dev = qdev_create(NULL, TYPE_VIRTUAL_CSS_BRIDGE); | |
864c2512 CH |
105 | object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE, |
106 | OBJECT(dev), NULL); | |
dd70bd0d JL |
107 | qdev_init_nofail(dev); |
108 | ||
109 | /* Create bus on bridge device */ | |
110 | bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); | |
111 | cbus = VIRTUAL_CSS_BUS(bus); | |
112 | ||
113 | /* Enable hotplugging */ | |
94d1cc5f | 114 | qbus_set_hotplug_handler(bus, OBJECT(dev), &error_abort); |
dd70bd0d | 115 | |
dde522bb | 116 | css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false, |
1497c160 | 117 | 0, &error_abort); |
dde522bb | 118 | |
dd70bd0d JL |
119 | return cbus; |
120 | } | |
121 | ||
122 | /***************** Virtual-css Bus Bridge Device ********************/ | |
123 | ||
2a79eb1a CH |
124 | static Property virtual_css_bridge_properties[] = { |
125 | DEFINE_PROP_BOOL("css_dev_path", VirtualCssBridge, css_dev_path, | |
126 | true), | |
127 | DEFINE_PROP_END_OF_LIST(), | |
128 | }; | |
129 | ||
99577c49 HP |
130 | static bool prop_get_true(Object *obj, Error **errp) |
131 | { | |
132 | return true; | |
133 | } | |
134 | ||
dd70bd0d JL |
135 | static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) |
136 | { | |
137 | HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); | |
138 | DeviceClass *dc = DEVICE_CLASS(klass); | |
139 | ||
b804e8a6 | 140 | hc->unplug = ccw_device_unplug; |
dd70bd0d | 141 | set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); |
2a79eb1a | 142 | dc->props = virtual_css_bridge_properties; |
99577c49 HP |
143 | object_class_property_add_bool(klass, "cssid-unrestricted", |
144 | prop_get_true, NULL, NULL); | |
145 | object_class_property_set_description(klass, "cssid-unrestricted", | |
146 | "A css device can use any cssid, regardless whether virtual" | |
147 | " or not (read only, always true)", | |
148 | NULL); | |
dd70bd0d JL |
149 | } |
150 | ||
151 | static const TypeInfo virtual_css_bridge_info = { | |
152 | .name = TYPE_VIRTUAL_CSS_BRIDGE, | |
153 | .parent = TYPE_SYS_BUS_DEVICE, | |
2a79eb1a | 154 | .instance_size = sizeof(VirtualCssBridge), |
dd70bd0d JL |
155 | .class_init = virtual_css_bridge_class_init, |
156 | .interfaces = (InterfaceInfo[]) { | |
157 | { TYPE_HOTPLUG_HANDLER }, | |
158 | { } | |
159 | } | |
160 | }; | |
161 | ||
162 | static void virtual_css_register(void) | |
163 | { | |
164 | type_register_static(&virtual_css_bridge_info); | |
165 | type_register_static(&virtual_css_bus_info); | |
166 | } | |
167 | ||
168 | type_init(virtual_css_register) |