Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.14.15.
 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
10unsigned long __bootdata_preserved(__abs_lowcore);
11bool __ro_after_init abs_lowcore_mapped;
12
13int 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
42void 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
53struct 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
79void 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}