virtio,pci,qom

Work by Alex to support VGA assignment,
 pci and virtio fixes by Stefan, Jason and myself, and a
 new qmp event for hotplug support by myself.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.13 (GNU/Linux)
 
 iQEcBAABAgAGBQJRUfDAAAoJECgfDbjSjVRp5wwH/RiNzEuC0SNuMArXh2LS+qjn
 EavcSRTas5800Rl8bW2iYwJV38WhyW7jKs3JxbL5iK6XLeZvr7mureMRpsT6N5cR
 WPqoZBw2jIxcHmYZODHTGd9SrAmF2LpfKypN3a86P5P4sQvV/dEusPQx7ZNyi5I5
 kdhqNyP6Q6scAUbJVrNUbcOy8euLUtpEO2VQju/gikz2KLsQj6Hyxt9vKV2ZquYU
 B7pKvYt5UZhNPqhfBmRptW+U0CMYUPiZBZkZsTEPUibIFHQqGkMD/KtthFFDZc/U
 hjxttuETzjACR3KKgegwLVYCFEF8WadPJark4LWb4D9TA1MIdgo2NabNpqYxqrA=
 =PY9F
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'mst/tags/for_anthony' into staging

virtio,pci,qom

Work by Alex to support VGA assignment,
pci and virtio fixes by Stefan, Jason and myself, and a
new qmp event for hotplug support by myself.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Tue 26 Mar 2013 02:02:24 PM CDT using RSA key ID D28D5469
# gpg: Can't check signature: public key not found

# By Alex Williamson (13) and others
# Via Michael S. Tsirkin
* mst/tags/for_anthony: (23 commits)
  pcie: Add endpoint capability initialization wrapper
  roms: switch oldnoconfig to olddefconfig
  pcie: Mangle types to match topology
  pci: Create and use API to determine root buses
  pci: Create pci_bus_is_express helper
  pci: Q35, Root Ports, and Switches create PCI Express buses
  pci: Allow PCI bus creation interfaces to specify the type of bus
  pci: Move PCI and PCIE type defines
  pci: Create and register a new PCI Express TypeInfo
  exec: assert that RAMBlock size is non-zero
  pci: refuse empty ROM files
  pci_bridge: Remove duplicate IRQ swizzle function
  pci_bridge: Use a default map_irq function
  pci: Fix INTx routing notifier recursion
  pci_bridge: drop formatting from source
  pci_bridge: factor out common code
  pci: Teach PCI Bridges about VGA routing
  pci: Add PCI VGA helpers
  virtio-pci: guest notifier mask without non-irqfd
  virtio-net: remove layout assumptions for mq ctrl
  ...
This commit is contained in:
Anthony Liguori 2013-03-26 16:16:43 -05:00
commit 404e7a4f4a
39 changed files with 348 additions and 131 deletions

View File

@ -136,6 +136,24 @@ Example:
Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
event.
DEVICE_DELETED
-----------------
Emitted whenever the device removal completion is acknowledged
by the guest.
At this point, it's safe to reuse the specified device ID.
Device removal can be initiated by the guest or by HMP/QMP commands.
Data:
- "device": device name (json-string, optional)
- "path": device path (json-string)
{ "event": "DEVICE_DELETED",
"data": { "device": "virtio-net-pci-0",
"path": "/machine/peripheral/virtio-net-pci-0" },
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
DEVICE_TRAY_MOVED
-----------------

2
exec.c
View File

@ -925,6 +925,8 @@ static ram_addr_t find_ram_offset(ram_addr_t size)
RAMBlock *block, *next_block;
ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX;
assert(size != 0); /* it would hand out same offset multiple times */
if (QTAILQ_EMPTY(&ram_list.blocks))
return 0;

View File

@ -775,7 +775,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
b = pci_register_bus(dev, "pci",
typhoon_set_irq, sys_map_irq, s,
&s->pchip.reg_mem, addr_space_io, 0, 64);
&s->pchip.reg_mem, addr_space_io, 0, 64, TYPE_PCI_BUS);
phb->bus = b;
/* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */

View File

@ -329,7 +329,7 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
{
int rc;
rc = pci_bridge_initfn(dev);
rc = pci_bridge_initfn(dev, TYPE_PCI_BUS);
if (rc < 0) {
return rc;
}
@ -381,7 +381,7 @@ PCIBus *pci_apb_init(hwaddr special_base,
pci_apb_set_irq, pci_pbm_map_irq, d,
&d->pci_mmio,
get_system_io(),
0, 32);
0, 32, TYPE_PCI_BUS);
*pbm_irqs = d->pbm_irqs;
d->ivec_irqs = ivec_irqs;

View File

