> -----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

Reply via email to