Merge remote branch 'mst/for_anthony' into staging
This commit is contained in:
commit
5dbbda3405
37
docs/specs/acpi_pci_hotplug.txt
Normal file
37
docs/specs/acpi_pci_hotplug.txt
Normal file
@ -0,0 +1,37 @@
|
||||
QEMU<->ACPI BIOS PCI hotplug interface
|
||||
--------------------------------------
|
||||
|
||||
QEMU supports PCI hotplug via ACPI, for PCI bus 0. This document
|
||||
describes the interface between QEMU and the ACPI BIOS.
|
||||
|
||||
ACPI GPE block (IO ports 0xafe0-0xafe3, byte access):
|
||||
-----------------------------------------
|
||||
|
||||
Generic ACPI GPE block. Bit 1 (GPE.1) used to notify PCI hotplug/eject
|
||||
event to ACPI BIOS, via SCI interrupt.
|
||||
|
||||
PCI slot injection notification pending (IO port 0xae00-0xae03, 4-byte access):
|
||||
---------------------------------------------------------------
|
||||
Slot injection notification pending. One bit per slot.
|
||||
|
||||
Read by ACPI BIOS GPE.1 handler to notify OS of injection
|
||||
events.
|
||||
|
||||
PCI slot removal notification (IO port 0xae04-0xae07, 4-byte access):
|
||||
-----------------------------------------------------
|
||||
Slot removal notification pending. One bit per slot.
|
||||
|
||||
Read by ACPI BIOS GPE.1 handler to notify OS of removal
|
||||
events.
|
||||
|
||||
PCI device eject (IO port 0xae08-0xae0b, 4-byte access):
|
||||
----------------------------------------
|
||||
|
||||
Used by ACPI BIOS _EJ0 method to request device removal. One bit per slot.
|
||||
Reads return 0.
|
||||
|
||||
PCI removability status (IO port 0xae0c-0xae0f, 4-byte access):
|
||||
-----------------------------------------------
|
||||
|
||||
Used by ACPI BIOS _RMV method to indicate removability status to OS. One
|
||||
bit per slot.
|
@ -37,6 +37,7 @@
|
||||
#define GPE_BASE 0xafe0
|
||||
#define PCI_BASE 0xae00
|
||||
#define PCI_EJ_BASE 0xae08
|
||||
#define PCI_RMV_BASE 0xae0c
|
||||
|
||||
#define PIIX4_PCI_HOTPLUG_STATUS 2
|
||||
|
||||
@ -73,6 +74,7 @@ typedef struct PIIX4PMState {
|
||||
/* for pci hotplug */
|
||||
struct gpe_regs gpe;
|
||||
struct pci_status pci0_status;
|
||||
uint32_t pci0_hotplug_enable;
|
||||
} PIIX4PMState;
|
||||
|
||||
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s);
|
||||
@ -322,6 +324,25 @@ static const VMStateDescription vmstate_acpi = {
|
||||
}
|
||||
};
|
||||
|
||||
static void piix4_update_hotplug(PIIX4PMState *s)
|
||||
{
|
||||
PCIDevice *dev = &s->dev;
|
||||
BusState *bus = qdev_get_parent_bus(&dev->qdev);
|
||||
DeviceState *qdev, *next;
|
||||
|
||||
s->pci0_hotplug_enable = ~0;
|
||||
|
||||
QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
|
||||
PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
|
||||
PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
|
||||
int slot = PCI_SLOT(pdev->devfn);
|
||||
|
||||
if (info->no_hotplug) {
|
||||
s->pci0_hotplug_enable &= ~(1 << slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void piix4_reset(void *opaque)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
@ -336,6 +357,7 @@ static void piix4_reset(void *opaque)
|
||||
/* Mark SMM as already inited (until KVM supports SMM). */
|
||||
pci_conf[0x5B] = 0x02;
|
||||
}
|
||||
piix4_update_hotplug(s);
|
||||
}
|
||||
|
||||
static void piix4_powerdown(void *opaque, int irq, int power_failing)
|
||||
@ -576,6 +598,18 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val);
|
||||
}
|
||||
|
||||
static uint32_t pcirmv_read(void *opaque, uint32_t addr)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
|
||||
return s->pci0_hotplug_enable;
|
||||
}
|
||||
|
||||
static void pcirmv_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
|
||||
PCIHotplugState state);
|
||||
|
||||
@ -592,6 +626,9 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
|
||||
register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus);
|
||||
register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus);
|
||||
|
||||
register_ioport_write(PCI_RMV_BASE, 4, 4, pcirmv_write, s);
|
||||
register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s);
|
||||
|
||||
pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
|
||||
}
|
||||
|
||||
|
5
hw/msi.c
5
hw/msi.c
@ -255,7 +255,6 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
|
||||
uint8_t log_max_vecs;
|
||||
unsigned int vector;
|
||||
uint32_t pending;
|
||||
int i;
|
||||
|
||||
if (!ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
|
||||
return;
|
||||
@ -296,9 +295,7 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
|
||||
* from using its INTx# pin (if implemented) to request
|
||||
* service (MSI, MSI-X, and INTx# are mutually exclusive).
|
||||
*/
|
||||
for (i = 0; i < PCI_NUM_PINS; ++i) {
|
||||
qemu_set_irq(dev->irq[i], 0);
|
||||
}
|
||||
pci_device_deassert_intx(dev);
|
||||
|
||||
/*
|
||||
* nr_vectors might be set bigger than capable. So clamp it.
|
||||
|
@ -159,7 +159,6 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
|
||||
{
|
||||
unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
|
||||
int vector;
|
||||
int i;
|
||||
|
||||
if (!range_covers_byte(addr, len, enable_pos)) {
|
||||
return;
|
||||
@ -169,9 +168,7 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < PCI_NUM_PINS; ++i) {
|
||||
qemu_set_irq(dev->irq[i], 0);
|
||||
}
|
||||
pci_device_deassert_intx(dev);
|
||||
|
||||
if (msix_function_masked(dev)) {
|
||||
return;
|
||||
|
27
hw/pci.c
27
hw/pci.c
@ -137,6 +137,14 @@ static void pci_update_irq_status(PCIDevice *dev)
|
||||
}
|
||||
}
|
||||
|
||||
void pci_device_deassert_intx(PCIDevice *dev)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < PCI_NUM_PINS; ++i) {
|
||||
qemu_set_irq(dev->irq[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called on #RST and FLR.
|
||||
* FLR if PCI_EXP_DEVCTL_BCR_FLR is set
|
||||
@ -152,6 +160,7 @@ void pci_device_reset(PCIDevice *dev)
|
||||
|
||||
dev->irq_state = 0;
|
||||
pci_update_irq_status(dev);
|
||||
pci_device_deassert_intx(dev);
|
||||
/* Clear all writeable bits */
|
||||
pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
|
||||
pci_get_word(dev->wmask + PCI_COMMAND) |
|
||||
@ -2032,10 +2041,13 @@ static char *pcibus_get_dev_path(DeviceState *dev)
|
||||
* domain:Bus:Slot.Func for systems without nested PCI bridges.
|
||||
* Slot.Function list specifies the slot and function numbers for all
|
||||
* devices on the path from root to the specific device. */
|
||||
int domain_len = strlen("DDDD:00");
|
||||
int slot_len = strlen(":SS.F");
|
||||
char domain[] = "DDDD:00";
|
||||
char slot[] = ":SS.F";
|
||||
int domain_len = sizeof domain - 1 /* For '\0' */;
|
||||
int slot_len = sizeof slot - 1 /* For '\0' */;
|
||||
int path_len;
|
||||
char *path, *p;
|
||||
int s;
|
||||
|
||||
/* Calculate # of slots on path between device and root. */;
|
||||
slot_depth = 0;
|
||||
@ -2046,18 +2058,23 @@ static char *pcibus_get_dev_path(DeviceState *dev)
|
||||
path_len = domain_len + slot_len * slot_depth;
|
||||
|
||||
/* Allocate memory, fill in the terminating null byte. */
|
||||
path = malloc(path_len + 1 /* For '\0' */);
|
||||
path = qemu_malloc(path_len + 1 /* For '\0' */);
|
||||
path[path_len] = '\0';
|
||||
|
||||
/* First field is the domain. */
|
||||
snprintf(path, domain_len, "%04x:00", pci_find_domain(d->bus));
|
||||
s = snprintf(domain, sizeof domain, "%04x:00", pci_find_domain(d->bus));
|
||||
assert(s == domain_len);
|
||||
memcpy(path, domain, domain_len);
|
||||
|
||||
/* Fill in slot numbers. We walk up from device to root, so need to print
|
||||
* them in the reverse order, last to first. */
|
||||
p = path + path_len;
|
||||
for (t = d; t; t = t->bus->parent_dev) {
|
||||
p -= slot_len;
|
||||
snprintf(p, slot_len, ":%02x.%x", PCI_SLOT(t->devfn), PCI_FUNC(d->devfn));
|
||||
s = snprintf(slot, sizeof slot, ":%02x.%x",
|
||||
PCI_SLOT(t->devfn), PCI_FUNC(d->devfn));
|
||||
assert(s == slot_len);
|
||||
memcpy(p, slot, slot_len);
|
||||
}
|
||||
|
||||
return path;
|
||||
|
2
hw/pci.h
2
hw/pci.h
@ -264,6 +264,8 @@ void do_pci_info_print(Monitor *mon, const QObject *data);
|
||||
void do_pci_info(Monitor *mon, QObject **ret_data);
|
||||
void pci_bridge_update_mappings(PCIBus *b);
|
||||
|
||||
void pci_device_deassert_intx(PCIDevice *dev);
|
||||
|
||||
static inline void
|
||||
pci_set_byte(uint8_t *config, uint8_t val)
|
||||
{
|
||||
|
@ -769,10 +769,16 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
|
||||
/* Add a queue for guest to host transfers for port 0 (backward compat) */
|
||||
vser->ovqs[0] = virtio_add_queue(vdev, 128, handle_output);
|
||||
|
||||
/* TODO: host to guest notifications can get dropped
|
||||
* if the queue fills up. Implement queueing in host,
|
||||
* this might also make it possible to reduce the control
|
||||
* queue size: as guest preposts buffers there,
|
||||
* this will save 4Kbyte of guest memory per entry. */
|
||||
|
||||
/* control queue: host to guest */
|
||||
vser->c_ivq = virtio_add_queue(vdev, 16, control_in);
|
||||
vser->c_ivq = virtio_add_queue(vdev, 32, control_in);
|
||||
/* control queue: guest to host */
|
||||
vser->c_ovq = virtio_add_queue(vdev, 16, control_out);
|
||||
vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
|
||||
|
||||
for (i = 1; i < vser->bus->max_nr_ports; i++) {
|
||||
/* Add a per-port queue for host to guest transfers */
|
||||
|
@ -88,6 +88,10 @@ int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qemu_savevm_state_blocked(mon)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strstart(uri, "tcp:", &p)) {
|
||||
s = tcp_start_outgoing_migration(mon, p, max_throttle, detach,
|
||||
blk, inc);
|
||||
|
40
savevm.c
40
savevm.c
@ -1401,19 +1401,13 @@ static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
|
||||
return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
|
||||
}
|
||||
|
||||
static int vmstate_save(QEMUFile *f, SaveStateEntry *se)
|
||||
static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
|
||||
{
|
||||
if (se->no_migrate) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!se->vmsd) { /* Old style */
|
||||
se->save_state(f, se->opaque);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
vmstate_save_state(f,se->vmsd, se->opaque);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define QEMU_VM_FILE_MAGIC 0x5145564d
|
||||
@ -1427,6 +1421,20 @@ static int vmstate_save(QEMUFile *f, SaveStateEntry *se)
|
||||
#define QEMU_VM_SECTION_FULL 0x04
|
||||
#define QEMU_VM_SUBSECTION 0x05
|
||||
|
||||
bool qemu_savevm_state_blocked(Monitor *mon)
|
||||
{
|
||||
SaveStateEntry *se;
|
||||
|
||||
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
|
||||
if (se->no_migrate) {
|
||||
monitor_printf(mon, "state blocked by non-migratable device '%s'\n",
|
||||
se->idstr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
|
||||
int shared)
|
||||
{
|
||||
@ -1508,7 +1516,6 @@ int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f)
|
||||
int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
|
||||
{
|
||||
SaveStateEntry *se;
|
||||
int r;
|
||||
|
||||
cpu_synchronize_all_states();
|
||||
|
||||
@ -1541,11 +1548,7 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f)
|
||||
qemu_put_be32(f, se->instance_id);
|
||||
qemu_put_be32(f, se->version_id);
|
||||
|
||||
r = vmstate_save(f, se);
|
||||
if (r < 0) {
|
||||
monitor_printf(mon, "cannot migrate with device '%s'\n", se->idstr);
|
||||
return r;
|
||||
}
|
||||
vmstate_save(f, se);
|
||||
}
|
||||
|
||||
qemu_put_byte(f, QEMU_VM_EOF);
|
||||
@ -1575,6 +1578,11 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
|
||||
saved_vm_running = vm_running;
|
||||
vm_stop(0);
|
||||
|
||||
if (qemu_savevm_state_blocked(mon)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = qemu_savevm_state_begin(mon, f, 0, 0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
@ -1692,6 +1700,10 @@ int qemu_loadvm_state(QEMUFile *f)
|
||||
unsigned int v;
|
||||
int ret;
|
||||
|
||||
if (qemu_savevm_state_blocked(default_mon)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
v = qemu_get_be32(f);
|
||||
if (v != QEMU_VM_FILE_MAGIC)
|
||||
return -EINVAL;
|
||||
|
Loading…
Reference in New Issue
Block a user