@ -707,7 +707,7 @@ static int bonito_pcihost_initfn(SysBusDevice *dev)
phb->bus = pci_register_bus(DEVICE(dev), "pci",
pci_bonito_set_irq, pci_bonito_map_irq, dev,
get_system_memory(), get_system_io(),
0x28, 32);
0x28, 32, TYPE_PCI_BUS);
return 0;
}

View File

@ -51,12 +51,17 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
return irq_num;
}
static int dec_pci_bridge_initfn(PCIDevice *pci_dev)
{
return pci_bridge_initfn(pci_dev, TYPE_PCI_BUS);
}
static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = pci_bridge_initfn;
k->init = dec_pci_bridge_initfn;
k->exit = pci_bridge_exitfn;
k->vendor_id = PCI_VENDOR_ID_DEC;
k->device_id = PCI_DEVICE_ID_DEC_21154;

View File

@ -88,7 +88,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
pic,
&d->pci_mmio,
address_space_io,
0, 4);
0, 4, TYPE_PCI_BUS);
pci_create_simple(phb->bus, 0, "grackle");

View File

@ -1107,7 +1107,7 @@ PCIBus *gt64120_register(qemu_irq *pic)
pic,
get_system_memory(),
get_system_io(),
PCI_DEVFN(18, 0), 4);
PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS);
memory_region_init_io(&d->ISD_mem, &isd_mem_ops, d, "isd-mem", 0x1000);
pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci");

View File

