Merge tag 'loongarch-fixes-6.15-2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
Pull LoongArch fixes from Huacai Chen:
"Fix some bugs in kernel-fpu, cpu idle function, hibernation and
uprobes"
* tag 'loongarch-fixes-6.15-2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson:
LoongArch: uprobes: Remove redundant code about resume_era
LoongArch: uprobes: Remove user_{en,dis}able_single_step()
LoongArch: Save and restore CSR.CNTC for hibernation
LoongArch: Move __arch_cpu_idle() to .cpuidle.text section
LoongArch: Fix MAX_REG_OFFSET calculation
LoongArch: Prevent cond_resched() occurring within kernel-fpu
This commit is contained in:
@@ -55,7 +55,7 @@ static inline void instruction_pointer_set(struct pt_regs *regs, unsigned long v
|
||||
|
||||
/* Query offset/name of register from its name/offset */
|
||||
extern int regs_query_register_offset(const char *name);
|
||||
#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last))
|
||||
#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last) - sizeof(unsigned long))
|
||||
|
||||
/**
|
||||
* regs_get_register() - get register value from its offset
|
||||
|
||||
@@ -15,7 +15,6 @@ typedef u32 uprobe_opcode_t;
|
||||
#define UPROBE_XOLBP_INSN __emit_break(BRK_UPROBE_XOLBP)
|
||||
|
||||
struct arch_uprobe {
|
||||
unsigned long resume_era;
|
||||
u32 insn[2];
|
||||
u32 ixol[2];
|
||||
bool simulate;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <asm/stackframe.h>
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
.section .cpuidle.text, "ax"
|
||||
.align 5
|
||||
SYM_FUNC_START(__arch_cpu_idle)
|
||||
/* start of idle interrupt region */
|
||||
@@ -31,14 +32,16 @@ SYM_FUNC_START(__arch_cpu_idle)
|
||||
*/
|
||||
idle 0
|
||||
/* end of idle interrupt region */
|
||||
1: jr ra
|
||||
idle_exit:
|
||||
jr ra
|
||||
SYM_FUNC_END(__arch_cpu_idle)
|
||||
.previous
|
||||
|
||||
SYM_CODE_START(handle_vint)
|
||||
UNWIND_HINT_UNDEFINED
|
||||
BACKUP_T0T1
|
||||
SAVE_ALL
|
||||
la_abs t1, 1b
|
||||
la_abs t1, idle_exit
|
||||
LONG_L t0, sp, PT_ERA
|
||||
/* 3 instructions idle interrupt region */
|
||||
ori t0, t0, 0b1100
|
||||
|
||||
@@ -18,11 +18,28 @@ static unsigned int euen_mask = CSR_EUEN_FPEN;
|
||||
static DEFINE_PER_CPU(bool, in_kernel_fpu);
|
||||
static DEFINE_PER_CPU(unsigned int, euen_current);
|
||||
|
||||
static inline void fpregs_lock(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_PREEMPT_RT))
|
||||
preempt_disable();
|
||||
else
|
||||
local_bh_disable();
|
||||
}
|
||||
|
||||
static inline void fpregs_unlock(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_PREEMPT_RT))
|
||||
preempt_enable();
|
||||
else
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
void kernel_fpu_begin(void)
|
||||
{
|
||||
unsigned int *euen_curr;
|
||||
|
||||
preempt_disable();
|
||||
if (!irqs_disabled())
|
||||
fpregs_lock();
|
||||
|
||||
WARN_ON(this_cpu_read(in_kernel_fpu));
|
||||
|
||||
@@ -73,7 +90,8 @@ void kernel_fpu_end(void)
|
||||
|
||||
this_cpu_write(in_kernel_fpu, false);
|
||||
|
||||
preempt_enable();
|
||||
if (!irqs_disabled())
|
||||
fpregs_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kernel_fpu_end);
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ static unsigned long __init get_loops_per_jiffy(void)
|
||||
return lpj;
|
||||
}
|
||||
|
||||
static long init_offset __nosavedata;
|
||||
static long init_offset;
|
||||
|
||||
void save_counter(void)
|
||||
{
|
||||
|
||||
@@ -42,7 +42,6 @@ int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
|
||||
utask->autask.saved_trap_nr = current->thread.trap_nr;
|
||||
current->thread.trap_nr = UPROBE_TRAP_NR;
|
||||
instruction_pointer_set(regs, utask->xol_vaddr);
|
||||
user_enable_single_step(current);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -53,13 +52,7 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
|
||||
|
||||
WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
|
||||
current->thread.trap_nr = utask->autask.saved_trap_nr;
|
||||
|
||||
if (auprobe->simulate)
|
||||
instruction_pointer_set(regs, auprobe->resume_era);
|
||||
else
|
||||
instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE);
|
||||
|
||||
user_disable_single_step(current);
|
||||
instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -70,7 +63,6 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
|
||||
|
||||
current->thread.trap_nr = utask->autask.saved_trap_nr;
|
||||
instruction_pointer_set(regs, utask->vaddr);
|
||||
user_disable_single_step(current);
|
||||
}
|
||||
|
||||
bool arch_uprobe_xol_was_trapped(struct task_struct *t)
|
||||
@@ -90,7 +82,6 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
|
||||
|
||||
insn.word = auprobe->insn[0];
|
||||
arch_simulate_insn(insn, regs);
|
||||
auprobe->resume_era = regs->csr_era;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/loongson.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
@@ -14,6 +15,7 @@ struct pt_regs saved_regs;
|
||||
|
||||
void save_processor_state(void)
|
||||
{
|
||||
save_counter();
|
||||
saved_crmd = csr_read32(LOONGARCH_CSR_CRMD);
|
||||
saved_prmd = csr_read32(LOONGARCH_CSR_PRMD);
|
||||
saved_euen = csr_read32(LOONGARCH_CSR_EUEN);
|
||||
@@ -26,6 +28,7 @@ void save_processor_state(void)
|
||||
|
||||
void restore_processor_state(void)
|
||||
{
|
||||
sync_counter();
|
||||
csr_write32(saved_crmd, LOONGARCH_CSR_CRMD);
|
||||
csr_write32(saved_prmd, LOONGARCH_CSR_PRMD);
|
||||
csr_write32(saved_euen, LOONGARCH_CSR_EUEN);
|
||||
|
||||
Reference in New Issue
Block a user