xref: /qemu/hw/core/qdev-hotplug.c (revision 7433709a147706ad7d1956b15669279933d0f82b)
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"
151bff035bSAkihiko Odaki #include "qapi/error.h"
1681c7b381SPhilippe Mathieu-Daudé 
qdev_get_machine_hotplug_handler(DeviceState * dev)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é 
qdev_hotplug_unplug_allowed_common(DeviceState * dev,BusState * bus,Error ** errp)34f2694f1bSAkihiko Odaki static bool qdev_hotplug_unplug_allowed_common(DeviceState *dev, BusState *bus,
35f2694f1bSAkihiko Odaki                                                Error **errp)
36f2694f1bSAkihiko Odaki {
371bff035bSAkihiko Odaki     DeviceClass *dc = DEVICE_GET_CLASS(dev);
381bff035bSAkihiko Odaki 
391bff035bSAkihiko Odaki     if (!dc->hotpluggable) {
401bff035bSAkihiko Odaki         error_setg(errp, "Device '%s' does not support hotplugging",
411bff035bSAkihiko Odaki                    object_get_typename(OBJECT(dev)));
421bff035bSAkihiko Odaki         return false;
431bff035bSAkihiko Odaki     }
441bff035bSAkihiko Odaki 
45ccaca892SAkihiko Odaki     if (bus) {
46ccaca892SAkihiko Odaki         if (!qbus_is_hotpluggable(bus)) {
47ccaca892SAkihiko Odaki             error_setg(errp, "Bus '%s' does not support hotplugging",
48ccaca892SAkihiko Odaki                        bus->name);
49ccaca892SAkihiko Odaki             return false;
50ccaca892SAkihiko Odaki         }
51*937874a8SAkihiko Odaki     } else {
52*937874a8SAkihiko Odaki         if (!qdev_get_machine_hotplug_handler(dev)) {
53*937874a8SAkihiko Odaki             /*
54*937874a8SAkihiko Odaki              * No bus, no machine hotplug handler --> device is not hotpluggable
55*937874a8SAkihiko Odaki              */
56*937874a8SAkihiko Odaki             error_setg(errp,
57*937874a8SAkihiko Odaki                        "Device '%s' can not be hotplugged on this machine",
58*937874a8SAkihiko Odaki                        object_get_typename(OBJECT(dev)));
59*937874a8SAkihiko Odaki             return false;
60*937874a8SAkihiko Odaki         }
61ccaca892SAkihiko Odaki     }
62ccaca892SAkihiko Odaki 
63f2694f1bSAkihiko Odaki     return true;
64f2694f1bSAkihiko Odaki }
65f2694f1bSAkihiko Odaki 
qdev_hotplug_allowed(DeviceState * dev,BusState * bus,Error ** errp)668915c118SAkihiko Odaki bool qdev_hotplug_allowed(DeviceState *dev, BusState *bus, Error **errp)
6781c7b381SPhilippe Mathieu-Daudé {
6881c7b381SPhilippe Mathieu-Daudé     MachineState *machine;
6981c7b381SPhilippe Mathieu-Daudé     MachineClass *mc;
7081c7b381SPhilippe Mathieu-Daudé     Object *m_obj = qdev_get_machine();
7181c7b381SPhilippe Mathieu-Daudé 
72f2694f1bSAkihiko Odaki     if (!qdev_hotplug_unplug_allowed_common(dev, bus, errp)) {
73f2694f1bSAkihiko Odaki         return false;
74f2694f1bSAkihiko Odaki     }
75f2694f1bSAkihiko Odaki 
7681c7b381SPhilippe Mathieu-Daudé     if (object_dynamic_cast(m_obj, TYPE_MACHINE)) {
7781c7b381SPhilippe Mathieu-Daudé         machine = MACHINE(m_obj);
7881c7b381SPhilippe Mathieu-Daudé         mc = MACHINE_GET_CLASS(machine);
7981c7b381SPhilippe Mathieu-Daudé         if (mc->hotplug_allowed) {
8081c7b381SPhilippe Mathieu-Daudé             return mc->hotplug_allowed(machine, dev, errp);
8181c7b381SPhilippe Mathieu-Daudé         }
8281c7b381SPhilippe Mathieu-Daudé     }
8381c7b381SPhilippe Mathieu-Daudé 
8481c7b381SPhilippe Mathieu-Daudé     return true;
8581c7b381SPhilippe Mathieu-Daudé }
8681c7b381SPhilippe Mathieu-Daudé 
qdev_hotunplug_allowed(DeviceState * dev,Error ** errp)87206d602eSAkihiko Odaki bool qdev_hotunplug_allowed(DeviceState *dev, Error **errp)
88206d602eSAkihiko Odaki {
89f2694f1bSAkihiko Odaki     return !qdev_unplug_blocked(dev, errp) &&
90f2694f1bSAkihiko Odaki            qdev_hotplug_unplug_allowed_common(dev, dev->parent_bus, errp);
91206d602eSAkihiko Odaki }
92206d602eSAkihiko Odaki 
qdev_get_bus_hotplug_handler(DeviceState * dev)9381c7b381SPhilippe Mathieu-Daudé HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev)
9481c7b381SPhilippe Mathieu-Daudé {
9581c7b381SPhilippe Mathieu-Daudé     if (dev->parent_bus) {
9681c7b381SPhilippe Mathieu-Daudé         return dev->parent_bus->hotplug_handler;
9781c7b381SPhilippe Mathieu-Daudé     }
9881c7b381SPhilippe Mathieu-Daudé     return NULL;
9981c7b381SPhilippe Mathieu-Daudé }
10081c7b381SPhilippe Mathieu-Daudé 
qdev_get_hotplug_handler(DeviceState * dev)10181c7b381SPhilippe Mathieu-Daudé HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
10281c7b381SPhilippe Mathieu-Daudé {
10381c7b381SPhilippe Mathieu-Daudé     HotplugHandler *hotplug_ctrl = qdev_get_machine_hotplug_handler(dev);
10481c7b381SPhilippe Mathieu-Daudé 
10581c7b381SPhilippe Mathieu-Daudé     if (hotplug_ctrl == NULL && dev->parent_bus) {
10681c7b381SPhilippe Mathieu-Daudé         hotplug_ctrl = qdev_get_bus_hotplug_handler(dev);
10781c7b381SPhilippe Mathieu-Daudé     }
10881c7b381SPhilippe Mathieu-Daudé     return hotplug_ctrl;
10981c7b381SPhilippe Mathieu-Daudé }
11081c7b381SPhilippe Mathieu-Daudé 
11181c7b381SPhilippe Mathieu-Daudé /* can be used as ->unplug() callback for the simple cases */
qdev_simple_device_unplug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)11281c7b381SPhilippe Mathieu-Daudé void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
11381c7b381SPhilippe Mathieu-Daudé                                   DeviceState *dev, Error **errp)
11481c7b381SPhilippe Mathieu-Daudé {
11581c7b381SPhilippe Mathieu-Daudé     qdev_unrealize(dev);
11681c7b381SPhilippe Mathieu-Daudé }
117