> -----Original Message----- > From: kvm-ppc-ow...@vger.kernel.org > [mailto:kvm-ppc-ow...@vger.kernel.org] On Behalf Of Hollis Blanchard > Sent: Saturday, January 10, 2009 4:25 AM > To: Liu Yu-B13201 > Cc: kvm-ppc@vger.kernel.org > Subject: Re: [PATCH 3/5] qemu/kvm: MPIC and E500 PCI > controller emualtion > > On Fri, 2009-01-09 at 15:56 +0800, Liu Yu wrote: > > Signed-off-by: Liu Yu <yu....@freescale.com> > > --- > > hw/mpic.c | 903 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++ > > hw/ppce500_pci.c | 322 +++++++++++++++++++ > > 2 files changed, 1225 insertions(+), 0 deletions(-) > > create mode 100644 hw/mpic.c > > create mode 100644 hw/ppce500_pci.c > > > > diff --git a/hw/mpic.c b/hw/mpic.c > > new file mode 100644 > > index 0000000..a68948a > > --- /dev/null > > +++ b/hw/mpic.c > > @@ -0,0 +1,903 @@ > > +/* > > + * MPIC emulation > > + * > > + * Copyright (C) 2009 Freescale Semiconductor, Inc. All > rights reserved. > > + * > > + * Author: Yu Liu, <yu....@freescale.com> > > + * > > + * This file is derived from hw/openpic.c, > > + * the copyright for that material belongs to the original owners. > > The Linux drivers for MPIC and OpenPIC share a lot of code. Can't you > modify hw/openpic.c instead of copy/paste/hack?
I will try to do that. > > The MPIC patch should be separate from the PCI patch. Fixed. Thanks. > > > diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c > > new file mode 100644 > > index 0000000..9242639 > > --- /dev/null > > +++ b/hw/ppce500_pci.c > > @@ -0,0 +1,322 @@ > > +/* > > + * QEMU PowerPC E500 embedded processors pci controller emulation > > + * > > + * Copyright (C) 2009 Freescale Semiconductor, Inc. All > rights reserved. > > + * > > + * Author: Yu Liu, <yu....@freescale.com> > > + * > > + * This file is derived from hw/ppc4xx_pci.c, > > + * the copyright for that material belongs to the original owners. > > + * > > + * This is free software; you can redistribute it and/or modify > > + * it under the terms of the GNU General Public License > as published by > > + * the Free Software Foundation; either version 2 of the > License, or > > + * (at your option) any later version. > > + */ > > + > > +#include "hw.h" > > +#include "ppc.h" > > +#include "ppce500.h" > > +#include "sysemu.h" > > +#include "pci.h" > > +#include "bswap.h" > > +#include "qemu-log.h" > > + > > +#ifdef DEBUG_PCI > > +#define pci_debug(fmt, arg...) fprintf(stderr, fmt, ##arg) > > +#else > > +#define pci_debug(fmt, arg...) > > +#endif > > + > > +#define PPCE500_PCI_REG_SIZE 0x1000 > > + > > +#define PPCE500_PCI_CONFIG_ADDR 0x0 > > +#define PPCE500_PCI_CONFIG_DATA 0x4 > > +#define PPCE500_PCI_INTACK 0x8 > > + > > +#define PPCE500_PCI_OW1 0xC20 > > +#define PPCE500_PCI_OW2 0xC40 > > +#define PPCE500_PCI_OW3 0xC60 > > +#define PPCE500_PCI_OW4 0xC80 > > +#define PPCE500_PCI_IW3 0xDA0 > > +#define PPCE500_PCI_IW2 0xDC0 > > +#define PPCE500_PCI_IW1 0xDE0 > > + > > +#define PPCE500_PCI_GAS_TIMR 0xE20 > > + > > +#define PCI_POTAR 0x0 > > +#define PCI_POTEAR 0x4 > > +#define PCI_POWBAR 0x8 > > +#define PCI_POWAR 0x10 > > + > > +#define PCI_PITAR 0x0 > > +#define PCI_PIWBAR 0x8 > > +#define PCI_PIWBEAR 0xC > > +#define PCI_PIWAR 0x10 > > + > > +#define PPCE500_PCI_NR_POBS 5 > > +#define PPCE500_PCI_NR_PIBS 3 > > + > > +struct ppce500_pci_t { > > + target_phys_addr_t registers; > > + struct pci_outbound pob[PPCE500_PCI_NR_POBS]; > > + struct pci_inbound pib[PPCE500_PCI_NR_PIBS]; > > + uint32_t gas_time; > > + > > + qemu_irq *pic; > > + > > + uint32_t pcic0_cfgaddr; > > + PCIBus *bus; > > +}; > > + > > +typedef struct ppce500_pci_t ppce500_pci_t; > > + > > +static uint32_t pci_reg_read(void *opaque, > target_phys_addr_t addr, int size) > > +{ > > + ppce500_pci_t *pci = opaque; > > + unsigned long offset = addr - pci->registers, win; > > I don't think this could possibly work now, since a patch > went in a few > weeks back that passes "offset" to MMIO callbacks, instead of "addr". Thanks. Fixed. > > > + uint32_t value = 0; > > + > > + win = offset & 0xfe0; > > + > > + switch (win) { > > + case 0: > > + switch(offset & 0xC) { > > + case PPCE500_PCI_CONFIG_ADDR: > > + value = pci->pcic0_cfgaddr; > > + break; > > + > > + case PPCE500_PCI_CONFIG_DATA: { > > + uint32_t cfgaddr = pci->pcic0_cfgaddr; > > + > > + if (!(cfgaddr & (1<<31))) > > + return 0xffffffff; > > + > > + value = pci_data_read(pci->bus, cfgaddr | (offset & > 0x3), size); > > + > > + if (size == 2) > > + value = cpu_to_le16(value); > > + else if (size == 4) > > + value = cpu_to_le32(value); > > + > > + break; > > + } > > + default:; > > + } > > + break; > > + > > + case PPCE500_PCI_OW1: > > + case PPCE500_PCI_OW2: > > + case PPCE500_PCI_OW3: > > + case PPCE500_PCI_OW4: > > + switch (offset & 0xC) { > > + case PCI_POTAR: value = pci->pob[(offset >> 5) & > 0x7].potar; break; > > + case PCI_POTEAR: value = pci->pob[(offset >> 5) & > 0x7].potear; break; > > + case PCI_POWBAR: value = pci->pob[(offset >> 5) & > 0x7].powbar; break; > > + case PCI_POWAR: value = pci->pob[(offset >> 5) & > 0x7].powar; break; > > + default: break; > > + } > > + break; > > + > > + case PPCE500_PCI_IW3: > > + case PPCE500_PCI_IW2: > > + case PPCE500_PCI_IW1: > > + switch (offset & 0xC) { > > + case PCI_PITAR: value = pci->pib[(offset >> 5) & > 0x3].pitar; break; > > + case PCI_PIWBAR: value = pci->pib[(offset >> 5) & > 0x3].piwbar; break; > > + case PCI_PIWBEAR: value = pci->pib[(offset >> 5) & > 0x3].piwbear; break; > > + case PCI_PIWAR: value = pci->pib[(offset >> 5) & > 0x3].piwar; break; > > + default: break; > > + }; > > + break; > > + > > + case PPCE500_PCI_GAS_TIMR: > > + value = pci->gas_time; > > + break; > > + > > + default: > > + break; > > + } > > + > > + pci_debug("%s: offset:%p -> value:%x\n", __func__, > offset, value); > > + return value; > > +} > > + > > +static uint32_t pci_reg_read1(void *opaque, > target_phys_addr_t addr) > > +{ > > + return pci_reg_read(opaque, addr, 1); > > +} > > + > > +static uint32_t pci_reg_read2(void *opaque, > target_phys_addr_t addr) > > +{ > > + return pci_reg_read(opaque, addr, 2); > > +} > > + > > +static uint32_t pci_reg_read4(void *opaque, > target_phys_addr_t addr) > > +{ > > + return pci_reg_read(opaque, addr, 4); > > +} > > + > > +static CPUReadMemoryFunc *e500_pci_reg_read[] = { > > + &pci_reg_read1, > > + &pci_reg_read2, > > + &pci_reg_read4, > > +}; > > + > > +static void pci_reg_write(void *opaque, target_phys_addr_t addr, > > + uint32_t value, int size) > > +{ > > + ppce500_pci_t *pci = opaque; > > + unsigned long offset = addr - pci->registers, win; > > + > > + pci_debug("%s: value:%x -> offset:%p(addr:%Lx - > base:%Lx)\n", __func__, value, offset, addr, pci->registers); > > + > > + win = offset & 0xfe0; > > + > > + switch (win) { > > + case 0: > > + switch(offset & 0xC) { > > + case PPCE500_PCI_CONFIG_ADDR: > > + pci->pcic0_cfgaddr = value & ~0x3; > > + break; > > + > > + case PPCE500_PCI_CONFIG_DATA: > > + if (size == 2) > > + value = le16_to_cpu(value); > > + else if (size == 4) > > + value = le32_to_cpu(value); > > + > > + pci_data_write(pci->bus, pci->pcic0_cfgaddr | > (offset & 0x3), > > + value, size); > > + break; > > + default: > > + break; > > + }; > > + break; > > + > > + case PPCE500_PCI_OW1: > > + case PPCE500_PCI_OW2: > > + case PPCE500_PCI_OW3: > > + case PPCE500_PCI_OW4: > > + switch (offset & 0xC) { > > + case PCI_POTAR: pci->pob[(offset >> 5) & 0x7].potar = > value; break; > > + case PCI_POTEAR: pci->pob[(offset >> 5) & 0x7].potear = > value; break; > > + case PCI_POWBAR: pci->pob[(offset >> 5) & 0x7].powbar = > value; break; > > + case PCI_POWAR: pci->pob[(offset >> 5) & 0x7].powar = > value; break; > > + default: break; > > + }; > > + break; > > + > > + case PPCE500_PCI_IW3: > > + case PPCE500_PCI_IW2: > > + case PPCE500_PCI_IW1: > > + switch (offset & 0xC) { > > + case PCI_PITAR: pci->pib[(offset >> 5) & 0x3].pitar = > value; break; > > + case PCI_PIWBAR: pci->pib[(offset >> 5) & 0x3].piwbar = > value; break; > > + case PCI_PIWBEAR: pci->pib[(offset >> 5) & 0x3].piwbear > = value; break; > > + case PCI_PIWAR: pci->pib[(offset >> 5) & 0x3].piwar = > value; break; > > + default: break; > > + }; > > + break; > > + > > + case PPCE500_PCI_GAS_TIMR: > > + pci->gas_time = value; > > + break; > > + > > + default: > > + break; > > + }; > > +} > > + > > +static void pci_reg_write1(void *opaque, target_phys_addr_t addr, > > + uint32_t value) > > +{ > > + pci_reg_write(opaque, addr, value, 1); > > +} > > + > > +static void pci_reg_write2(void *opaque, target_phys_addr_t addr, > > + uint32_t value) > > +{ > > + pci_reg_write(opaque, addr, value, 2); > > +} > > + > > +static void pci_reg_write4(void *opaque, target_phys_addr_t addr, > > + uint32_t value) > > +{ > > + pci_reg_write(opaque, addr, value, 4); > > +} > > + > > +static CPUWriteMemoryFunc *e500_pci_reg_write[] = { > > + &pci_reg_write1, > > + &pci_reg_write2, > > + &pci_reg_write4, > > +}; > > + > > +static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num) > > +{ > > + int devno = pci_dev->devfn >> 3, ret = 0; > > + > > + switch (devno) { > > + /* Two PCI slot */ > > + case 0x11: > > + case 0x12: > > + ret = (irq_num + devno - 0x10) % 4; > > + break; > > + default: > > + printf("Error:%s:unknow dev number\n", __func__); > > + } > > + > > + pci_debug("%s: devfn %x irq %d -> %d devno:%x\n", __func__, > > + pci_dev->devfn, irq_num, ret, devno); > > + > > + return ret; > > +} > > + > > +static void mpc85xx_pci_set_irq(qemu_irq *pic, int > irq_num, int level) > > +{ > > + pci_debug("%s: PCI irq %d, level:%d\n", __func__, > irq_num, level); > > + > > + qemu_set_irq(pic[irq_num], level); > > +} > > + > > +PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], > target_phys_addr_t registers) > > +{ > > + ppce500_pci_t *pci; > > + PCIDevice *d; > > + int index; > > + > > + pci = qemu_mallocz(sizeof(ppce500_pci_t)); > > + if (!pci) > > + return NULL; > > + > > + pci->registers = registers; > > + pci->pic = pci_irqs; > > + > > + pci->bus = pci_register_bus(mpc85xx_pci_set_irq, > mpc85xx_pci_map_irq, > > + pci_irqs, 0x88, 4); > > + d = pci_register_device(pci->bus, "host bridge", > sizeof(PCIDevice), > > + 0, NULL, NULL); > > + > > + d->config[0x00] = 0x57; // vendor_id > > + d->config[0x01] = 0x19; > > + d->config[0x02] = 0x30; // device_id > > + d->config[0x03] = 0x00; > > + d->config[0x0a] = 0x20; // class_sub = other bridge type > > + d->config[0x0b] = 0x0B; // class_base = PCI_bridge > > + > > + index = cpu_register_io_memory(0, e500_pci_reg_read, > > + e500_pci_reg_write, pci); > > + if (index < 0) > > + goto free; > > + cpu_register_physical_memory(registers, > PPCE500_PCI_REG_SIZE, index); > > + > > + /* XXX register_savevm() */ > > savevm() isn't hard to implement, even if you can't test it. > > > + return pci->bus; > > + > > +free: > > + printf("%s error\n", __func__); > > + qemu_free(pci); > > + return NULL; > > +} > > + > > I suspect the byteswapping isn't correct here, so it wouldn't > work on an > LE host. It swaps the config space value. I don't think I have to swap the internal register value as well. As LE host will store LE value into register. Unless you mean emulating a LE guest on a BE host... > > Is this PCI controller shared with any chips qemu currently > implements? > If so, you should add it to those platforms (and you could > test it with > plain qemu that way, since the e500 MMU isn't emulated). > Seems no this kind of chip. The controller is developed by freescale, seem only exists in freescale's chips. -- To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html