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
This commit is contained in:
Leandro Lupori 2021-10-14 10:39:52 -03:00
parent 0a8159d8ca
commit 76384bd10f
4 changed files with 46 additions and 16 deletions

View File

@ -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);
}

View File

@ -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));
}
@ -2071,12 +2071,6 @@ mmu_radix_late_bootstrap(vm_offset_t start, vm_offset_t end)
for (i = 0; phys_avail[i + 2] != 0; i += 2)
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.)
*/

View File

@ -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);

View File

@ -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.
*/