From 0402a5d65ec004df5345d1f736e2ddaa7aee6665 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 6 Mar 2013 14:58:59 +0200 Subject: qdev: DEVICE_DELETED event libvirt has a long-standing bug: when removing the device, it can request removal but does not know when the removal completes. Add an event so we can fix this in a robust way. Signed-off-by: Michael S. Tsirkin --- QMP/qmp-events.txt | 16 ++++++++++++++++ hw/qdev.c | 11 +++++++++++ include/monitor/monitor.h | 1 + monitor.c | 1 + qapi-schema.json | 4 +++- 5 files changed, 32 insertions(+), 1 deletion(-) diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt index b2698e4153..24cf3e8aa3 100644 --- a/QMP/qmp-events.txt +++ b/QMP/qmp-events.txt @@ -136,6 +136,22 @@ 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) + +{ "event": "DEVICE_DELETED", + "data": { "device": "virtio-net-pci-0" }, + "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } + DEVICE_TRAY_MOVED ----------------- diff --git a/hw/qdev.c b/hw/qdev.c index 0b20280133..5e8a89c06e 100644 --- a/hw/qdev.c +++ b/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; @@ -761,6 +763,7 @@ static void device_unparent(Object *obj) DeviceState *dev = DEVICE(obj); DeviceClass *dc = DEVICE_GET_CLASS(dev); BusState *bus; + QObject *event_data; while (dev->num_child_bus) { bus = QLIST_FIRST(&dev->child_bus); @@ -779,6 +782,14 @@ 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 }", dev->id); + } else { + event_data = qobject_from_jsonf("{ }"); + } + monitor_protocol_event(QEVENT_DEVICE_DELETED, event_data); + qobject_decref(event_data); } static void device_class_init(ObjectClass *class, void *data) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index 87fb49c092..b868760d7c 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -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, diff --git a/monitor.c b/monitor.c index 112e92064d..2fdfb79cab 100644 --- a/monitor.c +++ b/monitor.c @@ -458,6 +458,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", diff --git a/qapi-schema.json b/qapi-schema.json index fdaa9da133..080dc39784 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2354,7 +2354,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 ## -- cgit v1.2.1 From e998fa8df828ef68ea540a12917d10b4d335c1dd Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 18 Mar 2013 21:01:37 +0200 Subject: qom: call class destructor before unparent It seems more logical to have destruction flow start with the subclass and move up to the base class. This ensures object has a valid canonical path when destructor is called. Signed-off-by: Michael S. Tsirkin --- qom/object.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qom/object.c b/qom/object.c index 3d638ff273..a0e3cbe559 100644 --- a/qom/object.c +++ b/qom/object.c @@ -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); } -- cgit v1.2.1 From 15054fce2df8592dec70bba23faf126f0f372f81 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 11 Mar 2013 15:11:04 +0200 Subject: qmp: add path to device_deleted event Add QOM path to device deleted event. It now becomes useful to report it for devices which don't have an ID assigned. Signed-off-by: Michael S. Tsirkin --- QMP/qmp-events.txt | 4 +++- hw/qdev.c | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt index 24cf3e8aa3..dcc826d9f4 100644 --- a/QMP/qmp-events.txt +++ b/QMP/qmp-events.txt @@ -147,9 +147,11 @@ 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" }, + "data": { "device": "virtio-net-pci-0", + "path": "/machine/peripheral/virtio-net-pci-0" }, "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } DEVICE_TRAY_MOVED diff --git a/hw/qdev.c b/hw/qdev.c index 5e8a89c06e..0cdf568df9 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -764,6 +764,7 @@ static void device_unparent(Object *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); @@ -784,12 +785,14 @@ static void device_unparent(Object *obj) } if (dev->id) { - event_data = qobject_from_jsonf("{ 'device': %s }", dev->id); + event_data = qobject_from_jsonf("{ 'device': %s, 'path': %s }", + dev->id, path); } else { - event_data = qobject_from_jsonf("{ }"); + 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) -- cgit v1.2.1 From f8f7c533e20d1681feeb665109301151bdb739b4 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 6 Mar 2013 13:50:27 +0800 Subject: virtio-net: remove layout assumptions for mq ctrl Following commit 921ac5d0f3a0df869db5ce4edf752f51d8b1596a (virtio-net: remove layout assumptions for ctrl vq), this patch makes multiqueue ctrl handling not rely on the layout of descriptors. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin --- hw/virtio-net.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 8c9d8713f3..4590557352 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -578,13 +578,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; } @@ -592,16 +593,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); @@ -639,7 +640,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)); -- cgit v1.2.1 From a38b2c49bfd3f1cfc2aadd08cd049af16a342b1e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 13 Mar 2013 21:37:08 +0200 Subject: virtio-pci: guest notifier mask without non-irqfd non-irqfd setups are currently broken with vhost: we start up masked and nothing unmasks the interrupts. Fix by using mask notifiers, same as the irqfd path. Sharing irqchip/non irqchip code is always a good thing, in this case it will help non irqchip benefit from backend masking optimization. Signed-off-by: Michael S. Tsirkin --- hw/virtio-pci.c | 79 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 39c1966cfc..19965e5a31 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -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. */ -- cgit v1.2.1 From e01fd687185444944b0b5b0f8c739ae4b33eb029 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Sun, 3 Mar 2013 10:21:26 -0700 Subject: pci: Add PCI VGA helpers Allow devices to register VGA memory regions for handling PCI spec defined VGA I/O port and MMIO areas. PCI will attach these to the bus address spaces and enable them according to the device command register value. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pci/pci.h | 21 +++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 2f45c8f02f..ed43111bce 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -875,6 +875,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 +939,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 +1095,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) diff --git a/hw/pci/pci.h b/hw/pci/pci.h index f340fe57c9..d837a65c2d 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -108,6 +108,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 */ @@ -234,6 +248,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; @@ -287,6 +305,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, -- cgit v1.2.1 From ba7d8515c1e929baccea9f53d06d131fd2b007a1 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Sun, 3 Mar 2013 10:21:32 -0700 Subject: pci: Teach PCI Bridges about VGA routing Each PCI Bridge has a set of implied VGA regions that are enabled when the VGA bit is set in the bridge control register. This allows VGA devices behind bridges. Unfortunately with VGA Enable, which we formerly allowed but didn't back, comes along some required VGA baggage. VGA Palette Snooping is required, along with VGA 16-bit decoding. We don't yet have support for palette snooping. We also don't have support for 10-bit VGA aliases, the default mode, but we enable the register, even on root ports, to avoid confusing guests. Fortunately there's likely nothing from this century that requires these features, so the missing bits are noted with TODOs. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 4 ++++ hw/pci/pci_bridge.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- hw/pci/pci_bus.h | 7 +++++++ hw/pci/pcie_port.c | 2 ++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index ed43111bce..a88160236e 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -674,6 +674,10 @@ static void pci_init_mask_bridge(PCIDevice *d) #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 | diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 995842a72d..edb8c8d9c9 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -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); } @@ -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) | diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h index f905b9e11e..aef559ae1f 100644 --- a/hw/pci/pci_bus.h +++ b/hw/pci/pci_bus.h @@ -47,6 +47,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 { diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index 33a6b0a08a..1be107b0c9 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -28,10 +28,12 @@ void pcie_port_init_reg(PCIDevice *d) pci_set_word(d->config + PCI_SEC_STATUS, 0); /* Unlike conventional pci bridge, some bits are hardwired to 0. */ +#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_ISA | PCI_BRIDGE_CTL_VGA | + PCI_BRIDGE_CTL_VGA_16BIT | /* Req, but no alias support yet */ PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_BUS_RESET); } -- cgit v1.2.1 From 45eb768c706d3a5fbe55224c589e8b4e252781d9 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 4 Mar 2013 11:23:49 +0200 Subject: pci_bridge: factor out common code Reuse common code in pcie_port, override the hardwired-to-0 bits per PCI Express spec. No functional change but makes the code easier to follow. Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 14 ++++---------- hw/pci/pci_bridge.h | 7 +++++++ hw/pci/pcie_port.c | 20 +++++++++++--------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index a88160236e..8772707b81 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -668,16 +668,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). - */ + /* + * 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 | diff --git a/hw/pci/pci_bridge.h b/hw/pci/pci_bridge.h index 455cb6677a..9d25c1beb1 100644 --- a/hw/pci/pci_bridge.h +++ b/hw/pci/pci_bridge.h @@ -55,6 +55,13 @@ 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: diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index 1be107b0c9..91b53a0fc2 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -27,15 +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. */ -#define PCI_BRIDGE_CTL_VGA_16BIT 0x10 /* VGA 16-bit decode */ - pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, - PCI_BRIDGE_CTL_PARITY | - PCI_BRIDGE_CTL_ISA | - PCI_BRIDGE_CTL_VGA | - PCI_BRIDGE_CTL_VGA_16BIT | /* Req, but no alias support yet */ - 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); } /************************************************************************** -- cgit v1.2.1 From 600d05b9aa4b4d23775fc17968dd6b581928001d Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 4 Mar 2013 11:31:21 +0200 Subject: pci_bridge: drop formatting from source We use the same formatting for all files, it doesn't make sense to have formatting directives only in pci bridge header. Signed-off-by: Michael S. Tsirkin --- hw/pci/pci_bridge.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/hw/pci/pci_bridge.h b/hw/pci/pci_bridge.h index 9d25c1beb1..e549b78a38 100644 --- a/hw/pci/pci_bridge.h +++ b/hw/pci/pci_bridge.h @@ -63,11 +63,3 @@ void pci_bridge_map_irq(PCIBridge *br, const char* bus_name, #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: - */ -- cgit v1.2.1 From e5368f0da75c1c668e85398aa930be2f4273e684 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 7 Mar 2013 11:29:19 -0700 Subject: pci: Fix INTx routing notifier recursion For some reason we recurse to fire the INTx routing notifier for each child of a bus, for each possible device of a bus. That means that if we add a root port, the notifier gets called for that bridge 256 times. If we add an upstream switch behind that root port, 256^2. But of course we need a downstream switch, 256^3. This starts to be noticeable. Stop the insanity. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 8772707b81..f24c389627 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1215,9 +1215,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); } } -- cgit v1.2.1 From 659fefeed36a4b58191595cebab2dbc003788d90 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 7 Mar 2013 16:16:54 -0700 Subject: pci_bridge: Use a default map_irq function The PCI bridge spec defines a default swizzle for translating INTx IRQs from secondary bus to primary. Use this by default for any bridge that doesn't set a function. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci_bridge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index edb8c8d9c9..bf93ac6ed1 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -366,7 +366,7 @@ int pci_bridge_initfn(PCIDevice *dev) qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &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; -- cgit v1.2.1 From ea7cfed68bb4f26fc65b078ab735a4097e9b4fe2 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 7 Mar 2013 16:17:00 -0700 Subject: pci_bridge: Remove duplicate IRQ swizzle function pci_bridge_dev_map_irq_fn() is identical to pci_swizzle_map_irq_fn(), which is now the default for all PCI bridges. We can therefore remove this function and the pci_bridge_map_irq() call that used it. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci_bridge_dev.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index 9cc6a4082d..840ef43f00 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -36,21 +36,12 @@ 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); if (err) { goto bridge_error; -- cgit v1.2.1 From 8c7f3dd05e4f1ee90000c89e428e69ae2e6bd691 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 11 Mar 2013 10:20:20 +0100 Subject: pci: refuse empty ROM files A zero size ROM file is invalid and should produce a warning. Attempting to use a zero size file ends up hitting an assertion qemu_ram_set_idstr() because RAMBlocks with duplicate addresses are allocated - due to zero size the allocator doesn't increment the next available RAMBlock offset. Also convert __FUNCTION__ to __func__ while we're touching this code. There are no other __FUNCTION__ instances in pci.c anymore. Reported-by: Milos Ivanovic Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index f24c389627..81028cb083 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1912,7 +1912,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; } -- cgit v1.2.1 From 49cd9ac6a1929467e2df5783a5183fc7708ec3ff Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 11 Mar 2013 10:20:21 +0100 Subject: exec: assert that RAMBlock size is non-zero find_ram_offset() does not handle size=0 gracefully. It hands out the same RAMBlock offset multiple times, leading to obscure failures later on. Add an assert to warn early if something is incorrectly allocating a zero size RAMBlock. Signed-off-by: Stefan Hajnoczi Signed-off-by: Michael S. Tsirkin --- exec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exec.c b/exec.c index 8a6aac36e3..786987a016 100644 --- a/exec.c +++ b/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; -- cgit v1.2.1 From 3a861c466cee46fed042d76100fa0fd9644f3091 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Mar 2013 16:00:59 -0600 Subject: pci: Create and register a new PCI Express TypeInfo This will allow us to differentiate Express and Legacy buses. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 6 ++++++ hw/pci/pci_bus.h | 1 + 2 files changed, 7 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 81028cb083..74f449d38e 100644 --- a/hw/pci/pci.c +++ b/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); @@ -2236,6 +2241,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); } diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h index aef559ae1f..6d3155f14b 100644 --- a/hw/pci/pci_bus.h +++ b/hw/pci/pci_bus.h @@ -10,6 +10,7 @@ #define TYPE_PCI_BUS "PCI" #define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) +#define TYPE_PCIE_BUS "PCIE" struct PCIBus { BusState qbus; -- cgit v1.2.1 From cf09458d644934976aa64e88bb41ef9a4cc2766a Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Mar 2013 16:01:05 -0600 Subject: pci: Move PCI and PCIE type defines Move these so that we can reference them from a more common header instead of including pci_bus.h everywhere. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.h | 5 +++++ hw/pci/pci_bus.h | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/hw/pci/pci.h b/hw/pci/pci.h index d837a65c2d..37fb52222f 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -339,6 +339,11 @@ 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" + void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h index 6d3155f14b..6ee443cf88 100644 --- a/hw/pci/pci_bus.h +++ b/hw/pci/pci_bus.h @@ -8,10 +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) -#define TYPE_PCIE_BUS "PCIE" - struct PCIBus { BusState qbus; PCIDMAContextFunc dma_context_fn; -- cgit v1.2.1 From 60a0e44320cc2601236450fbe95d952830192a1d Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Mar 2013 16:01:11 -0600 Subject: pci: Allow PCI bus creation interfaces to specify the type of bus No change to any types. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/alpha_typhoon.c | 2 +- hw/apb_pci.c | 4 ++-- hw/bonito.c | 2 +- hw/dec_pci.c | 7 ++++++- hw/grackle_pci.c | 2 +- hw/gt64xxx.c | 2 +- hw/i82801b11.c | 2 +- hw/ioh3420.c | 2 +- hw/pci/pci.c | 12 ++++++------ hw/pci/pci.h | 6 +++--- hw/pci/pci_bridge.c | 5 ++--- hw/pci/pci_bridge.h | 2 +- hw/pci_bridge_dev.c | 2 +- hw/piix_pci.c | 2 +- hw/ppc4xx_pci.c | 2 +- hw/ppce500_pci.c | 2 +- hw/prep_pci.c | 2 +- hw/q35.c | 3 ++- hw/sh_pci.c | 2 +- hw/spapr_pci.c | 2 +- hw/unin_pci.c | 4 ++-- hw/versatile_pci.c | 2 +- hw/xio3130_downstream.c | 2 +- hw/xio3130_upstream.c | 2 +- 24 files changed, 40 insertions(+), 35 deletions(-) diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index 770dc8cf0d..b1e0044a35 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -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. */ diff --git a/hw/apb_pci.c b/hw/apb_pci.c index 7992d6f6fd..754ca6ca8f 100644 --- a/hw/apb_pci.c +++ b/hw/apb_pci.c @@ -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; diff --git a/hw/bonito.c b/hw/bonito.c index 3456e7840e..e58655a64d 100644 --- a/hw/bonito.c +++ b/hw/bonito.c @@ -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; } diff --git a/hw/dec_pci.c b/hw/dec_pci.c index 64a50924f6..6ec3d226bd 100644 --- a/hw/dec_pci.c +++ b/hw/dec_pci.c @@ -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; diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 11e47d560e..69344d9f6a 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -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"); diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c index c73a58a045..37be9c2a56 100644 --- a/hw/gt64xxx.c +++ b/hw/gt64xxx.c @@ -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"); diff --git a/hw/i82801b11.c b/hw/i82801b11.c index 992095c80f..8b4a9c6e54 100644 --- a/hw/i82801b11.c +++ b/hw/i82801b11.c @@ -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; } diff --git a/hw/ioh3420.c b/hw/ioh3420.c index 43f855427b..74d84d4dda 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -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_PCI_BUS); if (rc < 0) { return rc; } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 74f449d38e..7c5f2e283d 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -301,9 +301,9 @@ 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); } @@ -311,11 +311,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; @@ -343,12 +343,12 @@ 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; } diff --git a/hw/pci/pci.h b/hw/pci/pci.h index 37fb52222f..10aeaf0cc6 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -348,11 +348,11 @@ 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); @@ -364,7 +364,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); diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index bf93ac6ed1..24be6c5067 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -328,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); @@ -363,8 +363,7 @@ 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 ? br->map_irq : pci_swizzle_map_irq_fn; sec_bus->address_space_mem = &br->address_space_mem; diff --git a/hw/pci/pci_bridge.h b/hw/pci/pci_bridge.h index e549b78a38..1868f7aea8 100644 --- a/hw/pci/pci_bridge.h +++ b/hw/pci/pci_bridge.h @@ -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); diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c index 840ef43f00..971b432474 100644 --- a/hw/pci_bridge_dev.c +++ b/hw/pci_bridge_dev.c @@ -42,7 +42,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev) PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br); int err; - err = pci_bridge_initfn(dev); + err = pci_bridge_initfn(dev, TYPE_PCI_BUS); if (err) { goto bridge_error; } diff --git a/hw/piix_pci.c b/hw/piix_pci.c index e10bc1c6a0..ce397797fc 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -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); diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index f3bbe88529..854e17048f 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -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"); diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c index 310ae1c03d..abc7ebe1bf 100644 --- a/hw/ppce500_pci.c +++ b/hw/ppce500_pci.c @@ -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"); diff --git a/hw/prep_pci.c b/hw/prep_pci.c index d21e87671e..58df2452cd 100644 --- a/hw/prep_pci.c +++ b/hw/prep_pci.c @@ -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); diff --git a/hw/q35.c b/hw/q35.c index 0a25b8bf1f..37592bc088 100644 --- a/hw/q35.c +++ b/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_PCI_BUS); s->host.pci.bus = b; qdev_set_parent_bus(DEVICE(&s->mch), BUS(b)); qdev_init_nofail(DEVICE(&s->mch)); diff --git a/hw/sh_pci.c b/hw/sh_pci.c index 96535dbe01..e3e7550ae7 100644 --- a/hw/sh_pci.c +++ b/hw/sh_pci.c @@ -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, diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 36adbc5592..20b9015502 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -624,7 +624,7 @@ static int spapr_phb_init(SysBusDevice *s) bus = pci_register_bus(DEVICE(s), sphb->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; diff --git a/hw/unin_pci.c b/hw/unin_pci.c index cb95ad1f5e..fff235d523 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -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); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 0b97a4073d..d67ca796fb 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -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. */ diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index 4bccd0ddcd..a76d89bb6f 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -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_PCI_BUS); if (rc < 0) { return rc; } diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index 82556aaadc..d8fd19e196 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -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_PCI_BUS); if (rc < 0) { return rc; } -- cgit v1.2.1 From afb661eb902f4ad1456d57b31cdd02f0b4aac33f Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Mar 2013 16:01:17 -0600 Subject: pci: Q35, Root Ports, and Switches create PCI Express buses Convert q35, ioh3420, xio3130_upstream, and xio3130_downstream to use the new TYPE_PCIE_BUS. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/ioh3420.c | 2 +- hw/q35.c | 2 +- hw/xio3130_downstream.c | 2 +- hw/xio3130_upstream.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/ioh3420.c b/hw/ioh3420.c index 74d84d4dda..5cff61e095 100644 --- a/hw/ioh3420.c +++ b/hw/ioh3420.c @@ -97,7 +97,7 @@ static int ioh3420_initfn(PCIDevice *d) PCIESlot *s = DO_UPCAST(PCIESlot, port, p); int rc; - rc = pci_bridge_initfn(d, TYPE_PCI_BUS); + rc = pci_bridge_initfn(d, TYPE_PCIE_BUS); if (rc < 0) { return rc; } diff --git a/hw/q35.c b/hw/q35.c index 37592bc088..6ea081aaa3 100644 --- a/hw/q35.c +++ b/hw/q35.c @@ -55,7 +55,7 @@ static int q35_host_init(SysBusDevice *dev) } b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0", s->mch.pci_address_space, s->mch.address_space_io, - 0, TYPE_PCI_BUS); + 0, TYPE_PCIE_BUS); s->host.pci.bus = b; qdev_set_parent_bus(DEVICE(&s->mch), BUS(b)); qdev_init_nofail(DEVICE(&s->mch)); diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c index a76d89bb6f..b868f56ff9 100644 --- a/hw/xio3130_downstream.c +++ b/hw/xio3130_downstream.c @@ -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, TYPE_PCI_BUS); + rc = pci_bridge_initfn(d, TYPE_PCIE_BUS); if (rc < 0) { return rc; } diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c index d8fd19e196..cd5d97d211 100644 --- a/hw/xio3130_upstream.c +++ b/hw/xio3130_upstream.c @@ -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, TYPE_PCI_BUS); + rc = pci_bridge_initfn(d, TYPE_PCIE_BUS); if (rc < 0) { return rc; } -- cgit v1.2.1 From 8c0bf9e24242c89c1abbd708c714dd2a89febbd2 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Mar 2013 16:01:23 -0600 Subject: pci: Create pci_bus_is_express helper For testing the bus type. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 5 +++++ hw/pci/pci.h | 1 + 2 files changed, 6 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 7c5f2e283d..7f28101cb4 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -297,6 +297,11 @@ 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); +} + void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, diff --git a/hw/pci/pci.h b/hw/pci/pci.h index 10aeaf0cc6..d715e6f09d 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -344,6 +344,7 @@ typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, #define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS) #define TYPE_PCIE_BUS "PCIE" +bool pci_bus_is_express(PCIBus *bus); void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent, const char *name, MemoryRegion *address_space_mem, -- cgit v1.2.1 From 0889464a5050c25611d08ca33d8447796c88c7f7 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Mar 2013 16:01:29 -0600 Subject: pci: Create and use API to determine root buses Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 13 +++++++++---- hw/pci/pci.h | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 7f28101cb4..d5257ed4c5 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -302,6 +302,11 @@ 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, @@ -360,7 +365,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name, 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]; } @@ -1186,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; } @@ -1651,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; } @@ -1659,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; } diff --git a/hw/pci/pci.h b/hw/pci/pci.h index d715e6f09d..774369cd9e 100644 --- a/hw/pci/pci.h +++ b/hw/pci/pci.h @@ -345,6 +345,7 @@ typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, #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, -- cgit v1.2.1 From eb28cb1bb0cb156aef7e613395af403bba0e7f30 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 14 Mar 2013 16:01:35 -0600 Subject: pcie: Mangle types to match topology Windows will fail to start drivers for devices with an Endpoint type PCIe capability attached to a Root Complex (code 10 - Device cannot start). The proper type for such a device is Root Complex Integrated Endpoint. Devices don't care which they are, so do this conversion automatically. This allows the Windows driver to load for nec-usb-xhci when attached to pcie.0 of a q35 machine. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 485c94c1b2..bcfbae4332 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -48,6 +48,19 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) assert(pci_is_express(dev)); + /* + * Mangle type to convert Endpoints to Root Complex Integrated Endpoints. + * Windows will report Code 10 (device cannot start) for regular Endpoints + * on the Root Complex. + */ + if (pci_bus_is_express(dev->bus) && pci_bus_is_root(dev->bus)) { + switch (type) { + case PCI_EXP_TYPE_ENDPOINT: + type = PCI_EXP_TYPE_RC_END; + break; + } + } + pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, PCI_EXP_VER2_SIZEOF); if (pos < 0) { -- cgit v1.2.1 From a5519b42cfd6c00e9f8b31c5aad7682e7a9f1181 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 21 Mar 2013 14:04:21 +0200 Subject: roms: switch oldnoconfig to olddefconfig When a new option is added that qemu does not know about, the prudent thing is to use the default not force it to "no". Signed-off-by: Michael S. Tsirkin --- roms/configure-seabios.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roms/configure-seabios.sh b/roms/configure-seabios.sh index 98f59a24ba..4bb6c2b90f 100755 --- a/roms/configure-seabios.sh +++ b/roms/configure-seabios.sh @@ -2,4 +2,4 @@ config="$1" make -C seabios clean distclean cp "$config" seabios/.config -make -C seabios oldnoconfig +make -C seabios olddefconfig -- cgit v1.2.1 From 6214e73cc5b75a4f8d89a70d71727edfa47a81b3 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 19 Mar 2013 12:11:24 -0600 Subject: pcie: Add endpoint capability initialization wrapper Fix the awkward API of mangling the caller specified PCIe type and just provide an interface to initialize an endpoint device. This will pick either a regular endpoint or integrated endpoint based on the bus and return pcie_cap_init to doing exactly what is asked. Signed-off-by: Alex Williamson Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie.c | 29 ++++++++++++++++------------- hw/pci/pcie.h | 1 + hw/usb/hcd-xhci.c | 2 +- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index bcfbae4332..62bd0b8b3e 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -48,19 +48,6 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port) assert(pci_is_express(dev)); - /* - * Mangle type to convert Endpoints to Root Complex Integrated Endpoints. - * Windows will report Code 10 (device cannot start) for regular Endpoints - * on the Root Complex. - */ - if (pci_bus_is_express(dev->bus) && pci_bus_is_root(dev->bus)) { - switch (type) { - case PCI_EXP_TYPE_ENDPOINT: - type = PCI_EXP_TYPE_RC_END; - break; - } - } - pos = pci_add_capability(dev, PCI_CAP_ID_EXP, offset, PCI_EXP_VER2_SIZEOF); if (pos < 0) { @@ -100,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); diff --git a/hw/pci/pcie.h b/hw/pci/pcie.h index 31604e2742..c010007c5e 100644 --- a/hw/pci/pcie.h +++ b/hw/pci/pcie.h @@ -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); diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 07afdeef5b..5aa342bda5 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -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)) { -- cgit v1.2.1