@ -59,7 +59,7 @@ static int i82801b11_bridge_initfn(PCIDevice *d)
{
int rc;
rc = pci_bridge_initfn(d);
rc = pci_bridge_initfn(d, TYPE_PCI_BUS);
if (rc < 0) {
return rc;
}

View File

@ -97,7 +97,7 @@ static int ioh3420_initfn(PCIDevice *d)
PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
int rc;
rc = pci_bridge_initfn(d);
rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
if (rc < 0) {
return rc;
}

View File

@ -75,6 +75,11 @@ static const TypeInfo pci_bus_info = {
.class_init = pci_bus_class_init,
};
static const TypeInfo pcie_bus_info = {
.name = TYPE_PCIE_BUS,
.parent = TYPE_PCI_BUS,
};
static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
static void pci_update_mappings(PCIDevice *d);
static void pci_set_irq(void *opaque, int irq_num, int level);
@ -292,13 +297,23 @@ static void pci_bus_init(PCIBus *bus, DeviceState *parent,
vmstate_register(NULL, -1, &vmstate_pcibus, bus);
}
bool pci_bus_is_express(PCIBus *bus)
{
return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS);
}
bool pci_bus_is_root(PCIBus *bus)
{
return !bus->parent_dev;
}
void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
const char *name,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min)
uint8_t devfn_min, const char *typename)
{
qbus_create_inplace(bus, TYPE_PCI_BUS, parent, name);
qbus_create_inplace(bus, typename, parent, name);
pci_bus_init(bus, parent, name, address_space_mem,
address_space_io, devfn_min);
}
@ -306,11 +321,11 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
PCIBus *pci_bus_new(DeviceState *parent, const char *name,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min)
uint8_t devfn_min, const char *typename)
{
PCIBus *bus;
bus = PCI_BUS(qbus_create(TYPE_PCI_BUS, parent, name));
bus = PCI_BUS(qbus_create(typename, parent, name));
pci_bus_init(bus, parent, name, address_space_mem,
address_space_io, devfn_min);
return bus;
@ -338,19 +353,19 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
void *irq_opaque,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min, int nirq)
uint8_t devfn_min, int nirq, const char *typename)
{
PCIBus *bus;
bus = pci_bus_new(parent, name, address_space_mem,
address_space_io, devfn_min);
address_space_io, devfn_min, typename);
pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);
return bus;
}
int pci_bus_num(PCIBus *s)
{
if (!s->parent_dev)
if (pci_bus_is_root(s))
return 0; /* pci host bridge */
return s->parent_dev->config[PCI_SECONDARY_BUS];
}
@ -668,12 +683,10 @@ static void pci_init_mask_bridge(PCIDevice *d)
pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
PCI_PREF_RANGE_TYPE_64);
/* TODO: add this define to pci_regs.h in linux and then in qemu. */
#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */
#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */
#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */
#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */
#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */
/*
* TODO: Bridges default to 10-bit VGA decoding but we currently only
* implement 16-bit decoding (no alias support).
*/
pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
PCI_BRIDGE_CTL_PARITY |
PCI_BRIDGE_CTL_SERR |
@ -875,6 +888,8 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
continue;
memory_region_del_subregion(r->address_space, r->memory);
}
pci_unregister_vga(pci_dev);
}
static int pci_unregister_device(DeviceState *dev)
@ -937,6 +952,63 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
: pci_dev->bus->address_space_mem;
}
static void pci_update_vga(PCIDevice *pci_dev)
{
uint16_t cmd;
if (!pci_dev->has_vga) {
return;
}
cmd = pci_get_word(pci_dev->config + PCI_COMMAND);
memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_MEM],
cmd & PCI_COMMAND_MEMORY);
memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO],
cmd & PCI_COMMAND_IO);
memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI],
cmd & PCI_COMMAND_IO);
}
void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
MemoryRegion *io_lo, MemoryRegion *io_hi)
{
assert(!pci_dev->has_vga);
assert(memory_region_size(mem) == QEMU_PCI_VGA_MEM_SIZE);
pci_dev->vga_regions[QEMU_PCI_VGA_MEM] = mem;
memory_region_add_subregion_overlap(pci_dev->bus->address_space_mem,
QEMU_PCI_VGA_MEM_BASE, mem, 1);
assert(memory_region_size(io_lo) == QEMU_PCI_VGA_IO_LO_SIZE);
pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO] = io_lo;
memory_region_add_subregion_overlap(pci_dev->bus->address_space_io,
QEMU_PCI_VGA_IO_LO_BASE, io_lo, 1);
assert(memory_region_size(io_hi) == QEMU_PCI_VGA_IO_HI_SIZE);
pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI] = io_hi;
memory_region_add_subregion_overlap(pci_dev->bus->address_space_io,
QEMU_PCI_VGA_IO_HI_BASE, io_hi, 1);
pci_dev->has_vga = true;
pci_update_vga(pci_dev);
}
void pci_unregister_vga(PCIDevice *pci_dev)
{
if (!pci_dev->has_vga) {
return;
}
memory_region_del_subregion(pci_dev->bus->address_space_mem,
pci_dev->vga_regions[QEMU_PCI_VGA_MEM]);
memory_region_del_subregion(pci_dev->bus->address_space_io,
pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO]);
memory_region_del_subregion(pci_dev->bus->address_space_io,
pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI]);
pci_dev->has_vga = false;
}
pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
{
return pci_dev->io_regions[region_num].addr;
@ -1036,6 +1108,8 @@ static void pci_update_mappings(PCIDevice *d)
r->addr, r->memory, 1);
}
}
pci_update_vga(d);
}
static inline int pci_irq_disabled(PCIDevice *d)
@ -1117,7 +1191,7 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
/* Special hooks used by device assignment */
void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq)
{
assert(!bus->parent_dev);
assert(pci_bus_is_root(bus));
bus->route_intx_to_irq = route_intx_to_irq;
}
@ -1156,9 +1230,10 @@ void pci_bus_fire_intx_routing_notifier(PCIBus *bus)
if (dev && dev->intx_routing_notifier) {
dev->intx_routing_notifier(dev);
}
QLIST_FOREACH(sec, &bus->child, sibling) {
pci_bus_fire_intx_routing_notifier(sec);
}
}
QLIST_FOREACH(sec, &bus->child, sibling) {
pci_bus_fire_intx_routing_notifier(sec);
}
}
@ -1581,7 +1656,7 @@ static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
}
/* Consider all bus numbers in range for the host pci bridge. */
if (bus->parent_dev &&
if (!pci_bus_is_root(bus) &&
!pci_secondary_bus_in_range(bus->parent_dev, bus_num)) {
return NULL;
}
@ -1589,7 +1664,7 @@ static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
/* try child bus */
for (; bus; bus = sec) {
QLIST_FOREACH(sec, &bus->child, sibling) {
assert(sec->parent_dev);
assert(!pci_bus_is_root(sec));
if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {
return sec;
}
@ -1852,7 +1927,12 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
size = get_image_size(path);
if (size < 0) {
error_report("%s: failed to find romfile \"%s\"",
__FUNCTION__, pdev->romfile);
__func__, pdev->romfile);
g_free(path);
return -1;
} else if (size == 0) {
error_report("%s: ignoring empty romfile \"%s\"",
__func__, pdev->romfile);
g_free(path);
return -1;
}
@ -2171,6 +2251,7 @@ static const TypeInfo pci_device_type_info = {
static void pci_register_types(void)
{
type_register_static(&pci_bus_info);
type_register_static(&pcie_bus_info);
type_register_static(&pci_device_type_info);
}

View File

@ -109,6 +109,20 @@ typedef struct PCIIORegion {
#define PCI_ROM_SLOT 6
#define PCI_NUM_REGIONS 7
enum {
QEMU_PCI_VGA_MEM,
QEMU_PCI_VGA_IO_LO,
QEMU_PCI_VGA_IO_HI,
QEMU_PCI_VGA_NUM_REGIONS,
};
#define QEMU_PCI_VGA_MEM_BASE 0xa0000
#define QEMU_PCI_VGA_MEM_SIZE 0x20000
#define QEMU_PCI_VGA_IO_LO_BASE 0x3b0
#define QEMU_PCI_VGA_IO_LO_SIZE 0xc
#define QEMU_PCI_VGA_IO_HI_BASE 0x3c0
#define QEMU_PCI_VGA_IO_HI_SIZE 0x20
#include "hw/pci/pci_regs.h"
/* PCI HEADER_TYPE */
@ -235,6 +249,10 @@ struct PCIDevice {
/* IRQ objects for the INTA-INTD pins. */
qemu_irq *irq;
/* Legacy PCI VGA regions */
MemoryRegion *vga_regions[QEMU_PCI_VGA_NUM_REGIONS];
bool has_vga;
/* Current IRQ levels. Used internally by the generic PCI code. */
uint8_t irq_state;
@ -288,6 +306,9 @@ struct PCIDevice {
void pci_register_bar(PCIDevice *pci_dev, int region_num,
uint8_t attr, MemoryRegion *memory);
void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
MemoryRegion *io_lo, MemoryRegion *io_hi);
void pci_unregister_vga(PCIDevice *pci_dev);
pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
@ -319,15 +340,22 @@ typedef enum {
typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
PCIHotplugState state);
#define TYPE_PCI_BUS "PCI"
#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
#define TYPE_PCIE_BUS "PCIE"
bool pci_bus_is_express(PCIBus *bus);
bool pci_bus_is_root(PCIBus *bus);
void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
const char *name,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min);
uint8_t devfn_min, const char *typename);
PCIBus *pci_bus_new(DeviceState *parent, const char *name,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min);
uint8_t devfn_min, const char *typename);
void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int nirq);
int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
@ -339,7 +367,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
void *irq_opaque,
MemoryRegion *address_space_mem,
MemoryRegion *address_space_io,
uint8_t devfn_min, int nirq);
uint8_t devfn_min, int nirq, const char *typename);
void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn);
PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin);
bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new);

