PPC: Uninorth config space accessor

The Uninorth PCI bridge requires different layouts in its PCI config space
accessors.

This patch introduces a conversion function that makes it compatible with
the way Linux accesses it.

I also kept an OpenBIOS compatibility hack in. I think it'd be better to
take small steps here and do the config space access rework in OpenBIOS
later on. When that's done we can remove that hack.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Alexander Graf 2010-02-09 17:37:01 +01:00 committed by Michael S. Tsirkin
parent 9f6f0423cf
commit d86f0e32c6

View File

@ -39,6 +39,7 @@
typedef struct UNINState { typedef struct UNINState {
SysBusDevice busdev; SysBusDevice busdev;
PCIHostState host_state; PCIHostState host_state;
ReadWriteHandler data_handler;
} UNINState; } UNINState;
/* Don't know if this matches real hardware, but it agrees with OHW. */ /* Don't know if this matches real hardware, but it agrees with OHW. */
@ -75,6 +76,68 @@ static void pci_unin_reset(void *opaque)
{ {
} }
static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
{
uint32_t retval;
if (reg & (1u << 31)) {
/* XXX OpenBIOS compatibility hack */
retval = reg | (addr & 3);
} else if (reg & 1) {
/* CFA1 style */
retval = (reg & ~7u) | (addr & 7);
} else {
uint32_t slot, func;
/* Grab CFA0 style values */
slot = ffs(reg & 0xfffff800) - 1;
func = (reg >> 8) & 7;
/* ... and then convert them to x86 format */
/* config pointer */
retval = (reg & (0xff - 7)) | (addr & 7);
/* slot */
retval |= slot << 11;
/* fn */
retval |= func << 8;
}
UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n",
reg, addr, retval);
return retval;
}
static void unin_data_write(ReadWriteHandler *handler,
pcibus_t addr, uint32_t val, int len)
{
UNINState *s = container_of(handler, UNINState, data_handler);
#ifdef TARGET_WORDS_BIGENDIAN
val = qemu_bswap_len(val, len);
#endif
UNIN_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
pci_data_write(s->host_state.bus,
unin_get_config_reg(s->host_state.config_reg, addr),
val, len);
}
static uint32_t unin_data_read(ReadWriteHandler *handler,
pcibus_t addr, int len)
{
UNINState *s = container_of(handler, UNINState, data_handler);
uint32_t val;
val = pci_data_read(s->host_state.bus,
unin_get_config_reg(s->host_state.config_reg, addr),
len);
UNIN_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val);
#ifdef TARGET_WORDS_BIGENDIAN
val = qemu_bswap_len(val, len);
#endif
return val;
}
static int pci_unin_main_init_device(SysBusDevice *dev) static int pci_unin_main_init_device(SysBusDevice *dev)
{ {
UNINState *s; UNINState *s;
@ -85,7 +148,9 @@ static int pci_unin_main_init_device(SysBusDevice *dev)
s = FROM_SYSBUS(UNINState, dev); s = FROM_SYSBUS(UNINState, dev);
pci_mem_config = pci_host_conf_register_mmio(&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); s->data_handler.read = unin_data_read;
s->data_handler.write = unin_data_write;
pci_mem_data = cpu_register_io_memory_simple(&s->data_handler);
sysbus_init_mmio(dev, 0x1000, pci_mem_config); sysbus_init_mmio(dev, 0x1000, pci_mem_config);
sysbus_init_mmio(dev, 0x1000, pci_mem_data); sysbus_init_mmio(dev, 0x1000, pci_mem_data);