diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-07 12:52:36 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-07 12:52:36 -0800 |
commit | d72cb8c7d9dbd9ce820c80f3fddb56b296ba96fc (patch) | |
tree | 0a5c1fce60589ead0a9fb719ddbbdf8daef83bca /arch/riscv/mm/init.c | |
parent | be37f21a08ce65c7632c7f45e1755a4b07f278a0 (diff) | |
parent | 13fd5de06514458eb320188b7a815d65696efd99 (diff) |
Merge tag 'riscv-for-linus-5.1-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux
Pull RISC-V updates from Palmer Dabbelt:
"This contains the vast majority of the RISC-V patches for this merge
window. It includes:
- A handful of cleanups to our kernel prints, most of which are
things I should have caught the first time.
- We now provide an HWCAP that contains the ISA extensions that all
enabled processors support, as supposed to just looking at the
first enabled processor.
- We no longer spin forever waiting for all harts to boot.
- A fixmap implementation, which is coupled to some cleanups in our
MM code.
The only outstanding patches I know of right now are Vincent Chen's
patches to fix c.ebreak handling in the kernel, the v2 of which was
posted this morning. I'd like those in the MW, but I didn't want to
hold up everything else. The patch set is based on top of my last
fixes submission, but I've tested it with a conflict-free merge from
v5.0. I'm doing this rather than my "just go rebase everything" flow
due to a discussion with Linus, but if I misunderstood then just let
me know and I'll do something else. It's also the first time I've
taken a PR into my own tree, so let me know if I screwed that one up.
I've used my standard testing flow (QEMU in Fedora), but now that
we're starting to get the kernel in better shape I think it's time to
impose some more testing here -- specifically I'm going to require
that patches boot on the HiFive Unleashed because we're getting to the
point where we can actually expect that to work. I haven't done that
for this tag, but I'm going to do it for future ones.
I know the board is a bit expensive and not everyone has one, but if
I've sent you a free one and your patches break the boot then I'm
going to yell at you :). If you don't have one then please indicate
how you tested in your cover letter, and if you have a board then
please add your Tested-by to patches if they work for your testing
flow"
* tag 'riscv-for-linus-5.1-mw0' of git://git.kernel.org/pub/scm/linux/kernel/git/palmer/riscv-linux:
arch: riscv: fix logic error in parse_dtb
RISC-V: Assign hwcap as per comman capabilities.
RISC-V: Compare cpuid with NR_CPUS before mapping.
RISC-V: Allow hartid-to-cpuid function to fail.
RISC-V: Remove NR_CPUs check during hartid search from DT
RISC-V: Move cpuid to hartid mapping to SMP.
RISC-V: Do not wait indefinitely in __cpu_up
RISC-V: Free-up initrd in free_initrd_mem()
RISC-V: Implement compile-time fixed mappings
RISC-V: Move setup_vm() to mm/init.c
RISC-V: Move setup_bootmem() to mm/init.c
RISC-V: Setup init_mm before parse_early_param()
riscv: remove the HAVE_KPROBES option
riscv: use for_each_of_cpu_node iterator
riscv: treat cpu devicetree nodes without status as enabled
riscv: fix riscv_of_processor_hartid() comment
riscv: use pr_info and friends
riscv: add missing newlines to printk messages
Diffstat (limited to 'arch/riscv/mm/init.c')
-rw-r--r-- | arch/riscv/mm/init.c | 156 |
1 files changed, 155 insertions, 1 deletions
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 658ebf645f42..b379a75ac6a6 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -17,7 +17,9 @@ #include <linux/initrd.h> #include <linux/swap.h> #include <linux/sizes.h> +#include <linux/of_fdt.h> +#include <asm/fixmap.h> #include <asm/tlbflush.h> #include <asm/sections.h> #include <asm/pgtable.h> @@ -66,7 +68,159 @@ void free_initmem(void) } #ifdef CONFIG_BLK_DEV_INITRD -void free_initrd_mem(unsigned long start, unsigned long end) +static void __init setup_initrd(void) { + unsigned long size; + + if (initrd_start >= initrd_end) { + pr_info("initrd not found or empty"); + goto disable; + } + if (__pa(initrd_end) > PFN_PHYS(max_low_pfn)) { + pr_err("initrd extends beyond end of memory"); + goto disable; + } + + size = initrd_end - initrd_start; + memblock_reserve(__pa(initrd_start), size); + initrd_below_start_ok = 1; + + pr_info("Initial ramdisk at: 0x%p (%lu bytes)\n", + (void *)(initrd_start), size); + return; +disable: + pr_cont(" - disabling initrd\n"); + initrd_start = 0; + initrd_end = 0; +} + +void __init free_initrd_mem(unsigned long start, unsigned long end) +{ + free_reserved_area((void *)start, (void *)end, -1, "initrd"); } #endif /* CONFIG_BLK_DEV_INITRD */ + +void __init setup_bootmem(void) +{ + struct memblock_region *reg; + phys_addr_t mem_size = 0; + + /* Find the memory region containing the kernel */ + for_each_memblock(memory, reg) { + phys_addr_t vmlinux_end = __pa(_end); + phys_addr_t end = reg->base + reg->size; + + if (reg->base <= vmlinux_end && vmlinux_end <= end) { + /* + * Reserve from the start of the region to the end of + * the kernel + */ + memblock_reserve(reg->base, vmlinux_end - reg->base); + mem_size = min(reg->size, (phys_addr_t)-PAGE_OFFSET); + } + } + BUG_ON(mem_size == 0); + + set_max_mapnr(PFN_DOWN(mem_size)); + max_low_pfn = PFN_DOWN(memblock_end_of_DRAM()); + +#ifdef CONFIG_BLK_DEV_INITRD + setup_initrd(); +#endif /* CONFIG_BLK_DEV_INITRD */ + + early_init_fdt_reserve_self(); + early_init_fdt_scan_reserved_mem(); + memblock_allow_resize(); + memblock_dump_all(); + + for_each_memblock(memory, reg) { + unsigned long start_pfn = memblock_region_memory_base_pfn(reg); + unsigned long end_pfn = memblock_region_memory_end_pfn(reg); + + memblock_set_node(PFN_PHYS(start_pfn), + PFN_PHYS(end_pfn - start_pfn), + &memblock.memory, 0); + } +} + +pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_bss; +pgd_t trampoline_pg_dir[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); + +#ifndef __PAGETABLE_PMD_FOLDED +#define NUM_SWAPPER_PMDS ((uintptr_t)-PAGE_OFFSET >> PGDIR_SHIFT) +pmd_t swapper_pmd[PTRS_PER_PMD*((-PAGE_OFFSET)/PGDIR_SIZE)] __page_aligned_bss; +pmd_t trampoline_pmd[PTRS_PER_PGD] __initdata __aligned(PAGE_SIZE); +pmd_t fixmap_pmd[PTRS_PER_PMD] __page_aligned_bss; +#endif + +pte_t fixmap_pte[PTRS_PER_PTE] __page_aligned_bss; + +void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot) +{ + unsigned long addr = __fix_to_virt(idx); + pte_t *ptep; + + BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses); + + ptep = &fixmap_pte[pte_index(addr)]; + + if (pgprot_val(prot)) { + set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot)); + } else { + pte_clear(&init_mm, addr, ptep); + local_flush_tlb_page(addr); + } +} + +asmlinkage void __init setup_vm(void) +{ + extern char _start; + uintptr_t i; + uintptr_t pa = (uintptr_t) &_start; + pgprot_t prot = __pgprot(pgprot_val(PAGE_KERNEL) | _PAGE_EXEC); + + va_pa_offset = PAGE_OFFSET - pa; + pfn_base = PFN_DOWN(pa); + + /* Sanity check alignment and size */ + BUG_ON((PAGE_OFFSET % PGDIR_SIZE) != 0); + BUG_ON((pa % (PAGE_SIZE * PTRS_PER_PTE)) != 0); + +#ifndef __PAGETABLE_PMD_FOLDED + trampoline_pg_dir[(PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD] = + pfn_pgd(PFN_DOWN((uintptr_t)trampoline_pmd), + __pgprot(_PAGE_TABLE)); + trampoline_pmd[0] = pfn_pmd(PFN_DOWN(pa), prot); + + for (i = 0; i < (-PAGE_OFFSET)/PGDIR_SIZE; ++i) { + size_t o = (PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD + i; + + swapper_pg_dir[o] = + pfn_pgd(PFN_DOWN((uintptr_t)swapper_pmd) + i, + __pgprot(_PAGE_TABLE)); + } + for (i = 0; i < ARRAY_SIZE(swapper_pmd); i++) + swapper_pmd[i] = pfn_pmd(PFN_DOWN(pa + i * PMD_SIZE), prot); + + swapper_pg_dir[(FIXADDR_START >> PGDIR_SHIFT) % PTRS_PER_PGD] = + pfn_pgd(PFN_DOWN((uintptr_t)fixmap_pmd), + __pgprot(_PAGE_TABLE)); + fixmap_pmd[(FIXADDR_START >> PMD_SHIFT) % PTRS_PER_PMD] = + pfn_pmd(PFN_DOWN((uintptr_t)fixmap_pte), + __pgprot(_PAGE_TABLE)); +#else + trampoline_pg_dir[(PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD] = + pfn_pgd(PFN_DOWN(pa), prot); + + for (i = 0; i < (-PAGE_OFFSET)/PGDIR_SIZE; ++i) { + size_t o = (PAGE_OFFSET >> PGDIR_SHIFT) % PTRS_PER_PGD + i; + + swapper_pg_dir[o] = + pfn_pgd(PFN_DOWN(pa + i * PGDIR_SIZE), prot); + } + + swapper_pg_dir[(FIXADDR_START >> PGDIR_SHIFT) % PTRS_PER_PGD] = + pfn_pgd(PFN_DOWN((uintptr_t)fixmap_pte), + __pgprot(_PAGE_TABLE)); +#endif +} |