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