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