arm64: add early_ioremap support
[cascardo/linux.git] / arch / arm64 / mm / ioremap.c
index 2bb1d58..7ec3283 100644 (file)
 #include <linux/vmalloc.h>
 #include <linux/io.h>
 
+#include <asm/fixmap.h>
+#include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
+
 static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
                                      pgprot_t prot, void *caller)
 {
@@ -98,3 +102,84 @@ void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
                                __builtin_return_address(0));
 }
 EXPORT_SYMBOL(ioremap_cache);
+
+#ifndef CONFIG_ARM64_64K_PAGES
+static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
+#endif
+
+static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+
+       pgd = pgd_offset_k(addr);
+       BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
+
+       pud = pud_offset(pgd, addr);
+       BUG_ON(pud_none(*pud) || pud_bad(*pud));
+
+       return pmd_offset(pud, addr);
+}
+
+static inline pte_t * __init early_ioremap_pte(unsigned long addr)
+{
+       pmd_t *pmd = early_ioremap_pmd(addr);
+
+       BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd));
+
+       return pte_offset_kernel(pmd, addr);
+}
+
+void __init early_ioremap_init(void)
+{
+       pmd_t *pmd;
+
+       pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN));
+#ifndef CONFIG_ARM64_64K_PAGES
+       /* need to populate pmd for 4k pagesize only */
+       pmd_populate_kernel(&init_mm, pmd, bm_pte);
+#endif
+       /*
+        * The boot-ioremap range spans multiple pmds, for which
+        * we are not prepared:
+        */
+       BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
+                    != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
+
+       if (pmd != early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END))) {
+               WARN_ON(1);
+               pr_warn("pmd %p != %p\n",
+                       pmd, early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END)));
+               pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
+                       fix_to_virt(FIX_BTMAP_BEGIN));
+               pr_warn("fix_to_virt(FIX_BTMAP_END):   %08lx\n",
+                       fix_to_virt(FIX_BTMAP_END));
+
+               pr_warn("FIX_BTMAP_END:       %d\n", FIX_BTMAP_END);
+               pr_warn("FIX_BTMAP_BEGIN:     %d\n",
+                       FIX_BTMAP_BEGIN);
+       }
+
+       early_ioremap_setup();
+}
+
+void __init __early_set_fixmap(enum fixed_addresses idx,
+                              phys_addr_t phys, pgprot_t flags)
+{
+       unsigned long addr = __fix_to_virt(idx);
+       pte_t *pte;
+
+       if (idx >= __end_of_fixed_addresses) {
+               BUG();
+               return;
+       }
+
+       pte = early_ioremap_pte(addr);
+
+       if (pgprot_val(flags))
+               set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
+       else {
+               pte_clear(&init_mm, addr, pte);
+               flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
+       }
+}