Commit a362ade8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'loongarch-6.11' of...

Merge tag 'loongarch-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson

Pull LoongArch updates from Huacai Chen:

 - Define __ARCH_WANT_NEW_STAT in unistd.h

 - Always enumerate MADT and setup logical-physical CPU mapping

 - Add irq_work support via self IPIs

 - Add RANDOMIZE_KSTACK_OFFSET support

 - Add ARCH_HAS_PTE_DEVMAP support

 - Add ARCH_HAS_DEBUG_VM_PGTABLE support

 - Add writecombine support for DMW-based ioremap()

 - Add architectural preparation for CPUFreq

 - Add ACPI standard hardware register based S3 support

 - Add support for relocating the kernel with RELR relocation

 - Some bug fixes and other small changes

* tag 'loongarch-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson:
  LoongArch: Make the users of larch_insn_gen_break() constant
  LoongArch: Check TIF_LOAD_WATCH to enable user space watchpoint
  LoongArch: Use rustc option -Zdirect-access-external-data
  LoongArch: Add support for relocating the kernel with RELR relocation
  LoongArch: Remove a redundant checking in relocator
  LoongArch: Use correct API to map cmdline in relocate_kernel()
  LoongArch: Automatically disable KASLR for hibernation
  LoongArch: Add ACPI standard hardware register based S3 support
  LoongArch: Add architectural preparation for CPUFreq
  LoongArch: Add writecombine support for DMW-based ioremap()
  LoongArch: Add ARCH_HAS_DEBUG_VM_PGTABLE support
  LoongArch: Add ARCH_HAS_PTE_DEVMAP support
  LoongArch: Add RANDOMIZE_KSTACK_OFFSET support
  LoongArch: Add irq_work support via self IPIs
  LoongArch: Always enumerate MADT and setup logical-physical CPU mapping
  LoongArch: Define __ARCH_WANT_NEW_STAT in unistd.h
