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",