qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

bus.c (9509B)


      1 /*
      2  *  Dynamic device configuration and creation -- buses.
      3  *
      4  *  Copyright (c) 2009 CodeSourcery
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Lesser General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2.1 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Lesser General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Lesser General Public
     17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18  */
     19 
     20 #include "qemu/osdep.h"
     21 #include "hw/qdev-properties.h"
     22 #include "qemu/ctype.h"
     23 #include "qemu/module.h"
     24 #include "qapi/error.h"
     25 
     26 void qbus_set_hotplug_handler(BusState *bus, Object *handler)
     27 {
     28     object_property_set_link(OBJECT(bus), QDEV_HOTPLUG_HANDLER_PROPERTY,
     29                              handler, &error_abort);
     30 }
     31 
     32 void qbus_set_bus_hotplug_handler(BusState *bus)
     33 {
     34     qbus_set_hotplug_handler(bus, OBJECT(bus));
     35 }
     36 
     37 int qbus_walk_children(BusState *bus,
     38                        qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn,
     39                        qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn,
     40                        void *opaque)
     41 {
     42     BusChild *kid;
     43     int err;
     44 
     45     if (pre_busfn) {
     46         err = pre_busfn(bus, opaque);
     47         if (err) {
     48             return err;
     49         }
     50     }
     51 
     52     WITH_RCU_READ_LOCK_GUARD() {
     53         QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) {
     54             err = qdev_walk_children(kid->child,
     55                                      pre_devfn, pre_busfn,
     56                                      post_devfn, post_busfn, opaque);
     57             if (err < 0) {
     58                 return err;
     59             }
     60         }
     61     }
     62 
     63     if (post_busfn) {
     64         err = post_busfn(bus, opaque);
     65         if (err) {
     66             return err;
     67         }
     68     }
     69 
     70     return 0;
     71 }
     72 
     73 void bus_cold_reset(BusState *bus)
     74 {
     75     resettable_reset(OBJECT(bus), RESET_TYPE_COLD);
     76 }
     77 
     78 bool bus_is_in_reset(BusState *bus)
     79 {
     80     return resettable_is_in_reset(OBJECT(bus));
     81 }
     82 
     83 static ResettableState *bus_get_reset_state(Object *obj)
     84 {
     85     BusState *bus = BUS(obj);
     86     return &bus->reset;
     87 }
     88 
     89 static void bus_reset_child_foreach(Object *obj, ResettableChildCallback cb,
     90                                     void *opaque, ResetType type)
     91 {
     92     BusState *bus = BUS(obj);
     93     BusChild *kid;
     94 
     95     WITH_RCU_READ_LOCK_GUARD() {
     96         QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) {
     97             cb(OBJECT(kid->child), opaque, type);
     98         }
     99     }
    100 }
    101 
    102 static void qbus_init_internal(BusState *bus, DeviceState *parent,
    103                                const char *name)
    104 {
    105     const char *typename = object_get_typename(OBJECT(bus));
    106     BusClass *bc;
    107     int i, bus_id;
    108 
    109     bus->parent = parent;
    110 
    111     if (name) {
    112         bus->name = g_strdup(name);
    113     } else if (bus->parent && bus->parent->id) {
    114         /* parent device has id -> use it plus parent-bus-id for bus name */
    115         bus_id = bus->parent->num_child_bus;
    116         bus->name = g_strdup_printf("%s.%d", bus->parent->id, bus_id);
    117     } else {
    118         /* no id -> use lowercase bus type plus global bus-id for bus name */
    119         bc = BUS_GET_CLASS(bus);
    120         bus_id = bc->automatic_ids++;
    121         bus->name = g_strdup_printf("%s.%d", typename, bus_id);
    122         for (i = 0; bus->name[i]; i++) {
    123             bus->name[i] = qemu_tolower(bus->name[i]);
    124         }
    125     }
    126 
    127     if (bus->parent) {
    128         QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling);
    129         bus->parent->num_child_bus++;
    130         object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus));
    131         object_unref(OBJECT(bus));
    132     } else {
    133         /* The only bus without a parent is the main system bus */
    134         assert(bus == sysbus_get_default());
    135     }
    136 }
    137 
    138 static void bus_unparent(Object *obj)
    139 {
    140     BusState *bus = BUS(obj);
    141     BusChild *kid;
    142 
    143     /* Only the main system bus has no parent, and that bus is never freed */
    144     assert(bus->parent);
    145 
    146     while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
    147         DeviceState *dev = kid->child;
    148         object_unparent(OBJECT(dev));
    149     }
    150     QLIST_REMOVE(bus, sibling);
    151     bus->parent->num_child_bus--;
    152     bus->parent = NULL;
    153 }
    154 
    155 void qbus_init(void *bus, size_t size, const char *typename,
    156                DeviceState *parent, const char *name)
    157 {
    158     object_initialize(bus, size, typename);
    159     qbus_init_internal(bus, parent, name);
    160 }
    161 
    162 BusState *qbus_new(const char *typename, DeviceState *parent, const char *name)
    163 {
    164     BusState *bus;
    165 
    166     bus = BUS(object_new(typename));
    167     qbus_init_internal(bus, parent, name);
    168 
    169     return bus;
    170 }
    171 
    172 bool qbus_realize(BusState *bus, Error **errp)
    173 {
    174     return object_property_set_bool(OBJECT(bus), "realized", true, errp);
    175 }
    176 
    177 void qbus_unrealize(BusState *bus)
    178 {
    179     object_property_set_bool(OBJECT(bus), "realized", false, &error_abort);
    180 }
    181 
    182 static bool bus_get_realized(Object *obj, Error **errp)
    183 {
    184     BusState *bus = BUS(obj);
    185 
    186     return bus->realized;
    187 }
    188 
    189 static void bus_set_realized(Object *obj, bool value, Error **errp)
    190 {
    191     BusState *bus = BUS(obj);
    192     BusClass *bc = BUS_GET_CLASS(bus);
    193     BusChild *kid;
    194 
    195     if (value && !bus->realized) {
    196         if (bc->realize) {
    197             bc->realize(bus, errp);
    198         }
    199 
    200         /* TODO: recursive realization */
    201     } else if (!value && bus->realized) {
    202         WITH_RCU_READ_LOCK_GUARD() {
    203             QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) {
    204                 DeviceState *dev = kid->child;
    205                 qdev_unrealize(dev);
    206             }
    207         }
    208         if (bc->unrealize) {
    209             bc->unrealize(bus);
    210         }
    211     }
    212 
    213     bus->realized = value;
    214 }
    215 
    216 static void qbus_initfn(Object *obj)
    217 {
    218     BusState *bus = BUS(obj);
    219 
    220     QTAILQ_INIT(&bus->children);
    221     object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY,
    222                              TYPE_HOTPLUG_HANDLER,
    223                              (Object **)&bus->hotplug_handler,
    224                              object_property_allow_set_link,
    225                              0);
    226     object_property_add_bool(obj, "realized",
    227                              bus_get_realized, bus_set_realized);
    228 }
    229 
    230 static char *default_bus_get_fw_dev_path(DeviceState *dev)
    231 {
    232     return g_strdup(object_get_typename(OBJECT(dev)));
    233 }
    234 
    235 /**
    236  * bus_phases_reset:
    237  * Transition reset method for buses to allow moving
    238  * smoothly from legacy reset method to multi-phases
    239  */
    240 static void bus_phases_reset(BusState *bus)
    241 {
    242     ResettableClass *rc = RESETTABLE_GET_CLASS(bus);
    243 
    244     if (rc->phases.enter) {
    245         rc->phases.enter(OBJECT(bus), RESET_TYPE_COLD);
    246     }
    247     if (rc->phases.hold) {
    248         rc->phases.hold(OBJECT(bus));
    249     }
    250     if (rc->phases.exit) {
    251         rc->phases.exit(OBJECT(bus));
    252     }
    253 }
    254 
    255 static void bus_transitional_reset(Object *obj)
    256 {
    257     BusClass *bc = BUS_GET_CLASS(obj);
    258 
    259     /*
    260      * This will call either @bus_phases_reset (for multi-phases transitioned
    261      * buses) or a bus's specific method for not-yet transitioned buses.
    262      * In both case, it does not reset children.
    263      */
    264     if (bc->reset) {
    265         bc->reset(BUS(obj));
    266     }
    267 }
    268 
    269 /**
    270  * bus_get_transitional_reset:
    271  * check if the bus's class is ready for multi-phase
    272  */
    273 static ResettableTrFunction bus_get_transitional_reset(Object *obj)
    274 {
    275     BusClass *dc = BUS_GET_CLASS(obj);
    276     if (dc->reset != bus_phases_reset) {
    277         /*
    278          * dc->reset has been overridden by a subclass,
    279          * the bus is not ready for multi phase yet.
    280          */
    281         return bus_transitional_reset;
    282     }
    283     return NULL;
    284 }
    285 
    286 static void bus_class_init(ObjectClass *class, void *data)
    287 {
    288     BusClass *bc = BUS_CLASS(class);
    289     ResettableClass *rc = RESETTABLE_CLASS(class);
    290 
    291     class->unparent = bus_unparent;
    292     bc->get_fw_dev_path = default_bus_get_fw_dev_path;
    293 
    294     rc->get_state = bus_get_reset_state;
    295     rc->child_foreach = bus_reset_child_foreach;
    296 
    297     /*
    298      * @bus_phases_reset is put as the default reset method below, allowing
    299      * to do the multi-phase transition from base classes to leaf classes. It
    300      * allows a legacy-reset Bus class to extend a multi-phases-reset
    301      * Bus class for the following reason:
    302      * + If a base class B has been moved to multi-phase, then it does not
    303      *   override this default reset method and may have defined phase methods.
    304      * + A child class C (extending class B) which uses
    305      *   bus_class_set_parent_reset() (or similar means) to override the
    306      *   reset method will still work as expected. @bus_phases_reset function
    307      *   will be registered as the parent reset method and effectively call
    308      *   parent reset phases.
    309      */
    310     bc->reset = bus_phases_reset;
    311     rc->get_transitional_function = bus_get_transitional_reset;
    312 }
    313 
    314 static void qbus_finalize(Object *obj)
    315 {
    316     BusState *bus = BUS(obj);
    317 
    318     g_free(bus->name);
    319 }
    320 
    321 static const TypeInfo bus_info = {
    322     .name = TYPE_BUS,
    323     .parent = TYPE_OBJECT,
    324     .instance_size = sizeof(BusState),
    325     .abstract = true,
    326     .class_size = sizeof(BusClass),
    327     .instance_init = qbus_initfn,
    328     .instance_finalize = qbus_finalize,
    329     .class_init = bus_class_init,
    330     .interfaces = (InterfaceInfo[]) {
    331         { TYPE_RESETTABLE_INTERFACE },
    332         { }
    333     },
    334 };
    335 
    336 static void bus_register_types(void)
    337 {
    338     type_register_static(&bus_info);
    339 }
    340 
    341 type_init(bus_register_types)