parents 539fbb91 998b17d4
......@@ -12,7 +12,7 @@
| arm64: | ok |
| csky: | TODO |
| hexagon: | TODO |
| loongarch: | TODO |
| loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
......
......@@ -16,12 +16,14 @@ config LOONGARCH
select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
select ARCH_HAS_CPU_FINALIZE_INIT
select ARCH_HAS_CURRENT_STACK_POINTER
select ARCH_HAS_DEBUG_VM_PGTABLE
select ARCH_HAS_FAST_MULTIPLIER
select ARCH_HAS_FORTIFY_SOURCE
select ARCH_HAS_KCOV
select ARCH_HAS_KERNEL_FPU_SUPPORT if CPU_HAS_FPU
select ARCH_HAS_NMI_SAFE_THIS_CPU_OPS
select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
select ARCH_HAS_PTE_DEVMAP
select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_INLINE_READ_LOCK if !PREEMPTION
......@@ -106,6 +108,7 @@ config LOONGARCH
select HAVE_ARCH_KFENCE
select HAVE_ARCH_KGDB if PERF_EVENTS
select HAVE_ARCH_MMAP_RND_BITS if MMU
select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
select HAVE_ARCH_SECCOMP
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
......@@ -607,6 +610,7 @@ config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
config RELOCATABLE
bool "Relocatable kernel"
select ARCH_HAS_RELR
help
This builds the kernel as a Position Independent Executable (PIE),
which retains all relocation metadata required, so as to relocate
......@@ -710,6 +714,7 @@ config ARCH_HIBERNATION_POSSIBLE
source "kernel/power/Kconfig"
source "drivers/acpi/Kconfig"
source "drivers/cpufreq/Kconfig"
endmenu
......
......@@ -105,7 +105,8 @@ KBUILD_CFLAGS += -fno-jump-tables
endif
KBUILD_RUSTFLAGS += --target=loongarch64-unknown-none-softfloat
KBUILD_RUSTFLAGS_MODULE += -Crelocation-model=pic
KBUILD_RUSTFLAGS_KERNEL += -Zdirect-access-external-data=yes
KBUILD_RUSTFLAGS_MODULE += -Zdirect-access-external-data=no
ifeq ($(CONFIG_RELOCATABLE),y)
KBUILD_CFLAGS_KERNEL += -fPIE
......
......@@ -37,6 +37,10 @@ extern unsigned long vm_map_base;
#define UNCACHE_BASE CSR_DMW0_BASE
#endif
#ifndef WRITECOMBINE_BASE
#define WRITECOMBINE_BASE CSR_DMW2_BASE
#endif
#define DMW_PABITS 48
#define TO_PHYS_MASK ((1ULL << DMW_PABITS) - 1)
......
......@@ -609,6 +609,7 @@
lu32i.d \reg, 0
lu52i.d \reg, \reg, 0
.pushsection ".la_abs", "aw", %progbits
.p2align 3
.dword 766b
.dword \sym
.popsection
......
......@@ -12,11 +12,12 @@
extern void ack_bad_irq(unsigned int irq);
#define ack_bad_irq ack_bad_irq
#define NR_IPI 2
#define NR_IPI 3
enum ipi_msg_type {
IPI_RESCHEDULE,
IPI_CALL_FUNCTION,
IPI_IRQ_WORK,
};
typedef struct {
......
......@@ -532,6 +532,9 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \
DEF_EMIT_REG0I15_FORMAT(break, break_op)
/* like emit_break(imm) but returns a constant expression */
#define __emit_break(imm) ((u32)((imm) | (break_op << 15)))
#define DEF_EMIT_REG0I26_FORMAT(NAME, OP) \
static inline void emit_##NAME(union loongarch_instruction *insn, \
int offset) \
......
......@@ -25,10 +25,16 @@ extern void __init early_iounmap(void __iomem *addr, unsigned long size);
static inline void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
unsigned long prot_val)
{
if (prot_val & _CACHE_CC)
switch (prot_val & _CACHE_MASK) {
case _CACHE_CC:
return (void __iomem *)(unsigned long)(CACHE_BASE + offset);
else
case _CACHE_SUC:
return (void __iomem *)(unsigned long)(UNCACHE_BASE + offset);
case _CACHE_WUC:
return (void __iomem *)(unsigned long)(WRITECOMBINE_BASE + offset);
default:
return NULL;
}
}
#define ioremap(offset, size) \
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_LOONGARCH_IRQ_WORK_H
#define _ASM_LOONGARCH_IRQ_WORK_H
static inline bool arch_irq_work_has_interrupt(void)
{
return IS_ENABLED(CONFIG_SMP);
}
#endif /* _ASM_LOONGARCH_IRQ_WORK_H */
......@@ -878,7 +878,7 @@
#define LOONGARCH_CSR_DMWIN2 0x182 /* 64 direct map win2: MEM */
#define LOONGARCH_CSR_DMWIN3 0x183 /* 64 direct map win3: MEM */
/* Direct Map window 0/1 */
/* Direct Map window 0/1/2/3 */
#define CSR_DMW0_PLV0 _CONST64_(1 << 0)
#define CSR_DMW0_VSEG _CONST64_(0x8000)
#define CSR_DMW0_BASE (CSR_DMW0_VSEG << DMW_PABITS)
......@@ -890,6 +890,14 @@
#define CSR_DMW1_BASE (CSR_DMW1_VSEG << DMW_PABITS)
#define CSR_DMW1_INIT (CSR_DMW1_BASE | CSR_DMW1_MAT | CSR_DMW1_PLV0)
#define CSR_DMW2_PLV0 _CONST64_(1 << 0)
#define CSR_DMW2_MAT _CONST64_(2 << 4)
#define CSR_DMW2_VSEG _CONST64_(0xa000)
#define CSR_DMW2_BASE (CSR_DMW2_VSEG << DMW_PABITS)
#define CSR_DMW2_INIT (CSR_DMW2_BASE | CSR_DMW2_MAT | CSR_DMW2_PLV0)
#define CSR_DMW3_INIT 0x0
/* Performance Counter registers */
#define LOONGARCH_CSR_PERFCTRL0 0x200 /* 32 perf event 0 config */
#define LOONGARCH_CSR_PERFCNTR0 0x201 /* 64 perf event 0 count value */
......@@ -1054,11 +1062,14 @@
#define LOONGARCH_IOCSR_NODECNT 0x408
#define LOONGARCH_IOCSR_MISC_FUNC 0x420
#define IOCSR_MISC_FUNC_SOFT_INT BIT_ULL(10)
#define IOCSR_MISC_FUNC_TIMER_RESET BIT_ULL(21)
#define IOCSR_MISC_FUNC_EXT_IOI_EN BIT_ULL(48)
#define LOONGARCH_IOCSR_CPUTEMP 0x428
#define LOONGARCH_IOCSR_SMCMBX 0x51c
/* PerCore CSR, only accessible by local cores */
#define LOONGARCH_IOCSR_IPI_STATUS 0x1000
#define LOONGARCH_IOCSR_IPI_EN 0x1004
......
......@@ -22,6 +22,7 @@
#define _PAGE_PFN_SHIFT 12
#define _PAGE_SWP_EXCLUSIVE_SHIFT 23
#define _PAGE_PFN_END_SHIFT 48
#define _PAGE_DEVMAP_SHIFT 59
#define _PAGE_PRESENT_INVALID_SHIFT 60
#define _PAGE_NO_READ_SHIFT 61
#define _PAGE_NO_EXEC_SHIFT 62
......@@ -35,6 +36,7 @@
#define _PAGE_MODIFIED (_ULCAST_(1) << _PAGE_MODIFIED_SHIFT)
#define _PAGE_PROTNONE (_ULCAST_(1) << _PAGE_PROTNONE_SHIFT)
#define _PAGE_SPECIAL (_ULCAST_(1) << _PAGE_SPECIAL_SHIFT)
#define _PAGE_DEVMAP (_ULCAST_(1) << _PAGE_DEVMAP_SHIFT)
/* We borrow bit 23 to store the exclusive marker in swap PTEs. */
#define _PAGE_SWP_EXCLUSIVE (_ULCAST_(1) << _PAGE_SWP_EXCLUSIVE_SHIFT)
......@@ -74,8 +76,8 @@
#define __READABLE (_PAGE_VALID)
#define __WRITEABLE (_PAGE_DIRTY | _PAGE_WRITE)
#define _PAGE_CHG_MASK (_PAGE_MODIFIED | _PAGE_SPECIAL | _PFN_MASK | _CACHE_MASK | _PAGE_PLV)
#define _HPAGE_CHG_MASK (_PAGE_MODIFIED | _PAGE_SPECIAL | _PFN_MASK | _CACHE_MASK | _PAGE_PLV | _PAGE_HUGE)
#define _PAGE_CHG_MASK (_PAGE_MODIFIED | _PAGE_SPECIAL | _PAGE_DEVMAP | _PFN_MASK | _CACHE_MASK | _PAGE_PLV)
#define _HPAGE_CHG_MASK (_PAGE_MODIFIED | _PAGE_SPECIAL | _PAGE_DEVMAP | _PFN_MASK | _CACHE_MASK | _PAGE_PLV | _PAGE_HUGE)
#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_NO_READ | \
_PAGE_USER | _CACHE_CC)
......
......@@ -424,6 +424,9 @@ static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL;
static inline pte_t pte_mkspecial(pte_t pte) { pte_val(pte) |= _PAGE_SPECIAL; return pte; }
#endif /* CONFIG_ARCH_HAS_PTE_SPECIAL */
static inline int pte_devmap(pte_t pte) { return !!(pte_val(pte) & _PAGE_DEVMAP); }
static inline pte_t pte_mkdevmap(pte_t pte) { pte_val(pte) |= _PAGE_DEVMAP; return pte; }
#define pte_accessible pte_accessible
static inline unsigned long pte_accessible(struct mm_struct *mm, pte_t a)
{
......@@ -558,6 +561,17 @@ static inline pmd_t pmd_mkyoung(pmd_t pmd)
return pmd;
}
static inline int pmd_devmap(pmd_t pmd)
{
return !!(pmd_val(pmd) & _PAGE_DEVMAP);
}
static inline pmd_t pmd_mkdevmap(pmd_t pmd)
{
pmd_val(pmd) |= _PAGE_DEVMAP;
return pmd;
}
static inline struct page *pmd_page(pmd_t pmd)
{
if (pmd_trans_huge(pmd))
......@@ -613,6 +627,11 @@ static inline long pmd_protnone(pmd_t pmd)
#define pmd_leaf(pmd) ((pmd_val(pmd) & _PAGE_HUGE) != 0)
#define pud_leaf(pud) ((pud_val(pud) & _PAGE_HUGE) != 0)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define pud_devmap(pud) (0)
#define pgd_devmap(pgd) (0)
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
/*
* We provide our own get_unmapped area to cope with the virtual aliasing
* constraints placed on us by the cache architecture.
......
......@@ -34,6 +34,11 @@ extern long __la_abs_end;
extern long __rela_dyn_begin;
extern long __rela_dyn_end;
#ifdef CONFIG_RELR
extern long __relr_dyn_begin;
extern long __relr_dyn_end;
#endif
extern unsigned long __init relocate_kernel(void);
#endif
......
......@@ -69,9 +69,11 @@ extern int __cpu_logical_map[NR_CPUS];
#define ACTION_BOOT_CPU 0
#define ACTION_RESCHEDULE 1
#define ACTION_CALL_FUNCTION 2
#define ACTION_IRQ_WORK 3
#define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU)
#define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE)
#define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION)
#define SMP_IRQ_WORK BIT(ACTION_IRQ_WORK)
struct secondary_data {
unsigned long stack;
......
......@@ -38,6 +38,17 @@
cfi_restore \reg \offset \docfi
.endm
.macro SETUP_DMWINS temp
li.d \temp, CSR_DMW0_INIT # WUC, PLV0, 0x8000 xxxx xxxx xxxx
csrwr \temp, LOONGARCH_CSR_DMWIN0
li.d \temp, CSR_DMW1_INIT # CAC, PLV0, 0x9000 xxxx xxxx xxxx
csrwr \temp, LOONGARCH_CSR_DMWIN1
li.d \temp, CSR_DMW2_INIT # WUC, PLV0, 0xa000 xxxx xxxx xxxx
csrwr \temp, LOONGARCH_CSR_DMWIN2
li.d \temp, CSR_DMW3_INIT # 0x0, unused
csrwr \temp, LOONGARCH_CSR_DMWIN3
.endm
/* Jump to the runtime virtual address. */
.macro JUMP_VIRT_ADDR temp1 temp2
li.d \temp1, CACHE_BASE
......
......@@ -8,6 +8,7 @@
#include <uapi/asm/unistd.h>
#define __ARCH_WANT_NEW_STAT
#define __ARCH_WANT_SYS_CLONE
#define NR_syscalls (__NR_syscalls)
......@@ -9,10 +9,10 @@ typedef u32 uprobe_opcode_t;
#define MAX_UINSN_BYTES 8
#define UPROBE_XOL_SLOT_BYTES MAX_UINSN_BYTES
#define UPROBE_SWBP_INSN larch_insn_gen_break(BRK_UPROBE_BP)
#define UPROBE_SWBP_INSN __emit_break(BRK_UPROBE_BP)
#define UPROBE_SWBP_INSN_SIZE LOONGARCH_INSN_SIZE
#define UPROBE_XOLBP_INSN larch_insn_gen_break(BRK_UPROBE_XOLBP)
#define UPROBE_XOLBP_INSN __emit_break(BRK_UPROBE_XOLBP)
struct arch_uprobe {
unsigned long resume_era;
......
# SPDX-License-Identifier: GPL-2.0
# No special ABIs on loongarch so far
syscall_abis_64 +=
syscall_abis_64 += newstat
......@@ -57,15 +57,22 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
return ioremap_cache(phys, size);
}
static int cpu_enumerated = 0;
#ifdef CONFIG_SMP
static int set_processor_mask(u32 id, u32 flags)
{
int nr_cpus;
int cpu, cpuid = id;
if (num_processors >= nr_cpu_ids) {
pr_warn(PREFIX "nr_cpus/possible_cpus limit of %i reached."
" processor 0x%x ignored.\n", nr_cpu_ids, cpuid);
if (!cpu_enumerated)
nr_cpus = NR_CPUS;
else
nr_cpus = nr_cpu_ids;
if (num_processors >= nr_cpus) {
pr_warn(PREFIX "nr_cpus limit of %i reached."
" processor 0x%x ignored.\n", nr_cpus, cpuid);
return -ENODEV;
......@@ -73,11 +80,13 @@ static int set_processor_mask(u32 id, u32 flags)
if (cpuid == loongson_sysconf.boot_cpu_id)
cpu = 0;
else
cpu = cpumask_next_zero(-1, cpu_present_mask);
cpu = find_first_zero_bit(cpumask_bits(cpu_present_mask), NR_CPUS);
if (!cpu_enumerated)
set_cpu_possible(cpu, true);
if (flags & ACPI_MADT_ENABLED) {
num_processors++;
set_cpu_possible(cpu, true);
set_cpu_present(cpu, true);
__cpu_number_map[cpuid] = cpu;
__cpu_logical_map[cpu] = cpuid;
......@@ -138,6 +147,7 @@ static void __init acpi_process_madt(void)
acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC,
acpi_parse_eio_master, MAX_IO_PICS);
cpu_enumerated = 1;
loongson_sysconf.nr_cpus = num_processors;
}
......
......@@ -44,11 +44,7 @@ SYM_DATA(kernel_fsize, .long _kernel_fsize);
SYM_CODE_START(kernel_entry) # kernel entry point
/* Config direct window and set PG */
li.d t0, CSR_DMW0_INIT # UC, PLV0, 0x8000 xxxx xxxx xxxx
csrwr t0, LOONGARCH_CSR_DMWIN0
li.d t0, CSR_DMW1_INIT # CA, PLV0, 0x9000 xxxx xxxx xxxx
csrwr t0, LOONGARCH_CSR_DMWIN1
SETUP_DMWINS t0
JUMP_VIRT_ADDR t0, t1
/* Enable PG */
......@@ -124,11 +120,8 @@ SYM_CODE_END(kernel_entry)
* function after setting up the stack and tp registers.
*/
SYM_CODE_START(smpboot_entry)
li.d t0, CSR_DMW0_INIT # UC, PLV0
csrwr t0, LOONGARCH_CSR_DMWIN0
li.d t0, CSR_DMW1_INIT # CA, PLV0
csrwr t0, LOONGARCH_CSR_DMWIN1
SETUP_DMWINS t0
JUMP_VIRT_ADDR t0, t1
#ifdef CONFIG_PAGE_SIZE_4KB
......
......@@ -221,7 +221,7 @@ static int hw_breakpoint_control(struct perf_event *bp,
}
enable = csr_read64(LOONGARCH_CSR_CRMD);
csr_write64(CSR_CRMD_WE | enable, LOONGARCH_CSR_CRMD);
if (bp->hw.target)
if (bp->hw.target && test_tsk_thread_flag(bp->hw.target, TIF_LOAD_WATCH))
regs->csr_prmd |= CSR_PRMD_PWE;
break;
case HW_BREAKPOINT_UNINSTALL:
......
......@@ -4,8 +4,8 @@
#include <linux/preempt.h>
#include <asm/break.h>
#define KPROBE_BP_INSN larch_insn_gen_break(BRK_KPROBE_BP)
#define KPROBE_SSTEPBP_INSN larch_insn_gen_break(BRK_KPROBE_SSTEPBP)
#define KPROBE_BP_INSN __emit_break(BRK_KPROBE_BP)
#define KPROBE_SSTEPBP_INSN __emit_break(BRK_KPROBE_SSTEPBP)
DEFINE_PER_CPU(struct kprobe *, current_kprobe);
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
......
......@@ -2,6 +2,7 @@
#include <linux/export.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/irq_work.h>
#include <linux/jump_label.h>
#include <linux/kvm_para.h>
#include <linux/reboot.h>
......@@ -128,6 +129,11 @@ static irqreturn_t pv_ipi_interrupt(int irq, void *dev)
info->ipi_irqs[IPI_CALL_FUNCTION]++;
}
if (action & SMP_IRQ_WORK) {
irq_work_run();
info->ipi_irqs[IPI_IRQ_WORK]++;
}
return IRQ_HANDLED;
}
......
......@@ -589,6 +589,7 @@ static int ptrace_hbp_set_ctrl(unsigned int note_type,
struct perf_event *bp;
struct perf_event_attr attr;
struct arch_hw_breakpoint_ctrl ctrl;
struct thread_info *ti = task_thread_info(tsk);
bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
if (IS_ERR(bp))
......@@ -613,8 +614,10 @@ static int ptrace_hbp_set_ctrl(unsigned int note_type,
if (err)
return err;
attr.disabled = 0;
set_ti_thread_flag(ti, TIF_LOAD_WATCH);
} else {
attr.disabled = 1;
clear_ti_thread_flag(ti, TIF_LOAD_WATCH);
}
return modify_user_hw_breakpoint(bp, &attr);
......
......@@ -13,6 +13,7 @@
#include <asm/bootinfo.h>
#include <asm/early_ioremap.h>
#include <asm/inst.h>
#include <asm/io.h>
#include <asm/sections.h>
#include <asm/setup.h>
......@@ -34,11 +35,27 @@ static inline void __init relocate_relative(void)
if (rela->r_info != R_LARCH_RELATIVE)
continue;
if (relocated_addr >= VMLINUX_LOAD_ADDRESS)
relocated_addr = (Elf64_Addr)RELOCATED(relocated_addr);
relocated_addr = (Elf64_Addr)RELOCATED(relocated_addr);
*(Elf64_Addr *)RELOCATED(addr) = relocated_addr;
}
#ifdef CONFIG_RELR
u64 *addr = NULL;
u64 *relr = (u64 *)&__relr_dyn_begin;
u64 *relr_end = (u64 *)&__relr_dyn_end;
for ( ; relr < relr_end; relr++) {
if ((*relr & 1) == 0) {
addr = (u64 *)(*relr + reloc_offset);
*addr++ += reloc_offset;
} else {
for (u64 *p = addr, r = *relr >> 1; r; p++, r >>= 1)
if (r & 1)
*p += reloc_offset;
addr += 63;
}
}
#endif
}
static inline void __init relocate_absolute(long random_offset)
......@@ -123,6 +140,32 @@ static inline __init bool kaslr_disabled(void)
if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' '))
return true;
#ifdef CONFIG_HIBERNATION
str = strstr(builtin_cmdline, "nohibernate");
if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' '))
return false;
str = strstr(boot_command_line, "nohibernate");
if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' '))
return false;
str = strstr(builtin_cmdline, "noresume");
if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' '))
return false;
str = strstr(boot_command_line, "noresume");
if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' '))
return false;
str = strstr(builtin_cmdline, "resume=");
if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' '))
return true;
str = strstr(boot_command_line, "resume=");
if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' '))
return true;
#endif
return false;
}
......@@ -170,7 +213,7 @@ unsigned long __init relocate_kernel(void)
unsigned long kernel_length;
unsigned long random_offset = 0;
void *location_new = _text; /* Default to original kernel start */
char *cmdline = early_ioremap(fw_arg1, COMMAND_LINE_SIZE); /* Boot command line is passed in fw_arg1 */
char *cmdline = early_memremap_ro(fw_arg1, COMMAND_LINE_SIZE); /* Boot command line is passed in fw_arg1 */
strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE);
......@@ -182,6 +225,7 @@ unsigned long __init relocate_kernel(void)
random_offset = (unsigned long)location_new - (unsigned long)(_text);
#endif
reloc_offset = (unsigned long)_text - VMLINUX_LOAD_ADDRESS;
early_memunmap(cmdline, COMMAND_LINE_SIZE);
if (random_offset) {
kernel_length = (long)(_end) - (long)(_text);
......
......@@ -576,8 +576,10 @@ static void __init prefill_possible_map(void)
for (i = 0; i < possible; i++)
set_cpu_possible(i, true);
for (; i < NR_CPUS; i++)
for (; i < NR_CPUS; i++) {
set_cpu_present(i, false);
set_cpu_possible(i, false);
}
set_nr_cpu_ids(possible);
}
......
......@@ -13,6 +13,7 @@
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq_work.h>
#include <linux/profile.h>
#include <linux/seq_file.h>
#include <linux/smp.h>
......@@ -70,6 +71,7 @@ static DEFINE_PER_CPU(int, cpu_state);
static const char *ipi_types[NR_IPI] __tracepoint_string = {
[IPI_RESCHEDULE] = "Rescheduling interrupts",
[IPI_CALL_FUNCTION] = "Function call interrupts",
[IPI_IRQ_WORK] = "IRQ work interrupts",
};
void show_ipi_list(struct seq_file *p, int prec)
......@@ -217,6 +219,13 @@ void arch_smp_send_reschedule(int cpu)
}
EXPORT_SYMBOL_GPL(arch_smp_send_reschedule);
#ifdef CONFIG_IRQ_WORK
void arch_irq_work_raise(void)
{
mp_ops.send_ipi_single(smp_processor_id(), ACTION_IRQ_WORK);
}
#endif
static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
{
unsigned int action;
......@@ -234,6 +243,11 @@ static irqreturn_t loongson_ipi_interrupt(int irq, void *dev)
per_cpu(irq_stat, cpu).ipi_irqs[IPI_CALL_FUNCTION]++;
}
if (action & SMP_IRQ_WORK) {
irq_work_run();
per_cpu(irq_stat, cpu).ipi_irqs[IPI_IRQ_WORK]++;
}
return IRQ_HANDLED;
}
......@@ -271,11 +285,10 @@ static void __init fdt_smp_setup(void)
if (cpuid >= nr_cpu_ids)
continue;
if (cpuid == loongson_sysconf.boot_cpu_id) {
if (cpuid == loongson_sysconf.boot_cpu_id)
cpu = 0;
} else {
cpu = cpumask_next_zero(-1, cpu_present_mask);
}
else
cpu = find_first_zero_bit(cpumask_bits(cpu_present_mask), NR_CPUS);
num_processors++;
set_cpu_possible(cpu, true);
......
......@@ -9,11 +9,14 @@
#include <linux/entry-common.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/objtool.h>
#include <linux/randomize_kstack.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
#include <asm/asm.h>
#include <asm/exception.h>
#include <asm/loongarch.h>
#include <asm/signal.h>
#include <asm/switch_to.h>
#include <asm-generic/syscalls.h>
......@@ -39,7 +42,7 @@ void *sys_call_table[__NR_syscalls] = {
typedef long (*sys_call_fn)(unsigned long, unsigned long,
unsigned long, unsigned long, unsigned long, unsigned long);
void noinstr do_syscall(struct pt_regs *regs)
void noinstr __no_stack_protector do_syscall(struct pt_regs *regs)
{
unsigned long nr;
sys_call_fn syscall_fn;
......@@ -55,11 +58,28 @@ void noinstr do_syscall(struct pt_regs *regs)
nr = syscall_enter_from_user_mode(regs, nr);
add_random_kstack_offset();
if (nr < NR_syscalls) {
syscall_fn = sys_call_table[nr];
regs->regs[4] = syscall_fn(regs->orig_a0, regs->regs[5], regs->regs[6],
regs->regs[7], regs->regs[8], regs->regs[9]);
}
/*
* This value will get limited by KSTACK_OFFSET_MAX(), which is 10
* bits. The actual entropy will be further reduced by the compiler
* when applying stack alignment constraints: 16-bytes (i.e. 4-bits)
* aligned, which will remove the 4 low bits from any entropy chosen
* here.
*
* The resulting 6 bits of entropy is seen in SP[9:4].
*/
choose_random_kstack_offset(drdtime());
syscall_exit_to_user_mode(regs);
}
#ifdef CONFIG_RANDOMIZE_KSTACK_OFFSET
STACK_FRAME_NON_STANDARD(do_syscall);
#endif
......@@ -113,6 +113,14 @@ SECTIONS
__rela_dyn_end = .;
}
#ifdef CONFIG_RELR
.relr.dyn : ALIGN(8) {
__relr_dyn_begin = .;
*(.relr.dyn)
__relr_dyn_end = .;
}
#endif
.data.rel : { *(.data.rel*) }
#ifdef CONFIG_RELOCATABLE
......
......@@ -34,22 +34,49 @@ void enable_pci_wakeup(void)
acpi_write_bit_register(ACPI_BITREG_PCIEXP_WAKE_DISABLE, 0);
}
static struct platform_device loongson3_cpufreq_device = {
.name = "loongson3_cpufreq",
.id = -1,
};
static int __init loongson_cpufreq_init(void)
{
if (!cpu_has_scalefreq)
return -ENODEV;
return platform_device_register(&loongson3_cpufreq_device);
}
arch_initcall(loongson_cpufreq_init);
static void default_suspend_addr(void)
{
acpi_enter_sleep_state(ACPI_STATE_S3);
}
static int __init loongson3_acpi_suspend_init(void)
{
#ifdef CONFIG_ACPI
acpi_status status;
uint64_t suspend_addr = 0;
if (acpi_disabled || acpi_gbl_reduced_hardware)
if (acpi_disabled)
return 0;
if (!acpi_gbl_reduced_hardware)
acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
if (!acpi_sleep_state_supported(ACPI_STATE_S3))
return 0;
acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
status = acpi_evaluate_integer(NULL, "\\SADR", NULL, &suspend_addr);
if (ACPI_FAILURE(status) || !suspend_addr) {
pr_err("ACPI S3 is not support!\n");
return -1;
pr_info("ACPI S3 supported with hardware register default\n");
loongson_sysconf.suspend_addr = (u64)default_suspend_addr;
} else {
pr_info("ACPI S3 supported with Loongson ACPI SADR extension\n");
loongson_sysconf.suspend_addr = (u64)phys_to_virt(PHYSADDR(suspend_addr));
}
loongson_sysconf.suspend_addr = (u64)phys_to_virt(PHYSADDR(suspend_addr));
#endif
return 0;
}
......
......@@ -66,18 +66,14 @@ SYM_FUNC_START(loongarch_suspend_enter)
la.pcrel a0, loongarch_wakeup_start
la.pcrel t0, loongarch_suspend_addr
ld.d t0, t0, 0
jirl a0, t0, 0 /* Call BIOS's STR sleep routine */
jirl ra, t0, 0 /* Call BIOS's STR sleep routine */
/*
* This is where we return upon wakeup.
* Reload all of the registers and return.
*/
SYM_INNER_LABEL(loongarch_wakeup_start, SYM_L_GLOBAL)
li.d t0, CSR_DMW0_INIT # UC, PLV0
csrwr t0, LOONGARCH_CSR_DMWIN0
li.d t0, CSR_DMW1_INIT # CA, PLV0
csrwr t0, LOONGARCH_CSR_DMWIN1
SETUP_DMWINS t0
JUMP_VIRT_ADDR t0, t1
/* Enable PG */
......
......@@ -74,6 +74,8 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
/* Config Direct Mapping */
csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
csr_write64(CSR_DMW2_INIT, LOONGARCH_CSR_DMWIN2);
csr_write64(CSR_DMW3_INIT, LOONGARCH_CSR_DMWIN3);
real_kernel_entry = (void *)kernel_entry_address(kernel_addr, image);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment