96 lines
2.2 KiB
C
96 lines
2.2 KiB
C
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
|
||
|
#include <linux/pgtable.h>
|
||
|
#include <asm/abs_lowcore.h>
|
||
|
|
||
|
#define ABS_LOWCORE_UNMAPPED 1
|
||
|
#define ABS_LOWCORE_LAP_ON 2
|
||
|
#define ABS_LOWCORE_IRQS_ON 4
|
||
|
|
||
|
unsigned long __bootdata_preserved(__abs_lowcore);
|
||
|
bool __ro_after_init abs_lowcore_mapped;
|
||
|
|
||
|
int abs_lowcore_map(int cpu, struct lowcore *lc, bool alloc)
|
||
|
{
|
||
|
unsigned long addr = __abs_lowcore + (cpu * sizeof(struct lowcore));
|
||
|
unsigned long phys = __pa(lc);
|
||
|
int rc, i;
|
||
|
|
||
|
for (i = 0; i < LC_PAGES; i++) {
|
||
|
rc = __vmem_map_4k_page(addr, phys, PAGE_KERNEL, alloc);
|
||
|
if (rc) {
|
||
|
/*
|
||
|
* Do not unmap allocated page tables in case the
|
||
|
* allocation was not requested. In such a case the
|
||
|
* request is expected coming from an atomic context,
|
||
|
* while the unmap attempt might sleep.
|
||
|
*/
|
||
|
if (alloc) {
|
||
|
for (--i; i >= 0; i--) {
|
||
|
addr -= PAGE_SIZE;
|
||
|
vmem_unmap_4k_page(addr);
|
||
|
}
|
||
|
}
|
||
|
return rc;
|
||
|
}
|
||
|
addr += PAGE_SIZE;
|
||
|
phys += PAGE_SIZE;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void abs_lowcore_unmap(int cpu)
|
||
|
{
|
||
|
unsigned long addr = __abs_lowcore + (cpu * sizeof(struct lowcore));
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < LC_PAGES; i++) {
|
||
|
vmem_unmap_4k_page(addr);
|
||
|
addr += PAGE_SIZE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct lowcore *get_abs_lowcore(unsigned long *flags)
|
||
|
{
|
||
|
unsigned long irq_flags;
|
||
|
union ctlreg0 cr0;
|
||
|
int cpu;
|
||
|
|
||
|
*flags = 0;
|
||
|
cpu = get_cpu();
|
||
|
if (abs_lowcore_mapped) {
|
||
|
return ((struct lowcore *)__abs_lowcore) + cpu;
|
||
|
} else {
|
||
|
if (cpu != 0)
|
||
|
panic("Invalid unmapped absolute lowcore access\n");
|
||
|
local_irq_save(irq_flags);
|
||
|
if (!irqs_disabled_flags(irq_flags))
|
||
|
*flags |= ABS_LOWCORE_IRQS_ON;
|
||
|
__ctl_store(cr0.val, 0, 0);
|
||
|
if (cr0.lap) {
|
||
|
*flags |= ABS_LOWCORE_LAP_ON;
|
||
|
__ctl_clear_bit(0, 28);
|
||
|
}
|
||
|
*flags |= ABS_LOWCORE_UNMAPPED;
|
||
|
return lowcore_ptr[0];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void put_abs_lowcore(struct lowcore *lc, unsigned long flags)
|
||
|
{
|
||
|
if (abs_lowcore_mapped) {
|
||
|
if (flags)
|
||
|
panic("Invalid mapped absolute lowcore release\n");
|
||
|
} else {
|
||
|
if (smp_processor_id() != 0)
|
||
|
panic("Invalid mapped absolute lowcore access\n");
|
||
|
if (!(flags & ABS_LOWCORE_UNMAPPED))
|
||
|
panic("Invalid unmapped absolute lowcore release\n");
|
||
|
if (flags & ABS_LOWCORE_LAP_ON)
|
||
|
__ctl_set_bit(0, 28);
|
||
|
if (flags & ABS_LOWCORE_IRQS_ON)
|
||
|
local_irq_enable();
|
||
|
}
|
||
|
put_cpu();
|
||
|
}
|