xref: /qemu/hw/core/qdev-hotplug.c (revision 1bff035be76cc30ff0fc4e8f0b0fbda84db7d1dc)
181c7b381SPhilippe Mathieu-Daudé /*
281c7b381SPhilippe Mathieu-Daudé  * QDev Hotplug handlers
381c7b381SPhilippe Mathieu-Daudé  *
481c7b381SPhilippe Mathieu-Daudé  * Copyright (c) Red Hat
581c7b381SPhilippe Mathieu-Daudé  *
681c7b381SPhilippe Mathieu-Daudé  * SPDX-License-Identifier: GPL-2.0-or-later
781c7b381SPhilippe Mathieu-Daudé  *
881c7b381SPhilippe Mathieu-Daudé  * This work is licensed under the terms of the GNU GPL, version 2 or later.
981c7b381SPhilippe Mathieu-Daudé  * See the COPYING file in the top-level directory.
1081c7b381SPhilippe Mathieu-Daudé  */
1181c7b381SPhilippe Mathieu-Daudé 
1281c7b381SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
1381c7b381SPhilippe Mathieu-Daudé #include "hw/qdev-core.h"
1481c7b381SPhilippe Mathieu-Daudé #include "hw/boards.h"
15*1bff035bSAkihiko Odaki #include "qapi/error.h"
1681c7b381SPhilippe Mathieu-Daudé 
1781c7b381SPhilippe Mathieu-Daudé HotplugHandler *qdev_get_machine_hotplug_handler(DeviceState *dev)
1881c7b381SPhilippe Mathieu-Daudé {
1981c7b381SPhilippe Mathieu-Daudé     MachineState *machine;
2081c7b381SPhilippe Mathieu-Daudé     MachineClass *mc;
2181c7b381SPhilippe Mathieu-Daudé     Object *m_obj = qdev_get_machine();
2281c7b381SPhilippe Mathieu-Daudé 
2381c7b381SPhilippe Mathieu-Daudé     if (object_dynamic_cast(m_obj, TYPE_MACHINE)) {
2481c7b381SPhilippe Mathieu-Daudé         machine = MACHINE(m_obj);
2581c7b381SPhilippe Mathieu-Daudé         mc = MACHINE_GET_CLASS(machine);
2681c7b381SPhilippe Mathieu-Daudé         if (mc->get_hotplug_handler) {
2781c7b381SPhilippe Mathieu-Daudé             return mc->get_hotplug_handler(machine, dev);
2881c7b381SPhilippe Mathieu-Daudé         }
2981c7b381SPhilippe Mathieu-Daudé     }
3081c7b381SPhilippe Mathieu-Daudé 
3181c7b381SPhilippe Mathieu-Daudé     return NULL;
3281c7b381SPhilippe Mathieu-Daudé }
3381c7b381SPhilippe Mathieu-Daudé 
34f2694f1bSAkihiko Odaki static bool qdev_hotplug_unplug_allowed_common(DeviceState *dev, BusState *bus,
35f2694f1bSAkihiko Odaki                                                Error **errp)
36f2694f1bSAkihiko Odaki {
37*1bff035bSAkihiko Odaki     DeviceClass *dc = DEVICE_GET_CLASS(dev);
38*1bff035bSAkihiko Odaki 
39*1bff035bSAkihiko Odaki     if (!dc->hotpluggable) {
40*1bff035bSAkihiko Odaki         error_setg(errp, "Device '%s' does not support hotplugging",
41*1bff035bSAkihiko Odaki                    object_get_typename(OBJECT(dev)));
42*1bff035bSAkihiko Odaki         return false;
43*1bff035bSAkihiko Odaki     }
44*1bff035bSAkihiko Odaki 
45f2694f1bSAkihiko Odaki     return true;
46f2694f1bSAkihiko Odaki }
47f2694f1bSAkihiko Odaki 
488915c118SAkihiko Odaki bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp)
4981c7b381SPhilippe Mathieu-Daudé {
5081c7b381SPhilippe Mathieu-Daudé     MachineState *machine;
5181c7b381SPhilippe Mathieu-Daudé     MachineClass *mc;
5281c7b381SPhilippe Mathieu-Daudé     Object *m_obj = qdev_get_machine();
5381c7b381SPhilippe Mathieu-Daudé 
54f2694f1bSAkihiko Odaki     if (!qdev_hotplug_unplug_allowed_common(dev, bus, errp)) {
55f2694f1bSAkihiko Odaki         return false;
56f2694f1bSAkihiko Odaki     }
57f2694f1bSAkihiko Odaki 
5881c7b381SPhilippe Mathieu-Daudé     if (object_dynamic_cast(m_obj, TYPE_MACHINE)) {
5981c7b381SPhilippe Mathieu-Daudé         machine = MACHINE(m_obj);
6081c7b381SPhilippe Mathieu-Daudé         mc = MACHINE_GET_CLASS(machine);
6181c7b381SPhilippe Mathieu-Daudé         if (mc->hotplug_allowed) {
6281c7b381SPhilippe Mathieu-Daudé             return mc->hotplug_allowed(machine, dev, errp);
6381c7b381SPhilippe Mathieu-Daudé         }
6481c7b381SPhilippe Mathieu-Daudé     }
6581c7b381SPhilippe Mathieu-Daudé 
6681c7b381SPhilippe Mathieu-Daudé     return true;
6781c7b381SPhilippe Mathieu-Daudé }
6881c7b381SPhilippe Mathieu-Daudé 
69206d602eSAkihiko Odaki bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp)
70206d602eSAkihiko Odaki {
71f2694f1bSAkihiko Odaki     return !qdev_unplug_blocked(dev, errp) &&
72f2694f1bSAkihiko Odaki            qdev_hotplug_unplug_allowed_common(dev, dev->parent_bus, errp);
73206d602eSAkihiko Odaki }
74206d602eSAkihiko Odaki 
7581c7b381SPhilippe Mathieu-Daudé HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev)
7681c7b381SPhilippe Mathieu-Daudé {
7781c7b381SPhilippe Mathieu-Daudé     if (dev->parent_bus) {
7881c7b381SPhilippe Mathieu-Daudé         return dev->parent_bus->hotplug_handler;
7981c7b381SPhilippe Mathieu-Daudé     }
8081c7b381SPhilippe Mathieu-Daudé     return NULL;
8181c7b381SPhilippe Mathieu-Daudé }
8281c7b381SPhilippe Mathieu-Daudé 
8381c7b381SPhilippe Mathieu-Daudé HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
8481c7b381SPhilippe Mathieu-Daudé {
8581c7b381SPhilippe Mathieu-Daudé     HotplugHandler *hotplug_ctrl = qdev_get_machine_hotplug_handler(dev);
8681c7b381SPhilippe Mathieu-Daudé 
8781c7b381SPhilippe Mathieu-Daudé     if (hotplug_ctrl == NULL && dev->parent_bus) {
8881c7b381SPhilippe Mathieu-Daudé         hotplug_ctrl = qdev_get_bus_hotplug_handler(dev);
8981c7b381SPhilippe Mathieu-Daudé     }
9081c7b381SPhilippe Mathieu-Daudé     return hotplug_ctrl;
9181c7b381SPhilippe Mathieu-Daudé }
9281c7b381SPhilippe Mathieu-Daudé 
9381c7b381SPhilippe Mathieu-Daudé /* can be used as ->unplug() callback for the simple cases */
9481c7b381SPhilippe Mathieu-Daudé void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
9581c7b381SPhilippe Mathieu-Daudé                                   DeviceState *dev, Error **errp)
9681c7b381SPhilippe Mathieu-Daudé {
9781c7b381SPhilippe Mathieu-Daudé     qdev_unrealize(dev);
9881c7b381SPhilippe Mathieu-Daudé }
99