View File

@ -151,6 +151,28 @@ static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias,
memory_region_add_subregion_overlap(parent_space, base, alias, 1);
}
static void pci_bridge_init_vga_aliases(PCIBridge *br, PCIBus *parent,
MemoryRegion *alias_vga)
{
uint16_t brctl = pci_get_word(br->dev.config + PCI_BRIDGE_CONTROL);
memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_IO_LO],
"pci_bridge_vga_io_lo", &br->address_space_io,
QEMU_PCI_VGA_IO_LO_BASE, QEMU_PCI_VGA_IO_LO_SIZE);
memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_IO_HI],
"pci_bridge_vga_io_hi", &br->address_space_io,
QEMU_PCI_VGA_IO_HI_BASE, QEMU_PCI_VGA_IO_HI_SIZE);
memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_MEM],
"pci_bridge_vga_mem", &br->address_space_mem,
QEMU_PCI_VGA_MEM_BASE, QEMU_PCI_VGA_MEM_SIZE);
if (brctl & PCI_BRIDGE_CTL_VGA) {
pci_register_vga(&br->dev, &alias_vga[QEMU_PCI_VGA_MEM],
&alias_vga[QEMU_PCI_VGA_IO_LO],
&alias_vga[QEMU_PCI_VGA_IO_HI]);
}
}
static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br)
{
PCIBus *parent = br->dev.bus;
@ -175,7 +197,8 @@ static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br)
&br->address_space_io,
parent->address_space_io,
cmd & PCI_COMMAND_IO);
/* TODO: optinal VGA and VGA palette snooping support. */
pci_bridge_init_vga_aliases(br, parent, w->alias_vga);
return w;
}
@ -187,6 +210,7 @@ static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w)
memory_region_del_subregion(parent->address_space_io, &w->alias_io);
memory_region_del_subregion(parent->address_space_mem, &w->alias_mem);
memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem);
pci_unregister_vga(&br->dev);
}
static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w)
@ -194,6 +218,9 @@ static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w)
memory_region_destroy(&w->alias_io);
memory_region_destroy(&w->alias_mem);
memory_region_destroy(&w->alias_pref_mem);
memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_IO_LO]);
memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_IO_HI]);
memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_MEM]);
g_free(w);
}
@ -227,7 +254,10 @@ void pci_bridge_write_config(PCIDevice *d,
/* memory base/limit, prefetchable base/limit and
io base/limit upper 16 */
ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
ranges_overlap(address, len, PCI_MEMORY_BASE, 20) ||
/* vga enable */
ranges_overlap(address, len, PCI_BRIDGE_CONTROL, 2)) {
pci_bridge_update_mappings(s);
}
@ -298,7 +328,7 @@ void pci_bridge_reset(DeviceState *qdev)
}
/* default qdev initialization function for PCI-to-PCI bridge */
int pci_bridge_initfn(PCIDevice *dev)
int pci_bridge_initfn(PCIDevice *dev, const char *typename)
{
PCIBus *parent = dev->bus;
PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
@ -306,6 +336,16 @@ int pci_bridge_initfn(PCIDevice *dev)
pci_word_test_and_set_mask(dev->config + PCI_STATUS,
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
/*
* TODO: We implement VGA Enable in the Bridge Control Register
* therefore per the PCI to PCI bridge spec we must also implement
* VGA Palette Snooping. When done, set this bit writable:
*
* pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND,
* PCI_COMMAND_VGA_PALETTE);
*/
pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
dev->config[PCI_HEADER_TYPE] =
(dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
@ -323,10 +363,9 @@ int pci_bridge_initfn(PCIDevice *dev)
br->bus_name = dev->qdev.id;
}
qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev,
br->bus_name);
qbus_create_inplace(&sec_bus->qbus, typename, &dev->qdev, br->bus_name);
sec_bus->parent_dev = dev;
sec_bus->map_irq = br->map_irq;
sec_bus->map_irq = br->map_irq ? br->map_irq : pci_swizzle_map_irq_fn;
sec_bus->address_space_mem = &br->address_space_mem;
memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX);
sec_bus->address_space_io = &br->address_space_io;

