From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50730) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YBL0d-0006fi-CH for qemu-devel@nongnu.org; Wed, 14 Jan 2015 05:17:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YBL0Z-0004zH-8q for qemu-devel@nongnu.org; Wed, 14 Jan 2015 05:17:07 -0500 Received: from mail-wi0-f169.google.com ([209.85.212.169]:44750) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YBL0Y-0004z7-W9 for qemu-devel@nongnu.org; Wed, 14 Jan 2015 05:17:03 -0500 Received: by mail-wi0-f169.google.com with SMTP id n3so10324260wiv.0 for ; Wed, 14 Jan 2015 02:17:02 -0800 (PST) From: Alvise Rigo Date: Wed, 14 Jan 2015 11:16:50 +0100 Message-Id: <1421230611-12481-2-git-send-email-a.rigo@virtualopensystems.com> In-Reply-To: <1421230611-12481-1-git-send-email-a.rigo@virtualopensystems.com> References: <1421230611-12481-1-git-send-email-a.rigo@virtualopensystems.com> Subject: [Qemu-devel] [RFC v3 1/2] pci/pci-host: Add generic-pci PCI host controller device List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: peter.maydell@linaro.org, rob.herring@linaro.org, claudio.fontana@huawei.com, Alvise Rigo , agraf@suse.de, tech@virtualopensystems.com Add a generic PCI host controller for virtual platforms, based on the previous work by Rob Herring: http://lists.gnu.org/archive/html/qemu-devel/2014-06/msg03482.html The controller relies on a configuration memory region and provides two PCI memory regions for I/O (one port and one memory mapped). The device needs the following qdev properties to configure the memory regions: - cfg_win_size: size of the configuration memory - pio_win_size: size of the port I/O space - mmio_win_size: size of the MMIO space - mmio_win_addr: offset of MMIO space in the system memory Signed-off-by: Alvise Rigo --- hw/pci-host/Makefile.objs | 2 +- hw/pci-host/generic-pci.c | 140 ++++++++++++++++++++++++++++++++++++++ include/hw/pci-host/generic-pci.h | 45 ++++++++++++ 3 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 hw/pci-host/generic-pci.c create mode 100644 include/hw/pci-host/generic-pci.h diff --git a/hw/pci-host/Makefile.objs b/hw/pci-host/Makefile.objs index bb65f9c..8ef9fac 100644 --- a/hw/pci-host/Makefile.objs +++ b/hw/pci-host/Makefile.objs @@ -1,4 +1,4 @@ -common-obj-y += pam.o +common-obj-y += pam.o generic-pci.o # PPC devices common-obj-$(CONFIG_PREP_PCI) += prep.o diff --git a/hw/pci-host/generic-pci.c b/hw/pci-host/generic-pci.c new file mode 100644 index 0000000..54c9647 --- /dev/null +++ b/hw/pci-host/generic-pci.c @@ -0,0 +1,140 @@ +/* + * Generic PCI host controller + * + * Copyright (c) 2014 Linaro, Ltd. + * Author: Rob Herring + * + * Based on ARM Versatile PCI controller (hw/pci-host/versatile.c): + * Copyright (c) 2006-2009 CodeSourcery. + * Written by Paul Brook + * + * This code is licensed under the LGPL. + */ + +#include "hw/sysbus.h" +#include "hw/pci-host/generic-pci.h" +#include "exec/address-spaces.h" +#include "sysemu/device_tree.h" + +static const VMStateDescription pci_generic_host_vmstate = { + .name = "generic-host-pci", + .version_id = 1, + .minimum_version_id = 1, +}; + +static void pci_cam_config_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + PCIGenState *s = opaque; + pci_data_write(&s->pci_bus, addr, val, size); +} + +static uint64_t pci_cam_config_read(void *opaque, hwaddr addr, unsigned size) +{ + PCIGenState *s = opaque; + uint32_t val; + val = pci_data_read(&s->pci_bus, addr, size); + return val; +} + +static const MemoryRegionOps pci_generic_config_ops = { + .read = pci_cam_config_read, + .write = pci_cam_config_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void pci_generic_set_irq(void *opaque, int irq_num, int level) +{ + qemu_irq *pic = opaque; + qemu_set_irq(pic[irq_num], level); +} + +static void pci_generic_host_realize(DeviceState *dev, Error **errp) +{ + PCIHostState *h = PCI_HOST_BRIDGE(dev); + PCIGenState *s = PCI_GEN(dev); + GenericPCIHostState *gps = &s->pci_gen; + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + int i; + + memory_region_init(&s->pci_io_window, OBJECT(s), "pci_io", s->pio_win_size); + memory_region_init(&s->pci_mem_space, OBJECT(s), "pci_mem", 1ULL << 32); + + pci_bus_new_inplace(&s->pci_bus, sizeof(s->pci_bus), dev, "pci", + &s->pci_mem_space, &s->pci_io_window, + PCI_DEVFN(0, 0), TYPE_PCI_BUS); + h->bus = &s->pci_bus; + + object_initialize(gps, sizeof(*gps), TYPE_GENERIC_PCI_HOST); + qdev_set_parent_bus(DEVICE(gps), BUS(&s->pci_bus)); + + for (i = 0; i < s->irqs; i++) { + sysbus_init_irq(sbd, &s->irq[i]); + } + + pci_bus_irqs(&s->pci_bus, pci_generic_set_irq, pci_swizzle_map_irq_fn, + s->irq, s->irqs); + memory_region_init_io(&s->mem_config, OBJECT(s), &pci_generic_config_ops, s, + "pci-config", s->cfg_win_size); + memory_region_init_alias(&s->pci_mem_window, OBJECT(s), "pci-mem-win", + &s->pci_mem_space, s->mmio_win_addr, s->mmio_win_size); + + sysbus_init_mmio(sbd, &s->mem_config); + sysbus_init_mmio(sbd, &s->pci_io_window); + sysbus_init_mmio(sbd, &s->pci_mem_window); +} + +static void pci_generic_host_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->vendor_id = PCI_VENDOR_ID_REDHAT; + k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE; + k->class_id = PCI_CLASS_PROCESSOR_CO; + /* + * PCI-facing part of the host bridge, not usable without the + * host-facing part, which can't be device_add'ed, yet. + */ + dc->cannot_instantiate_with_device_add_yet = true; +} + +static const TypeInfo pci_generic_host_info = { + .name = TYPE_GENERIC_PCI_HOST, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(GenericPCIHostState), + .class_init = pci_generic_host_class_init, +}; + +static Property pci_generic_props[] = { + DEFINE_PROP_UINT32("cfg_win_size", PCIGenState, cfg_win_size, 1ULL << 20), + DEFINE_PROP_UINT32("pio_win_size", PCIGenState, pio_win_size, 64 * 1024), + DEFINE_PROP_UINT64("mmio_win_size", PCIGenState, mmio_win_size, 1ULL << 32), + DEFINE_PROP_UINT64("mmio_win_addr", PCIGenState, mmio_win_addr, 0), + DEFINE_PROP_UINT32("irqs", PCIGenState, irqs, 4), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pci_generic_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = pci_generic_host_realize; + dc->vmsd = &pci_generic_host_vmstate; + dc->props = pci_generic_props; +} + +static const TypeInfo pci_generic_info = { + .name = TYPE_GENERIC_PCI, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(PCIGenState), + .class_init = pci_generic_class_init, +}; + +static void generic_pci_host_register_types(void) +{ + type_register_static(&pci_generic_info); + type_register_static(&pci_generic_host_info); +} + +type_init(generic_pci_host_register_types) \ No newline at end of file diff --git a/include/hw/pci-host/generic-pci.h b/include/hw/pci-host/generic-pci.h new file mode 100644 index 0000000..830542e --- /dev/null +++ b/include/hw/pci-host/generic-pci.h @@ -0,0 +1,45 @@ +#ifndef QEMU_GENERIC_PCI_H +#define QEMU_GENERIC_PCI_H + +#include "hw/pci/pci.h" +#include "hw/pci/pci_bus.h" +#include "hw/pci/pci_host.h" + +#define MAX_PCI_DEVICES (PCI_SLOT_MAX * PCI_FUNC_MAX) + +typedef struct { + /*< private >*/ + PCIDevice parent_obj; +} GenericPCIHostState; + +typedef struct PCIGenState { + /*< private >*/ + PCIHostState parent_obj; + + qemu_irq irq[MAX_PCI_DEVICES]; + MemoryRegion mem_config; + /* Container representing the PCI address MMIO space */ + MemoryRegion pci_mem_space; + /* Alias region into PCI address spaces which we expose as sysbus region */ + MemoryRegion pci_mem_window; + /* PCI I/O region */ + MemoryRegion pci_io_window; + PCIBus pci_bus; + GenericPCIHostState pci_gen; + + uint32_t cfg_win_size; + uint32_t pio_win_size; + uint64_t mmio_win_addr; // offset of pci_mem_window inside pci_mem_space + uint64_t mmio_win_size; + uint32_t irqs; +} PCIGenState; + +#define TYPE_GENERIC_PCI "generic_pci" +#define PCI_GEN(obj) \ + OBJECT_CHECK(PCIGenState, (obj), TYPE_GENERIC_PCI) + +#define TYPE_GENERIC_PCI_HOST "generic_pci_host" +#define PCI_GEN_HOST(obj) \ + OBJECT_CHECK(GenericPCIHostState, (obj), TYPE_GENERIC_PCI_HOST) + +#endif \ No newline at end of file -- 2.1.0