Merge tag 'rtc-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
[linux-2.6-microblaze.git] / arch / nds32 / mm / mm-nds32.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2005-2017 Andes Technology Corporation
3
4 #include <linux/init_task.h>
5
6 #define __HAVE_ARCH_PGD_FREE
7 #include <asm/pgalloc.h>
8
9 #define FIRST_KERNEL_PGD_NR     (USER_PTRS_PER_PGD)
10
11 /*
12  * need to get a page for level 1
13  */
14
15 pgd_t *pgd_alloc(struct mm_struct *mm)
16 {
17         pgd_t *new_pgd, *init_pgd;
18         int i;
19
20         new_pgd = (pgd_t *) __get_free_pages(GFP_KERNEL, 0);
21         if (!new_pgd)
22                 return NULL;
23         for (i = 0; i < PTRS_PER_PGD; i++) {
24                 (*new_pgd) = 1;
25                 new_pgd++;
26         }
27         new_pgd -= PTRS_PER_PGD;
28
29         init_pgd = pgd_offset_k(0);
30
31         memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
32                (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
33
34         cpu_dcache_wb_range((unsigned long)new_pgd,
35                             (unsigned long)new_pgd +
36                             PTRS_PER_PGD * sizeof(pgd_t));
37         inc_lruvec_page_state(virt_to_page((unsigned long *)new_pgd),
38                               NR_PAGETABLE);
39
40         return new_pgd;
41 }
42
43 void pgd_free(struct mm_struct *mm, pgd_t * pgd)
44 {
45         pmd_t *pmd;
46         struct page *pte;
47
48         if (!pgd)
49                 return;
50
51         pmd = (pmd_t *) pgd;
52         if (pmd_none(*pmd))
53                 goto free;
54         if (pmd_bad(*pmd)) {
55                 pmd_ERROR(*pmd);
56                 pmd_clear(pmd);
57                 goto free;
58         }
59
60         pte = pmd_page(*pmd);
61         pmd_clear(pmd);
62         dec_lruvec_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE);
63         pte_free(mm, pte);
64         mm_dec_nr_ptes(mm);
65         pmd_free(mm, pmd);
66 free:
67         free_pages((unsigned long)pgd, 0);
68 }
69
70 /*
71  * In order to soft-boot, we need to insert a 1:1 mapping in place of
72  * the user-mode pages.  This will then ensure that we have predictable
73  * results when turning the mmu off
74  */
75 void setup_mm_for_reboot(char mode)
76 {
77         unsigned long pmdval;
78         pgd_t *pgd;
79         p4d_t *p4d;
80         pud_t *pud;
81         pmd_t *pmd;
82         int i;
83
84         if (current->mm && current->mm->pgd)
85                 pgd = current->mm->pgd;
86         else
87                 pgd = init_mm.pgd;
88
89         for (i = 0; i < USER_PTRS_PER_PGD; i++) {
90                 pmdval = (i << PGDIR_SHIFT);
91                 p4d = p4d_offset(pgd, i << PGDIR_SHIFT);
92                 pud = pud_offset(p4d, i << PGDIR_SHIFT);
93                 pmd = pmd_offset(pud + i, i << PGDIR_SHIFT);
94                 set_pmd(pmd, __pmd(pmdval));
95         }
96 }