View File

@ -43,7 +43,7 @@ void pci_bridge_disable_base_limit(PCIDevice *dev);
void pci_bridge_reset_reg(PCIDevice *dev);
void pci_bridge_reset(DeviceState *qdev);
int pci_bridge_initfn(PCIDevice *pci_dev);
int pci_bridge_initfn(PCIDevice *pci_dev, const char *typename);
void pci_bridge_exitfn(PCIDevice *pci_dev);
@ -55,12 +55,11 @@ void pci_bridge_exitfn(PCIDevice *pci_dev);
void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
pci_map_irq_fn map_irq);
/* TODO: add this define to pci_regs.h in linux and then in qemu. */
#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */
#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */
#define PCI_BRIDGE_CTL_SEC_DISCARD 0x200 /* Secondary discard timer */
#define PCI_BRIDGE_CTL_DISCARD_STATUS 0x400 /* Discard timer status */
#define PCI_BRIDGE_CTL_DISCARD_SERR 0x800 /* Discard timer SERR# enable */
#endif /* QEMU_PCI_BRIDGE_H */
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 8
* indent-tab-mode: nil
* End:
*/

View File

@ -8,9 +8,6 @@
* use accessor functions in pci.h, pci_bridge.h
*/
#define TYPE_PCI_BUS "PCI"
#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
struct PCIBus {
BusState qbus;
PCIDMAContextFunc dma_context_fn;
@ -47,6 +44,13 @@ struct PCIBridgeWindows {
MemoryRegion alias_pref_mem;
MemoryRegion alias_mem;
MemoryRegion alias_io;
/*
* When bridge control VGA forwarding is enabled, bridges will
* provide positive decode on the PCI VGA defined I/O port and
* MMIO ranges. When enabled forwarding is only qualified on the
* I/O and memory enable bits in the bridge command register.
*/
MemoryRegion alias_vga[QEMU_PCI_VGA_NUM_REGIONS];
};
struct PCIBridge {

View File

@ -87,6 +87,22 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
return pos;
}
int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset)
{
uint8_t type = PCI_EXP_TYPE_ENDPOINT;
/*
* Windows guests will report Code 10, device cannot start, if
* a regular Endpoint type is exposed on a root complex. These
* should instead be Root Complex Integrated Endpoints.
*/
if (pci_bus_is_express(dev->bus) && pci_bus_is_root(dev->bus)) {
type = PCI_EXP_TYPE_RC_END;
}
return pcie_cap_init(dev, offset, type, 0);
}
void pcie_cap_exit(PCIDevice *dev)
{
pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF);

View File

@ -95,6 +95,7 @@ struct PCIExpressDevice {
/* PCI express capability helper functions */
int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port);
int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset);
void pcie_cap_exit(PCIDevice *dev);
uint8_t pcie_cap_get_type(const PCIDevice *dev);
void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);

View File

