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