mirror of https://github.com/xqemu/xqemu.git
pci/pcie: convert PCIE hotplug to use hotplug-handler API
Split pcie_cap_slot_hotplug() into hotplug/unplug callbacks and register them as "hotplug-handler" interface implementation of PCIE_SLOT device. Replace pci_bus_hotplug() wiring with setting link on PCI BUS "hotplug-handler" property to PCI_BRIDGE_DEV device. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
5d268704d7
commit
a66e657e18
|
@ -26,6 +26,7 @@
|
||||||
#include "hw/pci/pci_bus.h"
|
#include "hw/pci/pci_bus.h"
|
||||||
#include "hw/pci/pcie_regs.h"
|
#include "hw/pci/pcie_regs.h"
|
||||||
#include "qemu/range.h"
|
#include "qemu/range.h"
|
||||||
|
#include "qapi/qmp/qerror.h"
|
||||||
|
|
||||||
//#define DEBUG_PCIE
|
//#define DEBUG_PCIE
|
||||||
#ifdef DEBUG_PCIE
|
#ifdef DEBUG_PCIE
|
||||||
|
@ -216,28 +217,20 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
|
||||||
hotplug_event_notify(dev);
|
hotplug_event_notify(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pcie_cap_slot_hotplug(DeviceState *qdev,
|
static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev,
|
||||||
PCIDevice *pci_dev, PCIHotplugState state)
|
DeviceState *dev,
|
||||||
|
uint8_t **exp_cap, Error **errp)
|
||||||
{
|
{
|
||||||
PCIDevice *d = PCI_DEVICE(qdev);
|
PCIDevice *pci_dev = PCI_DEVICE(dev);
|
||||||
uint8_t *exp_cap = d->config + d->exp.exp_cap;
|
*exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
|
||||||
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
|
uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA);
|
||||||
|
|
||||||
/* Don't send event when device is enabled during qemu machine creation:
|
|
||||||
* it is present on boot, no hotplug event is necessary. We do send an
|
|
||||||
* event when the device is disabled later. */
|
|
||||||
if (state == PCI_COLDPLUG_ENABLED) {
|
|
||||||
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
|
|
||||||
PCI_EXP_SLTSTA_PDS);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
|
PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
|
||||||
if (sltsta & PCI_EXP_SLTSTA_EIS) {
|
if (sltsta & PCI_EXP_SLTSTA_EIS) {
|
||||||
/* the slot is electromechanically locked.
|
/* the slot is electromechanically locked.
|
||||||
* This error is propagated up to qdev and then to HMP/QMP.
|
* This error is propagated up to qdev and then to HMP/QMP.
|
||||||
*/
|
*/
|
||||||
return -EBUSY;
|
error_setg_errno(errp, -EBUSY, "slot is electromechanically locked");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: multifunction hot-plug.
|
/* TODO: multifunction hot-plug.
|
||||||
|
@ -245,18 +238,40 @@ static int pcie_cap_slot_hotplug(DeviceState *qdev,
|
||||||
* hot plugged/unplugged.
|
* hot plugged/unplugged.
|
||||||
*/
|
*/
|
||||||
assert(PCI_FUNC(pci_dev->devfn) == 0);
|
assert(PCI_FUNC(pci_dev->devfn) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (state == PCI_HOTPLUG_ENABLED) {
|
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
uint8_t *exp_cap;
|
||||||
|
|
||||||
|
pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
|
||||||
|
|
||||||
|
/* Don't send event when device is enabled during qemu machine creation:
|
||||||
|
* it is present on boot, no hotplug event is necessary. We do send an
|
||||||
|
* event when the device is disabled later. */
|
||||||
|
if (!dev->hotplugged) {
|
||||||
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
|
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
|
||||||
PCI_EXP_SLTSTA_PDS);
|
PCI_EXP_SLTSTA_PDS);
|
||||||
pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
|
return;
|
||||||
} else {
|
|
||||||
object_unparent(OBJECT(pci_dev));
|
|
||||||
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
|
|
||||||
PCI_EXP_SLTSTA_PDS);
|
|
||||||
pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
|
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
|
||||||
|
PCI_EXP_SLTSTA_PDS);
|
||||||
|
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pcie_cap_slot_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
|
Error **errp)
|
||||||
|
{
|
||||||
|
uint8_t *exp_cap;
|
||||||
|
|
||||||
|
pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
|
||||||
|
|
||||||
|
object_unparent(OBJECT(dev));
|
||||||
|
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
|
||||||
|
PCI_EXP_SLTSTA_PDS);
|
||||||
|
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pci express slot for pci express root/downstream port
|
/* pci express slot for pci express root/downstream port
|
||||||
|
@ -305,8 +320,8 @@ void pcie_cap_slot_init(PCIDevice *dev, uint16_t slot)
|
||||||
|
|
||||||
dev->exp.hpev_notified = false;
|
dev->exp.hpev_notified = false;
|
||||||
|
|
||||||
pci_bus_hotplug(pci_bridge_get_sec_bus(PCI_BRIDGE(dev)),
|
qbus_set_hotplug_handler(BUS(pci_bridge_get_sec_bus(PCI_BRIDGE(dev))),
|
||||||
pcie_cap_slot_hotplug, &dev->qdev);
|
DEVICE(dev), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcie_cap_slot_reset(PCIDevice *dev)
|
void pcie_cap_slot_reset(PCIDevice *dev)
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hw/pci/pcie_port.h"
|
#include "hw/pci/pcie_port.h"
|
||||||
|
#include "hw/hotplug.h"
|
||||||
|
|
||||||
void pcie_port_init_reg(PCIDevice *d)
|
void pcie_port_init_reg(PCIDevice *d)
|
||||||
{
|
{
|
||||||
|
@ -149,8 +150,11 @@ static Property pcie_slot_props[] = {
|
||||||
static void pcie_slot_class_init(ObjectClass *oc, void *data)
|
static void pcie_slot_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||||
|
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
|
||||||
|
|
||||||
dc->props = pcie_slot_props;
|
dc->props = pcie_slot_props;
|
||||||
|
hc->plug = pcie_cap_slot_hotplug_cb;
|
||||||
|
hc->unplug = pcie_cap_slot_hot_unplug_cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo pcie_slot_type_info = {
|
static const TypeInfo pcie_slot_type_info = {
|
||||||
|
@ -159,6 +163,10 @@ static const TypeInfo pcie_slot_type_info = {
|
||||||
.instance_size = sizeof(PCIESlot),
|
.instance_size = sizeof(PCIESlot),
|
||||||
.abstract = true,
|
.abstract = true,
|
||||||
.class_init = pcie_slot_class_init,
|
.class_init = pcie_slot_class_init,
|
||||||
|
.interfaces = (InterfaceInfo[]) {
|
||||||
|
{ TYPE_HOTPLUG_HANDLER },
|
||||||
|
{ }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void pcie_port_register_types(void)
|
static void pcie_port_register_types(void)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "hw/pci/pci_regs.h"
|
#include "hw/pci/pci_regs.h"
|
||||||
#include "hw/pci/pcie_regs.h"
|
#include "hw/pci/pcie_regs.h"
|
||||||
#include "hw/pci/pcie_aer.h"
|
#include "hw/pci/pcie_aer.h"
|
||||||
|
#include "hw/hotplug.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* for attention and power indicator */
|
/* for attention and power indicator */
|
||||||
|
@ -122,4 +123,8 @@ extern const VMStateDescription vmstate_pcie_device;
|
||||||
.offset = vmstate_offset_value(_state, _field, PCIDevice), \
|
.offset = vmstate_offset_value(_state, _field, PCIDevice), \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
|
Error **errp);
|
||||||
|
void pcie_cap_slot_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||||
|
Error **errp);
|
||||||
#endif /* QEMU_PCIE_H */
|
#endif /* QEMU_PCIE_H */
|
||||||
|
|
Loading…
Reference in New Issue