Message ID | 1421230611-12481-2-git-send-email-a.rigo@virtualopensystems.com |
---|---|
State | New |
Headers | show |
On 14.01.2015 11:16, Alvise Rigo wrote: > 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 <a.rigo@virtualopensystems.com> > --- > 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 <rob.herring@linaro.org> > + * > + * 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; why do some of these assigments have the & and some not? > +} > + > +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 >
Hi Claudio, Sorry, I should have missed this one. On Wed, Jan 14, 2015 at 2:12 PM, Claudio Fontana <claudio.fontana@huawei.com> wrote: > On 14.01.2015 11:16, Alvise Rigo wrote: >> 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 <a.rigo@virtualopensystems.com> >> --- >> 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 <rob.herring@linaro.org> >> + * >> + * 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; > > why do some of these assigments have the & and some not? pci_generic_host_vmstate is a VMStateDescription structure defined and initialized at the top of the source file while vmsd is a pointer to such a structure. Regards, alvise > >> +} >> + >> +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 >> > > > -- > Claudio Fontana > Server Virtualization Architect > Huawei Technologies Duesseldorf GmbH > Riesstraße 25 - 80992 München > > office: +49 89 158834 4135 > mobile: +49 15253060158
On 15.01.2015 09:19, alvise rigo wrote: > Hi Claudio, > > Sorry, I should have missed this one. > > On Wed, Jan 14, 2015 at 2:12 PM, Claudio Fontana > <claudio.fontana@huawei.com> wrote: >> On 14.01.2015 11:16, Alvise Rigo wrote: >>> 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 <a.rigo@virtualopensystems.com> >>> --- >>> 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 <rob.herring@linaro.org> >>> + * >>> + * 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; >> >> why do some of these assigments have the & and some not? > > pci_generic_host_vmstate is a VMStateDescription structure defined and > initialized at the top of the source file while vmsd is a pointer to > such a structure. > > Regards, > alvise > doh.. of course. Thanks, C. >> >>> +} >>> + >>> +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 >>> >> >> >> -- >> Claudio Fontana >> Server Virtualization Architect >> Huawei Technologies Duesseldorf GmbH >> Riesstraße 25 - 80992 München >> >> office: +49 89 158834 4135 >> mobile: +49 15253060158
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 <rob.herring@linaro.org> + * + * 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
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 <a.rigo@virtualopensystems.com> --- 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 \ No newline at end of file