On Sun, Jan 03, 2010 at 02:50:45AM +0100, Alexander Graf wrote: > Different host buses may have different layouts for config space accessors. > > The Mac U3 for example uses the following define to access Type 0 (directly > attached) devices: > > #define MACRISC_CFA0(devfn, off) \ > ((1 << (unsigned int)PCI_SLOT(dev_fn)) \ > | (((unsigned int)PCI_FUNC(dev_fn)) << 8) \ > | (((unsigned int)(off)) & 0xFCUL)) > > Obviously, this is different from the encoding we interpret in qemu. In > order to let host controllers take some influence there, we can just > introduce a converter function that takes whatever accessor we have and > makes a qemu understandable one out of it. > > This patch is the groundwork for Uninorth PCI config space fixes. > > Signed-off-by: Alexander Graf <ag...@suse.de> > CC: Michael S. Tsirkin <m...@redhat.com>
Thanks! It always bothered me that the code in pci_host uses x86 encoding and other architectures are converted to x86. As long as we are adding redirection, maybe we should get rid of this, and make get_config_reg return register and devfn separately, so we don't need to encode/decode back and forth? OTOH if we are after a quick fix, won't it be simpler to have unin_pci simply use its own routines instead of pci_host_conf_register_mmio etc? > --- > hw/apb_pci.c | 1 + > hw/grackle_pci.c | 1 + > hw/gt64xxx.c | 1 + > hw/pci_host.c | 11 +++++++++++ > hw/pci_host.h | 5 +++++ > hw/pci_host_template.h | 30 ++++++++++++++++++------------ > hw/piix_pci.c | 1 + > hw/ppc4xx_pci.c | 1 + > hw/ppce500_pci.c | 1 + > hw/unin_pci.c | 1 + > 10 files changed, 41 insertions(+), 12 deletions(-) > > diff --git a/hw/apb_pci.c b/hw/apb_pci.c > index f05308b..fedb84c 100644 > --- a/hw/apb_pci.c > +++ b/hw/apb_pci.c > @@ -222,6 +222,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base, > /* mem_data */ > sysbus_mmio_map(s, 3, mem_base); > d = FROM_SYSBUS(APBState, s); > + pci_host_init(&d->host_state); > d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", > pci_apb_set_irq, pci_pbm_map_irq, > pic, > 0, 32); > diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c > index ee4fed5..7feba63 100644 > --- a/hw/grackle_pci.c > +++ b/hw/grackle_pci.c > @@ -88,6 +88,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic) > qdev_init_nofail(dev); > s = sysbus_from_qdev(dev); > d = FROM_SYSBUS(GrackleState, s); > + pci_host_init(&d->host_state); > d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", > pci_grackle_set_irq, > pci_grackle_map_irq, > diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c > index fb7f5bd..8cf93ca 100644 > --- a/hw/gt64xxx.c > +++ b/hw/gt64xxx.c > @@ -1120,6 +1120,7 @@ PCIBus *pci_gt64120_init(qemu_irq *pic) > s = qemu_mallocz(sizeof(GT64120State)); > s->pci = qemu_mallocz(sizeof(GT64120PCIState)); > > + pci_host_init(s->pci); > s->pci->bus = pci_register_bus(NULL, "pci", > pci_gt64120_set_irq, pci_gt64120_map_irq, > pic, 144, 4); > diff --git a/hw/pci_host.c b/hw/pci_host.c > index eeb8dee..2d12887 100644 > --- a/hw/pci_host.c > +++ b/hw/pci_host.c > @@ -228,3 +228,14 @@ void pci_host_data_register_ioport(pio_addr_t ioport, > PCIHostState *s) > register_ioport_read(ioport, 4, 2, pci_host_data_readw_ioport, s); > register_ioport_read(ioport, 4, 4, pci_host_data_readl_ioport, s); > } > + > +/* This implements the default x86 way of interpreting the config register */ > +static uint32_t pci_host_get_config_reg(PCIHostState *s, uint32_t addr) > +{ > + return s->config_reg | (addr & 3); > +} > + > +void pci_host_init(PCIHostState *s) > +{ > + s->get_config_reg = pci_host_get_config_reg; > +} So config_reg is always set but only used for PC now? This is not very pretty ... > diff --git a/hw/pci_host.h b/hw/pci_host.h > index a006687..90a4c63 100644 > --- a/hw/pci_host.h > +++ b/hw/pci_host.h > @@ -30,14 +30,19 @@ > > #include "sysbus.h" > > +/* for config space access */ > +typedef uint32_t (*pci_config_reg_fn)(PCIHostState *s, uint32_t addr); > + > struct PCIHostState { > SysBusDevice busdev; > + pci_config_reg_fn get_config_reg; > uint32_t config_reg; > PCIBus *bus; > }; > > void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len); > uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len); > +void pci_host_init(PCIHostState *s); > > /* for mmio */ > int pci_host_conf_register_mmio(PCIHostState *s); > diff --git a/hw/pci_host_template.h b/hw/pci_host_template.h > index 11e6c88..55aa85e 100644 > --- a/hw/pci_host_template.h > +++ b/hw/pci_host_template.h > @@ -29,48 +29,52 @@ static void glue(pci_host_data_writeb, PCI_HOST_SUFFIX)( > void* opaque, PCI_ADDR_T addr, uint32_t val) > { > PCIHostState *s = opaque; > + uint32_t config_reg = s->get_config_reg(s, (uint32_t)addr); > > PCI_DPRINTF("writeb addr " TARGET_FMT_plx " val %x\n", > (target_phys_addr_t)addr, val); > - if (s->config_reg & (1u << 31)) > - pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1); > + if (config_reg & (1u << 31)) > + pci_data_write(s->bus, config_reg, val, 1); > } > > static void glue(pci_host_data_writew, PCI_HOST_SUFFIX)( > void* opaque, PCI_ADDR_T addr, uint32_t val) > { > PCIHostState *s = opaque; > + uint32_t config_reg = s->get_config_reg(s, (uint32_t)addr); > #ifdef TARGET_WORDS_BIGENDIAN > val = bswap16(val); > #endif > PCI_DPRINTF("writew addr " TARGET_FMT_plx " val %x\n", > (target_phys_addr_t)addr, val); > - if (s->config_reg & (1u << 31)) > - pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2); > + if (config_reg & (1u << 31)) > + pci_data_write(s->bus, config_reg, val, 2); > } > > static void glue(pci_host_data_writel, PCI_HOST_SUFFIX)( > void* opaque, PCI_ADDR_T addr, uint32_t val) > { > PCIHostState *s = opaque; > + uint32_t config_reg = s->get_config_reg(s, (uint32_t)addr); > #ifdef TARGET_WORDS_BIGENDIAN > val = bswap32(val); > #endif > PCI_DPRINTF("writel addr " TARGET_FMT_plx " val %x\n", > (target_phys_addr_t)addr, val); > - if (s->config_reg & (1u << 31)) > - pci_data_write(s->bus, s->config_reg, val, 4); > + if (config_reg & (1u << 31)) > + pci_data_write(s->bus, config_reg, val, 4); > } > > static uint32_t glue(pci_host_data_readb, PCI_HOST_SUFFIX)( > void* opaque, PCI_ADDR_T addr) > { > PCIHostState *s = opaque; > + uint32_t config_reg = s->get_config_reg(s, (uint32_t)addr); > uint32_t val; > > - if (!(s->config_reg & (1 << 31))) > + if (!(config_reg & (1 << 31))) > return 0xff; > - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 1); > + val = pci_data_read(s->bus, config_reg, 1); > PCI_DPRINTF("readb addr " TARGET_FMT_plx " val %x\n", > (target_phys_addr_t)addr, val); > return val; > @@ -80,10 +84,11 @@ static uint32_t glue(pci_host_data_readw, > PCI_HOST_SUFFIX)( > void* opaque, PCI_ADDR_T addr) > { > PCIHostState *s = opaque; > + uint32_t config_reg = s->get_config_reg(s, (uint32_t)addr); > uint32_t val; > - if (!(s->config_reg & (1 << 31))) > + if (!(config_reg & (1 << 31))) > return 0xffff; > - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2); > + val = pci_data_read(s->bus, config_reg, 2); > PCI_DPRINTF("readw addr " TARGET_FMT_plx " val %x\n", > (target_phys_addr_t)addr, val); > #ifdef TARGET_WORDS_BIGENDIAN > @@ -96,10 +101,11 @@ static uint32_t glue(pci_host_data_readl, > PCI_HOST_SUFFIX)( > void* opaque, PCI_ADDR_T addr) > { > PCIHostState *s = opaque; > + uint32_t config_reg = s->get_config_reg(s, (uint32_t)addr); > uint32_t val; > - if (!(s->config_reg & (1 << 31))) > + if (!(config_reg)) > return 0xffffffff; > - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4); > + val = pci_data_read(s->bus, config_reg, 4); > PCI_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n", > (target_phys_addr_t)addr, val); > #ifdef TARGET_WORDS_BIGENDIAN > diff --git a/hw/piix_pci.c b/hw/piix_pci.c > index 1b67475..97500e0 100644 > --- a/hw/piix_pci.c > +++ b/hw/piix_pci.c > @@ -211,6 +211,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int > *piix3_devfn, qemu_irq * > > dev = qdev_create(NULL, "i440FX-pcihost"); > s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev)); > + pci_host_init(s); > b = pci_bus_new(&s->busdev.qdev, NULL, 0); > s->bus = b; > qdev_init_nofail(dev); > diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c > index 2d00b61..dd8e290 100644 > --- a/hw/ppc4xx_pci.c > +++ b/hw/ppc4xx_pci.c > @@ -357,6 +357,7 @@ PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq > pci_irqs[4], > > controller = qemu_mallocz(sizeof(PPC4xxPCIState)); > > + pci_host_init(&controller->pci_state); > controller->pci_state.bus = pci_register_bus(NULL, "pci", > ppc4xx_pci_set_irq, > ppc4xx_pci_map_irq, > diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c > index a72fb86..5914183 100644 > --- a/hw/ppce500_pci.c > +++ b/hw/ppce500_pci.c > @@ -278,6 +278,7 @@ PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], > target_phys_addr_t registers) > > controller = qemu_mallocz(sizeof(PPCE500PCIState)); > > + pci_host_init(&controller->pci_state); > controller->pci_state.bus = pci_register_bus(NULL, "pci", > mpc85xx_pci_set_irq, > mpc85xx_pci_map_irq, > diff --git a/hw/unin_pci.c b/hw/unin_pci.c > index 3ae4e7a..fdb9401 100644 > --- a/hw/unin_pci.c > +++ b/hw/unin_pci.c > @@ -84,6 +84,7 @@ static int pci_unin_main_init_device(SysBusDevice *dev) > /* Uninorth main bus */ > s = FROM_SYSBUS(UNINState, dev); > > + pci_host_init(&s->host_state); > pci_mem_config = pci_host_conf_register_mmio(&s->host_state); > pci_mem_data = pci_host_data_register_mmio(&s->host_state); > sysbus_init_mmio(dev, 0x1000, pci_mem_config); > -- > 1.6.0.2 > >