The I/O adapters should exist as soon as the bus/infrastructure exists, and not only when the guest is actually trying to do something with them. While the lazy allocation was not wrong, allocating at init time is cleaner, both for the architecture and the code. Let's adjust this by having each device type (currently for PCI and virtio-ccw) register the adapters for each ISC (as now we don't know which ISC the guest will use) as soon as it initializes. Use a two-dimensional array io_adapters[type][isc] to store adapters in ChannelSubSys, so that we can conveniently get the adapter id by the helper function css_get_adapter_id(type, isc). Signed-off-by: Fei Li <sherrylf@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
152 lines
4.2 KiB
C
152 lines
4.2 KiB
C
/*
|
|
* css bridge implementation
|
|
*
|
|
* Copyright 2012,2016 IBM Corp.
|
|
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
|
|
* Pierre Morel <pmorel@linux.vnet.ibm.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
|
* your option) any later version. See the COPYING file in the top-level
|
|
* directory.
|
|
*/
|
|
#include "qemu/osdep.h"
|
|
#include "qapi/error.h"
|
|
#include "hw/hotplug.h"
|
|
#include "hw/sysbus.h"
|
|
#include "qemu/bitops.h"
|
|
#include "hw/s390x/css.h"
|
|
#include "ccw-device.h"
|
|
#include "hw/s390x/css-bridge.h"
|
|
|
|
/*
|
|
* Invoke device-specific unplug handler, disable the subchannel
|
|
* (including sending a channel report to the guest) and remove the
|
|
* device from the virtual css bus.
|
|
*/
|
|
static void ccw_device_unplug(HotplugHandler *hotplug_dev,
|
|
DeviceState *dev, Error **errp)
|
|
{
|
|
CcwDevice *ccw_dev = CCW_DEVICE(dev);
|
|
CCWDeviceClass *k = CCW_DEVICE_GET_CLASS(ccw_dev);
|
|
SubchDev *sch = ccw_dev->sch;
|
|
Error *err = NULL;
|
|
|
|
if (k->unplug) {
|
|
k->unplug(hotplug_dev, dev, &err);
|
|
if (err) {
|
|
error_propagate(errp, err);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We should arrive here only for device_del, since we don't support
|
|
* direct hot(un)plug of channels.
|
|
*/
|
|
assert(sch != NULL);
|
|
/* Subchannel is now disabled and no longer valid. */
|
|
sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA |
|
|
PMCW_FLAGS_MASK_DNV);
|
|
|
|
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0);
|
|
|
|
object_unparent(OBJECT(dev));
|
|
}
|
|
|
|
static void virtual_css_bus_reset(BusState *qbus)
|
|
{
|
|
/* This should actually be modelled via the generic css */
|
|
css_reset();
|
|
}
|
|
|
|
static char *virtual_css_bus_get_dev_path(DeviceState *dev)
|
|
{
|
|
CcwDevice *ccw_dev = CCW_DEVICE(dev);
|
|
SubchDev *sch = ccw_dev->sch;
|
|
VirtualCssBridge *bridge =
|
|
VIRTUAL_CSS_BRIDGE(qdev_get_parent_bus(dev)->parent);
|
|
|
|
/*
|
|
* We can't provide a dev path for backward compatibility on
|
|
* older machines, as it is visible in the migration stream.
|
|
*/
|
|
return bridge->css_dev_path ?
|
|
g_strdup_printf("/%02x.%1x.%04x", sch->cssid, sch->ssid, sch->devno) :
|
|
NULL;
|
|
}
|
|
|
|
static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
BusClass *k = BUS_CLASS(klass);
|
|
|
|
k->reset = virtual_css_bus_reset;
|
|
k->get_dev_path = virtual_css_bus_get_dev_path;
|
|
}
|
|
|
|
static const TypeInfo virtual_css_bus_info = {
|
|
.name = TYPE_VIRTUAL_CSS_BUS,
|
|
.parent = TYPE_BUS,
|
|
.instance_size = sizeof(VirtualCssBus),
|
|
.class_init = virtual_css_bus_class_init,
|
|
};
|
|
|
|
VirtualCssBus *virtual_css_bus_init(void)
|
|
{
|
|
VirtualCssBus *cbus;
|
|
BusState *bus;
|
|
DeviceState *dev;
|
|
|
|
/* Create bridge device */
|
|
dev = qdev_create(NULL, TYPE_VIRTUAL_CSS_BRIDGE);
|
|
qdev_init_nofail(dev);
|
|
|
|
/* Create bus on bridge device */
|
|
bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
|
|
cbus = VIRTUAL_CSS_BUS(bus);
|
|
|
|
/* Enable hotplugging */
|
|
qbus_set_hotplug_handler(bus, dev, &error_abort);
|
|
|
|
css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false,
|
|
&error_abort);
|
|
|
|
return cbus;
|
|
}
|
|
|
|
/***************** Virtual-css Bus Bridge Device ********************/
|
|
|
|
static Property virtual_css_bridge_properties[] = {
|
|
DEFINE_PROP_BOOL("css_dev_path", VirtualCssBridge, css_dev_path,
|
|
true),
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
};
|
|
|
|
static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
hc->unplug = ccw_device_unplug;
|
|
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
|
dc->props = virtual_css_bridge_properties;
|
|
}
|
|
|
|
static const TypeInfo virtual_css_bridge_info = {
|
|
.name = TYPE_VIRTUAL_CSS_BRIDGE,
|
|
.parent = TYPE_SYS_BUS_DEVICE,
|
|
.instance_size = sizeof(VirtualCssBridge),
|
|
.class_init = virtual_css_bridge_class_init,
|
|
.interfaces = (InterfaceInfo[]) {
|
|
{ TYPE_HOTPLUG_HANDLER },
|
|
{ }
|
|
}
|
|
};
|
|
|
|
static void virtual_css_register(void)
|
|
{
|
|
type_register_static(&virtual_css_bridge_info);
|
|
type_register_static(&virtual_css_bus_info);
|
|
}
|
|
|
|
type_init(virtual_css_register)
|