提交 404e7a4f 编写于 作者: A Anthony Liguori

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: NMichael 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
  ...
...@@ -136,6 +136,24 @@ Example: ...@@ -136,6 +136,24 @@ Example:
Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
event. 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 DEVICE_TRAY_MOVED
----------------- -----------------
......
...@@ -925,6 +925,8 @@ static ram_addr_t find_ram_offset(ram_addr_t size) ...@@ -925,6 +925,8 @@ static ram_addr_t find_ram_offset(ram_addr_t size)
RAMBlock *block, *next_block; RAMBlock *block, *next_block;
ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX; 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)) if (QTAILQ_EMPTY(&ram_list.blocks))
return 0; return 0;
......
...@@ -775,7 +775,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, ...@@ -775,7 +775,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
b = pci_register_bus(dev, "pci", b = pci_register_bus(dev, "pci",
typhoon_set_irq, sys_map_irq, s, 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; phb->bus = b;
/* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */ /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB. */
......
...@@ -329,7 +329,7 @@ static int apb_pci_bridge_initfn(PCIDevice *dev) ...@@ -329,7 +329,7 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
{ {
int rc; int rc;
rc = pci_bridge_initfn(dev); rc = pci_bridge_initfn(dev, TYPE_PCI_BUS);
if (rc < 0) { if (rc < 0) {
return rc; return rc;
} }
...@@ -381,7 +381,7 @@ PCIBus *pci_apb_init(hwaddr special_base, ...@@ -381,7 +381,7 @@ PCIBus *pci_apb_init(hwaddr special_base,
pci_apb_set_irq, pci_pbm_map_irq, d, pci_apb_set_irq, pci_pbm_map_irq, d,
&d->pci_mmio, &d->pci_mmio,
get_system_io(), get_system_io(),
0, 32); 0, 32, TYPE_PCI_BUS);
*pbm_irqs = d->pbm_irqs; *pbm_irqs = d->pbm_irqs;
d->ivec_irqs = ivec_irqs; d->ivec_irqs = ivec_irqs;
......
...@@ -707,7 +707,7 @@ static int bonito_pcihost_initfn(SysBusDevice *dev) ...@@ -707,7 +707,7 @@ static int bonito_pcihost_initfn(SysBusDevice *dev)
phb->bus = pci_register_bus(DEVICE(dev), "pci", phb->bus = pci_register_bus(DEVICE(dev), "pci",
pci_bonito_set_irq, pci_bonito_map_irq, dev, pci_bonito_set_irq, pci_bonito_map_irq, dev,
get_system_memory(), get_system_io(), get_system_memory(), get_system_io(),
0x28, 32); 0x28, 32, TYPE_PCI_BUS);
return 0; return 0;
} }
......
...@@ -51,12 +51,17 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num) ...@@ -51,12 +51,17 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
return 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) static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_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->exit = pci_bridge_exitfn;
k->vendor_id = PCI_VENDOR_ID_DEC; k->vendor_id = PCI_VENDOR_ID_DEC;
k->device_id = PCI_DEVICE_ID_DEC_21154; k->device_id = PCI_DEVICE_ID_DEC_21154;
......
...@@ -88,7 +88,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, ...@@ -88,7 +88,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
pic, pic,
&d->pci_mmio, &d->pci_mmio,
address_space_io, address_space_io,
0, 4); 0, 4, TYPE_PCI_BUS);
pci_create_simple(phb->bus, 0, "grackle"); pci_create_simple(phb->bus, 0, "grackle");
......
...@@ -1107,7 +1107,7 @@ PCIBus *gt64120_register(qemu_irq *pic) ...@@ -1107,7 +1107,7 @@ PCIBus *gt64120_register(qemu_irq *pic)
pic, pic,
get_system_memory(), get_system_memory(),
get_system_io(), 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); 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"); pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci");
......
...@@ -59,7 +59,7 @@ static int i82801b11_bridge_initfn(PCIDevice *d) ...@@ -59,7 +59,7 @@ static int i82801b11_bridge_initfn(PCIDevice *d)
{ {
int rc; int rc;
rc = pci_bridge_initfn(d); rc = pci_bridge_initfn(d, TYPE_PCI_BUS);
if (rc < 0) { if (rc < 0) {
return rc; return rc;
} }
......
...@@ -97,7 +97,7 @@ static int ioh3420_initfn(PCIDevice *d) ...@@ -97,7 +97,7 @@ static int ioh3420_initfn(PCIDevice *d)
PCIESlot *s = DO_UPCAST(PCIESlot, port, p); PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
int rc; int rc;
rc = pci_bridge_initfn(d); rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
if (rc < 0) { if (rc < 0) {
return rc; return rc;
} }
......
...@@ -75,6 +75,11 @@ static const TypeInfo pci_bus_info = { ...@@ -75,6 +75,11 @@ static const TypeInfo pci_bus_info = {
.class_init = pci_bus_class_init, .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 PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
static void pci_update_mappings(PCIDevice *d); static void pci_update_mappings(PCIDevice *d);
static void pci_set_irq(void *opaque, int irq_num, int level); 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, ...@@ -292,13 +297,23 @@ static void pci_bus_init(PCIBus *bus, DeviceState *parent,
vmstate_register(NULL, -1, &vmstate_pcibus, bus); 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, void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
const char *name, const char *name,
MemoryRegion *address_space_mem, MemoryRegion *address_space_mem,
MemoryRegion *address_space_io, 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, pci_bus_init(bus, parent, name, address_space_mem,
address_space_io, devfn_min); address_space_io, devfn_min);
} }
...@@ -306,11 +321,11 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, ...@@ -306,11 +321,11 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
PCIBus *pci_bus_new(DeviceState *parent, const char *name, PCIBus *pci_bus_new(DeviceState *parent, const char *name,
MemoryRegion *address_space_mem, MemoryRegion *address_space_mem,
MemoryRegion *address_space_io, MemoryRegion *address_space_io,
uint8_t devfn_min) uint8_t devfn_min, const char *typename)
{ {
PCIBus *bus; 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, pci_bus_init(bus, parent, name, address_space_mem,
address_space_io, devfn_min); address_space_io, devfn_min);
return bus; return bus;
...@@ -338,19 +353,19 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, ...@@ -338,19 +353,19 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
void *irq_opaque, void *irq_opaque,
MemoryRegion *address_space_mem, MemoryRegion *address_space_mem,
MemoryRegion *address_space_io, MemoryRegion *address_space_io,
uint8_t devfn_min, int nirq) uint8_t devfn_min, int nirq, const char *typename)
{ {
PCIBus *bus; PCIBus *bus;
bus = pci_bus_new(parent, name, address_space_mem, 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); pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);
return bus; return bus;
} }
int pci_bus_num(PCIBus *s) int pci_bus_num(PCIBus *s)
{ {
if (!s->parent_dev) if (pci_bus_is_root(s))
return 0; /* pci host bridge */ return 0; /* pci host bridge */
return s->parent_dev->config[PCI_SECONDARY_BUS]; return s->parent_dev->config[PCI_SECONDARY_BUS];
} }
...@@ -668,12 +683,10 @@ static void pci_init_mask_bridge(PCIDevice *d) ...@@ -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_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
PCI_PREF_RANGE_TYPE_64); 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 */ * TODO: Bridges default to 10-bit VGA decoding but we currently only
#define PCI_BRIDGE_CTL_DISCARD 0x100 /* Primary discard timer */ * implement 16-bit decoding (no alias support).
#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 */
pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_PARITY |
PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_SERR |
...@@ -875,6 +888,8 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev) ...@@ -875,6 +888,8 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
continue; continue;
memory_region_del_subregion(r->address_space, r->memory); memory_region_del_subregion(r->address_space, r->memory);
} }
pci_unregister_vga(pci_dev);
} }
static int pci_unregister_device(DeviceState *dev) static int pci_unregister_device(DeviceState *dev)
...@@ -937,6 +952,63 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, ...@@ -937,6 +952,63 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
: pci_dev->bus->address_space_mem; : 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) pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
{ {
return pci_dev->io_regions[region_num].addr; return pci_dev->io_regions[region_num].addr;
...@@ -1036,6 +1108,8 @@ static void pci_update_mappings(PCIDevice *d) ...@@ -1036,6 +1108,8 @@ static void pci_update_mappings(PCIDevice *d)
r->addr, r->memory, 1); r->addr, r->memory, 1);
} }
} }
pci_update_vga(d);
} }
static inline int pci_irq_disabled(PCIDevice *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) ...@@ -1117,7 +1191,7 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
/* Special hooks used by device assignment */ /* Special hooks used by device assignment */
void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq) 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; bus->route_intx_to_irq = route_intx_to_irq;
} }
...@@ -1156,9 +1230,10 @@ void pci_bus_fire_intx_routing_notifier(PCIBus *bus) ...@@ -1156,9 +1230,10 @@ void pci_bus_fire_intx_routing_notifier(PCIBus *bus)
if (dev && dev->intx_routing_notifier) { if (dev && dev->intx_routing_notifier) {
dev->intx_routing_notifier(dev); 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) ...@@ -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. */ /* 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)) { !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) {
return NULL; return NULL;
} }
...@@ -1589,7 +1664,7 @@ static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num) ...@@ -1589,7 +1664,7 @@ static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
/* try child bus */ /* try child bus */
for (; bus; bus = sec) { for (; bus; bus = sec) {
QLIST_FOREACH(sec, &bus->child, sibling) { 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) { if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {
return sec; return sec;
} }
...@@ -1852,7 +1927,12 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) ...@@ -1852,7 +1927,12 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
size = get_image_size(path); size = get_image_size(path);
if (size < 0) { if (size < 0) {
error_report("%s: failed to find romfile \"%s\"", 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); g_free(path);
return -1; return -1;
} }
...@@ -2171,6 +2251,7 @@ static const TypeInfo pci_device_type_info = { ...@@ -2171,6 +2251,7 @@ static const TypeInfo pci_device_type_info = {
static void pci_register_types(void) static void pci_register_types(void)
{ {
type_register_static(&pci_bus_info); type_register_static(&pci_bus_info);
type_register_static(&pcie_bus_info);
type_register_static(&pci_device_type_info); type_register_static(&pci_device_type_info);
} }
......
...@@ -109,6 +109,20 @@ typedef struct PCIIORegion { ...@@ -109,6 +109,20 @@ typedef struct PCIIORegion {
#define PCI_ROM_SLOT 6 #define PCI_ROM_SLOT 6
#define PCI_NUM_REGIONS 7 #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" #include "hw/pci/pci_regs.h"
/* PCI HEADER_TYPE */ /* PCI HEADER_TYPE */
...@@ -235,6 +249,10 @@ struct PCIDevice { ...@@ -235,6 +249,10 @@ struct PCIDevice {
/* IRQ objects for the INTA-INTD pins. */ /* IRQ objects for the INTA-INTD pins. */
qemu_irq *irq; 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. */ /* Current IRQ levels. Used internally by the generic PCI code. */
uint8_t irq_state; uint8_t irq_state;
...@@ -288,6 +306,9 @@ struct PCIDevice { ...@@ -288,6 +306,9 @@ struct PCIDevice {
void pci_register_bar(PCIDevice *pci_dev, int region_num, void pci_register_bar(PCIDevice *pci_dev, int region_num,
uint8_t attr, MemoryRegion *memory); 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); pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
...@@ -319,15 +340,22 @@ typedef enum { ...@@ -319,15 +340,22 @@ typedef enum {
typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
PCIHotplugState state); 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, void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
const char *name, const char *name,
MemoryRegion *address_space_mem, MemoryRegion *address_space_mem,
MemoryRegion *address_space_io, MemoryRegion *address_space_io,
uint8_t devfn_min); uint8_t devfn_min, const char *typename);
PCIBus *pci_bus_new(DeviceState *parent, const char *name, PCIBus *pci_bus_new(DeviceState *parent, const char *name,
MemoryRegion *address_space_mem, MemoryRegion *address_space_mem,
MemoryRegion *address_space_io, 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 pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int nirq); void *irq_opaque, int nirq);
int pci_bus_get_irq_level(PCIBus *bus, int irq_num); int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
...@@ -339,7 +367,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, ...@@ -339,7 +367,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
void *irq_opaque, void *irq_opaque,
MemoryRegion *address_space_mem, MemoryRegion *address_space_mem,
MemoryRegion *address_space_io, 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); void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn);
PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin); PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin);
bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new); bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new);
......
...@@ -151,6 +151,28 @@ static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias, ...@@ -151,6 +151,28 @@ static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias,
memory_region_add_subregion_overlap(parent_space, base, alias, 1); 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) static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br)
{ {
PCIBus *parent = br->dev.bus; PCIBus *parent = br->dev.bus;
...@@ -175,7 +197,8 @@ static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br) ...@@ -175,7 +197,8 @@ static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br)
&br->address_space_io, &br->address_space_io,
parent->address_space_io, parent->address_space_io,
cmd & PCI_COMMAND_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; return w;
} }
...@@ -187,6 +210,7 @@ static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *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_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_mem);
memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_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) static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w)
...@@ -194,6 +218,9 @@ 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_io);
memory_region_destroy(&w->alias_mem); memory_region_destroy(&w->alias_mem);
memory_region_destroy(&w->alias_pref_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); g_free(w);
} }
...@@ -227,7 +254,10 @@ void pci_bridge_write_config(PCIDevice *d, ...@@ -227,7 +254,10 @@ void pci_bridge_write_config(PCIDevice *d,
/* memory base/limit, prefetchable base/limit and /* memory base/limit, prefetchable base/limit and
io base/limit upper 16 */ 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); pci_bridge_update_mappings(s);
} }
...@@ -298,7 +328,7 @@ void pci_bridge_reset(DeviceState *qdev) ...@@ -298,7 +328,7 @@ void pci_bridge_reset(DeviceState *qdev)
} }
/* default qdev initialization function for PCI-to-PCI bridge */ /* 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; PCIBus *parent = dev->bus;
PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
...@@ -306,6 +336,16 @@ int pci_bridge_initfn(PCIDevice *dev) ...@@ -306,6 +336,16 @@ int pci_bridge_initfn(PCIDevice *dev)
pci_word_test_and_set_mask(dev->config + PCI_STATUS, pci_word_test_and_set_mask(dev->config + PCI_STATUS,
PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); 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); pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
dev->config[PCI_HEADER_TYPE] = dev->config[PCI_HEADER_TYPE] =
(dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) | (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
...@@ -323,10 +363,9 @@ int pci_bridge_initfn(PCIDevice *dev) ...@@ -323,10 +363,9 @@ int pci_bridge_initfn(PCIDevice *dev)
br->bus_name = dev->qdev.id; br->bus_name = dev->qdev.id;
} }
qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev, qbus_create_inplace(&sec_bus->qbus, typename, &dev->qdev, br->bus_name);
br->bus_name);
sec_bus->parent_dev = dev; 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; sec_bus->address_space_mem = &br->address_space_mem;
memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX); memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX);
sec_bus->address_space_io = &br->address_space_io; sec_bus->address_space_io = &br->address_space_io;
......
...@@ -43,7 +43,7 @@ void pci_bridge_disable_base_limit(PCIDevice *dev); ...@@ -43,7 +43,7 @@ void pci_bridge_disable_base_limit(PCIDevice *dev);
void pci_bridge_reset_reg(PCIDevice *dev); void pci_bridge_reset_reg(PCIDevice *dev);
void pci_bridge_reset(DeviceState *qdev); 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); void pci_bridge_exitfn(PCIDevice *pci_dev);
...@@ -55,12 +55,11 @@ 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, void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
pci_map_irq_fn map_irq); 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 */ #endif /* QEMU_PCI_BRIDGE_H */
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 8
* indent-tab-mode: nil
* End:
*/
...@@ -8,9 +8,6 @@ ...@@ -8,9 +8,6 @@
* use accessor functions in pci.h, pci_bridge.h * 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 { struct PCIBus {
BusState qbus; BusState qbus;
PCIDMAContextFunc dma_context_fn; PCIDMAContextFunc dma_context_fn;
...@@ -47,6 +44,13 @@ struct PCIBridgeWindows { ...@@ -47,6 +44,13 @@ struct PCIBridgeWindows {
MemoryRegion alias_pref_mem; MemoryRegion alias_pref_mem;
MemoryRegion alias_mem; MemoryRegion alias_mem;
MemoryRegion alias_io; 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 { struct PCIBridge {
......
...@@ -87,6 +87,22 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) ...@@ -87,6 +87,22 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
return pos; 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) void pcie_cap_exit(PCIDevice *dev)
{ {
pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF); pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF);
......
...@@ -95,6 +95,7 @@ struct PCIExpressDevice { ...@@ -95,6 +95,7 @@ struct PCIExpressDevice {
/* PCI express capability helper functions */ /* PCI express capability helper functions */
int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port); 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); void pcie_cap_exit(PCIDevice *dev);
uint8_t pcie_cap_get_type(const PCIDevice *dev); uint8_t pcie_cap_get_type(const PCIDevice *dev);
void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector); void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
......
...@@ -27,13 +27,17 @@ void pcie_port_init_reg(PCIDevice *d) ...@@ -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_STATUS, 0);
pci_set_word(d->config + PCI_SEC_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, * Unlike conventional pci bridge, for some bits the spec states:
PCI_BRIDGE_CTL_PARITY | * Does not apply to PCI Express and must be hardwired to 0.
PCI_BRIDGE_CTL_ISA | */
PCI_BRIDGE_CTL_VGA | pci_word_test_and_clear_mask(d->wmask + PCI_BRIDGE_CONTROL,
PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_MASTER_ABORT |
PCI_BRIDGE_CTL_BUS_RESET); PCI_BRIDGE_CTL_FAST_BACK |
PCI_BRIDGE_CTL_DISCARD |
PCI_BRIDGE_CTL_SEC_DISCARD |
PCI_BRIDGE_CTL_DISCARD_STATUS |
PCI_BRIDGE_CTL_DISCARD_SERR);
} }
/************************************************************************** /**************************************************************************
......
...@@ -36,22 +36,13 @@ struct PCIBridgeDev { ...@@ -36,22 +36,13 @@ struct PCIBridgeDev {
}; };
typedef struct PCIBridgeDev 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) static int pci_bridge_dev_initfn(PCIDevice *dev)
{ {
PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev); PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br); PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
int err; int err;
pci_bridge_map_irq(br, NULL, pci_bridge_dev_map_irq_fn); err = pci_bridge_initfn(dev, TYPE_PCI_BUS);
err = pci_bridge_initfn(dev);
if (err) { if (err) {
goto bridge_error; goto bridge_error;
} }
......
...@@ -245,7 +245,7 @@ static PCIBus *i440fx_common_init(const char *device_name, ...@@ -245,7 +245,7 @@ static PCIBus *i440fx_common_init(const char *device_name,
dev = qdev_create(NULL, "i440FX-pcihost"); dev = qdev_create(NULL, "i440FX-pcihost");
s = PCI_HOST_BRIDGE(dev); s = PCI_HOST_BRIDGE(dev);
b = pci_bus_new(dev, NULL, pci_address_space, b = pci_bus_new(dev, NULL, pci_address_space,
address_space_io, 0); address_space_io, 0, TYPE_PCI_BUS);
s->bus = b; s->bus = b;
object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL); object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
qdev_init_nofail(dev); qdev_init_nofail(dev);
......
...@@ -349,7 +349,7 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev) ...@@ -349,7 +349,7 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
b = pci_register_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq, b = pci_register_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq,
ppc4xx_pci_map_irq, s->irq, get_system_memory(), 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; h->bus = b;
pci_create_simple(b, 0, "ppc4xx-host-bridge"); pci_create_simple(b, 0, "ppc4xx-host-bridge");
......
...@@ -356,7 +356,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev) ...@@ -356,7 +356,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq, b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
mpc85xx_pci_map_irq, s->irq, address_space_mem, 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; h->bus = b;
pci_create_simple(b, 0, "e500-host-bridge"); pci_create_simple(b, 0, "e500-host-bridge");
......
...@@ -154,7 +154,7 @@ static void raven_pcihost_initfn(Object *obj) ...@@ -154,7 +154,7 @@ static void raven_pcihost_initfn(Object *obj)
DeviceState *pci_dev; DeviceState *pci_dev;
pci_bus_new_inplace(&s->pci_bus, DEVICE(obj), NULL, 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; h->bus = &s->pci_bus;
object_initialize(&s->pci_dev, TYPE_RAVEN_PCI_DEVICE); object_initialize(&s->pci_dev, TYPE_RAVEN_PCI_DEVICE);
......
...@@ -54,7 +54,8 @@ static int q35_host_init(SysBusDevice *dev) ...@@ -54,7 +54,8 @@ static int q35_host_init(SysBusDevice *dev)
return -1; return -1;
} }
b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0", 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; s->host.pci.bus = b;
qdev_set_parent_bus(DEVICE(&s->mch), BUS(b)); qdev_set_parent_bus(DEVICE(&s->mch), BUS(b));
qdev_init_nofail(DEVICE(&s->mch)); qdev_init_nofail(DEVICE(&s->mch));
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "qapi/qmp/qjson.h"
#include "monitor/monitor.h"
int qdev_hotplug = 0; int qdev_hotplug = 0;
static bool qdev_hot_added = false; static bool qdev_hot_added = false;
...@@ -764,6 +766,8 @@ static void device_unparent(Object *obj) ...@@ -764,6 +766,8 @@ static void device_unparent(Object *obj)
DeviceState *dev = DEVICE(obj); DeviceState *dev = DEVICE(obj);
DeviceClass *dc = DEVICE_GET_CLASS(dev); DeviceClass *dc = DEVICE_GET_CLASS(dev);
BusState *bus; BusState *bus;
QObject *event_data;
gchar *path = object_get_canonical_path(obj);
while (dev->num_child_bus) { while (dev->num_child_bus) {
bus = QLIST_FIRST(&dev->child_bus); bus = QLIST_FIRST(&dev->child_bus);
...@@ -782,6 +786,16 @@ static void device_unparent(Object *obj) ...@@ -782,6 +786,16 @@ static void device_unparent(Object *obj)
object_unref(OBJECT(dev->parent_bus)); object_unref(OBJECT(dev->parent_bus));
dev->parent_bus = NULL; 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) static void device_class_init(ObjectClass *class, void *data)
......
...@@ -124,7 +124,7 @@ static int sh_pci_device_init(SysBusDevice *dev) ...@@ -124,7 +124,7 @@ static int sh_pci_device_init(SysBusDevice *dev)
s->irq, s->irq,
get_system_memory(), get_system_memory(),
get_system_io(), 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, memory_region_init_io(&s->memconfig_p4, &sh_pci_reg_ops, s,
"sh_pci", 0x224); "sh_pci", 0x224);
memory_region_init_alias(&s->memconfig_a7, "sh_pci.2", &s->memconfig_p4, memory_region_init_alias(&s->memconfig_a7, "sh_pci.2", &s->memconfig_p4,
......
...@@ -641,7 +641,7 @@ static int spapr_phb_init(SysBusDevice *s) ...@@ -641,7 +641,7 @@ static int spapr_phb_init(SysBusDevice *s)
bus = pci_register_bus(DEVICE(s), busname, bus = pci_register_bus(DEVICE(s), busname,
pci_spapr_set_irq, pci_spapr_map_irq, sphb, pci_spapr_set_irq, pci_spapr_map_irq, sphb,
&sphb->memspace, &sphb->iospace, &sphb->memspace, &sphb->iospace,
PCI_DEVFN(0, 0), PCI_NUM_PINS); PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
phb->bus = bus; phb->bus = bus;
sphb->dma_window_start = 0; sphb->dma_window_start = 0;
......
...@@ -239,7 +239,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic, ...@@ -239,7 +239,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
pic, pic,
&d->pci_mmio, &d->pci_mmio,
address_space_io, address_space_io,
PCI_DEVFN(11, 0), 4); PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
#if 0 #if 0
pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north"); pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north");
...@@ -305,7 +305,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic, ...@@ -305,7 +305,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
pic, pic,
&d->pci_mmio, &d->pci_mmio,
address_space_io, 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, 0, 0xf0800000);
sysbus_mmio_map(s, 1, 0xf0c00000); sysbus_mmio_map(s, 1, 0xf0c00000);
......
...@@ -3332,7 +3332,7 @@ static int usb_xhci_initfn(struct PCIDevice *dev) ...@@ -3332,7 +3332,7 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
&xhci->mem); &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); assert(ret >= 0);
if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) { if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) {
......
...@@ -70,7 +70,7 @@ static int pci_vpb_init(SysBusDevice *dev) ...@@ -70,7 +70,7 @@ static int pci_vpb_init(SysBusDevice *dev)
bus = pci_register_bus(&dev->qdev, "pci", bus = pci_register_bus(&dev->qdev, "pci",
pci_vpb_set_irq, pci_vpb_map_irq, s->irq, pci_vpb_set_irq, pci_vpb_map_irq, s->irq,
get_system_memory(), get_system_io(), get_system_memory(), get_system_io(),
PCI_DEVFN(11, 0), 4); PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
/* ??? Register memory space. */ /* ??? Register memory space. */
......
...@@ -528,13 +528,14 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd, ...@@ -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, 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 || s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq));
elem->out_sg[1].iov_len != sizeof(struct virtio_net_ctrl_mq)) { if (s != sizeof(mq)) {
error_report("virtio-net ctrl invalid steering command");
return VIRTIO_NET_ERR; return VIRTIO_NET_ERR;
} }
...@@ -542,16 +543,16 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd, ...@@ -542,16 +543,16 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
return VIRTIO_NET_ERR; 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 || if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
s.virtqueue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX || queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
s.virtqueue_pairs > n->max_queues || queues > n->max_queues ||
!n->multiqueue) { !n->multiqueue) {
return VIRTIO_NET_ERR; 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 /* stop the backend before changing the number of queues to avoid handling a
* disabled queue */ * disabled queue */
virtio_net_set_status(&n->vdev, n->vdev.status); virtio_net_set_status(&n->vdev, n->vdev.status);
...@@ -589,7 +590,7 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) ...@@ -589,7 +590,7 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
} else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) { } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) {
status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt); status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt);
} else if (ctrl.class == VIRTIO_NET_CTRL_MQ) { } 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)); s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status));
......
...@@ -609,20 +609,23 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) ...@@ -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, static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
unsigned int queue_no, unsigned int queue_no,
unsigned int vector, unsigned int vector,
MSIMessage msg) MSIMessage msg)
{ {
VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
EventNotifier *n = virtio_queue_get_guest_notifier(vq); EventNotifier *n = virtio_queue_get_guest_notifier(vq);
VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; VirtIOIRQFD *irqfd;
int ret = 0; int ret = 0;
if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) { if (proxy->vector_irqfd) {
ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg); irqfd = &proxy->vector_irqfd[vector];
if (ret < 0) { if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
return ret; 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, ...@@ -642,7 +645,7 @@ static int kvm_virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
return ret; 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 queue_no,
unsigned int vector) unsigned int vector)
{ {
...@@ -656,8 +659,8 @@ static void kvm_virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, ...@@ -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, static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
MSIMessage msg) MSIMessage msg)
{ {
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = proxy->vdev; VirtIODevice *vdev = proxy->vdev;
...@@ -670,7 +673,7 @@ static int kvm_virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, ...@@ -670,7 +673,7 @@ static int kvm_virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
if (virtio_queue_vector(vdev, queue_no) != vector) { if (virtio_queue_vector(vdev, queue_no) != vector) {
continue; 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) { if (ret < 0) {
goto undo; goto undo;
} }
...@@ -682,12 +685,12 @@ undo: ...@@ -682,12 +685,12 @@ undo:
if (virtio_queue_vector(vdev, queue_no) != vector) { if (virtio_queue_vector(vdev, queue_no) != vector) {
continue; continue;
} }
kvm_virtio_pci_vq_vector_mask(proxy, queue_no, vector); virtio_pci_vq_vector_mask(proxy, queue_no, vector);
} }
return ret; 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); VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = proxy->vdev; VirtIODevice *vdev = proxy->vdev;
...@@ -700,13 +703,13 @@ static void kvm_virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) ...@@ -700,13 +703,13 @@ static void kvm_virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
if (virtio_queue_vector(vdev, queue_no) != vector) { if (virtio_queue_vector(vdev, queue_no) != vector) {
continue; 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, static void virtio_pci_vector_poll(PCIDevice *dev,
unsigned int vector_start, unsigned int vector_start,
unsigned int vector_end) unsigned int vector_end)
{ {
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = proxy->vdev; VirtIODevice *vdev = proxy->vdev;
...@@ -781,11 +784,13 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) ...@@ -781,11 +784,13 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
proxy->nvqs_with_notifiers = nvqs; proxy->nvqs_with_notifiers = nvqs;
/* Must unset vector notifier while guest notifier is still assigned */ /* 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); msix_unset_vector_notifiers(&proxy->pci_dev);
kvm_virtio_pci_vector_release(proxy, nvqs); if (proxy->vector_irqfd) {
g_free(proxy->vector_irqfd); kvm_virtio_pci_vector_release(proxy, nvqs);
proxy->vector_irqfd = NULL; g_free(proxy->vector_irqfd);
proxy->vector_irqfd = NULL;
}
} }
for (n = 0; n < nvqs; n++) { for (n = 0; n < nvqs; n++) {
...@@ -801,18 +806,20 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) ...@@ -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 */ /* Must set vector notifier after guest notifier has been assigned */
if (with_irqfd && assign) { if ((with_irqfd || vdev->guest_notifier_mask) && assign) {
proxy->vector_irqfd = if (with_irqfd) {
g_malloc0(sizeof(*proxy->vector_irqfd) * proxy->vector_irqfd =
msix_nr_vectors_allocated(&proxy->pci_dev)); g_malloc0(sizeof(*proxy->vector_irqfd) *
r = kvm_virtio_pci_vector_use(proxy, nvqs); msix_nr_vectors_allocated(&proxy->pci_dev));
if (r < 0) { r = kvm_virtio_pci_vector_use(proxy, nvqs);
goto assign_error; if (r < 0) {
goto assign_error;
}
} }
r = msix_set_vector_notifiers(&proxy->pci_dev, r = msix_set_vector_notifiers(&proxy->pci_dev,
kvm_virtio_pci_vector_unmask, virtio_pci_vector_unmask,
kvm_virtio_pci_vector_mask, virtio_pci_vector_mask,
kvm_virtio_pci_vector_poll); virtio_pci_vector_poll);
if (r < 0) { if (r < 0) {
goto notifiers_error; goto notifiers_error;
} }
...@@ -821,8 +828,10 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) ...@@ -821,8 +828,10 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
return 0; return 0;
notifiers_error: notifiers_error:
assert(assign); if (with_irqfd) {
kvm_virtio_pci_vector_release(proxy, nvqs); assert(assign);
kvm_virtio_pci_vector_release(proxy, nvqs);
}
assign_error: assign_error:
/* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */ /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
......
...@@ -61,7 +61,7 @@ static int xio3130_downstream_initfn(PCIDevice *d) ...@@ -61,7 +61,7 @@ static int xio3130_downstream_initfn(PCIDevice *d)
PCIESlot *s = DO_UPCAST(PCIESlot, port, p); PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
int rc; int rc;
rc = pci_bridge_initfn(d); rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
if (rc < 0) { if (rc < 0) {
return rc; return rc;
} }
......
...@@ -57,7 +57,7 @@ static int xio3130_upstream_initfn(PCIDevice *d) ...@@ -57,7 +57,7 @@ static int xio3130_upstream_initfn(PCIDevice *d)
PCIEPort *p = DO_UPCAST(PCIEPort, br, br); PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
int rc; int rc;
rc = pci_bridge_initfn(d); rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
if (rc < 0) { if (rc < 0) {
return rc; return rc;
} }
......
...@@ -39,6 +39,7 @@ typedef enum MonitorEvent { ...@@ -39,6 +39,7 @@ typedef enum MonitorEvent {
QEVENT_BLOCK_JOB_CANCELLED, QEVENT_BLOCK_JOB_CANCELLED,
QEVENT_BLOCK_JOB_ERROR, QEVENT_BLOCK_JOB_ERROR,
QEVENT_BLOCK_JOB_READY, QEVENT_BLOCK_JOB_READY,
QEVENT_DEVICE_DELETED,
QEVENT_DEVICE_TRAY_MOVED, QEVENT_DEVICE_TRAY_MOVED,
QEVENT_SUSPEND, QEVENT_SUSPEND,
QEVENT_SUSPEND_DISK, QEVENT_SUSPEND_DISK,
......
...@@ -477,6 +477,7 @@ static const char *monitor_event_names[] = { ...@@ -477,6 +477,7 @@ static const char *monitor_event_names[] = {
[QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED", [QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED",
[QEVENT_BLOCK_JOB_ERROR] = "BLOCK_JOB_ERROR", [QEVENT_BLOCK_JOB_ERROR] = "BLOCK_JOB_ERROR",
[QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY", [QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY",
[QEVENT_DEVICE_DELETED] = "DEVICE_DELETED",
[QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED", [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
[QEVENT_SUSPEND] = "SUSPEND", [QEVENT_SUSPEND] = "SUSPEND",
[QEVENT_SUSPEND_DISK] = "SUSPEND_DISK", [QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
......
...@@ -2367,7 +2367,9 @@ ...@@ -2367,7 +2367,9 @@
# Notes: When this command completes, the device may not be removed from the # Notes: When this command completes, the device may not be removed from the
# guest. Hot removal is an operation that requires guest cooperation. # guest. Hot removal is an operation that requires guest cooperation.
# This command merely requests that the guest begin the hot removal # 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 # Since: 0.14.0
## ##
......
...@@ -363,12 +363,12 @@ static void object_property_del_child(Object *obj, Object *child, Error **errp) ...@@ -363,12 +363,12 @@ static void object_property_del_child(Object *obj, Object *child, Error **errp)
void object_unparent(Object *obj) void object_unparent(Object *obj)
{ {
object_ref(obj); object_ref(obj);
if (obj->parent) {
object_property_del_child(obj->parent, obj, NULL);
}
if (obj->class->unparent) { if (obj->class->unparent) {
(obj->class->unparent)(obj); (obj->class->unparent)(obj);
} }
if (obj->parent) {
object_property_del_child(obj->parent, obj, NULL);
}
object_unref(obj); object_unref(obj);
} }
......
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
config="$1" config="$1"
make -C seabios clean distclean make -C seabios clean distclean
cp "$config" seabios/.config cp "$config" seabios/.config
make -C seabios oldnoconfig make -C seabios olddefconfig
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册