xref: /openbmc/qemu/hw/s390x/css-bridge.c (revision ad80e367)
1dd70bd0dSJing Liu /*
2dd70bd0dSJing Liu  * css bridge implementation
3dd70bd0dSJing Liu  *
4dd70bd0dSJing Liu  * Copyright 2012,2016 IBM Corp.
5dd70bd0dSJing Liu  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
6dd70bd0dSJing Liu  *            Pierre Morel <pmorel@linux.vnet.ibm.com>
7dd70bd0dSJing Liu  *
8dd70bd0dSJing Liu  * This work is licensed under the terms of the GNU GPL, version 2 or (at
9dd70bd0dSJing Liu  * your option) any later version. See the COPYING file in the top-level
10dd70bd0dSJing Liu  * directory.
11dd70bd0dSJing Liu  */
120b8fa32fSMarkus Armbruster 
13dd70bd0dSJing Liu #include "qemu/osdep.h"
14dd70bd0dSJing Liu #include "qapi/error.h"
15dd70bd0dSJing Liu #include "hw/hotplug.h"
16a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
17dd70bd0dSJing Liu #include "hw/sysbus.h"
18dd70bd0dSJing Liu #include "qemu/bitops.h"
190b8fa32fSMarkus Armbruster #include "qemu/module.h"
20dd70bd0dSJing Liu #include "hw/s390x/css.h"
21b804e8a6SJing Liu #include "ccw-device.h"
22dd70bd0dSJing Liu #include "hw/s390x/css-bridge.h"
23dd70bd0dSJing Liu 
24b804e8a6SJing Liu /*
25b804e8a6SJing Liu  * Invoke device-specific unplug handler, disable the subchannel
26b804e8a6SJing Liu  * (including sending a channel report to the guest) and remove the
27b804e8a6SJing Liu  * device from the virtual css bus.
28b804e8a6SJing Liu  */
ccw_device_unplug(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)29b804e8a6SJing Liu static void ccw_device_unplug(HotplugHandler *hotplug_dev,
30b804e8a6SJing Liu                               DeviceState *dev, Error **errp)
31b804e8a6SJing Liu {
32b804e8a6SJing Liu     CcwDevice *ccw_dev = CCW_DEVICE(dev);
33b804e8a6SJing Liu     CCWDeviceClass *k = CCW_DEVICE_GET_CLASS(ccw_dev);
34b804e8a6SJing Liu     SubchDev *sch = ccw_dev->sch;
35b804e8a6SJing Liu     Error *err = NULL;
36b804e8a6SJing Liu 
37b804e8a6SJing Liu     if (k->unplug) {
38b804e8a6SJing Liu         k->unplug(hotplug_dev, dev, &err);
39b804e8a6SJing Liu         if (err) {
40b804e8a6SJing Liu             error_propagate(errp, err);
41b804e8a6SJing Liu             return;
42b804e8a6SJing Liu         }
43b804e8a6SJing Liu     }
44b804e8a6SJing Liu 
45b804e8a6SJing Liu     /*
46b804e8a6SJing Liu      * We should arrive here only for device_del, since we don't support
47b804e8a6SJing Liu      * direct hot(un)plug of channels.
48b804e8a6SJing Liu      */
49b804e8a6SJing Liu     assert(sch != NULL);
50b804e8a6SJing Liu     /* Subchannel is now disabled and no longer valid. */
51b804e8a6SJing Liu     sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA |
52b804e8a6SJing Liu                                      PMCW_FLAGS_MASK_DNV);
53b804e8a6SJing Liu 
54b804e8a6SJing Liu     css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0);
55b804e8a6SJing Liu 
56981c3dcdSMarkus Armbruster     qdev_unrealize(dev);
57b804e8a6SJing Liu }
58b804e8a6SJing Liu 
virtual_css_bus_reset_hold(Object * obj,ResetType type)59*ad80e367SPeter Maydell static void virtual_css_bus_reset_hold(Object *obj, ResetType type)
60dd70bd0dSJing Liu {
61dd70bd0dSJing Liu     /* This should actually be modelled via the generic css */
62dd70bd0dSJing Liu     css_reset();
63dd70bd0dSJing Liu }
64dd70bd0dSJing Liu 
virtual_css_bus_get_dev_path(DeviceState * dev)652a79eb1aSCornelia Huck static char *virtual_css_bus_get_dev_path(DeviceState *dev)
662a79eb1aSCornelia Huck {
672a79eb1aSCornelia Huck     CcwDevice *ccw_dev = CCW_DEVICE(dev);
682a79eb1aSCornelia Huck     SubchDev *sch = ccw_dev->sch;
692a79eb1aSCornelia Huck     VirtualCssBridge *bridge =
702a79eb1aSCornelia Huck         VIRTUAL_CSS_BRIDGE(qdev_get_parent_bus(dev)->parent);
712a79eb1aSCornelia Huck 
722a79eb1aSCornelia Huck     /*
732a79eb1aSCornelia Huck      * We can't provide a dev path for backward compatibility on
742a79eb1aSCornelia Huck      * older machines, as it is visible in the migration stream.
752a79eb1aSCornelia Huck      */
762a79eb1aSCornelia Huck     return bridge->css_dev_path ?
772a79eb1aSCornelia Huck         g_strdup_printf("/%02x.%1x.%04x", sch->cssid, sch->ssid, sch->devno) :
782a79eb1aSCornelia Huck         NULL;
792a79eb1aSCornelia Huck }
802a79eb1aSCornelia Huck 
virtual_css_bus_class_init(ObjectClass * klass,void * data)81dd70bd0dSJing Liu static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
82dd70bd0dSJing Liu {
83dd70bd0dSJing Liu     BusClass *k = BUS_CLASS(klass);
84412a91f6SPeter Maydell     ResettableClass *rc = RESETTABLE_CLASS(klass);
85dd70bd0dSJing Liu 
86412a91f6SPeter Maydell     rc->phases.hold = virtual_css_bus_reset_hold;
872a79eb1aSCornelia Huck     k->get_dev_path = virtual_css_bus_get_dev_path;
88dd70bd0dSJing Liu }
89dd70bd0dSJing Liu 
90dd70bd0dSJing Liu static const TypeInfo virtual_css_bus_info = {
91dd70bd0dSJing Liu     .name = TYPE_VIRTUAL_CSS_BUS,
92dd70bd0dSJing Liu     .parent = TYPE_BUS,
93dd70bd0dSJing Liu     .instance_size = sizeof(VirtualCssBus),
94dd70bd0dSJing Liu     .class_init = virtual_css_bus_class_init,
95dd70bd0dSJing Liu };
96dd70bd0dSJing Liu 
virtual_css_bus_init(void)97dd70bd0dSJing Liu VirtualCssBus *virtual_css_bus_init(void)
98dd70bd0dSJing Liu {
99dd70bd0dSJing Liu     BusState *bus;
100dd70bd0dSJing Liu     DeviceState *dev;
101dd70bd0dSJing Liu 
102dd70bd0dSJing Liu     /* Create bridge device */
1033e80f690SMarkus Armbruster     dev = qdev_new(TYPE_VIRTUAL_CSS_BRIDGE);
104864c2512SCornelia Huck     object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE,
105d2623129SMarkus Armbruster                               OBJECT(dev));
106dd70bd0dSJing Liu 
107dd70bd0dSJing Liu     /* Create bus on bridge device */
1089388d170SPeter Maydell     bus = qbus_new(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
109dd70bd0dSJing Liu 
110dd70bd0dSJing Liu     /* Enable hotplugging */
1119bc6bfdfSMarkus Armbruster     qbus_set_hotplug_handler(bus, OBJECT(dev));
112dd70bd0dSJing Liu 
113840b4495SPhilippe Mathieu-Daudé     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
114840b4495SPhilippe Mathieu-Daudé 
115dde522bbSFei Li     css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false,
1161497c160SFei Li                              0, &error_abort);
117dde522bbSFei Li 
118840b4495SPhilippe Mathieu-Daudé     return VIRTUAL_CSS_BUS(bus);
119dd70bd0dSJing Liu  }
120dd70bd0dSJing Liu 
121dd70bd0dSJing Liu /***************** Virtual-css Bus Bridge Device ********************/
122dd70bd0dSJing Liu 
1232a79eb1aSCornelia Huck static Property virtual_css_bridge_properties[] = {
1242a79eb1aSCornelia Huck     DEFINE_PROP_BOOL("css_dev_path", VirtualCssBridge, css_dev_path,
1252a79eb1aSCornelia Huck                      true),
1262a79eb1aSCornelia Huck     DEFINE_PROP_END_OF_LIST(),
1272a79eb1aSCornelia Huck };
1282a79eb1aSCornelia Huck 
prop_get_true(Object * obj,Error ** errp)12999577c49SHalil Pasic static bool prop_get_true(Object *obj, Error **errp)
13099577c49SHalil Pasic {
13199577c49SHalil Pasic     return true;
13299577c49SHalil Pasic }
13399577c49SHalil Pasic 
virtual_css_bridge_class_init(ObjectClass * klass,void * data)134dd70bd0dSJing Liu static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
135dd70bd0dSJing Liu {
136dd70bd0dSJing Liu     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
137dd70bd0dSJing Liu     DeviceClass *dc = DEVICE_CLASS(klass);
138dd70bd0dSJing Liu 
139b804e8a6SJing Liu     hc->unplug = ccw_device_unplug;
140dd70bd0dSJing Liu     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
1414f67d30bSMarc-André Lureau     device_class_set_props(dc, virtual_css_bridge_properties);
14299577c49SHalil Pasic     object_class_property_add_bool(klass, "cssid-unrestricted",
143d2623129SMarkus Armbruster                                    prop_get_true, NULL);
14499577c49SHalil Pasic     object_class_property_set_description(klass, "cssid-unrestricted",
14599577c49SHalil Pasic             "A css device can use any cssid, regardless whether virtual"
1467eecec7dSMarkus Armbruster             " or not (read only, always true)");
147dd70bd0dSJing Liu }
148dd70bd0dSJing Liu 
149dd70bd0dSJing Liu static const TypeInfo virtual_css_bridge_info = {
150dd70bd0dSJing Liu     .name          = TYPE_VIRTUAL_CSS_BRIDGE,
151dd70bd0dSJing Liu     .parent        = TYPE_SYS_BUS_DEVICE,
1522a79eb1aSCornelia Huck     .instance_size = sizeof(VirtualCssBridge),
153dd70bd0dSJing Liu     .class_init    = virtual_css_bridge_class_init,
154dd70bd0dSJing Liu     .interfaces = (InterfaceInfo[]) {
155dd70bd0dSJing Liu         { TYPE_HOTPLUG_HANDLER },
156dd70bd0dSJing Liu         { }
157dd70bd0dSJing Liu     }
158dd70bd0dSJing Liu };
159dd70bd0dSJing Liu 
virtual_css_register(void)160dd70bd0dSJing Liu static void virtual_css_register(void)
161dd70bd0dSJing Liu {
162dd70bd0dSJing Liu     type_register_static(&virtual_css_bridge_info);
163dd70bd0dSJing Liu     type_register_static(&virtual_css_bus_info);
164dd70bd0dSJing Liu }
165dd70bd0dSJing Liu 
166dd70bd0dSJing Liu type_init(virtual_css_register)
167