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:
commit
404e7a4f4a
@ -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
2
exec.c
@ -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;
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
121
hw/pci/pci.c
121
hw/pci/pci.c
@ -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);
|
||||
}
|
||||
|
||||
|
34
hw/pci/pci.h
34
hw/pci/pci.h
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
*/
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
3
hw/q35.c
3
hw/q35.c
@ -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));
|
||||
|
14
hw/qdev.c
14
hw/qdev.c
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
##
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -2,4 +2,4 @@
|
||||
config="$1"
|
||||
make -C seabios clean distclean
|
||||
cp "$config" seabios/.config
|
||||
make -C seabios oldnoconfig
|
||||
make -C seabios olddefconfig
|
||||
|
Loading…
Reference in New Issue
Block a user