Message ID | 0362ffdbfb08b46edef0e2180387078299a9b721.1502643878.git.balaton@eik.bme.hu (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Sun, Aug 13, 2017 at 07:04:38PM +0200, BALATON Zoltan wrote: You know I'm going to say it, right: needs a commit message. What's a "plb-pcix", and what's an example of a 440 SoCs which has it. This is basically a new device, so I'm pretty willing to merge for 2.11 with minimal review once rebased with the rest of the series. Couple of comments below [snip] > +static void ppc440_pcix_reset(DeviceState *dev) > +{ > + struct PPC440PCIXState *s = PPC440_PCIX_HOST_BRIDGE(dev); > + int i; > + > + memset(s->pom, 0, sizeof(s->pom)); > + memset(s->pim, 0, sizeof(s->pim)); Is it safe to just memset() the memory region objects within the pim/pom arrays without cleaning them up? I'm guessing not.. > + for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) { > + s->pim[i].sa = 0xffffffff00000000ULL; > + } > + s->sts = 0; > +} > + > +/* All pins from each slot are tied to a single board IRQ. > + * This may need further refactoring for other boards. */ > +static int ppc440_pcix_map_irq(PCIDevice *pci_dev, int irq_num) > +{ > + int slot = pci_dev->devfn >> 3; > + > + DPRINTF("%s: devfn %x irq %d -> %d\n", __func__, > + pci_dev->devfn, irq_num, slot); > + > + return slot - 1; > +} > + > +static void ppc440_pcix_set_irq(void *opaque, int irq_num, int level) > +{ > + qemu_irq *pci_irqs = opaque; > + > + DPRINTF("%s: PCI irq %d\n", __func__, irq_num); > + if (irq_num < 0) { > + fprintf(stderr, "%s: PCI irq %d\n", __func__, irq_num); Use report_error() please. > + return; > + } > + qemu_set_irq(pci_irqs[irq_num], level); > +} > + > +static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn) > +{ > + PPC440PCIXState *s = opaque; > + > + return &s->bm_as; > +} > + > +static int ppc440_pcix_initfn(SysBusDevice *dev) > +{ > + PPC440PCIXState *s; > + PCIHostState *h; > + int i; > + > + h = PCI_HOST_BRIDGE(dev); > + s = PPC440_PCIX_HOST_BRIDGE(dev); > + > + for (i = 0; i < ARRAY_SIZE(s->irq); i++) { > + sysbus_init_irq(dev, &s->irq[i]); > + } > + > + memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX); > + h->bus = pci_register_bus(DEVICE(dev), NULL, ppc440_pcix_set_irq, > + ppc440_pcix_map_irq, s->irq, &s->busmem, > + get_system_io(), PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS); > + > + s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0), "ppc4xx-host-bridge"); > + > + memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX); > + memory_region_add_subregion(&s->bm, 0x0, &s->busmem); > + address_space_init(&s->bm_as, &s->bm, "pci-bm"); > + pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s); > + > + memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE); > + memory_region_init_io(&h->conf_mem, OBJECT(s), &pci_host_conf_le_ops, h, > + "pci-conf-idx", 4); > + memory_region_init_io(&h->data_mem, OBJECT(s), &pci_host_data_le_ops, h, > + "pci-conf-data", 4); > + memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s, > + "pci.reg", PPC440_REG_SIZE); > + memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem); > + memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem); > + memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem); > + sysbus_init_mmio(dev, &s->container); > + > + return 0; > +} > + > +static void ppc440_pcix_class_init(ObjectClass *klass, void *data) > +{ > + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); > + DeviceClass *dc = DEVICE_CLASS(klass); > + > + k->init = ppc440_pcix_initfn; > + dc->reset = ppc440_pcix_reset; > +} > + > +static const TypeInfo ppc440_pcix_info = { > + .name = TYPE_PPC440_PCIX_HOST_BRIDGE, > + .parent = TYPE_PCI_HOST_BRIDGE, > + .instance_size = sizeof(PPC440PCIXState), > + .class_init = ppc440_pcix_class_init, > +}; > + > +static void ppc440_pcix_register_types(void) > +{ > + type_register_static(&ppc440_pcix_info); > +} > + > +type_init(ppc440_pcix_register_types)
hi Balaton, i can help with amigaos4 for sam . i can test it on P5040 book3e and on G5 quad book3s machine. note sam for boot amigaos need a special modified version of uboot that is available on acube website it is a firmware update. without modified uboot will be not posdible auto boot amigaos. idont know if is possible use standard uboot incuded in qemu for boot amigaos from uboot command line. i can ask help to Enrico Vidale as my FB friend but i dont know if he will be available for this kind of helping. bye luigi Inviato da iPad > Il giorno 14 ago 2017, alle ore 01:30, BALATON Zoltan <balaton@eik.bme.hu> ha scritto: > > Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> > --- > hw/ppc/Makefile.objs | 2 +- > hw/ppc/ppc440_pcix.c | 506 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 507 insertions(+), 1 deletion(-) > create mode 100644 hw/ppc/ppc440_pcix.c > > diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs > index 2077216..9c5d58a 100644 > --- a/hw/ppc/Makefile.objs > +++ b/hw/ppc/Makefile.objs > @@ -13,7 +13,7 @@ endif > obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o > # PowerPC 4xx boards > obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o > -obj-y += ppc4xx_pci.o ppc4xx_i2c.o > +obj-y += ppc4xx_pci.o ppc440_pcix.o ppc4xx_i2c.o > # PReP > obj-$(CONFIG_PREP) += prep.o > obj-$(CONFIG_PREP) += prep_systemio.o > diff --git a/hw/ppc/ppc440_pcix.c b/hw/ppc/ppc440_pcix.c > new file mode 100644 > index 0000000..3abd0d0 > --- /dev/null > +++ b/hw/ppc/ppc440_pcix.c > @@ -0,0 +1,506 @@ > +/* > + * Emulation of the ibm,plb-pcix PCI controller > + * This is found in some 440 SoCs e.g. the 460EX. > + * > + * Copyright (c) 2016 BALATON Zoltan > + * > + * Derived from ppc4xx_pci.c and pci-host/ppce500.c > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License, version 2, as > + * published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "qemu/osdep.h" > +#include "hw/hw.h" > +#include "hw/ppc/ppc.h" > +#include "hw/ppc/ppc4xx.h" > +#include "hw/pci/pci.h" > +#include "hw/pci/pci_host.h" > +#include "exec/address-spaces.h" > + > +/*#define DEBUG_PCI*/ > + > +#ifdef DEBUG_PCI > +#define DPRINTF(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__); > +#else > +#define DPRINTF(fmt, ...) > +#endif /* DEBUG */ > + > +struct PLBOutMap { > + uint64_t la; > + uint64_t pcia; > + uint32_t sa; > + MemoryRegion mr; > +}; > + > +struct PLBInMap { > + uint64_t sa; > + uint64_t la; > + MemoryRegion mr; > +}; > + > +#define TYPE_PPC440_PCIX_HOST_BRIDGE "ppc440-pcix-host" > +#define PPC440_PCIX_HOST_BRIDGE(obj) \ > + OBJECT_CHECK(PPC440PCIXState, (obj), TYPE_PPC440_PCIX_HOST_BRIDGE) > + > +#define PPC440_PCIX_NR_POMS 3 > +#define PPC440_PCIX_NR_PIMS 3 > + > +typedef struct PPC440PCIXState { > + PCIHostState parent_obj; > + > + PCIDevice *dev; > + struct PLBOutMap pom[PPC440_PCIX_NR_POMS]; > + struct PLBInMap pim[PPC440_PCIX_NR_PIMS]; > + uint32_t sts; > + qemu_irq irq[PCI_NUM_PINS]; > + AddressSpace bm_as; > + MemoryRegion bm; > + > + MemoryRegion container; > + MemoryRegion iomem; > + MemoryRegion busmem; > +} PPC440PCIXState; > + > +#define PPC440_REG_BASE 0x80000 > +#define PPC440_REG_SIZE 0xff > + > +#define PCIC0_CFGADDR 0x0 > +#define PCIC0_CFGDATA 0x4 > + > +#define PCIX0_POM0LAL 0x68 > +#define PCIX0_POM0LAH 0x6c > +#define PCIX0_POM0SA 0x70 > +#define PCIX0_POM0PCIAL 0x74 > +#define PCIX0_POM0PCIAH 0x78 > +#define PCIX0_POM1LAL 0x7c > +#define PCIX0_POM1LAH 0x80 > +#define PCIX0_POM1SA 0x84 > +#define PCIX0_POM1PCIAL 0x88 > +#define PCIX0_POM1PCIAH 0x8c > +#define PCIX0_POM2SA 0x90 > + > +#define PCIX0_PIM0SAL 0x98 > +#define PCIX0_PIM0LAL 0x9c > +#define PCIX0_PIM0LAH 0xa0 > +#define PCIX0_PIM1SA 0xa4 > +#define PCIX0_PIM1LAL 0xa8 > +#define PCIX0_PIM1LAH 0xac > +#define PCIX0_PIM2SAL 0xb0 > +#define PCIX0_PIM2LAL 0xb4 > +#define PCIX0_PIM2LAH 0xb8 > +#define PCIX0_PIM0SAH 0xf8 > +#define PCIX0_PIM2SAH 0xfc > + > +#define PCIX0_STS 0xe0 > + > +#define PCI_ALL_SIZE (PPC440_REG_BASE + PPC440_REG_SIZE) > + > +/* DMA mapping */ > +static void ppc440_pcix_update_pim(PPC440PCIXState *s, int idx) > +{ > + MemoryRegion *mem = &s->pim[idx].mr; > + char *name; > + uint64_t size; > + > + if (memory_region_is_mapped(mem)) { > + /* Before we modify anything, unmap and destroy the region */ > + memory_region_del_subregion(&s->bm, mem); > + object_unparent(OBJECT(mem)); > + } > + > + if (!(s->pim[idx].sa & 1)) { > + /* Not enabled, nothing to do */ > + return; > + } > + > + name = g_strdup_printf("PCI Inbound Window %d", idx); > + size = ~(s->pim[idx].sa & ~7ULL) + 1; > + memory_region_init_alias(mem, OBJECT(s), name, get_system_memory(), > + s->pim[idx].la, size); > + memory_region_add_subregion_overlap(&s->bm, 0, mem, -1); > + g_free(name); > + > + DPRINTF("%s: Added window %d of size=%#"PRIx64" to CPU=%#"PRIx64"\n", > + __func__, idx, size, s->pim[idx].la); > +} > + > +/* BAR mapping */ > +static void ppc440_pcix_update_pom(PPC440PCIXState *s, int idx) > +{ > + MemoryRegion *mem = &s->pom[idx].mr; > + MemoryRegion *address_space_mem = get_system_memory(); > + char *name; > + uint32_t size; > + > + if (memory_region_is_mapped(mem)) { > + /* Before we modify anything, unmap and destroy the region */ > + memory_region_del_subregion(address_space_mem, mem); > + object_unparent(OBJECT(mem)); > + } > + > + if (!(s->pom[idx].sa & 1)) { > + /* Not enabled, nothing to do */ > + return; > + } > + > + name = g_strdup_printf("PCI Outbound Window %d", idx); > + size = ~(s->pom[idx].sa & 0xfffffffe) + 1; > + if (!size) { > + size = 0xffffffff; > + } > + memory_region_init_alias(mem, OBJECT(s), name, &s->busmem, > + s->pom[idx].pcia, size); > + memory_region_add_subregion(address_space_mem, s->pom[idx].la, mem); > + g_free(name); > + > + DPRINTF("%s: Added window %d of size=%#x from CPU=%#"PRIx64 > + " to PCI=%#"PRIx64"\n", __func__, idx, size, s->pom[idx].la, > + s->pom[idx].pcia); > +} > + > +static void ppc440_pcix_reg_write4(void *opaque, hwaddr addr, > + uint64_t val, unsigned size) > +{ > + struct PPC440PCIXState *s = opaque; > + > + DPRINTF("%s: addr 0x%"PRIx64 " = %"PRIx64 "\n", __func__, addr, val); > + switch (addr) { > + case PCI_VENDOR_ID ... PCI_MAX_LAT: > + stl_le_p(s->dev->config + addr, val); > + break; > + > + case PCIX0_POM0LAL: > + s->pom[0].la &= 0xffffffff00000000ULL; > + s->pom[0].la |= val; > + ppc440_pcix_update_pom(s, 0); > + break; > + case PCIX0_POM0LAH: > + s->pom[0].la &= 0xffffffffULL; > + s->pom[0].la |= val << 32; > + ppc440_pcix_update_pom(s, 0); > + break; > + case PCIX0_POM0SA: > + s->pom[0].sa = val; > + ppc440_pcix_update_pom(s, 0); > + break; > + case PCIX0_POM0PCIAL: > + s->pom[0].pcia &= 0xffffffff00000000ULL; > + s->pom[0].pcia |= val; > + ppc440_pcix_update_pom(s, 0); > + break; > + case PCIX0_POM0PCIAH: > + s->pom[0].pcia &= 0xffffffffULL; > + s->pom[0].pcia |= val << 32; > + ppc440_pcix_update_pom(s, 0); > + break; > + case PCIX0_POM1LAL: > + s->pom[1].la &= 0xffffffff00000000ULL; > + s->pom[1].la |= val; > + ppc440_pcix_update_pom(s, 1); > + break; > + case PCIX0_POM1LAH: > + s->pom[1].la &= 0xffffffffULL; > + s->pom[1].la |= val << 32; > + ppc440_pcix_update_pom(s, 1); > + break; > + case PCIX0_POM1SA: > + s->pom[1].sa = val; > + ppc440_pcix_update_pom(s, 1); > + break; > + case PCIX0_POM1PCIAL: > + s->pom[1].pcia &= 0xffffffff00000000ULL; > + s->pom[1].pcia |= val; > + ppc440_pcix_update_pom(s, 1); > + break; > + case PCIX0_POM1PCIAH: > + s->pom[1].pcia &= 0xffffffffULL; > + s->pom[1].pcia |= val << 32; > + ppc440_pcix_update_pom(s, 1); > + break; > + case PCIX0_POM2SA: > + s->pom[2].sa = val; > + break; > + > + case PCIX0_PIM0SAL: > + s->pim[0].sa &= 0xffffffff00000000ULL; > + s->pim[0].sa |= val; > + ppc440_pcix_update_pim(s, 0); > + break; > + case PCIX0_PIM0LAL: > + s->pim[0].la &= 0xffffffff00000000ULL; > + s->pim[0].la |= val; > + ppc440_pcix_update_pim(s, 0); > + break; > + case PCIX0_PIM0LAH: > + s->pim[0].la &= 0xffffffffULL; > + s->pim[0].la |= val << 32; > + ppc440_pcix_update_pim(s, 0); > + break; > + case PCIX0_PIM1SA: > + s->pim[1].sa = val; > + ppc440_pcix_update_pim(s, 1); > + break; > + case PCIX0_PIM1LAL: > + s->pim[1].la &= 0xffffffff00000000ULL; > + s->pim[1].la |= val; > + ppc440_pcix_update_pim(s, 1); > + break; > + case PCIX0_PIM1LAH: > + s->pim[1].la &= 0xffffffffULL; > + s->pim[1].la |= val << 32; > + ppc440_pcix_update_pim(s, 1); > + break; > + case PCIX0_PIM2SAL: > + s->pim[2].sa &= 0xffffffff00000000ULL; > + s->pim[2].sa = val; > + ppc440_pcix_update_pim(s, 2); > + break; > + case PCIX0_PIM2LAL: > + s->pim[2].la &= 0xffffffff00000000ULL; > + s->pim[2].la |= val; > + ppc440_pcix_update_pim(s, 2); > + break; > + case PCIX0_PIM2LAH: > + s->pim[2].la &= 0xffffffffULL; > + s->pim[2].la |= val << 32; > + ppc440_pcix_update_pim(s, 2); > + break; > + > + case PCIX0_STS: > + s->sts = val; > + break; > + > + case PCIX0_PIM0SAH: > + s->pim[0].sa &= 0xffffffffULL; > + s->pim[0].sa |= val << 32; > + ppc440_pcix_update_pim(s, 0); > + break; > + case PCIX0_PIM2SAH: > + s->pim[2].sa &= 0xffffffffULL; > + s->pim[2].sa |= val << 32; > + ppc440_pcix_update_pim(s, 2); > + break; > + > + default: > + printf("%s: unhandled PCI internal register 0x%lx\n", __func__, > + (unsigned long)addr); > + break; > + } > +} > + > +static uint64_t ppc440_pcix_reg_read4(void *opaque, hwaddr addr, > + unsigned size) > +{ > + struct PPC440PCIXState *s = opaque; > + uint32_t val; > + > + switch (addr) { > + case PCI_VENDOR_ID ... PCI_MAX_LAT: > + val = ldl_le_p(s->dev->config + addr); > + break; > + > + case PCIX0_POM0LAL: > + val = s->pom[0].la; > + break; > + case PCIX0_POM0LAH: > + val = s->pom[0].la >> 32; > + break; > + case PCIX0_POM0SA: > + val = s->pom[0].sa; > + break; > + case PCIX0_POM0PCIAL: > + val = s->pom[0].pcia; > + break; > + case PCIX0_POM0PCIAH: > + val = s->pom[0].pcia >> 32; > + break; > + case PCIX0_POM1LAL: > + val = s->pom[1].la; > + break; > + case PCIX0_POM1LAH: > + val = s->pom[1].la >> 32; > + break; > + case PCIX0_POM1SA: > + val = s->pom[1].sa; > + break; > + case PCIX0_POM1PCIAL: > + val = s->pom[1].pcia; > + break; > + case PCIX0_POM1PCIAH: > + val = s->pom[1].pcia >> 32; > + break; > + case PCIX0_POM2SA: > + val = s->pom[2].sa; > + break; > + > + case PCIX0_PIM0SAL: > + val = s->pim[0].sa; > + break; > + case PCIX0_PIM0LAL: > + val = s->pim[0].la; > + break; > + case PCIX0_PIM0LAH: > + val = s->pim[0].la >> 32; > + break; > + case PCIX0_PIM1SA: > + val = s->pim[1].sa; > + break; > + case PCIX0_PIM1LAL: > + val = s->pim[1].la; > + break; > + case PCIX0_PIM1LAH: > + val = s->pim[1].la >> 32; > + break; > + case PCIX0_PIM2SAL: > + val = s->pim[2].sa; > + break; > + case PCIX0_PIM2LAL: > + val = s->pim[2].la; > + break; > + case PCIX0_PIM2LAH: > + val = s->pim[2].la >> 32; > + break; > + > + case PCIX0_STS: > + val = s->sts; > + break; > + > + case PCIX0_PIM0SAH: > + val = s->pim[0].sa >> 32; > + break; > + case PCIX0_PIM2SAH: > + val = s->pim[2].sa >> 32; > + break; > + > + default: > + printf("%s: invalid PCI internal register 0x%lx\n", __func__, > + (unsigned long)addr); > + val = 0; > + } > + > + DPRINTF("%s: addr 0x%"PRIx64 " = %"PRIx32 "\n", __func__, addr, val); > + return val; > +} > + > +static const MemoryRegionOps pci_reg_ops = { > + .read = ppc440_pcix_reg_read4, > + .write = ppc440_pcix_reg_write4, > + .endianness = DEVICE_LITTLE_ENDIAN, > +}; > + > +static void ppc440_pcix_reset(DeviceState *dev) > +{ > + struct PPC440PCIXState *s = PPC440_PCIX_HOST_BRIDGE(dev); > + int i; > + > + memset(s->pom, 0, sizeof(s->pom)); > + memset(s->pim, 0, sizeof(s->pim)); > + for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) { > + s->pim[i].sa = 0xffffffff00000000ULL; > + } > + s->sts = 0; > +} > + > +/* All pins from each slot are tied to a single board IRQ. > + * This may need further refactoring for other boards. */ > +static int ppc440_pcix_map_irq(PCIDevice *pci_dev, int irq_num) > +{ > + int slot = pci_dev->devfn >> 3; > + > + DPRINTF("%s: devfn %x irq %d -> %d\n", __func__, > + pci_dev->devfn, irq_num, slot); > + > + return slot - 1; > +} > + > +static void ppc440_pcix_set_irq(void *opaque, int irq_num, int level) > +{ > + qemu_irq *pci_irqs = opaque; > + > + DPRINTF("%s: PCI irq %d\n", __func__, irq_num); > + if (irq_num < 0) { > + fprintf(stderr, "%s: PCI irq %d\n", __func__, irq_num); > + return; > + } > + qemu_set_irq(pci_irqs[irq_num], level); > +} > + > +static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn) > +{ > + PPC440PCIXState *s = opaque; > + > + return &s->bm_as; > +} > + > +static int ppc440_pcix_initfn(SysBusDevice *dev) > +{ > + PPC440PCIXState *s; > + PCIHostState *h; > + int i; > + > + h = PCI_HOST_BRIDGE(dev); > + s = PPC440_PCIX_HOST_BRIDGE(dev); > + > + for (i = 0; i < ARRAY_SIZE(s->irq); i++) { > + sysbus_init_irq(dev, &s->irq[i]); > + } > + > + memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX); > + h->bus = pci_register_bus(DEVICE(dev), NULL, ppc440_pcix_set_irq, > + ppc440_pcix_map_irq, s->irq, &s->busmem, > + get_system_io(), PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS); > + > + s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0), "ppc4xx-host-bridge"); > + > + memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX); > + memory_region_add_subregion(&s->bm, 0x0, &s->busmem); > + address_space_init(&s->bm_as, &s->bm, "pci-bm"); > + pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s); > + > + memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE); > + memory_region_init_io(&h->conf_mem, OBJECT(s), &pci_host_conf_le_ops, h, > + "pci-conf-idx", 4); > + memory_region_init_io(&h->data_mem, OBJECT(s), &pci_host_data_le_ops, h, > + "pci-conf-data", 4); > + memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s, > + "pci.reg", PPC440_REG_SIZE); > + memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem); > + memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem); > + memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem); > + sysbus_init_mmio(dev, &s->container); > + > + return 0; > +} > + > +static void ppc440_pcix_class_init(ObjectClass *klass, void *data) > +{ > + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); > + DeviceClass *dc = DEVICE_CLASS(klass); > + > + k->init = ppc440_pcix_initfn; > + dc->reset = ppc440_pcix_reset; > +} > + > +static const TypeInfo ppc440_pcix_info = { > + .name = TYPE_PPC440_PCIX_HOST_BRIDGE, > + .parent = TYPE_PCI_HOST_BRIDGE, > + .instance_size = sizeof(PPC440PCIXState), > + .class_init = ppc440_pcix_class_init, > +}; > + > +static void ppc440_pcix_register_types(void) > +{ > + type_register_static(&ppc440_pcix_info); > +} > + > +type_init(ppc440_pcix_register_types) > -- > 2.7.4 > >
Hi, Le 18/08/2017 à 03:53, David Gibson a écrit : > On Sun, Aug 13, 2017 at 07:04:38PM +0200, BALATON Zoltan wrote: > > You know I'm going to say it, right: needs a commit message. > > What's a "plb-pcix", and what's an example of a 440 SoCs which has it. IIRC that's the PCI(express) controller, which is not memory-mapped but inside the DCR address space, so accessed from the PLB. See: http://www.embeddeddeveloper.com/assets/processors/amcc/datasheets/PP460EX_DS2063.pdf page 9, 13. François.
Hi, Le 18/08/2017 à 11:30, luigi burdo a écrit : > hi Balaton, i can help with amigaos4 for sam . i can test it on P5040 > book3e and on G5 quad book3s machine. note sam for boot amigaos need > a special modified version of uboot that is available on acube > website it is a firmware update. without modified uboot will be not > posdible auto boot amigaos. idont know if is possible use standard > uboot incuded in qemu for boot amigaos from uboot command line. i can > ask help to Enrico Vidale as my FB friend but i dont know if he will > be available for this kind of helping. > Yes they use their own custom U-Boot, with a lot of changes and code duplication, and added x86 emulation to run a VGA BIOS, and never upstreamed the changes... much like any other vendor, sadly. I once managed to build a binary from their published source code with an old compiler, although it's not exactly the same of the binary used, which I think is actually run with the on-chip RAM or something weird alike. François.
On Fri, 18 Aug 2017, François Revol wrote: > Le 18/08/2017 à 03:53, David Gibson a écrit : >> On Sun, Aug 13, 2017 at 07:04:38PM +0200, BALATON Zoltan wrote: >> >> You know I'm going to say it, right: needs a commit message. >> >> What's a "plb-pcix", and what's an example of a 440 SoCs which has it. > > IIRC that's the PCI(express) controller, which is not memory-mapped but > inside the DCR address space, so accessed from the PLB. This is the PCI(X) controller only, the PCIe(xpress) controller is (partially) implemented in sam460ex.c TYPE_PPC460EX_PCIE_HOST/"ppc460ex-pcie-host". The plb-pcix is the compatible name the fdt refers to. I only know of the 460EX that has it but probably other similar SoCs (like some 440 variants) also have this kind of PCI controller (according to #defines in U-Boot source but don't remember the details). Regards, BALATON Zoltan
On Fri, Aug 18, 2017 at 01:07:28PM +0200, François Revol wrote: > Hi, > > Le 18/08/2017 à 03:53, David Gibson a écrit : > > On Sun, Aug 13, 2017 at 07:04:38PM +0200, BALATON Zoltan wrote: > > > > You know I'm going to say it, right: needs a commit message. > > > > What's a "plb-pcix", and what's an example of a 440 SoCs which has it. > > IIRC that's the PCI(express) controller, which is not memory-mapped but > inside the DCR address space, so accessed from the PLB. > > See: > > http://www.embeddeddeveloper.com/assets/processors/amcc/datasheets/PP460EX_DS2063.pdf > > page 9, 13. Sure, I can guess that. But my point is that this is the sort of information (including the link) that ought to be in the commit message.
On Fri, 18 Aug 2017, luigi burdo wrote: > hi Balaton, Ciao Luigi, > i can help with amigaos4 for sam . > i can test it on P5040 book3e and on G5 quad book3s machine. Thanks for the offer but unfortunately that would not help because these are different CPUs than the 460EX used in the Sam board. I'd definitely need logs from Sam460ex or Sam460cr, other logs are not the same and not help to find differences between real hardware and emulation. > note sam for boot amigaos need a special modified version of uboot that > is available on acube website it is a firmware update. without modified > uboot will be not posdible auto boot amigaos. I know about this and if you read the cover message (RFC PATCH 00/12) I link to a fixed version of that U-Boot firmware (rebuilt from source with the mentioned patches) which works with this emulation. (The original one from the updater also starts but cannot boot due to some problems which are fixed by these patches in my image. This is described in the cover message.) With that fixed firmware image it should be possible to at least try booting AmigaOS on the emulation and get some logs. I'd be surprised if it also worked at this point but I could not try it as it needs an appropriate AmigaOS version that runs on the Sam460. It should produce some logs though with -serial stdio which may help finding what is missing. > idont know if is possible use standard uboot incuded in qemu for boot > amigaos from uboot command line. i can ask help to Enrico Vidale as my > FB friend but i dont know if he will be available for this kind of > helping. I think it would not be possible to use the U-Boot in QEMU now as that is for e500 CPU but this is not needed either. See above, we are aiming to emulate enough of the board that it can run the original firmware which should be able to boot these Amiga like OSes and normal Linux images used on the Sam460ex. This already works but things fail after or during boot currently. This is what needs to be debugged. So we'd need someone who has a Sam460 (ex or cr) board and can test on that to get logs from OSes on real hardware for comparison. Regards, BALATON Zoltan
On Fri, 18 Aug 2017, François Revol wrote: > I once managed to build a binary from their published source code with > an old compiler, It builds here with the patch I've posted next to the bin image. > although it's not exactly the same of the binary used, > which I think is actually run with the on-chip RAM or something weird alike. Maybe it's the same but we may have a problem with MMU emulation so it behaves differently (or they've compiled with different compiler/version which generates different code, I haven't checked that deep). But AROS has a problem with MMU so it may be a bug. I'll send a separate message about that. Regards, BALATON Zoltan
hi Balaton, > I know about this and if you read the cover message (RFC PATCH 00/12) I link to a fixed version of that U-Boot firmware (rebuilt from source with the mentioned patches) which works with this emulation. (The original one from the updater also starts but cannot boot due to some problems which are fixed by these patches in my image. This is described in the cover message.) With that fixed firmware image it should be possible to at least try booting AmigaOS on the emulation and get some logs. I'd be surprised if it also worked at this point but I could not try it as it needs an appropriate AmigaOS version that runs on the Sam460. It should produce some logs though with -serial stdio which may help finding what is missing. i have sam460 amigaos cdrom iso as my backup and can test it inside qemu. sharing the logs if you needed. > I think it would not be possible to use the U-Boot in QEMU now as that is for e500 CPU but this is not needed either. See above, we are aiming to emulate enough of the board that it can run the original firmware which should be able to boot these Amiga like OSes and normal Linux images used on the Sam460ex. This already works but things fail after or during boot currently. This is what needs to be debugged. So we'd need someone who has a Sam460 (ex or cr) board and can test on that to get logs from OSes on real hardware for comparison. about real hardware no problem i will ask inside amigan community if someone have the opportunity to share the serial debug of sam 460 runinng amigaos. can i ask you something ? why you dont try to integrate in qemu the pegasos 2 or the efika machine. i have the feeling that probably it can be more simple because more old machine and components. bye luigi
Le 18/08/2017 à 21:43, luigi burdo a écrit : > can i ask you something ? why you dont try to integrate in qemu the > pegasos 2 or the efika machine. i have the feeling that probably it > can be more simple because more old machine and components. > Except they are antique, and the Pegasos at least has an horribly buggy OpenFirmware implementation. I'd rather work on BeBox support ;-) François.
On Fri, 18 Aug 2017, luigi burdo wrote: > i have sam460 amigaos cdrom iso as my backup and can test it inside > qemu. sharing the logs if you needed. It may help if you can do that. You need to compile QEMU from git with this patch series applied and copy the u-boot-sam460-20100605-fixed.bin linked from the cover message as u-boot-sam460-20100605.bin to the current dir. Then try booting the CD and see if it shows something. It should print some messages to console where it's started with -serial stdio when you start AmigaOS with debug (you may need to set os4_commandline in U-Boot for this but I don't know AmigaOS). > about real hardware no problem i will ask inside amigan community if > someone have the opportunity to share the serial debug of sam 460 > runinng amigaos. Do you know about a good place for such requests? Is there some forum or mailing list I should be aware of? > can i ask you something ? > why you dont try to integrate in qemu the pegasos 2 or the efika > machine. i have the feeling that probably it can be more simple because > more old machine and components. The age of a machine and components has nothing to do with how easy it is to emulate. It depends on what is already emulated in QEMU. If none of those old components are implemented by QEMU already then it's a lot of work to write emulation of them. (Such as the Marvell system controller chip in Pegasos or the SoC the Efika uses. Besides, does AmigaOS run on Efika?) If there are some previous work we can build on then it's easier. QEMU already had ppc440 emulation including a similar board and Francois has started sam460ex emulation so it was easier to finish this than making a new one. (Also firmware and graphics emulation may be more difficult for those other boards.) At the end it does not matter which machine we emulate if the goal is to run these OSes. If we have any of the supported boards they will run so we don't need more of these just one and it was the sam460 which was nearest to start working. (The MorphOS team or one of the developers may have some Pegasos 2 emulation but they don't intend to publish that and I don't know about previous work on Efika so the Sam460ex seems like a good choice with support for a lot of OSes, including porting Haiku which was why Francois has started emulating it so this may help that activity as well increasing the available OSes.) Regards, BALATON Zoltan
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index 2077216..9c5d58a 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -13,7 +13,7 @@ endif obj-$(CONFIG_PSERIES) += spapr_rtas_ddw.o # PowerPC 4xx boards obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o -obj-y += ppc4xx_pci.o ppc4xx_i2c.o +obj-y += ppc4xx_pci.o ppc440_pcix.o ppc4xx_i2c.o # PReP obj-$(CONFIG_PREP) += prep.o obj-$(CONFIG_PREP) += prep_systemio.o diff --git a/hw/ppc/ppc440_pcix.c b/hw/ppc/ppc440_pcix.c new file mode 100644 index 0000000..3abd0d0 --- /dev/null +++ b/hw/ppc/ppc440_pcix.c @@ -0,0 +1,506 @@ +/* + * Emulation of the ibm,plb-pcix PCI controller + * This is found in some 440 SoCs e.g. the 460EX. + * + * Copyright (c) 2016 BALATON Zoltan + * + * Derived from ppc4xx_pci.c and pci-host/ppce500.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/ppc/ppc.h" +#include "hw/ppc/ppc4xx.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_host.h" +#include "exec/address-spaces.h" + +/*#define DEBUG_PCI*/ + +#ifdef DEBUG_PCI +#define DPRINTF(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__); +#else +#define DPRINTF(fmt, ...) +#endif /* DEBUG */ + +struct PLBOutMap { + uint64_t la; + uint64_t pcia; + uint32_t sa; + MemoryRegion mr; +}; + +struct PLBInMap { + uint64_t sa; + uint64_t la; + MemoryRegion mr; +}; + +#define TYPE_PPC440_PCIX_HOST_BRIDGE "ppc440-pcix-host" +#define PPC440_PCIX_HOST_BRIDGE(obj) \ + OBJECT_CHECK(PPC440PCIXState, (obj), TYPE_PPC440_PCIX_HOST_BRIDGE) + +#define PPC440_PCIX_NR_POMS 3 +#define PPC440_PCIX_NR_PIMS 3 + +typedef struct PPC440PCIXState { + PCIHostState parent_obj; + + PCIDevice *dev; + struct PLBOutMap pom[PPC440_PCIX_NR_POMS]; + struct PLBInMap pim[PPC440_PCIX_NR_PIMS]; + uint32_t sts; + qemu_irq irq[PCI_NUM_PINS]; + AddressSpace bm_as; + MemoryRegion bm; + + MemoryRegion container; + MemoryRegion iomem; + MemoryRegion busmem; +} PPC440PCIXState; + +#define PPC440_REG_BASE 0x80000 +#define PPC440_REG_SIZE 0xff + +#define PCIC0_CFGADDR 0x0 +#define PCIC0_CFGDATA 0x4 + +#define PCIX0_POM0LAL 0x68 +#define PCIX0_POM0LAH 0x6c +#define PCIX0_POM0SA 0x70 +#define PCIX0_POM0PCIAL 0x74 +#define PCIX0_POM0PCIAH 0x78 +#define PCIX0_POM1LAL 0x7c +#define PCIX0_POM1LAH 0x80 +#define PCIX0_POM1SA 0x84 +#define PCIX0_POM1PCIAL 0x88 +#define PCIX0_POM1PCIAH 0x8c +#define PCIX0_POM2SA 0x90 + +#define PCIX0_PIM0SAL 0x98 +#define PCIX0_PIM0LAL 0x9c +#define PCIX0_PIM0LAH 0xa0 +#define PCIX0_PIM1SA 0xa4 +#define PCIX0_PIM1LAL 0xa8 +#define PCIX0_PIM1LAH 0xac +#define PCIX0_PIM2SAL 0xb0 +#define PCIX0_PIM2LAL 0xb4 +#define PCIX0_PIM2LAH 0xb8 +#define PCIX0_PIM0SAH 0xf8 +#define PCIX0_PIM2SAH 0xfc + +#define PCIX0_STS 0xe0 + +#define PCI_ALL_SIZE (PPC440_REG_BASE + PPC440_REG_SIZE) + +/* DMA mapping */ +static void ppc440_pcix_update_pim(PPC440PCIXState *s, int idx) +{ + MemoryRegion *mem = &s->pim[idx].mr; + char *name; + uint64_t size; + + if (memory_region_is_mapped(mem)) { + /* Before we modify anything, unmap and destroy the region */ + memory_region_del_subregion(&s->bm, mem); + object_unparent(OBJECT(mem)); + } + + if (!(s->pim[idx].sa & 1)) { + /* Not enabled, nothing to do */ + return; + } + + name = g_strdup_printf("PCI Inbound Window %d", idx); + size = ~(s->pim[idx].sa & ~7ULL) + 1; + memory_region_init_alias(mem, OBJECT(s), name, get_system_memory(), + s->pim[idx].la, size); + memory_region_add_subregion_overlap(&s->bm, 0, mem, -1); + g_free(name); + + DPRINTF("%s: Added window %d of size=%#"PRIx64" to CPU=%#"PRIx64"\n", + __func__, idx, size, s->pim[idx].la); +} + +/* BAR mapping */ +static void ppc440_pcix_update_pom(PPC440PCIXState *s, int idx) +{ + MemoryRegion *mem = &s->pom[idx].mr; + MemoryRegion *address_space_mem = get_system_memory(); + char *name; + uint32_t size; + + if (memory_region_is_mapped(mem)) { + /* Before we modify anything, unmap and destroy the region */ + memory_region_del_subregion(address_space_mem, mem); + object_unparent(OBJECT(mem)); + } + + if (!(s->pom[idx].sa & 1)) { + /* Not enabled, nothing to do */ + return; + } + + name = g_strdup_printf("PCI Outbound Window %d", idx); + size = ~(s->pom[idx].sa & 0xfffffffe) + 1; + if (!size) { + size = 0xffffffff; + } + memory_region_init_alias(mem, OBJECT(s), name, &s->busmem, + s->pom[idx].pcia, size); + memory_region_add_subregion(address_space_mem, s->pom[idx].la, mem); + g_free(name); + + DPRINTF("%s: Added window %d of size=%#x from CPU=%#"PRIx64 + " to PCI=%#"PRIx64"\n", __func__, idx, size, s->pom[idx].la, + s->pom[idx].pcia); +} + +static void ppc440_pcix_reg_write4(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + struct PPC440PCIXState *s = opaque; + + DPRINTF("%s: addr 0x%"PRIx64 " = %"PRIx64 "\n", __func__, addr, val); + switch (addr) { + case PCI_VENDOR_ID ... PCI_MAX_LAT: + stl_le_p(s->dev->config + addr, val); + break; + + case PCIX0_POM0LAL: + s->pom[0].la &= 0xffffffff00000000ULL; + s->pom[0].la |= val; + ppc440_pcix_update_pom(s, 0); + break; + case PCIX0_POM0LAH: + s->pom[0].la &= 0xffffffffULL; + s->pom[0].la |= val << 32; + ppc440_pcix_update_pom(s, 0); + break; + case PCIX0_POM0SA: + s->pom[0].sa = val; + ppc440_pcix_update_pom(s, 0); + break; + case PCIX0_POM0PCIAL: + s->pom[0].pcia &= 0xffffffff00000000ULL; + s->pom[0].pcia |= val; + ppc440_pcix_update_pom(s, 0); + break; + case PCIX0_POM0PCIAH: + s->pom[0].pcia &= 0xffffffffULL; + s->pom[0].pcia |= val << 32; + ppc440_pcix_update_pom(s, 0); + break; + case PCIX0_POM1LAL: + s->pom[1].la &= 0xffffffff00000000ULL; + s->pom[1].la |= val; + ppc440_pcix_update_pom(s, 1); + break; + case PCIX0_POM1LAH: + s->pom[1].la &= 0xffffffffULL; + s->pom[1].la |= val << 32; + ppc440_pcix_update_pom(s, 1); + break; + case PCIX0_POM1SA: + s->pom[1].sa = val; + ppc440_pcix_update_pom(s, 1); + break; + case PCIX0_POM1PCIAL: + s->pom[1].pcia &= 0xffffffff00000000ULL; + s->pom[1].pcia |= val; + ppc440_pcix_update_pom(s, 1); + break; + case PCIX0_POM1PCIAH: + s->pom[1].pcia &= 0xffffffffULL; + s->pom[1].pcia |= val << 32; + ppc440_pcix_update_pom(s, 1); + break; + case PCIX0_POM2SA: + s->pom[2].sa = val; + break; + + case PCIX0_PIM0SAL: + s->pim[0].sa &= 0xffffffff00000000ULL; + s->pim[0].sa |= val; + ppc440_pcix_update_pim(s, 0); + break; + case PCIX0_PIM0LAL: + s->pim[0].la &= 0xffffffff00000000ULL; + s->pim[0].la |= val; + ppc440_pcix_update_pim(s, 0); + break; + case PCIX0_PIM0LAH: + s->pim[0].la &= 0xffffffffULL; + s->pim[0].la |= val << 32; + ppc440_pcix_update_pim(s, 0); + break; + case PCIX0_PIM1SA: + s->pim[1].sa = val; + ppc440_pcix_update_pim(s, 1); + break; + case PCIX0_PIM1LAL: + s->pim[1].la &= 0xffffffff00000000ULL; + s->pim[1].la |= val; + ppc440_pcix_update_pim(s, 1); + break; + case PCIX0_PIM1LAH: + s->pim[1].la &= 0xffffffffULL; + s->pim[1].la |= val << 32; + ppc440_pcix_update_pim(s, 1); + break; + case PCIX0_PIM2SAL: + s->pim[2].sa &= 0xffffffff00000000ULL; + s->pim[2].sa = val; + ppc440_pcix_update_pim(s, 2); + break; + case PCIX0_PIM2LAL: + s->pim[2].la &= 0xffffffff00000000ULL; + s->pim[2].la |= val; + ppc440_pcix_update_pim(s, 2); + break; + case PCIX0_PIM2LAH: + s->pim[2].la &= 0xffffffffULL; + s->pim[2].la |= val << 32; + ppc440_pcix_update_pim(s, 2); + break; + + case PCIX0_STS: + s->sts = val; + break; + + case PCIX0_PIM0SAH: + s->pim[0].sa &= 0xffffffffULL; + s->pim[0].sa |= val << 32; + ppc440_pcix_update_pim(s, 0); + break; + case PCIX0_PIM2SAH: + s->pim[2].sa &= 0xffffffffULL; + s->pim[2].sa |= val << 32; + ppc440_pcix_update_pim(s, 2); + break; + + default: + printf("%s: unhandled PCI internal register 0x%lx\n", __func__, + (unsigned long)addr); + break; + } +} + +static uint64_t ppc440_pcix_reg_read4(void *opaque, hwaddr addr, + unsigned size) +{ + struct PPC440PCIXState *s = opaque; + uint32_t val; + + switch (addr) { + case PCI_VENDOR_ID ... PCI_MAX_LAT: + val = ldl_le_p(s->dev->config + addr); + break; + + case PCIX0_POM0LAL: + val = s->pom[0].la; + break; + case PCIX0_POM0LAH: + val = s->pom[0].la >> 32; + break; + case PCIX0_POM0SA: + val = s->pom[0].sa; + break; + case PCIX0_POM0PCIAL: + val = s->pom[0].pcia; + break; + case PCIX0_POM0PCIAH: + val = s->pom[0].pcia >> 32; + break; + case PCIX0_POM1LAL: + val = s->pom[1].la; + break; + case PCIX0_POM1LAH: + val = s->pom[1].la >> 32; + break; + case PCIX0_POM1SA: + val = s->pom[1].sa; + break; + case PCIX0_POM1PCIAL: + val = s->pom[1].pcia; + break; + case PCIX0_POM1PCIAH: + val = s->pom[1].pcia >> 32; + break; + case PCIX0_POM2SA: + val = s->pom[2].sa; + break; + + case PCIX0_PIM0SAL: + val = s->pim[0].sa; + break; + case PCIX0_PIM0LAL: + val = s->pim[0].la; + break; + case PCIX0_PIM0LAH: + val = s->pim[0].la >> 32; + break; + case PCIX0_PIM1SA: + val = s->pim[1].sa; + break; + case PCIX0_PIM1LAL: + val = s->pim[1].la; + break; + case PCIX0_PIM1LAH: + val = s->pim[1].la >> 32; + break; + case PCIX0_PIM2SAL: + val = s->pim[2].sa; + break; + case PCIX0_PIM2LAL: + val = s->pim[2].la; + break; + case PCIX0_PIM2LAH: + val = s->pim[2].la >> 32; + break; + + case PCIX0_STS: + val = s->sts; + break; + + case PCIX0_PIM0SAH: + val = s->pim[0].sa >> 32; + break; + case PCIX0_PIM2SAH: + val = s->pim[2].sa >> 32; + break; + + default: + printf("%s: invalid PCI internal register 0x%lx\n", __func__, + (unsigned long)addr); + val = 0; + } + + DPRINTF("%s: addr 0x%"PRIx64 " = %"PRIx32 "\n", __func__, addr, val); + return val; +} + +static const MemoryRegionOps pci_reg_ops = { + .read = ppc440_pcix_reg_read4, + .write = ppc440_pcix_reg_write4, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void ppc440_pcix_reset(DeviceState *dev) +{ + struct PPC440PCIXState *s = PPC440_PCIX_HOST_BRIDGE(dev); + int i; + + memset(s->pom, 0, sizeof(s->pom)); + memset(s->pim, 0, sizeof(s->pim)); + for (i = 0; i < PPC440_PCIX_NR_PIMS; i++) { + s->pim[i].sa = 0xffffffff00000000ULL; + } + s->sts = 0; +} + +/* All pins from each slot are tied to a single board IRQ. + * This may need further refactoring for other boards. */ +static int ppc440_pcix_map_irq(PCIDevice *pci_dev, int irq_num) +{ + int slot = pci_dev->devfn >> 3; + + DPRINTF("%s: devfn %x irq %d -> %d\n", __func__, + pci_dev->devfn, irq_num, slot); + + return slot - 1; +} + +static void ppc440_pcix_set_irq(void *opaque, int irq_num, int level) +{ + qemu_irq *pci_irqs = opaque; + + DPRINTF("%s: PCI irq %d\n", __func__, irq_num); + if (irq_num < 0) { + fprintf(stderr, "%s: PCI irq %d\n", __func__, irq_num); + return; + } + qemu_set_irq(pci_irqs[irq_num], level); +} + +static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn) +{ + PPC440PCIXState *s = opaque; + + return &s->bm_as; +} + +static int ppc440_pcix_initfn(SysBusDevice *dev) +{ + PPC440PCIXState *s; + PCIHostState *h; + int i; + + h = PCI_HOST_BRIDGE(dev); + s = PPC440_PCIX_HOST_BRIDGE(dev); + + for (i = 0; i < ARRAY_SIZE(s->irq); i++) { + sysbus_init_irq(dev, &s->irq[i]); + } + + memory_region_init(&s->busmem, OBJECT(dev), "pci bus memory", UINT64_MAX); + h->bus = pci_register_bus(DEVICE(dev), NULL, ppc440_pcix_set_irq, + ppc440_pcix_map_irq, s->irq, &s->busmem, + get_system_io(), PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS); + + s->dev = pci_create_simple(h->bus, PCI_DEVFN(0, 0), "ppc4xx-host-bridge"); + + memory_region_init(&s->bm, OBJECT(s), "bm-ppc440-pcix", UINT64_MAX); + memory_region_add_subregion(&s->bm, 0x0, &s->busmem); + address_space_init(&s->bm_as, &s->bm, "pci-bm"); + pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s); + + memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE); + memory_region_init_io(&h->conf_mem, OBJECT(s), &pci_host_conf_le_ops, h, + "pci-conf-idx", 4); + memory_region_init_io(&h->data_mem, OBJECT(s), &pci_host_data_le_ops, h, + "pci-conf-data", 4); + memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s, + "pci.reg", PPC440_REG_SIZE); + memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem); + memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem); + memory_region_add_subregion(&s->container, PPC440_REG_BASE, &s->iomem); + sysbus_init_mmio(dev, &s->container); + + return 0; +} + +static void ppc440_pcix_class_init(ObjectClass *klass, void *data) +{ + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = ppc440_pcix_initfn; + dc->reset = ppc440_pcix_reset; +} + +static const TypeInfo ppc440_pcix_info = { + .name = TYPE_PPC440_PCIX_HOST_BRIDGE, + .parent = TYPE_PCI_HOST_BRIDGE, + .instance_size = sizeof(PPC440PCIXState), + .class_init = ppc440_pcix_class_init, +}; + +static void ppc440_pcix_register_types(void) +{ + type_register_static(&ppc440_pcix_info); +} + +type_init(ppc440_pcix_register_types)
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> --- hw/ppc/Makefile.objs | 2 +- hw/ppc/ppc440_pcix.c | 506 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 507 insertions(+), 1 deletion(-) create mode 100644 hw/ppc/ppc440_pcix.c