mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-31 06:13:53 -06:00
hw/pci-host/gt64120: Fix endianness handling
The GT-64120 PCI controller requires special handling where:
1. Host bridge(bus 0 ,device 0) must never be byte-swapped
2. Other devices follow MByteSwap bit in GT_PCI0_CMD
The previous implementation incorrectly swapped all accesses, breaking
host bridge detection (lspci -d 11ab:4620).
Changes made:
1. Removed gt64120_update_pci_cfgdata_mapping() and moved data_mem initialization
to gt64120_realize() for cleaner setup
2. Implemented custom read/write handlers that:
- Preserve host bridge accesses (extract32(config_reg,11,13)==0)
- apply swapping only for non-bridge 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: Rakesh Jeyasingh <rakeshjb010@gmail.com>
Tested-by: Thomas Huth <thuth@redhat.com>
Link: https://lore.kernel.org/r/20250429170354.150581-2-rakeshjb010@gmail.com
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
7a48612306
commit
e5894fd6f4
1 changed files with 48 additions and 34 deletions
|
@ -320,38 +320,6 @@ static void gt64120_isd_mapping(GT64120State *s)
|
|||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
static void gt64120_update_pci_cfgdata_mapping(GT64120State *s)
|
||||
{
|
||||
/* Indexed on MByteSwap bit, see Table 158: PCI_0 Command, Offset: 0xc00 */
|
||||
static const MemoryRegionOps *pci_host_data_ops[] = {
|
||||
&pci_host_data_be_ops, &pci_host_data_le_ops
|
||||
};
|
||||
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
||||
|
||||
memory_region_transaction_begin();
|
||||
|
||||
/*
|
||||
* The setting of the MByteSwap bit and MWordSwap bit in the PCI Internal
|
||||
* Command Register determines how data transactions from the CPU to/from
|
||||
* PCI are handled along with the setting of the Endianness bit in the CPU
|
||||
* Configuration Register. See:
|
||||
* - Table 16: 32-bit PCI Transaction Endianness
|
||||
* - Table 158: PCI_0 Command, Offset: 0xc00
|
||||
*/
|
||||
|
||||
if (memory_region_is_mapped(&phb->data_mem)) {
|
||||
memory_region_del_subregion(&s->ISD_mem, &phb->data_mem);
|
||||
object_unparent(OBJECT(&phb->data_mem));
|
||||
}
|
||||
memory_region_init_io(&phb->data_mem, OBJECT(phb),
|
||||
pci_host_data_ops[s->regs[GT_PCI0_CMD] & 1],
|
||||
s, "pci-conf-data", 4);
|
||||
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2,
|
||||
&phb->data_mem, 1);
|
||||
|
||||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
static void gt64120_pci_mapping(GT64120State *s)
|
||||
{
|
||||
memory_region_transaction_begin();
|
||||
|
@ -645,7 +613,6 @@ static void gt64120_writel(void *opaque, hwaddr addr,
|
|||
case GT_PCI0_CMD:
|
||||
case GT_PCI1_CMD:
|
||||
s->regs[saddr] = val & 0x0401fc0f;
|
||||
gt64120_update_pci_cfgdata_mapping(s);
|
||||
break;
|
||||
case GT_PCI0_TOR:
|
||||
case GT_PCI0_BS_SCS10:
|
||||
|
@ -1024,6 +991,48 @@ static const MemoryRegionOps isd_mem_ops = {
|
|||
},
|
||||
};
|
||||
|
||||
static bool bswap(const GT64120State *s)
|
||||
{
|
||||
PCIHostState *phb = PCI_HOST_BRIDGE(s);
|
||||
/*check for bus == 0 && device == 0, Bits 11:15 = Device , Bits 16:23 = Bus*/
|
||||
bool is_phb_dev0 = extract32(phb->config_reg, 11, 13) == 0;
|
||||
bool le_mode = FIELD_EX32(s->regs[GT_PCI0_CMD], GT_PCI0_CMD, MByteSwap);
|
||||
/* Only swap for non-bridge devices in big-endian mode */
|
||||
return !le_mode && !is_phb_dev0;
|
||||
}
|
||||
|
||||
static uint64_t gt64120_pci_data_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
GT64120State *s = opaque;
|
||||
uint32_t val = pci_host_data_le_ops.read(opaque, addr, size);
|
||||
|
||||
if (bswap(s)) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void gt64120_pci_data_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
GT64120State *s = opaque;
|
||||
|
||||
if (bswap(s)) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
pci_host_data_le_ops.write(opaque, addr, val, size);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps gt64120_pci_data_ops = {
|
||||
.read = gt64120_pci_data_read,
|
||||
.write = gt64120_pci_data_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static void gt64120_reset(DeviceState *dev)
|
||||
{
|
||||
GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev);
|
||||
|
@ -1178,7 +1187,6 @@ static void gt64120_reset(DeviceState *dev)
|
|||
|
||||
gt64120_isd_mapping(s);
|
||||
gt64120_pci_mapping(s);
|
||||
gt64120_update_pci_cfgdata_mapping(s);
|
||||
}
|
||||
|
||||
static void gt64120_realize(DeviceState *dev, Error **errp)
|
||||
|
@ -1202,6 +1210,12 @@ static void gt64120_realize(DeviceState *dev, Error **errp)
|
|||
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGADDR << 2,
|
||||
&phb->conf_mem, 1);
|
||||
|
||||
memory_region_init_io(&phb->data_mem, OBJECT(phb),
|
||||
>64120_pci_data_ops,
|
||||
s, "pci-conf-data", 4);
|
||||
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2,
|
||||
&phb->data_mem, 1);
|
||||
|
||||
|
||||
/*
|
||||
* The whole address space decoded by the GT-64120A doesn't generate
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue