]>
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 JL |
22 | #include "hw/s390x/css-bridge.h" |
23 | ||
b804e8a6 JL |
24 | /* |
25 | * Invoke device-specific unplug handler, disable the subchannel | |
26 | * (including sending a channel report to the guest) and remove the | |
27 | * device from the virtual css bus. | |
28 | */ | |
29 | static void ccw_device_unplug(HotplugHandler *hotplug_dev, | |
30 | DeviceState *dev, Error **errp) | |
31 | { | |
32 | CcwDevice *ccw_dev = CCW_DEVICE(dev); | |
33 | CCWDeviceClass *k = CCW_DEVICE_GET_CLASS(ccw_dev); | |
34 | SubchDev *sch = ccw_dev->sch; | |
35 | Error *err = NULL; | |
36 | ||
37 | if (k->unplug) { | |
38 | k->unplug(hotplug_dev, dev, &err); | |
39 | if (err) { | |
40 | error_propagate(errp, err); | |
41 | return; | |
42 | } | |
43 | } | |
44 | ||
45 | /* | |
46 | * We should arrive here only for device_del, since we don't support | |
47 | * direct hot(un)plug of channels. | |
48 | */ | |
49 | assert(sch != NULL); | |
50 | /* Subchannel is now disabled and no longer valid. */ | |
51 | sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA | | |
52 | PMCW_FLAGS_MASK_DNV); | |
53 | ||
54 | css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); | |
55 | ||
981c3dcd | 56 | qdev_unrealize(dev); |
b804e8a6 JL |
57 | } |
58 | ||
dd70bd0d JL |
59 | static void virtual_css_bus_reset(BusState *qbus) |
60 | { | |
61 | /* This should actually be modelled via the generic css */ | |
62 | css_reset(); | |
63 | } | |
64 | ||
2a79eb1a CH |
65 | static char *virtual_css_bus_get_dev_path(DeviceState *dev) |
66 | { | |
67 | CcwDevice *ccw_dev = CCW_DEVICE(dev); | |
68 | SubchDev *sch = ccw_dev->sch; | |
69 | VirtualCssBridge *bridge = | |
70 | VIRTUAL_CSS_BRIDGE(qdev_get_parent_bus(dev)->parent); | |
71 | ||
72 | /* | |
73 | * We can't provide a dev path for backward compatibility on | |
74 | * older machines, as it is visible in the migration stream. | |
75 | */ | |
76 | return bridge->css_dev_path ? | |
77 | g_strdup_printf("/%02x.%1x.%04x", sch->cssid, sch->ssid, sch->devno) : | |
78 | NULL; | |
79 | } | |
80 | ||
dd70bd0d JL |
81 | static void virtual_css_bus_class_init(ObjectClass *klass, void *data) |
82 | { | |
83 | BusClass *k = BUS_CLASS(klass); | |
84 | ||
85 | k->reset = virtual_css_bus_reset; | |
2a79eb1a | 86 | k->get_dev_path = virtual_css_bus_get_dev_path; |
dd70bd0d JL |
87 | } |
88 | ||
89 | static const TypeInfo virtual_css_bus_info = { | |
90 | .name = TYPE_VIRTUAL_CSS_BUS, | |
91 | .parent = TYPE_BUS, | |
92 | .instance_size = sizeof(VirtualCssBus), | |
93 | .class_init = virtual_css_bus_class_init, | |
94 | }; | |
95 | ||
96 | VirtualCssBus *virtual_css_bus_init(void) | |
97 | { | |
98 | VirtualCssBus *cbus; | |
99 | BusState *bus; | |
100 | DeviceState *dev; | |
101 | ||
102 | /* Create bridge device */ | |
3e80f690 | 103 | dev = qdev_new(TYPE_VIRTUAL_CSS_BRIDGE); |
864c2512 | 104 | object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE, |
d2623129 | 105 | OBJECT(dev)); |
3c6ef471 | 106 | sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); |
dd70bd0d JL |
107 | |
108 | /* Create bus on bridge device */ | |
9388d170 | 109 | bus = qbus_new(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); |
dd70bd0d JL |
110 | cbus = VIRTUAL_CSS_BUS(bus); |
111 | ||
112 | /* Enable hotplugging */ | |
9bc6bfdf | 113 | qbus_set_hotplug_handler(bus, OBJECT(dev)); |
dd70bd0d | 114 | |
dde522bb | 115 | css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false, |
1497c160 | 116 | 0, &error_abort); |
dde522bb | 117 | |
dd70bd0d JL |
118 | return cbus; |
119 | } | |
120 | ||
121 | /***************** Virtual-css Bus Bridge Device ********************/ | |
122 | ||
2a79eb1a CH |
123 | static Property virtual_css_bridge_properties[] = { |
124 | DEFINE_PROP_BOOL("css_dev_path", VirtualCssBridge, css_dev_path, | |
125 | true), | |
126 | DEFINE_PROP_END_OF_LIST(), | |
127 | }; | |
128 | ||
99577c49 HP |
129 | static bool prop_get_true(Object *obj, Error **errp) |
130 | { | |
131 | return true; | |
132 | } | |
133 | ||
dd70bd0d JL |
134 | static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) |
135 | { | |
136 | HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); | |
137 | DeviceClass *dc = DEVICE_CLASS(klass); | |
138 | ||
b804e8a6 | 139 | hc->unplug = ccw_device_unplug; |
dd70bd0d | 140 | set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); |
4f67d30b | 141 | device_class_set_props(dc, virtual_css_bridge_properties); |
99577c49 | 142 | object_class_property_add_bool(klass, "cssid-unrestricted", |
d2623129 | 143 | prop_get_true, NULL); |
99577c49 HP |
144 | object_class_property_set_description(klass, "cssid-unrestricted", |
145 | "A css device can use any cssid, regardless whether virtual" | |
7eecec7d | 146 | " or not (read only, always true)"); |
dd70bd0d JL |
147 | } |
148 | ||
149 | static const TypeInfo virtual_css_bridge_info = { | |
150 | .name = TYPE_VIRTUAL_CSS_BRIDGE, | |
151 | .parent = TYPE_SYS_BUS_DEVICE, | |
2a79eb1a | 152 | .instance_size = sizeof(VirtualCssBridge), |
dd70bd0d JL |
153 | .class_init = virtual_css_bridge_class_init, |
154 | .interfaces = (InterfaceInfo[]) { | |
155 | { TYPE_HOTPLUG_HANDLER }, | |
156 | { } | |
157 | } | |
158 | }; | |
159 | ||
160 | static void virtual_css_register(void) | |
161 | { | |
162 | type_register_static(&virtual_css_bridge_info); | |
163 | type_register_static(&virtual_css_bus_info); | |
164 | } | |
165 | ||
166 | type_init(virtual_css_register) |