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