@ -27,13 +27,17 @@ void pcie_port_init_reg(PCIDevice *d)
pci_set_word(d->config + PCI_STATUS, 0);
pci_set_word(d->config + PCI_SEC_STATUS, 0);
/* Unlike conventional pci bridge, some bits are hardwired to 0. */
pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
PCI_BRIDGE_CTL_PARITY |
PCI_BRIDGE_CTL_ISA |
PCI_BRIDGE_CTL_VGA |
PCI_BRIDGE_CTL_SERR |
PCI_BRIDGE_CTL_BUS_RESET);
/*
* Unlike conventional pci bridge, for some bits the spec states:
* Does not apply to PCI Express and must be hardwired to 0.
*/
pci_word_test_and_clear_mask(d->wmask + PCI_BRIDGE_CONTROL,
PCI_BRIDGE_CTL_MASTER_ABORT |
PCI_BRIDGE_CTL_FAST_BACK |
PCI_BRIDGE_CTL_DISCARD |
PCI_BRIDGE_CTL_SEC_DISCARD |
PCI_BRIDGE_CTL_DISCARD_STATUS |
PCI_BRIDGE_CTL_DISCARD_SERR);
}
/**************************************************************************

View File

@ -36,22 +36,13 @@ struct PCIBridgeDev {
};
typedef struct PCIBridgeDev PCIBridgeDev;
/* Mapping mandated by PCI-to-PCI Bridge architecture specification,
* revision 1.2 */
/* Table 9-1: Interrupt Binding for Devices Behind a Bridge */
static int pci_bridge_dev_map_irq_fn(PCIDevice *dev, int irq_num)
{
return (irq_num + PCI_SLOT(dev->devfn)) % PCI_NUM_PINS;
}
static int pci_bridge_dev_initfn(PCIDevice *dev)
{
PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
int err;
pci_bridge_map_irq(br, NULL, pci_bridge_dev_map_irq_fn);
err = pci_bridge_initfn(dev);
err = pci_bridge_initfn(dev, TYPE_PCI_BUS);
if (err) {
goto bridge_error;
}

View File

@ -245,7 +245,7 @@ static PCIBus *i440fx_common_init(const char *device_name,
dev = qdev_create(NULL, "i440FX-pcihost");
s = PCI_HOST_BRIDGE(dev);
b = pci_bus_new(dev, NULL, pci_address_space,
address_space_io, 0);
address_space_io, 0, TYPE_PCI_BUS);
s->bus = b;
object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
qdev_init_nofail(dev);

View File

@ -349,7 +349,7 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
b = pci_register_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq,
ppc4xx_pci_map_irq, s->irq, get_system_memory(),
get_system_io(), 0, 4);
get_system_io(), 0, 4, TYPE_PCI_BUS);
h->bus = b;
pci_create_simple(b, 0, "ppc4xx-host-bridge");

View File

@ -356,7 +356,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
mpc85xx_pci_map_irq, s->irq, address_space_mem,
&s->pio, PCI_DEVFN(s->first_slot, 0), 4);
&s->pio, PCI_DEVFN(s->first_slot, 0), 4, TYPE_PCI_BUS);
h->bus = b;
pci_create_simple(b, 0, "e500-host-bridge");

View File

@ -154,7 +154,7 @@ static void raven_pcihost_initfn(Object *obj)
DeviceState *pci_dev;
pci_bus_new_inplace(&s->pci_bus, DEVICE(obj), NULL,
address_space_mem, address_space_io, 0);
address_space_mem, address_space_io, 0, TYPE_PCI_BUS);
h->bus = &s->pci_bus;
object_initialize(&s->pci_dev, TYPE_RAVEN_PCI_DEVICE);

View File

@ -54,7 +54,8 @@ static int q35_host_init(SysBusDevice *dev)
return -1;
}
b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0",
s->mch.pci_address_space, s->mch.address_space_io, 0);
s->mch.pci_address_space, s->mch.address_space_io,
0, TYPE_PCIE_BUS);
s->host.pci.bus = b;
qdev_set_parent_bus(DEVICE(&s->mch), BUS(b));
qdev_init_nofail(DEVICE(&s->mch));

View File

@ -30,6 +30,8 @@
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "qapi/visitor.h"
#include "qapi/qmp/qjson.h"
#include "monitor/monitor.h"
int qdev_hotplug = 0;
static bool qdev_hot_added = false;
@ -764,6 +766,8 @@ static void device_unparent(Object *obj)
DeviceState *dev = DEVICE(obj);
DeviceClass *dc = DEVICE_GET_CLASS(dev);
BusState *bus;
QObject *event_data;
gchar *path = object_get_canonical_path(obj);
while (dev->num_child_bus) {
bus = QLIST_FIRST(&dev->child_bus);
@ -782,6 +786,16 @@ static void device_unparent(Object *obj)
object_unref(OBJECT(dev->parent_bus));
dev->parent_bus = NULL;
}
if (dev->id) {
event_data = qobject_from_jsonf("{ 'device': %s, 'path': %s }",
dev->id, path);
} else {
event_data = qobject_from_jsonf("{ 'path': %s }", path);
}
monitor_protocol_event(QEVENT_DEVICE_DELETED, event_data);
qobject_decref(event_data);
g_free(path);
}
static void device_class_init(ObjectClass *class, void *data)

View File

