Commit 5dbbda34 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote branch 'mst/for_anthony' into staging

parents d788b570 e10990c3
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);
}
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -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;
......
......@@ -75,6 +75,7 @@ void qemu_announce_self(void);
void main_loop_wait(int nonblocking);
bool qemu_savevm_state_blocked(Monitor *mon);
int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
int shared);
int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment