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 b2698e4..24cf3e8 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 0b20280..5e8a89c 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 87fb49c..b868760 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 112e920..2fdfb79 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 fdaa9da..080dc39 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.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 3d638ff..a0e3cbe 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.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 24cf3e8..dcc826d 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 5e8a89c..0cdf568 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.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 8c9d871..4590557 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.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 39c1966..19965e5 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.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 2f45c8f..ed43111 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 f340fe5..d837a65 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.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 ed43111..a881602 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 995842a..edb8c8d 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 f905b9e..aef559a 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 33a6b0a..1be107b 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.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 a881602..8772707 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 455cb66..9d25c1b 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 1be107b..91b53a0 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.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 9d25c1b..e549b78 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.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 8772707..f24c389 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.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 edb8c8d..bf93ac6 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.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 9cc6a40..840ef43 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.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 f24c389..81028cb 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.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 8a6aac3..786987a 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.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 81028cb..74f449d 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 aef559a..6d3155f 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.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 d837a65..37fb522 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 6d3155f..6ee443c 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.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 770dc8c..b1e0044 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 7992d6f..754ca6c 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 3456e78..e58655a 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 64a5092..6ec3d22 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 11e47d5..69344d9 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 c73a58a..37be9c2 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 992095c..8b4a9c6 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 43f8554..74d84d4 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 74f449d..7c5f2e2 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 37fb522..10aeaf0 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 bf93ac6..24be6c5 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 e549b78..1868f7a 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 840ef43..971b432 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 e10bc1c..ce39779 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 f3bbe88..854e170 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 310ae1c..abc7ebe 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 d21e876..58df245 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 0a25b8b..37592bc 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 96535db..e3e7550 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 36adbc5..20b9015 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 cb95ad1..fff235d 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 0b97a40..d67ca79 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 4bccd0d..a76d89b 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 82556aa..d8fd19e 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.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 74d84d4..5cff61e 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 37592bc..6ea081a 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 a76d89b..b868f56 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 d8fd19e..cd5d97d 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.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 7c5f2e2..7f28101 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 10aeaf0..d715e6f 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.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 7f28101..d5257ed 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 d715e6f..774369c 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.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 485c94c..bcfbae4 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.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 98f59a2..4bb6c2b 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.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 bcfbae4..62bd0b8 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 31604e2..c010007 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 07afdee..5aa342b 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.1