Fix system hang when large FDT is in use
Summary: Kernel maps only one page of FDT. When FDT is more than one page in size, data TLB miss occurs on memmove() when FDT is moved to kernel storage (sys/powerpc/booke/booke_machdep.c, booke_init()) This introduces a pmap_early_io_unmap() to complement pmap_early_io_map(), which can be used for any early I/O mapping, but currently is only used when mapping the fdt. Submitted by: Ivan Krivonos <int0dster_gmail.com> Differential Revision: https://reviews.freebsd.org/D7605
This commit is contained in:
parent
e626c40eb5
commit
60152a4037
@ -249,6 +249,7 @@ static int
|
||||
booke_check_for_fdt(uint32_t arg1, vm_offset_t *dtbp)
|
||||
{
|
||||
void *ptr;
|
||||
int fdt_size;
|
||||
|
||||
if (arg1 % 8 != 0)
|
||||
return (-1);
|
||||
@ -257,6 +258,19 @@ booke_check_for_fdt(uint32_t arg1, vm_offset_t *dtbp)
|
||||
if (fdt_check_header(ptr) != 0)
|
||||
return (-1);
|
||||
|
||||
/*
|
||||
* Read FDT total size from the header of FDT.
|
||||
* This for sure hits within first page which is
|
||||
* already mapped.
|
||||
*/
|
||||
fdt_size = fdt_totalsize((void *)ptr);
|
||||
|
||||
/*
|
||||
* Ok, arg1 points to FDT, so we need to map it in.
|
||||
* First, unmap this page and then map FDT again with full size
|
||||
*/
|
||||
pmap_early_io_unmap((vm_offset_t)ptr, PAGE_SIZE);
|
||||
ptr = (void *)pmap_early_io_map(arg1, fdt_size);
|
||||
*dtbp = (vm_offset_t)ptr;
|
||||
|
||||
return (0);
|
||||
|
@ -3419,6 +3419,29 @@ tlb1_init()
|
||||
set_mas4_defaults();
|
||||
}
|
||||
|
||||
void
|
||||
pmap_early_io_unmap(vm_offset_t va, vm_size_t size)
|
||||
{
|
||||
int i;
|
||||
tlb_entry_t e;
|
||||
|
||||
for (i = 0; i < TLB1_ENTRIES && size > 0; i ++) {
|
||||
tlb1_read_entry(&e, i);
|
||||
if (!(e.mas1 & MAS1_VALID))
|
||||
continue;
|
||||
/*
|
||||
* FIXME: this code does not work if VA region
|
||||
* spans multiple TLB entries. This does not cause
|
||||
* problems right now but shall be fixed in the future
|
||||
*/
|
||||
if (va >= e.virt && (va + size) <= (e.virt + e.size)) {
|
||||
size -= e.size;
|
||||
e.mas1 &= ~MAS1_VALID;
|
||||
tlb1_write_entry(&e, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vm_offset_t
|
||||
pmap_early_io_map(vm_paddr_t pa, vm_size_t size)
|
||||
{
|
||||
|
@ -260,6 +260,7 @@ extern vm_offset_t msgbuf_phys;
|
||||
extern int pmap_bootstrapped;
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user