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