Octeon firmware provides a list of usable memory regions. I would like
to make the memory setup routine use the list instead of hardcoded
assumptions. EdgeRouter Pro has a memory layout that does not match
with the current code, which causes a kernel crash.

I have tested this patch on EdgeRouter Lite and EdgeRouter Pro. Tests on
other Octeon boards are welcome.

OK?

Index: arch/octeon/include/octeonvar.h
===================================================================
RCS file: src/sys/arch/octeon/include/octeonvar.h,v
retrieving revision 1.24
diff -u -p -r1.24 octeonvar.h
--- arch/octeon/include/octeonvar.h     20 Jul 2015 19:44:32 -0000      1.24
+++ arch/octeon/include/octeonvar.h     17 Mar 2016 14:05:37 -0000
@@ -273,6 +273,24 @@ struct boot_info {
        uint32_t config_flags;
 };
 
+struct octeon_bootmem_desc {
+       uint32_t        lock;
+       uint32_t        flags;
+       uint64_t        head_addr;
+       uint32_t        major_version;
+       uint32_t        minor_version;
+       uint64_t        app_data_addr;
+       uint64_t        app_data_size;
+       uint32_t        named_block_num_blocks;
+       uint32_t        named_block_name_len;
+       uint64_t        named_block_array_addr;
+};
+
+struct octeon_bootmem_block {
+       uint64_t        next;
+       uint64_t        size;
+};
+
 extern struct boot_desc *octeon_boot_desc;
 extern struct boot_info *octeon_boot_info;
 
Index: arch/octeon/octeon/machdep.c
===================================================================
RCS file: src/sys/arch/octeon/octeon/machdep.c,v
retrieving revision 1.72
diff -u -p -r1.72 machdep.c
--- arch/octeon/octeon/machdep.c        6 Mar 2016 19:42:27 -0000       1.72
+++ arch/octeon/octeon/machdep.c        17 Mar 2016 14:05:37 -0000
@@ -154,50 +154,48 @@ struct timecounter ipdclock_timecounter 
 void
 octeon_memory_init(struct boot_info *boot_info)
 {
-       extern char end[];
+       struct octeon_bootmem_block *block;
+       struct octeon_bootmem_desc *memdesc;
+       paddr_t blockaddr;
+       uint64_t fp, lp;
        int i;
-       uint32_t realmem_bytes;
 
-       realmem_bytes = boot_info->dram_size << 20;
-       physmem = atop(realmem_bytes);
+       physmem = atop((uint64_t)boot_info->dram_size << 20);
 
-       /*-
-        * Octeon Memory looks as follows:
-         *   PA
-        * First 256 MB DR0
-        * 0000 0000 0000 0000     to  0000 0000 0FFF FFFF
-        * Second 256 MB DR1
-        * 0000 0004 1000 0000     to  0000 0004 1FFF FFFF
-        * Over 512MB Memory DR2  15.5GB
-        * 0000 0000 2000 0000     to  0000 0003 FFFF FFFF
-        */
-
-       /* DR0, ignoring everything below the kernel image */
-       mem_layout[0].mem_first_page =
-           atop(CKSEG0_TO_PHYS(round_page((vaddr_t)&end)));
-       if (physmem > atop(256 << 20))
-               mem_layout[0].mem_last_page = atop(256 << 20);
-       else
-               mem_layout[0].mem_last_page = physmem;
-
-       /* DR1 */
-       i = 1;
-       if (physmem > atop(256 << 20)) {
-               mem_layout[i].mem_first_page = atop(0x410000000ULL);
-               if (physmem > atop(512 << 20))
-                       mem_layout[i].mem_last_page = atop(0x420000000ULL);
-               else
-                       mem_layout[i].mem_last_page =
-                           atop(0x410000000ULL) + physmem - atop(256 << 20);
-               i++;
-       }
+       if (boot_info->phys_mem_desc_addr == 0)
+               panic("bootmem desc is missing");
+       memdesc = (struct octeon_bootmem_desc *)PHYS_TO_XKPHYS(
+           boot_info->phys_mem_desc_addr, CCA_CACHED);
+       printf("bootmem desc 0x%x version %d.%d\n",
+           boot_info->phys_mem_desc_addr, memdesc->major_version,
+           memdesc->minor_version);
+       if (memdesc->major_version > 3)
+               panic("unhandled bootmem desc version %d.%d",
+                   memdesc->major_version, memdesc->minor_version);
+
+       blockaddr = memdesc->head_addr;
+       if (blockaddr == 0)
+               panic("bootmem list is empty");
+       for (i = 0; i < MAXMEMSEGS && blockaddr != 0; blockaddr = block->next) {
+               block = (struct octeon_bootmem_block *)PHYS_TO_XKPHYS(
+                   blockaddr, CCA_CACHED);
+               printf("avail phys mem 0x%016lx - 0x%016lx\n", blockaddr,
+                   (paddr_t)(blockaddr + block->size));
+
+               fp = atop(round_page(blockaddr));
+               lp = atop(trunc_page(blockaddr + block->size));
 
-       /* DR2 */
-       if (physmem > atop(512 << 20)) {
-               mem_layout[i].mem_first_page = atop(0x20000000ULL);
-               mem_layout[i].mem_last_page =
-                   atop(0x20000000ULL) + physmem - atop(512 << 20);
-               /* i++; */
+               /* Clamp to the range of the pmap. */
+               if (fp > atop(pfn_to_pad(PG_FRAME)))
+                       continue;
+               if (lp > atop(pfn_to_pad(PG_FRAME)) + 1)
+                       lp = atop(pfn_to_pad(PG_FRAME)) + 1;
+               if (fp >= lp)
+                       continue;
+
+               mem_layout[i].mem_first_page = fp;
+               mem_layout[i].mem_last_page = lp;
+               i++;
        }
 
        printf("Total DRAM Size 0x%016X\n",

Reply via email to