Author: jhibbits
Date: Wed Aug 24 03:51:40 2016
New Revision: 304727
URL: https://svnweb.freebsd.org/changeset/base/304727

Log:
  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

Modified:
  head/sys/powerpc/booke/booke_machdep.c
  head/sys/powerpc/booke/pmap.c
  head/sys/powerpc/include/pmap.h

Modified: head/sys/powerpc/booke/booke_machdep.c
==============================================================================
--- head/sys/powerpc/booke/booke_machdep.c      Wed Aug 24 03:44:20 2016        
(r304726)
+++ head/sys/powerpc/booke/booke_machdep.c      Wed Aug 24 03:51:40 2016        
(r304727)
@@ -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_of
        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);

Modified: head/sys/powerpc/booke/pmap.c
==============================================================================
--- head/sys/powerpc/booke/pmap.c       Wed Aug 24 03:44:20 2016        
(r304726)
+++ head/sys/powerpc/booke/pmap.c       Wed Aug 24 03:51:40 2016        
(r304727)
@@ -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)
 {

Modified: head/sys/powerpc/include/pmap.h
==============================================================================
--- head/sys/powerpc/include/pmap.h     Wed Aug 24 03:44:20 2016        
(r304726)
+++ head/sys/powerpc/include/pmap.h     Wed Aug 24 03:51:40 2016        
(r304727)
@@ -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
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to