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_unparent(OBJECT(dev));
  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    qdev_init_nofail(dev);
 103
 104    /* Create bus on bridge device */
 105    bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
 106    cbus = VIRTUAL_CSS_BUS(bus);
 107    cbus->squash_mcss = s390_get_squash_mcss();
 108
 109    /* Enable hotplugging */
 110    qbus_set_hotplug_handler(bus, dev, &error_abort);
 111
 112    css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false,
 113                             0, &error_abort);
 114
 115    return cbus;
 116 }
 117
 118/***************** Virtual-css Bus Bridge Device ********************/
 119
 120static Property virtual_css_bridge_properties[] = {
 121    DEFINE_PROP_BOOL("css_dev_path", VirtualCssBridge, css_dev_path,
 122                     true),
 123    DEFINE_PROP_END_OF_LIST(),
 124};
 125
 126static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
 127{
 128    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
 129    DeviceClass *dc = DEVICE_CLASS(klass);
 130
 131    hc->unplug = ccw_device_unplug;
 132    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 133    dc->props = virtual_css_bridge_properties;
 134}
 135
 136static const TypeInfo virtual_css_bridge_info = {
 137    .name          = TYPE_VIRTUAL_CSS_BRIDGE,
 138    .parent        = TYPE_SYS_BUS_DEVICE,
 139    .instance_size = sizeof(VirtualCssBridge),
 140    .class_init    = virtual_css_bridge_class_init,
 141    .interfaces = (InterfaceInfo[]) {
 142        { TYPE_HOTPLUG_HANDLER },
 143        { }
 144    }
 145};
 146
 147static void virtual_css_register(void)
 148{
 149    type_register_static(&virtual_css_bridge_info);
 150    type_register_static(&virtual_css_bus_info);
 151}
 152
 153type_init(virtual_css_register)
 154