1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <linux/pgtable.h>
4 #include <asm/abs_lowcore.h>
5
6 #define ABS_LOWCORE_UNMAPPED 1
7 #define ABS_LOWCORE_LAP_ON 2
8 #define ABS_LOWCORE_IRQS_ON 4
9
10 unsigned long __bootdata_preserved(__abs_lowcore);
11 bool __ro_after_init abs_lowcore_mapped;
12
abs_lowcore_map(int cpu,struct lowcore * lc,bool alloc)13 int abs_lowcore_map(int cpu, struct lowcore *lc, bool alloc)
14 {
15 unsigned long addr = __abs_lowcore + (cpu * sizeof(struct lowcore));
16 unsigned long phys = __pa(lc);
17 int rc, i;
18
19 for (i = 0; i < LC_PAGES; i++) {
20 rc = __vmem_map_4k_page(addr, phys, PAGE_KERNEL, alloc);
21 if (rc) {
22 /*
23 * Do not unmap allocated page tables in case the
24 * allocation was not requested. In such a case the
25 * request is expected coming from an atomic context,
26 * while the unmap attempt might sleep.
27 */
28 if (alloc) {
29 for (--i; i >= 0; i--) {
30 addr -= PAGE_SIZE;
31 vmem_unmap_4k_page(addr);
32 }
33 }
34 return rc;
35 }
36 addr += PAGE_SIZE;
37 phys += PAGE_SIZE;
38 }
39 return 0;
40 }
41
abs_lowcore_unmap(int cpu)42 void abs_lowcore_unmap(int cpu)
43 {
44 unsigned long addr = __abs_lowcore + (cpu * sizeof(struct lowcore));
45 int i;
46
47 for (i = 0; i < LC_PAGES; i++) {
48 vmem_unmap_4k_page(addr);
49 addr += PAGE_SIZE;
50 }
51 }
52
get_abs_lowcore(unsigned long * flags)53 struct lowcore *get_abs_lowcore(unsigned long *flags)
54 {
55 unsigned long irq_flags;
56 union ctlreg0 cr0;
57 int cpu;
58
59 *flags = 0;
60 cpu = get_cpu();
61 if (abs_lowcore_mapped) {
62 return ((struct lowcore *)__abs_lowcore) + cpu;
63 } else {
64 if (cpu != 0)
65 panic("Invalid unmapped absolute lowcore access\n");
66 local_irq_save(irq_flags);
67 if (!irqs_disabled_flags(irq_flags))
68 *flags |= ABS_LOWCORE_IRQS_ON;
69 __ctl_store(cr0.val, 0, 0);
70 if (cr0.lap) {
71 *flags |= ABS_LOWCORE_LAP_ON;
72 __ctl_clear_bit(0, 28);
73 }
74 *flags |= ABS_LOWCORE_UNMAPPED;
75 return lowcore_ptr[0];
76 }
77 }
78
put_abs_lowcore(struct lowcore * lc,unsigned long flags)79 void put_abs_lowcore(struct lowcore *lc, unsigned long flags)
80 {
81 if (abs_lowcore_mapped) {
82 if (flags)
83 panic("Invalid mapped absolute lowcore release\n");
84 } else {
85 if (smp_processor_id() != 0)
86 panic("Invalid mapped absolute lowcore access\n");
87 if (!(flags & ABS_LOWCORE_UNMAPPED))
88 panic("Invalid unmapped absolute lowcore release\n");
89 if (flags & ABS_LOWCORE_LAP_ON)
90 __ctl_set_bit(0, 28);
91 if (flags & ABS_LOWCORE_IRQS_ON)
92 local_irq_enable();
93 }
94 put_cpu();
95 }
96