Skip to content

Commit cdf3fb0

Browse files
blackjackal010Michael Tokarev
authored andcommitted
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: 145e219 ("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 <[email protected]> Tested-by: Thomas Huth <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Bonzini <[email protected]> (cherry picked from commit e5894fd) Signed-off-by: Michael Tokarev <[email protected]>
1 parent 3e59fcc commit cdf3fb0

File tree

1 file changed

+48
-34
lines changed

1 file changed

+48
-34
lines changed

hw/pci-host/gt64120.c

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -320,38 +320,6 @@ static void gt64120_isd_mapping(GT64120State *s)
320320
memory_region_transaction_commit();
321321
}
322322

323-
static void gt64120_update_pci_cfgdata_mapping(GT64120State *s)
324-
{
325-
/* Indexed on MByteSwap bit, see Table 158: PCI_0 Command, Offset: 0xc00 */
326-
static const MemoryRegionOps *pci_host_data_ops[] = {
327-
&pci_host_data_be_ops, &pci_host_data_le_ops
328-
};
329-
PCIHostState *phb = PCI_HOST_BRIDGE(s);
330-
331-
memory_region_transaction_begin();
332-
333-
/*
334-
* The setting of the MByteSwap bit and MWordSwap bit in the PCI Internal
335-
* Command Register determines how data transactions from the CPU to/from
336-
* PCI are handled along with the setting of the Endianness bit in the CPU
337-
* Configuration Register. See:
338-
* - Table 16: 32-bit PCI Transaction Endianness
339-
* - Table 158: PCI_0 Command, Offset: 0xc00
340-
*/
341-
342-
if (memory_region_is_mapped(&phb->data_mem)) {
343-
memory_region_del_subregion(&s->ISD_mem, &phb->data_mem);
344-
object_unparent(OBJECT(&phb->data_mem));
345-
}
346-
memory_region_init_io(&phb->data_mem, OBJECT(phb),
347-
pci_host_data_ops[s->regs[GT_PCI0_CMD] & 1],
348-
s, "pci-conf-data", 4);
349-
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2,
350-
&phb->data_mem, 1);
351-
352-
memory_region_transaction_commit();
353-
}
354-
355323
static void gt64120_pci_mapping(GT64120State *s)
356324
{
357325
memory_region_transaction_begin();
@@ -645,7 +613,6 @@ static void gt64120_writel(void *opaque, hwaddr addr,
645613
case GT_PCI0_CMD:
646614
case GT_PCI1_CMD:
647615
s->regs[saddr] = val & 0x0401fc0f;
648-
gt64120_update_pci_cfgdata_mapping(s);
649616
break;
650617
case GT_PCI0_TOR:
651618
case GT_PCI0_BS_SCS10:
@@ -1024,6 +991,48 @@ static const MemoryRegionOps isd_mem_ops = {
1024991
},
1025992
};
1026993

994+
static bool bswap(const GT64120State *s)
995+
{
996+
PCIHostState *phb = PCI_HOST_BRIDGE(s);
997+
/*check for bus == 0 && device == 0, Bits 11:15 = Device , Bits 16:23 = Bus*/
998+
bool is_phb_dev0 = extract32(phb->config_reg, 11, 13) == 0;
999+
bool le_mode = FIELD_EX32(s->regs[GT_PCI0_CMD], GT_PCI0_CMD, MByteSwap);
1000+
/* Only swap for non-bridge devices in big-endian mode */
1001+
return !le_mode && !is_phb_dev0;
1002+
}
1003+
1004+
static uint64_t gt64120_pci_data_read(void *opaque, hwaddr addr, unsigned size)
1005+
{
1006+
GT64120State *s = opaque;
1007+
uint32_t val = pci_host_data_le_ops.read(opaque, addr, size);
1008+
1009+
if (bswap(s)) {
1010+
val = bswap32(val);
1011+
}
1012+
return val;
1013+
}
1014+
1015+
static void gt64120_pci_data_write(void *opaque, hwaddr addr,
1016+
uint64_t val, unsigned size)
1017+
{
1018+
GT64120State *s = opaque;
1019+
1020+
if (bswap(s)) {
1021+
val = bswap32(val);
1022+
}
1023+
pci_host_data_le_ops.write(opaque, addr, val, size);
1024+
}
1025+
1026+
static const MemoryRegionOps gt64120_pci_data_ops = {
1027+
.read = gt64120_pci_data_read,
1028+
.write = gt64120_pci_data_write,
1029+
.endianness = DEVICE_LITTLE_ENDIAN,
1030+
.valid = {
1031+
.min_access_size = 4,
1032+
.max_access_size = 4,
1033+
},
1034+
};
1035+
10271036
static void gt64120_reset(DeviceState *dev)
10281037
{
10291038
GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev);
@@ -1178,7 +1187,6 @@ static void gt64120_reset(DeviceState *dev)
11781187

11791188
gt64120_isd_mapping(s);
11801189
gt64120_pci_mapping(s);
1181-
gt64120_update_pci_cfgdata_mapping(s);
11821190
}
11831191

11841192
static void gt64120_realize(DeviceState *dev, Error **errp)
@@ -1202,6 +1210,12 @@ static void gt64120_realize(DeviceState *dev, Error **errp)
12021210
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGADDR << 2,
12031211
&phb->conf_mem, 1);
12041212

1213+
memory_region_init_io(&phb->data_mem, OBJECT(phb),
1214+
&gt64120_pci_data_ops,
1215+
s, "pci-conf-data", 4);
1216+
memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2,
1217+
&phb->data_mem, 1);
1218+
12051219

12061220
/*
12071221
* The whole address space decoded by the GT-64120A doesn't generate

0 commit comments

Comments
 (0)