diff --git a/hw/ppc/ppc440_pcix.c b/hw/ppc/ppc440_pcix.c index 7829d3e556..91cbcd0504 100644 --- a/hw/ppc/ppc440_pcix.c +++ b/hw/ppc/ppc440_pcix.c @@ -449,28 +449,35 @@ static AddressSpace *ppc440_pcix_set_iommu(PCIBus *b, void *opaque, int devfn) return &s->bm_as; } -/* The default pci_host_data_{read,write} functions in pci/pci_host.c - * deny access to registers without bit 31 set but our clients want - * this to work so we have to override these here */ -static void pci_host_data_write(void *opaque, hwaddr addr, - uint64_t val, unsigned len) +/* + * Some guests on sam460ex write all kinds of garbage here such as + * missing enable bit and low bits set and still expect this to work + * (apparently it does on real hardware because these boot there) so + * we have to override these ops here and fix it up + */ +static void pci_host_config_write(void *opaque, hwaddr addr, + uint64_t val, unsigned len) { PCIHostState *s = opaque; - pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); + + if (addr != 0 || len != 4) { + return; + } + s->config_reg = (val & 0xfffffffcULL) | (1UL << 31); } -static uint64_t pci_host_data_read(void *opaque, - hwaddr addr, unsigned len) +static uint64_t pci_host_config_read(void *opaque, hwaddr addr, + unsigned len) { PCIHostState *s = opaque; - uint32_t val; - val = pci_data_read(s->bus, s->config_reg | (addr & 3), len); + uint32_t val = s->config_reg; + return val; } -const MemoryRegionOps ppc440_pcix_host_data_ops = { - .read = pci_host_data_read, - .write = pci_host_data_write, +const MemoryRegionOps ppc440_pcix_host_conf_ops = { + .read = pci_host_config_read, + .write = pci_host_config_write, .endianness = DEVICE_LITTLE_ENDIAN, }; @@ -497,9 +504,9 @@ static void ppc440_pcix_realize(DeviceState *dev, Error **errp) pci_setup_iommu(h->bus, ppc440_pcix_set_iommu, s); memory_region_init(&s->container, OBJECT(s), "pci-container", PCI_ALL_SIZE); - memory_region_init_io(&h->conf_mem, OBJECT(s), &pci_host_conf_le_ops, + memory_region_init_io(&h->conf_mem, OBJECT(s), &ppc440_pcix_host_conf_ops, h, "pci-conf-idx", 4); - memory_region_init_io(&h->data_mem, OBJECT(s), &ppc440_pcix_host_data_ops, + memory_region_init_io(&h->data_mem, OBJECT(s), &pci_host_data_le_ops, h, "pci-conf-data", 4); memory_region_init_io(&s->iomem, OBJECT(s), &pci_reg_ops, s, "pci.reg", PPC440_REG_SIZE);