aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeandro Lupori <luporl@FreeBSD.org>2021-10-14 13:39:52 +0000
committerLeandro Lupori <luporl@FreeBSD.org>2021-10-14 13:39:52 +0000
commit76384bd10fdbb97be2803d969905f15a84255d6a (patch)
treed440dcbf84669fc5a0845dfb4074b1521bb31ac1
parent0a8159d8ca85383ec84076396c0a457c6d3e08f9 (diff)
downloadsrc-76384bd10fdbb97be2803d969905f15a84255d6a.tar.gz
src-76384bd10fdbb97be2803d969905f15a84255d6a.zip
powerpc64: fix OFWFB with Radix MMU
Current implementation of Radix MMU doesn't support mapping arbitrary virtual addresses, such as the ones generated by "direct mapping" I/O addresses. This caused the system to hang, when early I/O addresses, such as those used by OpenFirmware Frame Buffer, were remapped after the MMU was up. To avoid having to modify mmu_radix_kenter_attr just to support this use case, this change makes early I/O map use virtual addresses from KVA area instead (similar to what mmu_radix_mapdev_attr does), as these can be safely remapped later. Reviewed by: alfredo (earlier version), jhibbits (in irc) MFC after: 2 weeks Sponsored by: Instituto de Pesquisas Eldorado (eldorado.org.br) Differential Revision: https://reviews.freebsd.org/D31232
-rw-r--r--sys/powerpc/aim/aim_machdep.c42
-rw-r--r--sys/powerpc/aim/mmu_radix.c8
-rw-r--r--sys/powerpc/include/pmap.h3
-rw-r--r--sys/powerpc/powerpc/machdep.c9
4 files changed, 46 insertions, 16 deletions
diff --git a/sys/powerpc/aim/aim_machdep.c b/sys/powerpc/aim/aim_machdep.c
index d582489d9f7e..914296440104 100644
--- a/sys/powerpc/aim/aim_machdep.c
+++ b/sys/powerpc/aim/aim_machdep.c
@@ -476,14 +476,9 @@ aim_cpu_init(vm_offset_t toc)
* in case the platform module had a better idea of what we
* should do.
*/
- if (cpu_features2 & PPC_FEATURE2_ARCH_3_00) {
- radix_mmu = 0;
- TUNABLE_INT_FETCH("radix_mmu", &radix_mmu);
- if (radix_mmu)
- pmap_mmu_install(MMU_TYPE_RADIX, BUS_PROBE_GENERIC);
- else
- pmap_mmu_install(MMU_TYPE_G5, BUS_PROBE_GENERIC);
- } else if (cpu_features & PPC_FEATURE_64)
+ if (radix_mmu)
+ pmap_mmu_install(MMU_TYPE_RADIX, BUS_PROBE_GENERIC);
+ else if (cpu_features & PPC_FEATURE_64)
pmap_mmu_install(MMU_TYPE_G5, BUS_PROBE_GENERIC);
else
pmap_mmu_install(MMU_TYPE_OEA, BUS_PROBE_GENERIC);
@@ -586,6 +581,25 @@ va_to_vsid(pmap_t pm, vm_offset_t va)
#endif
+void
+pmap_early_io_map_init(void)
+{
+ if ((cpu_features2 & PPC_FEATURE2_ARCH_3_00) == 0)
+ radix_mmu = 0;
+ else
+ TUNABLE_INT_FETCH("radix_mmu", &radix_mmu);
+
+ /*
+ * When using Radix, set the start and end of kva early, to be able to
+ * use KVAs on pmap_early_io_map and avoid issues when remapping them
+ * later.
+ */
+ if (radix_mmu) {
+ virtual_avail = VM_MIN_KERNEL_ADDRESS;
+ virtual_end = VM_MAX_SAFE_KERNEL_ADDRESS;
+ }
+}
+
/*
* These functions need to provide addresses that both (a) work in real mode
* (or whatever mode/circumstances the kernel is in in early boot (now)) and
@@ -601,10 +615,20 @@ pmap_early_io_map(vm_paddr_t pa, vm_size_t size)
* If we have the MMU up in early boot, assume it is 1:1. Otherwise,
* try to get the address in a memory region compatible with the
* direct map for efficiency later.
+ * Except for Radix MMU, for which current implementation doesn't
+ * support mapping arbitrary virtual addresses, such as the ones
+ * generated by "direct mapping" I/O addresses. In this case, use
+ * addresses from KVA area.
*/
if (mfmsr() & PSL_DR)
return (pa);
- else
+ else if (radix_mmu) {
+ vm_offset_t va;
+
+ va = virtual_avail;
+ virtual_avail += round_page(size + pa - trunc_page(pa));
+ return (va);
+ } else
return (DMAP_BASE_ADDRESS + pa);
}
diff --git a/sys/powerpc/aim/mmu_radix.c b/sys/powerpc/aim/mmu_radix.c
index 50c658e58a4a..ca1a4d2f4797 100644
--- a/sys/powerpc/aim/mmu_radix.c
+++ b/sys/powerpc/aim/mmu_radix.c
@@ -907,7 +907,7 @@ kvtopte(vm_offset_t va)
pt_entry_t *l3e;
l3e = pmap_pml3e(kernel_pmap, va);
- if ((be64toh(*l3e) & RPTE_VALID) == 0)
+ if (l3e == NULL || (be64toh(*l3e) & RPTE_VALID) == 0)
return (NULL);
return (pmap_l3e_to_pte(l3e, va));
}
@@ -2072,12 +2072,6 @@ mmu_radix_late_bootstrap(vm_offset_t start, vm_offset_t end)
Maxmem = MAX(Maxmem, powerpc_btop(phys_avail[i + 1]));
/*
- * Set the start and end of kva.
- */
- virtual_avail = VM_MIN_KERNEL_ADDRESS;
- virtual_end = VM_MAX_SAFE_KERNEL_ADDRESS;
-
- /*
* Remap any early IO mappings (console framebuffer, etc.)
*/
bs_remap_earlyboot();
diff --git a/sys/powerpc/include/pmap.h b/sys/powerpc/include/pmap.h
index 2f1886a27093..d14398750080 100644
--- a/sys/powerpc/include/pmap.h
+++ b/sys/powerpc/include/pmap.h
@@ -340,6 +340,9 @@ extern int pmap_bootstrapped;
extern int radix_mmu;
extern int superpages_enabled;
+#ifdef AIM
+void pmap_early_io_map_init(void);
+#endif
vm_offset_t pmap_early_io_map(vm_paddr_t pa, vm_size_t size);
void pmap_early_io_unmap(vm_offset_t va, vm_size_t size);
void pmap_track_page(pmap_t pmap, vm_offset_t va);
diff --git a/sys/powerpc/powerpc/machdep.c b/sys/powerpc/powerpc/machdep.c
index 622af17b3305..2dc9a3e9d549 100644
--- a/sys/powerpc/powerpc/machdep.c
+++ b/sys/powerpc/powerpc/machdep.c
@@ -419,6 +419,15 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp,
if (ofw_bootargs)
ofw_parse_bootargs();
+#ifdef AIM
+ /*
+ * Early I/O map needs to be initialized before console, in order to
+ * map frame buffers properly, and after boot args have been parsed,
+ * to handle tunables properly.
+ */
+ pmap_early_io_map_init();
+#endif
+
/*
* Initialize the console before printing anything.
*/