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