hw/pci-host/astro: Fix boot for C3700 machine
Apply the "32-bit PCI addressing on 40-bit Runway" as the default
iommu transformation. This allows PCI devices to dma PDC memory.
Signed-off-by: Helge Deller <deller@gmx.de>
Acked-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c
index bd22658..7d68cce 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 @@
};
-/*
- * 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 @@
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 de7bfb5..36d5ab7 100644
--- a/hw/pci-host/meson.build
+++ b/hw/pci-host/meson.build
@@ -29,7 +29,7 @@
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)