qemu/hw/s390x/css-bridge.c
<<
>>
Prefs
   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 */
  12
  13#include "qemu/osdep.h"
  14#include "qapi/error.h"
  15#include "hw/hotplug.h"
  16#include "hw/qdev-properties.h"
  17#include "hw/sysbus.h"
  18#include "qemu/bitops.h"
  19#include "qemu/module.h"
  20#include "hw/s390x/css.h"
  21#include "ccw-device.h"
  22#include "hw/s390x/css-bridge.h"
  23
  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 */
  29static 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
  56    qdev_unrealize(dev);
  57}
  58
  59static void virtual_css_bus_reset(BusState *qbus)
  60{
  61    /* This should actually be modelled via the generic css */
  62    css_reset();
  63}
  64
  65static 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
  81static 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;
  86    k->get_dev_path = virtual_css_bus_get_dev_path;
  87}
  88
  89static 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
  96VirtualCssBus *virtual_css_bus_init(void)
  97{
  98    VirtualCssBus *cbus;
  99    BusState *bus;
 100    DeviceState *dev;
 101
 102    /* Create bridge device */
 103    dev = qdev_new(TYPE_VIRTUAL_CSS_BRIDGE);
 104    object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE,
 105                              OBJECT(dev));
 106    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
 107
 108    /* Create bus on bridge device */
 109    bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
 110    cbus = VIRTUAL_CSS_BUS(bus);
 111
 112    /* Enable hotplugging */
 113    qbus_set_hotplug_handler(bus, OBJECT(dev));
 114
 115    css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false,
 116                             0, &error_abort);
 117
 118    return cbus;
 119 }
 120
 121/***************** Virtual-css Bus Bridge Device ********************/
 122
 123static 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
 129static bool prop_get_true(Object *obj, Error **errp)
 130{
 131    return true;
 132}
 133
 134static 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
 139    hc->unplug = ccw_device_unplug;
 140    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 141    device_class_set_props(dc, virtual_css_bridge_properties);
 142    object_class_property_add_bool(klass, "cssid-unrestricted",
 143                                   prop_get_true, NULL);
 144    object_class_property_set_description(klass, "cssid-unrestricted",
 145            "A css device can use any cssid, regardless whether virtual"
 146            " or not (read only, always true)");
 147}
 148
 149static const TypeInfo virtual_css_bridge_info = {
 150    .name          = TYPE_VIRTUAL_CSS_BRIDGE,
 151    .parent        = TYPE_SYS_BUS_DEVICE,
 152    .instance_size = sizeof(VirtualCssBridge),
 153    .class_init    = virtual_css_bridge_class_init,
 154    .interfaces = (InterfaceInfo[]) {
 155        { TYPE_HOTPLUG_HANDLER },
 156        { }
 157    }
 158};
 159
 160static void virtual_css_register(void)
 161{
 162    type_register_static(&virtual_css_bridge_info);
 163    type_register_static(&virtual_css_bus_info);
 164}
 165
 166type_init(virtual_css_register)
 167