mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -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
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+1
-1
@@ -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. */
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+6
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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");
|
||||
|
||||
|
||||
+1
-1
@@ -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");
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
+101
-20
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+31
-3
@@ -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);
|
||||
|
||||
+45
-6
@@ -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;
|
||||
|
||||
+8
-9
@@ -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:
|
||||
*/
|
||||
|
||||
+7
-3
@@ -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);
|
||||
|
||||
+11
-7
@@ -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);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
||||
+1
-10
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user