@ -124,7 +124,7 @@ static int sh_pci_device_init(SysBusDevice *dev)
s->irq,
get_system_memory(),
get_system_io(),
PCI_DEVFN(0, 0), 4);
PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
memory_region_init_io(&s->memconfig_p4, &sh_pci_reg_ops, s,
"sh_pci", 0x224);
memory_region_init_alias(&s->memconfig_a7, "sh_pci.2", &s->memconfig_p4,

View File

@ -641,7 +641,7 @@ static int spapr_phb_init(SysBusDevice *s)
bus = pci_register_bus(DEVICE(s), busname,
pci_spapr_set_irq, pci_spapr_map_irq, sphb,
&sphb->memspace, &sphb->iospace,
PCI_DEVFN(0, 0), PCI_NUM_PINS);
PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
phb->bus = bus;
sphb->dma_window_start = 0;

View File

@ -239,7 +239,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
pic,
&d->pci_mmio,
address_space_io,
PCI_DEVFN(11, 0), 4);
PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
#if 0
pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north");
@ -305,7 +305,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
pic,
&d->pci_mmio,
address_space_io,
PCI_DEVFN(11, 0), 4);
PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
sysbus_mmio_map(s, 0, 0xf0800000);
sysbus_mmio_map(s, 1, 0xf0c00000);

View File

@ -3332,7 +3332,7 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
&xhci->mem);
ret = pcie_cap_init(&xhci->pci_dev, 0xa0, PCI_EXP_TYPE_ENDPOINT, 0);
ret = pcie_endpoint_cap_init(&xhci->pci_dev, 0xa0);
assert(ret >= 0);
if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) {

View File

@ -70,7 +70,7 @@ static int pci_vpb_init(SysBusDevice *dev)
bus = pci_register_bus(&dev->qdev, "pci",
pci_vpb_set_irq, pci_vpb_map_irq, s->irq,
get_system_memory(), get_system_io(),
PCI_DEVFN(11, 0), 4);
PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
/* ??? Register memory space. */

View File

@ -528,13 +528,14 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
}
static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
VirtQueueElement *elem)
struct iovec *iov, unsigned int iov_cnt)
{
struct virtio_net_ctrl_mq s;
struct virtio_net_ctrl_mq mq;
size_t s;
uint16_t queues;
if (elem->out_num != 2 ||
elem->out_sg[1].iov_len != sizeof(struct virtio_net_ctrl_mq)) {
error_report("virtio-net ctrl invalid steering command");
s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq));
if (s != sizeof(mq)) {
return VIRTIO_NET_ERR;
}
@ -542,16 +543,16 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
return VIRTIO_NET_ERR;
}
memcpy(&s, elem->out_sg[1].iov_base, sizeof(struct virtio_net_ctrl_mq));
queues = lduw_p(&mq.virtqueue_pairs);
if (s.virtqueue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
s.virtqueue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
s.virtqueue_pairs > n->max_queues ||
if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
queues > n->max_queues ||
!n->multiqueue) {
return VIRTIO_NET_ERR;
}
n->curr_queues = s.virtqueue_pairs;
n->curr_queues = queues;
/* stop the backend before changing the number of queues to avoid handling a
* disabled queue */
virtio_net_set_status(&n->vdev, n->vdev.status);
@ -589,7 +590,7 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
} else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) {
status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt);
} else if (ctrl.class == VIRTIO_NET_CTRL_MQ) {
status = virtio_net_handle_mq(n, ctrl.cmd, &elem);
status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt);
}
s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status));

View File

