hw/mips/gt64xxx_pci: Endian-swap using PCI_HOST_BRIDGE MemoryRegionOps
GT64120's PCI endianness swapping works on little-endian hosts, but doesn't on big-endian ones. Instead of complicating how CFGADDR/CFGDATA registers deal with endianness, use the existing MemoryRegionOps from hw/pci/pci_host.c. Doing so also reduce the access to internal PCI_HOST_BRIDGE fields. Map the PCI_HOST_BRIDGE MemoryRegionOps into the corresponding CFGADDR/CFGDATA regions in the ISD MMIO and remove the unused code in the current ISD read/write handlers. Update the mapping when PCI0_CMD register is accessed (in case the endianness is changed). This allows using the GT64120 on a big-endian host (and boot the MIPS Malta machine in little-endian). Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20230104133935.4639-6-philmd@linaro.org>
This commit is contained in:
		| @@ -298,6 +298,50 @@ 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_conf_ops[] = { | ||||
|         &pci_host_conf_be_ops, &pci_host_conf_le_ops | ||||
|     }; | ||||
|     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 Endianess bit in the CPU | ||||
|      * Configuration Register. See: | ||||
|      * - Table 16: 32-bit PCI Transaction Endianess | ||||
|      * - Table 158: PCI_0 Command, Offset: 0xc00 | ||||
|      */ | ||||
|     if (memory_region_is_mapped(&phb->conf_mem)) { | ||||
|         memory_region_del_subregion(&s->ISD_mem, &phb->conf_mem); | ||||
|         object_unparent(OBJECT(&phb->conf_mem)); | ||||
|     } | ||||
|     memory_region_init_io(&phb->conf_mem, OBJECT(phb), | ||||
|                           pci_host_conf_ops[s->regs[GT_PCI0_CMD] & 1], | ||||
|                           s, "pci-conf-idx", 4); | ||||
|     memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGADDR << 2, | ||||
|                                         &phb->conf_mem, 1); | ||||
|  | ||||
|     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(); | ||||
| @@ -389,7 +433,6 @@ static void gt64120_writel(void *opaque, hwaddr addr, | ||||
|                            uint64_t val, unsigned size) | ||||
| { | ||||
|     GT64120State *s = opaque; | ||||
|     PCIHostState *phb = PCI_HOST_BRIDGE(s); | ||||
|     uint32_t saddr = addr >> 2; | ||||
|  | ||||
|     trace_gt64120_write(addr, val); | ||||
| @@ -592,6 +635,7 @@ 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: | ||||
| @@ -632,15 +676,9 @@ static void gt64120_writel(void *opaque, hwaddr addr, | ||||
|                       saddr << 2, size, size << 1, val); | ||||
|         break; | ||||
|     case GT_PCI0_CFGADDR: | ||||
|         phb->config_reg = val & 0x80fffffc; | ||||
|         break; | ||||
|     case GT_PCI0_CFGDATA: | ||||
|         if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) { | ||||
|             val = bswap32(val); | ||||
|         } | ||||
|         if (phb->config_reg & (1u << 31)) { | ||||
|             pci_data_write(phb->bus, phb->config_reg, val, 4); | ||||
|         } | ||||
|         /* Mapped via in gt64120_pci_mapping() */ | ||||
|         g_assert_not_reached(); | ||||
|         break; | ||||
|  | ||||
|     /* Interrupts */ | ||||
| @@ -698,7 +736,6 @@ static uint64_t gt64120_readl(void *opaque, | ||||
|                               hwaddr addr, unsigned size) | ||||
| { | ||||
|     GT64120State *s = opaque; | ||||
|     PCIHostState *phb = PCI_HOST_BRIDGE(s); | ||||
|     uint32_t val; | ||||
|     uint32_t saddr = addr >> 2; | ||||
|  | ||||
| @@ -883,17 +920,9 @@ static uint64_t gt64120_readl(void *opaque, | ||||
|  | ||||
|     /* PCI Internal */ | ||||
|     case GT_PCI0_CFGADDR: | ||||
|         val = phb->config_reg; | ||||
|         break; | ||||
|     case GT_PCI0_CFGDATA: | ||||
|         if (!(phb->config_reg & (1 << 31))) { | ||||
|             val = 0xffffffff; | ||||
|         } else { | ||||
|             val = pci_data_read(phb->bus, phb->config_reg, 4); | ||||
|         } | ||||
|         if (!(s->regs[GT_PCI0_CMD] & 1) && (phb->config_reg & 0x00fff800)) { | ||||
|             val = bswap32(val); | ||||
|         } | ||||
|         /* Mapped via in gt64120_pci_mapping() */ | ||||
|         g_assert_not_reached(); | ||||
|         break; | ||||
|  | ||||
|     case GT_PCI0_CMD: | ||||
| @@ -1153,6 +1182,7 @@ 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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user