diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c index bd226581af..7d68ccee7e 100644 --- a/hw/pci-host/astro.c +++ b/hw/pci-host/astro.c @@ -32,6 +32,7 @@ #include "hw/pci-host/astro.h" #include "hw/hppa/hppa_hardware.h" #include "migration/vmstate.h" +#include "target/hppa/cpu.h" #include "trace.h" #include "qom/object.h" @@ -268,22 +269,6 @@ static const MemoryRegionOps elroy_config_addr_ops = { }; -/* - * A subroutine of astro_translate_iommu that builds an IOMMUTLBEntry using the - * given translated address and mask. - */ -static bool make_iommu_tlbe(hwaddr addr, hwaddr taddr, hwaddr mask, - IOMMUTLBEntry *ret) -{ - hwaddr tce_mask = ~((1ull << 12) - 1); - ret->target_as = &address_space_memory; - ret->iova = addr & tce_mask; - ret->translated_addr = taddr & tce_mask; - ret->addr_mask = ~tce_mask; - ret->perm = IOMMU_RW; - return true; -} - /* Handle PCI-to-system address translation. */ static IOMMUTLBEntry astro_translate_iommu(IOMMUMemoryRegion *iommu, hwaddr addr, @@ -291,53 +276,59 @@ static IOMMUTLBEntry astro_translate_iommu(IOMMUMemoryRegion *iommu, int iommu_idx) { AstroState *s = container_of(iommu, AstroState, iommu); - IOMMUTLBEntry ret = { - .target_as = &address_space_memory, - .iova = addr, - .translated_addr = 0, - .addr_mask = ~(hwaddr)0, - .perm = IOMMU_NONE, - }; - hwaddr pdir_ptr, index, a, ibase; + hwaddr pdir_ptr, index, ibase; hwaddr addr_mask = 0xfff; /* 4k translation */ uint64_t entry; #define IOVP_SHIFT 12 /* equals PAGE_SHIFT */ #define PDIR_INDEX(iovp) ((iovp) >> IOVP_SHIFT) -#define IOVP_MASK PAGE_MASK #define SBA_PDIR_VALID_BIT 0x8000000000000000ULL + addr &= ~addr_mask; + + /* + * Default translation: "32-bit PCI Addressing on 40-bit Runway". + * For addresses in the 32-bit memory address range ... and then + * language which not-coincidentally matches the PSW.W=0 mapping. + */ + if (addr <= UINT32_MAX) { + entry = hppa_abs_to_phys_pa2_w0(addr); + } else { + entry = addr; + } + /* "range enable" flag cleared? */ if ((s->tlb_ibase & 1) == 0) { - make_iommu_tlbe(addr, addr, addr_mask, &ret); - return ret; + goto skip; } - a = addr; ibase = s->tlb_ibase & ~1ULL; - if ((a & s->tlb_imask) != ibase) { + if ((addr & s->tlb_imask) != ibase) { /* do not translate this one! */ - make_iommu_tlbe(addr, addr, addr_mask, &ret); - return ret; + goto skip; } - index = PDIR_INDEX(a); + + index = PDIR_INDEX(addr); pdir_ptr = s->tlb_pdir_base + index * sizeof(entry); entry = ldq_le_phys(&address_space_memory, pdir_ptr); + if (!(entry & SBA_PDIR_VALID_BIT)) { /* I/O PDIR entry valid ? */ - g_assert_not_reached(); - goto failure; + /* failure */ + return (IOMMUTLBEntry) { .perm = IOMMU_NONE }; } + entry &= ~SBA_PDIR_VALID_BIT; entry >>= IOVP_SHIFT; entry <<= 12; - entry |= addr & 0xfff; - make_iommu_tlbe(addr, entry, addr_mask, &ret); - goto success; - failure: - ret = (IOMMUTLBEntry) { .perm = IOMMU_NONE }; - success: - return ret; + skip: + return (IOMMUTLBEntry) { + .target_as = &address_space_memory, + .iova = addr, + .translated_addr = entry, + .addr_mask = addr_mask, + .perm = IOMMU_RW, + }; } static AddressSpace *elroy_pcihost_set_iommu(PCIBus *bus, void *opaque, diff --git a/hw/pci-host/meson.build b/hw/pci-host/meson.build index de7bfb5a62..36d5ab756f 100644 --- a/hw/pci-host/meson.build +++ b/hw/pci-host/meson.build @@ -29,7 +29,7 @@ pci_ss.add(when: 'CONFIG_MV64361', if_true: files('mv64361.c')) pci_ss.add(when: 'CONFIG_VERSATILE_PCI', if_true: files('versatile.c')) # HPPA devices -pci_ss.add(when: 'CONFIG_ASTRO', if_true: files('astro.c')) +specific_ss.add(when: 'CONFIG_ASTRO', if_true: files('astro.c')) pci_ss.add(when: 'CONFIG_DINO', if_true: files('dino.c')) system_ss.add_all(when: 'CONFIG_PCI', if_true: pci_ss)