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> --- 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; +} 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