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é 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 { 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 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é 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 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é 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 */ 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