@ -609,20 +609,23 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
}
}
static int kvm_virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
unsigned int queue_no,
unsigned int vector,
MSIMessage msg)
static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
unsigned int queue_no,
unsigned int vector,
MSIMessage msg)
{
VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
EventNotifier *n = virtio_queue_get_guest_notifier(vq);
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
VirtIOIRQFD *irqfd;
int ret = 0;
if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
if (ret < 0) {
return ret;
if (proxy->vector_irqfd) {
irqfd = &proxy->vector_irqfd[vector];
if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
if (ret < 0) {
return ret;
}
}
}
@ -642,7 +645,7 @@ static int kvm_virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
return ret;
}
static void kvm_virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
unsigned int queue_no,
unsigned int vector)
{
@ -656,8 +659,8 @@ static void kvm_virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
}
}
static int kvm_virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
MSIMessage msg)
static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
MSIMessage msg)
{
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = proxy->vdev;
@ -670,7 +673,7 @@ static int kvm_virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
if (virtio_queue_vector(vdev, queue_no) != vector) {
continue;
}
ret = kvm_virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
ret = virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
if (ret < 0) {
goto undo;
}
@ -682,12 +685,12 @@ undo:
if (virtio_queue_vector(vdev, queue_no) != vector) {
continue;
}
kvm_virtio_pci_vq_vector_mask(proxy, queue_no, vector);
virtio_pci_vq_vector_mask(proxy, queue_no, vector);
}
return ret;
}
static void kvm_virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
{
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = proxy->vdev;
@ -700,13 +703,13 @@ static void kvm_virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
if (virtio_queue_vector(vdev, queue_no) != vector) {
continue;
}
kvm_virtio_pci_vq_vector_mask(proxy, queue_no, vector);
virtio_pci_vq_vector_mask(proxy, queue_no, vector);
}
}
static void kvm_virtio_pci_vector_poll(PCIDevice *dev,
unsigned int vector_start,
unsigned int vector_end)
static void virtio_pci_vector_poll(PCIDevice *dev,
unsigned int vector_start,
unsigned int vector_end)
{
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = proxy->vdev;
@ -781,11 +784,13 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
proxy->nvqs_with_notifiers = nvqs;
/* Must unset vector notifier while guest notifier is still assigned */
if (proxy->vector_irqfd && !assign) {
if ((proxy->vector_irqfd || vdev->guest_notifier_mask) && !assign) {
msix_unset_vector_notifiers(&proxy->pci_dev);
kvm_virtio_pci_vector_release(proxy, nvqs);
g_free(proxy->vector_irqfd);
proxy->vector_irqfd = NULL;
if (proxy->vector_irqfd) {
kvm_virtio_pci_vector_release(proxy, nvqs);
g_free(proxy->vector_irqfd);
proxy->vector_irqfd = NULL;
}
}
for (n = 0; n < nvqs; n++) {
@ -801,18 +806,20 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
}
/* Must set vector notifier after guest notifier has been assigned */
if (with_irqfd && assign) {
proxy->vector_irqfd =
g_malloc0(sizeof(*proxy->vector_irqfd) *
msix_nr_vectors_allocated(&proxy->pci_dev));
r = kvm_virtio_pci_vector_use(proxy, nvqs);
if (r < 0) {
goto assign_error;
if ((with_irqfd || vdev->guest_notifier_mask) && assign) {
if (with_irqfd) {
proxy->vector_irqfd =
g_malloc0(sizeof(*proxy->vector_irqfd) *
msix_nr_vectors_allocated(&proxy->pci_dev));
r = kvm_virtio_pci_vector_use(proxy, nvqs);
if (r < 0) {
goto assign_error;
}
}
r = msix_set_vector_notifiers(&proxy->pci_dev,
kvm_virtio_pci_vector_unmask,
kvm_virtio_pci_vector_mask,
kvm_virtio_pci_vector_poll);
virtio_pci_vector_unmask,
virtio_pci_vector_mask,
virtio_pci_vector_poll);
if (r < 0) {
goto notifiers_error;
}
@ -821,8 +828,10 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
return 0;
notifiers_error:
assert(assign);
kvm_virtio_pci_vector_release(proxy, nvqs);
if (with_irqfd) {
assert(assign);
kvm_virtio_pci_vector_release(proxy, nvqs);
}
assign_error:
/* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */

View File

@ -61,7 +61,7 @@ static int xio3130_downstream_initfn(PCIDevice *d)
PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
int rc;
rc = pci_bridge_initfn(d);
rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
if (rc < 0) {
return rc;
}

View File

@ -57,7 +57,7 @@ static int xio3130_upstream_initfn(PCIDevice *d)
PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
int rc;
rc = pci_bridge_initfn(d);
rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
if (rc < 0) {
return rc;
}

View File

@ -39,6 +39,7 @@ typedef enum MonitorEvent {
QEVENT_BLOCK_JOB_CANCELLED,
QEVENT_BLOCK_JOB_ERROR,
QEVENT_BLOCK_JOB_READY,
QEVENT_DEVICE_DELETED,
QEVENT_DEVICE_TRAY_MOVED,
QEVENT_SUSPEND,
QEVENT_SUSPEND_DISK,

View File

@ -477,6 +477,7 @@ static const char *monitor_event_names[] = {
[QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED",
[QEVENT_BLOCK_JOB_ERROR] = "BLOCK_JOB_ERROR",
[QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY",
[QEVENT_DEVICE_DELETED] = "DEVICE_DELETED",
[QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
[QEVENT_SUSPEND] = "SUSPEND",
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",

View File

@ -2367,7 +2367,9 @@
# Notes: When this command completes, the device may not be removed from the
# guest. Hot removal is an operation that requires guest cooperation.
# This command merely requests that the guest begin the hot removal
# process.
# process. Completion of the device removal process is signaled with a
# DEVICE_DELETED event. Guest reset will automatically complete removal
# for all devices.
#
# Since: 0.14.0
##

View File

@ -363,12 +363,12 @@ static void object_property_del_child(Object *obj, Object *child, Error **errp)
void object_unparent(Object *obj)
{
object_ref(obj);
if (obj->parent) {
object_property_del_child(obj->parent, obj, NULL);
}
if (obj->class->unparent) {
(obj->class->unparent)(obj);
}
if (obj->parent) {
object_property_del_child(obj->parent, obj, NULL);
}
object_unref(obj);
}

View File

@ -2,4 +2,4 @@
config="$1"
make -C seabios clean distclean
cp "$config" seabios/.config
make -C seabios oldnoconfig
make -C seabios olddefconfig