On 3/27/25 21:50, BALATON Zoltan wrote:
On Thu, 27 Mar 2025, rakeshj wrote:
The GT-64120 PCI controller requires special handling where:
1. Host bridge (device 0) must use native endianness
2. Other devices follow MByteSwap bit in GT_PCI0_CMD

Previous implementation accidentally swapped all accesses, breaking
host bridge detection (lspci -d 11ab:4620). This fix:

- Adds device filtering via (phb->config_reg & 0x00FFF800)
- Preserves native endianness for host bridge
- Maintains swapping for other devices in big-endian mode

Fixes: 145e2198 ("hw/mips/gt64xxx_pci: Endian-swap using PCI_HOST_BRIDGE MemoryRegionOps")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2826
Signed-off-by: rakeshj <rakeshjb...@gmail.com>
---
hw/pci-host/gt64120.c | 37 ++++++++++++++++++++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)

diff --git a/hw/pci-host/gt64120.c b/hw/pci-host/gt64120.c
index d5c13a89b6..098f8e5988 100644
--- a/hw/pci-host/gt64120.c
+++ b/hw/pci-host/gt64120.c
@@ -320,11 +320,46 @@ static void gt64120_isd_mapping(GT64120State *s)
    memory_region_transaction_commit();
}

+static uint64_t gt64120_pci_data_read(void *opaque, hwaddr addr, unsigned size)
+{
+    GT64120State *s = opaque;
+    PCIHostState *phb = PCI_HOST_BRIDGE(s);
+    uint32_t val = pci_data_read(phb->bus, phb->config_reg, size);
+
+    /* Only swap for non-bridge devices in big-endian mode */
+    if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) {
+        val = bswap32(val);

I don't know if this is the best way to fix this issue as I don't know what the issue is in the first place (isn't PCI usually little endian?)

Yes but this particular PCI host bridge is the exception, as it is the only user of pci_host_data_be_ops.

but I think you can't just use bswap here because it also needs to take into account the endianness of the host QEMU is running on.

It should be fine.  You should take into account:

- the endianness produced by pci_data_read/pci_data_write (always little endian)

- the endianness expected by the guest (big endian under the conditions in the patch)

- the endianness expected by memory.c (always little endian, as specified in gt64120_pci_data_ops)

Because there is either zero or one mismatch, bswap32 is fine.

*However*, there is some extra complication that is unnecessary after this patch:

- right now the !(s->regs[GT_PCI0_CMD] & 1) that you have added is dead code: if it was ever 1, gt64120_update_pci_cfgdata_mapping() would pick pci_host_data_ops[1] and gt64120_pci_data_read/write would not run at all!

- but alternatively you could keep that conditional, and get rid completely of gt64120_update_pci_cfgdata_mapping(). Just keep the initialization code

    memory_region_init_io(&phb->data_mem, OBJECT(phb),
                          &gt64120_pci_data_ops,
                          s, "pci-conf-data", 4);
    memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2,
                                        &phb->data_mem, 1);

at the end of gt64120_realize() where the sister region phb->conf_mem is already being initialized. This would actually make me happy.

Either way, pci_host_data_be_ops is dead after this patch and you can remove it; and since you are at it, you may also want to remove the wrong comment

    /*
     * PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops,
     * so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops.
     */

in include/hw/pci-host/dino.h: DINO emulation has *never* used pci_host_data_be_ops.

This has snowballed a bit, but it should not be a problem. :)

Paolo


Reply via email to