mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-02 23:33:54 -06:00
pci/shpc: convert SHPC hotplug to use hotplug-handler API
Split shpc_device_hotplug() into hotplug/unplug callbacks and register them as "hotplug-handler" interface implementation of PCI_BRIDGE_DEV 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
c24d5e0b91
commit
5d268704d7
3 changed files with 94 additions and 47 deletions
124
hw/pci/shpc.c
124
hw/pci/shpc.c
|
@ -7,6 +7,7 @@
|
|||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
|
||||
/* TODO: model power only and disabled slot states. */
|
||||
/* TODO: handle SERR and wakeups */
|
||||
|
@ -490,65 +491,93 @@ static const MemoryRegionOps shpc_mmio_ops = {
|
|||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static int shpc_device_hotplug(DeviceState *qdev, PCIDevice *affected_dev,
|
||||
PCIHotplugState hotplug_state)
|
||||
static void shpc_device_hotplug_common(PCIDevice *affected_dev, int *slot,
|
||||
SHPCDevice *shpc, Error **errp)
|
||||
{
|
||||
int pci_slot = PCI_SLOT(affected_dev->devfn);
|
||||
uint8_t state;
|
||||
uint8_t led;
|
||||
PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
|
||||
SHPCDevice *shpc = d->shpc;
|
||||
int slot = SHPC_PCI_TO_IDX(pci_slot);
|
||||
if (pci_slot < SHPC_IDX_TO_PCI(0) || slot >= shpc->nslots) {
|
||||
error_report("Unsupported PCI slot %d for standard hotplug "
|
||||
"controller. Valid slots are between %d and %d.",
|
||||
pci_slot, SHPC_IDX_TO_PCI(0),
|
||||
SHPC_IDX_TO_PCI(shpc->nslots) - 1);
|
||||
return -1;
|
||||
*slot = SHPC_PCI_TO_IDX(pci_slot);
|
||||
|
||||
if (pci_slot < SHPC_IDX_TO_PCI(0) || *slot >= shpc->nslots) {
|
||||
error_setg(errp, "Unsupported PCI slot %d for standard hotplug "
|
||||
"controller. Valid slots are between %d and %d.",
|
||||
pci_slot, SHPC_IDX_TO_PCI(0),
|
||||
SHPC_IDX_TO_PCI(shpc->nslots) - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
|
||||
SHPCDevice *shpc = pci_hotplug_dev->shpc;
|
||||
int slot;
|
||||
|
||||
shpc_device_hotplug_common(PCI_DEVICE(dev), &slot, shpc, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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 (hotplug_state == PCI_COLDPLUG_ENABLED) {
|
||||
if (!dev->hotplugged) {
|
||||
shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
|
||||
shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
|
||||
SHPC_SLOT_STATUS_PRSNT_MASK);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
if (hotplug_state == PCI_HOTPLUG_DISABLED) {
|
||||
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON;
|
||||
state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
|
||||
led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
|
||||
if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) {
|
||||
shpc_free_devices_in_slot(shpc, slot);
|
||||
shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
|
||||
shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
|
||||
SHPC_SLOT_STATUS_PRSNT_MASK);
|
||||
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
|
||||
SHPC_SLOT_EVENT_MRL |
|
||||
SHPC_SLOT_EVENT_PRESENCE;
|
||||
}
|
||||
|
||||
/* This could be a cancellation of the previous removal.
|
||||
* We check MRL state to figure out. */
|
||||
if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) {
|
||||
shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
|
||||
shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
|
||||
SHPC_SLOT_STATUS_PRSNT_MASK);
|
||||
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
|
||||
SHPC_SLOT_EVENT_BUTTON |
|
||||
SHPC_SLOT_EVENT_MRL |
|
||||
SHPC_SLOT_EVENT_PRESENCE;
|
||||
} else {
|
||||
/* This could be a cancellation of the previous removal.
|
||||
* We check MRL state to figure out. */
|
||||
if (shpc_get_status(shpc, slot, SHPC_SLOT_STATUS_MRL_OPEN)) {
|
||||
shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_MRL_OPEN);
|
||||
shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_7_5W,
|
||||
SHPC_SLOT_STATUS_PRSNT_MASK);
|
||||
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
|
||||
SHPC_SLOT_EVENT_BUTTON |
|
||||
SHPC_SLOT_EVENT_MRL |
|
||||
SHPC_SLOT_EVENT_PRESENCE;
|
||||
} else {
|
||||
/* Press attention button to cancel removal */
|
||||
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
|
||||
SHPC_SLOT_EVENT_BUTTON;
|
||||
}
|
||||
/* Press attention button to cancel removal */
|
||||
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
|
||||
SHPC_SLOT_EVENT_BUTTON;
|
||||
}
|
||||
shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66);
|
||||
shpc_interrupt_update(d);
|
||||
return 0;
|
||||
shpc_interrupt_update(pci_hotplug_dev);
|
||||
}
|
||||
|
||||
void shpc_device_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
|
||||
SHPCDevice *shpc = pci_hotplug_dev->shpc;
|
||||
uint8_t state;
|
||||
uint8_t led;
|
||||
int slot;
|
||||
|
||||
shpc_device_hotplug_common(PCI_DEVICE(dev), &slot, shpc, errp);
|
||||
if (local_err) {
|
||||
return;
|
||||
}
|
||||
|
||||
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |= SHPC_SLOT_EVENT_BUTTON;
|
||||
state = shpc_get_status(shpc, slot, SHPC_SLOT_STATE_MASK);
|
||||
led = shpc_get_status(shpc, slot, SHPC_SLOT_PWR_LED_MASK);
|
||||
if (state == SHPC_STATE_DISABLED && led == SHPC_LED_OFF) {
|
||||
shpc_free_devices_in_slot(shpc, slot);
|
||||
shpc_set_status(shpc, slot, 1, SHPC_SLOT_STATUS_MRL_OPEN);
|
||||
shpc_set_status(shpc, slot, SHPC_SLOT_STATUS_PRSNT_EMPTY,
|
||||
SHPC_SLOT_STATUS_PRSNT_MASK);
|
||||
shpc->config[SHPC_SLOT_EVENT_LATCH(slot)] |=
|
||||
SHPC_SLOT_EVENT_MRL |
|
||||
SHPC_SLOT_EVENT_PRESENCE;
|
||||
}
|
||||
shpc_set_status(shpc, slot, 0, SHPC_SLOT_STATUS_66);
|
||||
shpc_interrupt_update(pci_hotplug_dev);
|
||||
}
|
||||
|
||||
/* Initialize the SHPC structure in bridge's BAR. */
|
||||
|
@ -616,7 +645,8 @@ int shpc_init(PCIDevice *d, PCIBus *sec_bus, MemoryRegion *bar, unsigned offset)
|
|||
d, "shpc-mmio", SHPC_SIZEOF(d));
|
||||
shpc_cap_update_dword(d);
|
||||
memory_region_add_subregion(bar, offset, &shpc->mmio);
|
||||
pci_bus_hotplug(sec_bus, shpc_device_hotplug, &d->qdev);
|
||||
|
||||
qbus_set_hotplug_handler(BUS(sec_bus), DEVICE(d), NULL);
|
||||
|
||||
d->cap_present |= QEMU_PCI_CAP_SHPC;
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue