Merge "Merge 5eea5820c7 ("Merge tag 'mm-stable-2023-09-04-14-00' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm") into android-mainline" into android-mainline
This commit is contained in:
@@ -461,6 +461,7 @@ Memory Area, or VMA) there is a series of lines such as the following::
|
||||
Private_Dirty: 0 kB
|
||||
Referenced: 892 kB
|
||||
Anonymous: 0 kB
|
||||
KSM: 0 kB
|
||||
LazyFree: 0 kB
|
||||
AnonHugePages: 0 kB
|
||||
ShmemPmdMapped: 0 kB
|
||||
@@ -501,6 +502,9 @@ accessed.
|
||||
a mapping associated with a file may contain anonymous pages: when MAP_PRIVATE
|
||||
and a page is modified, the file page is replaced by a private anonymous copy.
|
||||
|
||||
"KSM" reports how many of the pages are KSM pages. Note that KSM-placed zeropages
|
||||
are not included, only actual KSM pages.
|
||||
|
||||
"LazyFree" shows the amount of memory which is marked by madvise(MADV_FREE).
|
||||
The memory isn't freed immediately with madvise(). It's freed in memory
|
||||
pressure if the memory is clean. Please note that the printed value might
|
||||
|
||||
@@ -13749,6 +13749,7 @@ F: include/linux/memory_hotplug.h
|
||||
F: include/linux/mm.h
|
||||
F: include/linux/mmzone.h
|
||||
F: include/linux/pagewalk.h
|
||||
F: include/linux/rmap.h
|
||||
F: include/trace/events/ksm.h
|
||||
F: mm/
|
||||
F: tools/mm/
|
||||
|
||||
+5
-3
@@ -27,6 +27,8 @@ config ARC
|
||||
select GENERIC_SCHED_CLOCK
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select GENERIC_IOREMAP
|
||||
select GENERIC_STRNCPY_FROM_USER if MMU
|
||||
select GENERIC_STRNLEN_USER if MMU
|
||||
select HAVE_ARCH_KGDB
|
||||
select HAVE_ARCH_TRACEHOOK
|
||||
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if ARC_MMU_V4
|
||||
@@ -491,11 +493,11 @@ config ARC_KVADDR_SIZE
|
||||
kernel-user gutter)
|
||||
|
||||
config ARC_CURR_IN_REG
|
||||
bool "Dedicate Register r25 for current_task pointer"
|
||||
bool "cache current task pointer in gp"
|
||||
default y
|
||||
help
|
||||
This reserved Register R25 to point to Current Task in
|
||||
kernel mode. This saves memory access for each such access
|
||||
This reserves gp register to point to Current Task in
|
||||
kernel mode eliding memory access for each access
|
||||
|
||||
|
||||
config ARC_EMUL_UNALIGNED
|
||||
|
||||
+3
-3
@@ -28,14 +28,14 @@ cflags-y += $(tune-mcpu-def-y)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifdef CONFIG_ARC_CURR_IN_REG
|
||||
# For a global register definition, make sure it gets passed to every file
|
||||
# We had a customer reported bug where some code built in kernel was NOT using
|
||||
# any kernel headers, and missing the r25 global register
|
||||
# any kernel headers, and missing the global register
|
||||
# Can't do unconditionally because of recursive include issues
|
||||
# due to <linux/thread_info.h>
|
||||
LINUXINCLUDE += -include $(srctree)/arch/arc/include/asm/current.h
|
||||
cflags-y += -ffixed-gp
|
||||
endif
|
||||
|
||||
cflags-y += -fsection-anchors
|
||||
@@ -67,7 +67,7 @@ cflags-$(CONFIG_ARC_DW2_UNWIND) += -fasynchronous-unwind-tables $(cfi)
|
||||
# small data is default for elf32 tool-chain. If not usable, disable it
|
||||
# This also allows repurposing GP as scratch reg to gcc reg allocator
|
||||
disable_small_data := y
|
||||
cflags-$(disable_small_data) += -mno-sdata -fcall-used-gp
|
||||
cflags-$(disable_small_data) += -mno-sdata
|
||||
|
||||
cflags-$(CONFIG_CPU_BIG_ENDIAN) += -mbig-endian
|
||||
ldflags-$(CONFIG_CPU_BIG_ENDIAN) += -EB
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#define ARC_REG_ICCM_BUILD 0x78 /* ICCM size (common) */
|
||||
#define ARC_REG_XY_MEM_BCR 0x79
|
||||
#define ARC_REG_MAC_BCR 0x7a
|
||||
#define ARC_REG_MUL_BCR 0x7b
|
||||
#define ARC_REG_MPY_BCR 0x7b
|
||||
#define ARC_REG_SWAP_BCR 0x7c
|
||||
#define ARC_REG_NORM_BCR 0x7d
|
||||
#define ARC_REG_MIXMAX_BCR 0x7e
|
||||
@@ -177,7 +177,7 @@ struct bcr_isa_arcv2 {
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bcr_uarch_build_arcv2 {
|
||||
struct bcr_uarch_build {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int pad:8, prod:8, maj:8, min:8;
|
||||
#else
|
||||
@@ -185,6 +185,59 @@ struct bcr_uarch_build_arcv2 {
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bcr_mmu_3 {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int ver:8, ways:4, sets:4, res:3, sasid:1, pg_sz:4,
|
||||
u_itlb:4, u_dtlb:4;
|
||||
#else
|
||||
unsigned int u_dtlb:4, u_itlb:4, pg_sz:4, sasid:1, res:3, sets:4,
|
||||
ways:4, ver:8;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bcr_mmu_4 {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int ver:8, sasid:1, sz1:4, sz0:4, res:2, pae:1,
|
||||
n_ways:2, n_entry:2, n_super:2, u_itlb:3, u_dtlb:3;
|
||||
#else
|
||||
/* DTLB ITLB JES JE JA */
|
||||
unsigned int u_dtlb:3, u_itlb:3, n_super:2, n_entry:2, n_ways:2,
|
||||
pae:1, res:2, sz0:4, sz1:4, sasid:1, ver:8;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bcr_cache {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
|
||||
#else
|
||||
unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bcr_slc_cfg {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int pad:24, way:2, lsz:2, sz:4;
|
||||
#else
|
||||
unsigned int sz:4, lsz:2, way:2, pad:24;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bcr_clust_cfg {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8;
|
||||
#else
|
||||
unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bcr_volatile {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int start:4, limit:4, pad:22, order:1, disable:1;
|
||||
#else
|
||||
unsigned int disable:1, order:1, pad:22, limit:4, start:4;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct bcr_mpy {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int pad:8, x1616:8, dsp:4, cycles:2, type:2, ver:8;
|
||||
@@ -302,48 +355,6 @@ struct bcr_generic {
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
*******************************************************************
|
||||
* Generic structures to hold build configuration used at runtime
|
||||
*/
|
||||
|
||||
struct cpuinfo_arc_mmu {
|
||||
unsigned int ver:4, pg_sz_k:8, s_pg_sz_m:8, pad:10, sasid:1, pae:1;
|
||||
unsigned int sets:12, ways:4, u_dtlb:8, u_itlb:8;
|
||||
};
|
||||
|
||||
struct cpuinfo_arc_cache {
|
||||
unsigned int sz_k:14, line_len:8, assoc:4, alias:1, vipt:1, pad:4;
|
||||
};
|
||||
|
||||
struct cpuinfo_arc_bpu {
|
||||
unsigned int ver, full, num_cache, num_pred, ret_stk;
|
||||
};
|
||||
|
||||
struct cpuinfo_arc_ccm {
|
||||
unsigned int base_addr, sz;
|
||||
};
|
||||
|
||||
struct cpuinfo_arc {
|
||||
struct cpuinfo_arc_cache icache, dcache, slc;
|
||||
struct cpuinfo_arc_mmu mmu;
|
||||
struct cpuinfo_arc_bpu bpu;
|
||||
struct bcr_identity core;
|
||||
struct bcr_isa_arcv2 isa;
|
||||
const char *release, *name;
|
||||
unsigned int vec_base;
|
||||
struct cpuinfo_arc_ccm iccm, dccm;
|
||||
struct {
|
||||
unsigned int swap:1, norm:1, minmax:1, barrel:1, crc:1, swape:1, pad1:2,
|
||||
fpu_sp:1, fpu_dp:1, dual:1, dual_enb:1, pad2:4,
|
||||
ap_num:4, ap_full:1, smart:1, rtt:1, pad3:1,
|
||||
timer0:1, timer1:1, rtc:1, gfrc:1, pad4:4;
|
||||
} extn;
|
||||
struct bcr_mpy extn_mpy;
|
||||
};
|
||||
|
||||
extern struct cpuinfo_arc cpuinfo_arc700[];
|
||||
|
||||
static inline int is_isa_arcv2(void)
|
||||
{
|
||||
return IS_ENABLED(CONFIG_ISA_ARCV2);
|
||||
|
||||
@@ -18,7 +18,7 @@ static inline void arch_atomic_##op(int i, atomic_t *v) \
|
||||
: [val] "=&r" (val) /* Early clobber to prevent reg reuse */ \
|
||||
: [ctr] "r" (&v->counter), /* Not "m": llock only supports reg direct addr mode */ \
|
||||
[i] "ir" (i) \
|
||||
: "cc"); \
|
||||
: "cc", "memory"); \
|
||||
} \
|
||||
|
||||
#define ATOMIC_OP_RETURN(op, asm_op) \
|
||||
@@ -34,7 +34,7 @@ static inline int arch_atomic_##op##_return_relaxed(int i, atomic_t *v) \
|
||||
: [val] "=&r" (val) \
|
||||
: [ctr] "r" (&v->counter), \
|
||||
[i] "ir" (i) \
|
||||
: "cc"); \
|
||||
: "cc", "memory"); \
|
||||
\
|
||||
return val; \
|
||||
}
|
||||
@@ -56,7 +56,7 @@ static inline int arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v) \
|
||||
[orig] "=&r" (orig) \
|
||||
: [ctr] "r" (&v->counter), \
|
||||
[i] "ir" (i) \
|
||||
: "cc"); \
|
||||
: "cc", "memory"); \
|
||||
\
|
||||
return orig; \
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ static inline void arch_atomic64_##op(s64 a, atomic64_t *v) \
|
||||
" bnz 1b \n" \
|
||||
: "=&r"(val) \
|
||||
: "r"(&v->counter), "ir"(a) \
|
||||
: "cc"); \
|
||||
: "cc", "memory"); \
|
||||
} \
|
||||
|
||||
#define ATOMIC64_OP_RETURN(op, op1, op2) \
|
||||
@@ -77,7 +77,7 @@ static inline s64 arch_atomic64_##op##_return_relaxed(s64 a, atomic64_t *v) \
|
||||
" bnz 1b \n" \
|
||||
: [val] "=&r"(val) \
|
||||
: "r"(&v->counter), "ir"(a) \
|
||||
: "cc"); /* memory clobber comes from smp_mb() */ \
|
||||
: "cc", "memory"); \
|
||||
\
|
||||
return val; \
|
||||
}
|
||||
@@ -99,7 +99,7 @@ static inline s64 arch_atomic64_fetch_##op##_relaxed(s64 a, atomic64_t *v) \
|
||||
" bnz 1b \n" \
|
||||
: "=&r"(orig), "=&r"(val) \
|
||||
: "r"(&v->counter), "ir"(a) \
|
||||
: "cc"); /* memory clobber comes from smp_mb() */ \
|
||||
: "cc", "memory"); \
|
||||
\
|
||||
return orig; \
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
|
||||
register struct task_struct *curr_arc asm("r25");
|
||||
register struct task_struct *curr_arc asm("gp");
|
||||
#define current (curr_arc)
|
||||
|
||||
#else
|
||||
|
||||
@@ -10,23 +10,31 @@
|
||||
|
||||
#ifdef ARC_DW2_UNWIND_AS_CFI
|
||||
|
||||
#define CFI_STARTPROC .cfi_startproc
|
||||
#define CFI_ENDPROC .cfi_endproc
|
||||
#define CFI_DEF_CFA .cfi_def_cfa
|
||||
#define CFI_REGISTER .cfi_register
|
||||
#define CFI_REL_OFFSET .cfi_rel_offset
|
||||
#define CFI_UNDEFINED .cfi_undefined
|
||||
#define CFI_STARTPROC .cfi_startproc
|
||||
#define CFI_ENDPROC .cfi_endproc
|
||||
#define CFI_DEF_CFA .cfi_def_cfa
|
||||
#define CFI_DEF_CFA_OFFSET .cfi_def_cfa_offset
|
||||
#define CFI_DEF_CFA_REGISTER .cfi_def_cfa_register
|
||||
#define CFI_OFFSET .cfi_offset
|
||||
#define CFI_REL_OFFSET .cfi_rel_offset
|
||||
#define CFI_REGISTER .cfi_register
|
||||
#define CFI_RESTORE .cfi_restore
|
||||
#define CFI_UNDEFINED .cfi_undefined
|
||||
|
||||
#else
|
||||
|
||||
#define CFI_IGNORE #
|
||||
|
||||
#define CFI_STARTPROC CFI_IGNORE
|
||||
#define CFI_ENDPROC CFI_IGNORE
|
||||
#define CFI_DEF_CFA CFI_IGNORE
|
||||
#define CFI_REGISTER CFI_IGNORE
|
||||
#define CFI_REL_OFFSET CFI_IGNORE
|
||||
#define CFI_UNDEFINED CFI_IGNORE
|
||||
#define CFI_STARTPROC CFI_IGNORE
|
||||
#define CFI_ENDPROC CFI_IGNORE
|
||||
#define CFI_DEF_CFA CFI_IGNORE
|
||||
#define CFI_DEF_CFA_OFFSET CFI_IGNORE
|
||||
#define CFI_DEF_CFA_REGISTER CFI_IGNORE
|
||||
#define CFI_OFFSET CFI_IGNORE
|
||||
#define CFI_REL_OFFSET CFI_IGNORE
|
||||
#define CFI_REGISTER CFI_IGNORE
|
||||
#define CFI_RESTORE CFI_IGNORE
|
||||
#define CFI_UNDEFINED CFI_IGNORE
|
||||
|
||||
#endif /* !ARC_DW2_UNWIND_AS_CFI */
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
* | orig_r0 |
|
||||
* | event/ECR |
|
||||
* | bta |
|
||||
* | user_r25 |
|
||||
* | gp |
|
||||
* | fp |
|
||||
* | sp |
|
||||
@@ -49,14 +48,18 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
.macro INTERRUPT_PROLOGUE
|
||||
|
||||
; (A) Before jumping to Interrupt Vector, hardware micro-ops did following:
|
||||
; Before jumping to Interrupt Vector, hardware micro-ops did following:
|
||||
; 1. SP auto-switched to kernel mode stack
|
||||
; 2. STATUS32.Z flag set if in U mode at time of interrupt (U:1,K:0)
|
||||
; 3. Auto save: (mandatory) Push PC and STAT32 on stack
|
||||
; hardware does even if CONFIG_ARC_IRQ_NO_AUTOSAVE
|
||||
; 4. Auto save: (optional) r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI
|
||||
; 4a. Auto save: (optional) r0-r11, blink, LPE,LPS,LPC, JLI,LDI,EI
|
||||
;
|
||||
; (B) Manually saved some regs: r12,r25,r30, sp,fp,gp, ACCL pair
|
||||
; Now
|
||||
; 4b. If Auto-save (optional) not enabled in hw, manually save them
|
||||
; 5. Manually save: r12,r30, sp,fp,gp, ACCL pair
|
||||
;
|
||||
; At the end, SP points to pt_regs
|
||||
|
||||
#ifdef CONFIG_ARC_IRQ_NO_AUTOSAVE
|
||||
; carve pt_regs on stack (case #3), PC/STAT32 already on stack
|
||||
@@ -72,15 +75,16 @@
|
||||
.endm
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
.macro EXCEPTION_PROLOGUE
|
||||
.macro EXCEPTION_PROLOGUE_KEEP_AE
|
||||
|
||||
; (A) Before jumping to Exception Vector, hardware micro-ops did following:
|
||||
; Before jumping to Exception Vector, hardware micro-ops did following:
|
||||
; 1. SP auto-switched to kernel mode stack
|
||||
; 2. STATUS32.Z flag set if in U mode at time of exception (U:1,K:0)
|
||||
;
|
||||
; (B) Manually save the complete reg file below
|
||||
; Now manually save rest of reg file
|
||||
; At the end, SP points to pt_regs
|
||||
|
||||
sub sp, sp, SZ_PT_REGS ; carve pt_regs
|
||||
sub sp, sp, SZ_PT_REGS ; carve space for pt_regs
|
||||
|
||||
; _HARD saves r10 clobbered by _SOFT as scratch hence comes first
|
||||
|
||||
@@ -100,6 +104,16 @@
|
||||
; OUTPUT: r10 has ECR expected by EV_Trap
|
||||
.endm
|
||||
|
||||
.macro EXCEPTION_PROLOGUE
|
||||
|
||||
EXCEPTION_PROLOGUE_KEEP_AE ; return ECR in r10
|
||||
|
||||
lr r0, [efa]
|
||||
mov r1, sp
|
||||
|
||||
FAKE_RET_FROM_EXCPN ; clobbers r9
|
||||
.endm
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
* This macro saves the registers manually which would normally be autosaved
|
||||
* by hardware on taken interrupts. It is used by
|
||||
@@ -135,10 +149,10 @@
|
||||
*/
|
||||
.macro __SAVE_REGFILE_SOFT
|
||||
|
||||
ST2 gp, fp, PT_r26 ; gp (r26), fp (r27)
|
||||
|
||||
st r12, [sp, PT_sp + 4]
|
||||
st r30, [sp, PT_sp + 8]
|
||||
st fp, [sp, PT_fp] ; r27
|
||||
st r30, [sp, PT_r30]
|
||||
st r12, [sp, PT_r12]
|
||||
st r26, [sp, PT_r26] ; gp
|
||||
|
||||
; Saving pt_regs->sp correctly requires some extra work due to the way
|
||||
; Auto stack switch works
|
||||
@@ -153,30 +167,30 @@
|
||||
|
||||
; ISA requires ADD.nz to have same dest and src reg operands
|
||||
mov.nz r10, sp
|
||||
add.nz r10, r10, SZ_PT_REGS ; K mode SP
|
||||
add2.nz r10, r10, SZ_PT_REGS/4 ; K mode SP
|
||||
|
||||
st r10, [sp, PT_sp] ; SP (pt_regs->sp)
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
st r25, [sp, PT_user_r25]
|
||||
GET_CURR_TASK_ON_CPU r25
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARC_HAS_ACCL_REGS
|
||||
ST2 r58, r59, PT_r58
|
||||
#endif
|
||||
|
||||
/* clobbers r10, r11 registers pair */
|
||||
DSP_SAVE_REGFILE_IRQ
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
GET_CURR_TASK_ON_CPU gp
|
||||
#endif
|
||||
|
||||
.endm
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
.macro __RESTORE_REGFILE_SOFT
|
||||
|
||||
LD2 gp, fp, PT_r26 ; gp (r26), fp (r27)
|
||||
|
||||
ld r12, [sp, PT_r12]
|
||||
ld fp, [sp, PT_fp]
|
||||
ld r30, [sp, PT_r30]
|
||||
ld r12, [sp, PT_r12]
|
||||
ld r26, [sp, PT_r26]
|
||||
|
||||
; Restore SP (into AUX_USER_SP) only if returning to U mode
|
||||
; - for K mode, it will be implicitly restored as stack is unwound
|
||||
@@ -188,10 +202,6 @@
|
||||
sr r10, [AUX_USER_SP]
|
||||
1:
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
ld r25, [sp, PT_user_r25]
|
||||
#endif
|
||||
|
||||
/* clobbers r10, r11 registers pair */
|
||||
DSP_RESTORE_REGFILE_IRQ
|
||||
|
||||
@@ -249,7 +259,7 @@
|
||||
|
||||
btst r0, STATUS_U_BIT ; Z flag set if K, used in restoring SP
|
||||
|
||||
ld r10, [sp, PT_event + 4]
|
||||
ld r10, [sp, PT_bta]
|
||||
sr r10, [erbta]
|
||||
|
||||
LD2 r10, r11, PT_ret
|
||||
@@ -264,8 +274,8 @@
|
||||
|
||||
.macro FAKE_RET_FROM_EXCPN
|
||||
lr r9, [status32]
|
||||
bic r9, r9, STATUS_AE_MASK
|
||||
or r9, r9, STATUS_IE_MASK
|
||||
bclr r9, r9, STATUS_AE_BIT
|
||||
bset r9, r9, STATUS_IE_BIT
|
||||
kflag r9
|
||||
.endm
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
*
|
||||
* After this it is safe to call the "C" handlers
|
||||
*-------------------------------------------------------------*/
|
||||
.macro EXCEPTION_PROLOGUE
|
||||
.macro EXCEPTION_PROLOGUE_KEEP_AE
|
||||
|
||||
/* Need at least 1 reg to code the early exception prologue */
|
||||
PROLOG_FREEUP_REG r9, @ex_saved_reg1
|
||||
@@ -151,14 +151,6 @@
|
||||
/* ARC700 doesn't provide auto-stack switching */
|
||||
SWITCH_TO_KERNEL_STK
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
/* Treat r25 as scratch reg (save on stack) and load with "current" */
|
||||
PUSH r25
|
||||
GET_CURR_TASK_ON_CPU r25
|
||||
#else
|
||||
sub sp, sp, 4
|
||||
#endif
|
||||
|
||||
st.a r0, [sp, -8] /* orig_r0 needed for syscall (skip ECR slot) */
|
||||
sub sp, sp, 4 /* skip pt_regs->sp, already saved above */
|
||||
|
||||
@@ -178,7 +170,23 @@
|
||||
PUSHAX erbta
|
||||
|
||||
lr r10, [ecr]
|
||||
st r10, [sp, PT_event] /* EV_Trap expects r10 to have ECR */
|
||||
st r10, [sp, PT_event]
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
/* gp already saved on stack: now load with "current" */
|
||||
GET_CURR_TASK_ON_CPU gp
|
||||
#endif
|
||||
; OUTPUT: r10 has ECR expected by EV_Trap
|
||||
.endm
|
||||
|
||||
.macro EXCEPTION_PROLOGUE
|
||||
|
||||
EXCEPTION_PROLOGUE_KEEP_AE ; return ECR in r10
|
||||
|
||||
lr r0, [efa]
|
||||
mov r1, sp
|
||||
|
||||
FAKE_RET_FROM_EXCPN ; clobbers r9
|
||||
.endm
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
@@ -208,11 +216,8 @@
|
||||
POP gp
|
||||
RESTORE_R12_TO_R0
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
ld r25, [sp, 12]
|
||||
#endif
|
||||
ld sp, [sp] /* restore original sp */
|
||||
/* orig_r0, ECR, user_r25 skipped automatically */
|
||||
/* orig_r0, ECR skipped automatically */
|
||||
.endm
|
||||
|
||||
/* Dummy ECR values for Interrupts */
|
||||
@@ -229,13 +234,6 @@
|
||||
|
||||
SWITCH_TO_KERNEL_STK
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
/* Treat r25 as scratch reg (save on stack) and load with "current" */
|
||||
PUSH r25
|
||||
GET_CURR_TASK_ON_CPU r25
|
||||
#else
|
||||
sub sp, sp, 4
|
||||
#endif
|
||||
|
||||
PUSH 0x003\LVL\()abcd /* Dummy ECR */
|
||||
sub sp, sp, 8 /* skip orig_r0 (not needed)
|
||||
@@ -255,6 +253,10 @@
|
||||
PUSHAX lp_start
|
||||
PUSHAX bta_l\LVL\()
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
/* gp already saved on stack: now load with "current" */
|
||||
GET_CURR_TASK_ON_CPU gp
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
@@ -282,11 +284,7 @@
|
||||
POP gp
|
||||
RESTORE_R12_TO_R0
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
ld r25, [sp, 12]
|
||||
#endif
|
||||
ld sp, [sp] /* restore original sp */
|
||||
/* orig_r0, ECR, user_r25 skipped automatically */
|
||||
ld sp, [sp] /* restore original sp; orig_r0, ECR skipped implicitly */
|
||||
.endm
|
||||
|
||||
/* Get thread_info of "current" tsk */
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <asm/processor.h> /* For VMALLOC_START */
|
||||
#include <asm/mmu.h>
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
|
||||
#ifdef CONFIG_ISA_ARCOMPACT
|
||||
#include <asm/entry-compact.h> /* ISA specific bits */
|
||||
#else
|
||||
@@ -89,7 +91,7 @@
|
||||
* Helpers to save/restore callee-saved regs:
|
||||
* used by several macros below
|
||||
*-------------------------------------------------------------*/
|
||||
.macro SAVE_R13_TO_R24
|
||||
.macro SAVE_R13_TO_R25
|
||||
PUSH r13
|
||||
PUSH r14
|
||||
PUSH r15
|
||||
@@ -102,9 +104,11 @@
|
||||
PUSH r22
|
||||
PUSH r23
|
||||
PUSH r24
|
||||
PUSH r25
|
||||
.endm
|
||||
|
||||
.macro RESTORE_R24_TO_R13
|
||||
.macro RESTORE_R25_TO_R13
|
||||
POP r25
|
||||
POP r24
|
||||
POP r23
|
||||
POP r22
|
||||
@@ -119,81 +123,31 @@
|
||||
POP r13
|
||||
.endm
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
* Collect User Mode callee regs as struct callee_regs - needed by
|
||||
* fork/do_signal/unaligned-access-emulation.
|
||||
* (By default only scratch regs are saved on entry to kernel)
|
||||
*
|
||||
* Special handling for r25 if used for caching Task Pointer.
|
||||
* It would have been saved in task->thread.user_r25 already, but to keep
|
||||
* the interface same it is copied into regular r25 placeholder in
|
||||
* struct callee_regs.
|
||||
*-------------------------------------------------------------*/
|
||||
/*
|
||||
* save user mode callee regs as struct callee_regs
|
||||
* - needed by fork/do_signal/unaligned-access-emulation.
|
||||
*/
|
||||
.macro SAVE_CALLEE_SAVED_USER
|
||||
|
||||
mov r12, sp ; save SP as ref to pt_regs
|
||||
SAVE_R13_TO_R24
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
; Retrieve orig r25 and save it with rest of callee_regs
|
||||
ld r12, [r12, PT_user_r25]
|
||||
PUSH r12
|
||||
#else
|
||||
PUSH r25
|
||||
#endif
|
||||
|
||||
SAVE_R13_TO_R25
|
||||
.endm
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
* Save kernel Mode callee regs at the time of Contect Switch.
|
||||
*
|
||||
* Special handling for r25 if used for caching Task Pointer.
|
||||
* Kernel simply skips saving it since it will be loaded with
|
||||
* incoming task pointer anyways
|
||||
*-------------------------------------------------------------*/
|
||||
.macro SAVE_CALLEE_SAVED_KERNEL
|
||||
|
||||
SAVE_R13_TO_R24
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
sub sp, sp, 4
|
||||
#else
|
||||
PUSH r25
|
||||
#endif
|
||||
.endm
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
* Opposite of SAVE_CALLEE_SAVED_KERNEL
|
||||
*-------------------------------------------------------------*/
|
||||
.macro RESTORE_CALLEE_SAVED_KERNEL
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
add sp, sp, 4 /* skip usual r25 placeholder */
|
||||
#else
|
||||
POP r25
|
||||
#endif
|
||||
RESTORE_R24_TO_R13
|
||||
.endm
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
* Opposite of SAVE_CALLEE_SAVED_USER
|
||||
*
|
||||
* ptrace tracer or unaligned-access fixup might have changed a user mode
|
||||
* callee reg which is saved back to usual r25 storage location
|
||||
*-------------------------------------------------------------*/
|
||||
/*
|
||||
* restore user mode callee regs as struct callee_regs
|
||||
* - could have been changed by ptrace tracer or unaligned-access fixup
|
||||
*/
|
||||
.macro RESTORE_CALLEE_SAVED_USER
|
||||
RESTORE_R25_TO_R13
|
||||
.endm
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
POP r12
|
||||
#else
|
||||
POP r25
|
||||
#endif
|
||||
RESTORE_R24_TO_R13
|
||||
/*
|
||||
* save/restore kernel mode callee regs at the time of context switch
|
||||
*/
|
||||
.macro SAVE_CALLEE_SAVED_KERNEL
|
||||
SAVE_R13_TO_R25
|
||||
.endm
|
||||
|
||||
; SP is back to start of pt_regs
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
st r12, [sp, PT_user_r25]
|
||||
#endif
|
||||
.macro RESTORE_CALLEE_SAVED_KERNEL
|
||||
RESTORE_R25_TO_R13
|
||||
.endm
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
@@ -229,10 +183,10 @@
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
/*-------------------------------------------------
|
||||
/*
|
||||
* Retrieve the current running task on this CPU
|
||||
* 1. Determine curr CPU id.
|
||||
* 2. Use it to index into _current_task[ ]
|
||||
* - loads it from backing _current_task[] (and can't use the
|
||||
* caching reg for current task
|
||||
*/
|
||||
.macro GET_CURR_TASK_ON_CPU reg
|
||||
GET_CPU_ID \reg
|
||||
@@ -254,7 +208,7 @@
|
||||
add2 \tmp, @_current_task, \tmp
|
||||
st \tsk, [\tmp]
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
mov r25, \tsk
|
||||
mov gp, \tsk
|
||||
#endif
|
||||
|
||||
.endm
|
||||
@@ -269,21 +223,20 @@
|
||||
.macro SET_CURR_TASK_ON_CPU tsk, tmp
|
||||
st \tsk, [@_current_task]
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
mov r25, \tsk
|
||||
mov gp, \tsk
|
||||
#endif
|
||||
.endm
|
||||
|
||||
#endif /* SMP / UNI */
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
/*
|
||||
* Get the ptr to some field of Current Task at @off in task struct
|
||||
* -Uses r25 for Current task ptr if that is enabled
|
||||
* - Uses current task cached in reg if enabled
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
|
||||
.macro GET_CURR_TASK_FIELD_PTR off, reg
|
||||
add \reg, r25, \off
|
||||
add \reg, gp, \off
|
||||
.endm
|
||||
|
||||
#else
|
||||
@@ -295,4 +248,23 @@
|
||||
|
||||
#endif /* CONFIG_ARC_CURR_IN_REG */
|
||||
|
||||
#else /* !__ASSEMBLY__ */
|
||||
|
||||
extern void do_signal(struct pt_regs *);
|
||||
extern void do_notify_resume(struct pt_regs *);
|
||||
extern int do_privilege_fault(unsigned long, struct pt_regs *);
|
||||
extern int do_extension_fault(unsigned long, struct pt_regs *);
|
||||
extern int insterror_is_error(unsigned long, struct pt_regs *);
|
||||
extern int do_memory_error(unsigned long, struct pt_regs *);
|
||||
extern int trap_is_brkpt(unsigned long, struct pt_regs *);
|
||||
extern int do_misaligned_error(unsigned long, struct pt_regs *);
|
||||
extern int do_trap5_error(unsigned long, struct pt_regs *);
|
||||
extern int do_misaligned_access(unsigned long, struct pt_regs *, struct callee_regs *);
|
||||
extern void do_machine_check_fault(unsigned long, struct pt_regs *);
|
||||
extern void do_non_swi_trap(unsigned long, struct pt_regs *);
|
||||
extern void do_insterror_or_kprobe(unsigned long, struct pt_regs *);
|
||||
extern void do_page_fault(unsigned long, struct pt_regs *);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __ASM_ARC_ENTRY_H */
|
||||
|
||||
@@ -25,5 +25,6 @@
|
||||
#include <asm-generic/irq.h>
|
||||
|
||||
extern void arc_init_IRQ(void);
|
||||
extern void arch_do_IRQ(unsigned int, struct pt_regs *);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,6 +14,8 @@ typedef struct {
|
||||
unsigned long asid[NR_CPUS]; /* 8 bit MMU PID + Generation cycle */
|
||||
} mm_context_t;
|
||||
|
||||
extern void do_tlb_overlap_fault(unsigned long, unsigned long, struct pt_regs *);
|
||||
|
||||
#endif
|
||||
|
||||
#include <asm/mmu-arcv2.h>
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
* struct thread_info
|
||||
*/
|
||||
struct thread_struct {
|
||||
unsigned long ksp; /* kernel mode stack pointer */
|
||||
unsigned long callee_reg; /* pointer to callee regs */
|
||||
unsigned long fault_address; /* dbls as brkpt holder as well */
|
||||
#ifdef CONFIG_ARC_DSP_SAVE_RESTORE_REGS
|
||||
@@ -33,9 +32,7 @@ struct thread_struct {
|
||||
#endif
|
||||
};
|
||||
|
||||
#define INIT_THREAD { \
|
||||
.ksp = sizeof(init_stack) + (unsigned long) init_stack, \
|
||||
}
|
||||
#define INIT_THREAD { }
|
||||
|
||||
/* Forward declaration, a strange C thing */
|
||||
struct task_struct;
|
||||
@@ -56,7 +53,7 @@ struct task_struct;
|
||||
* Where about of Task's sp, fp, blink when it was last seen in kernel mode.
|
||||
* Look in process.c for details of kernel stack layout
|
||||
*/
|
||||
#define TSK_K_ESP(tsk) (tsk->thread.ksp)
|
||||
#define TSK_K_ESP(tsk) (task_thread_info(tsk)->ksp)
|
||||
|
||||
#define TSK_K_REG(tsk, off) (*((unsigned long *)(TSK_K_ESP(tsk) + \
|
||||
sizeof(struct callee_regs) + off)))
|
||||
|
||||
@@ -12,6 +12,17 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned long state:8, vec:8, cause:8, param:8;
|
||||
#else
|
||||
unsigned long param:8, cause:8, vec:8, state:8;
|
||||
#endif
|
||||
};
|
||||
unsigned long full;
|
||||
} ecr_reg;
|
||||
|
||||
/* THE pt_regs: Defines how regs are saved during entry into kernel */
|
||||
|
||||
#ifdef CONFIG_ISA_ARCOMPACT
|
||||
@@ -40,23 +51,10 @@ struct pt_regs {
|
||||
* Last word used by Linux for extra state mgmt (syscall-restart)
|
||||
* For interrupts, use artificial ECR values to note current prio-level
|
||||
*/
|
||||
union {
|
||||
struct {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned long state:8, ecr_vec:8,
|
||||
ecr_cause:8, ecr_param:8;
|
||||
#else
|
||||
unsigned long ecr_param:8, ecr_cause:8,
|
||||
ecr_vec:8, state:8;
|
||||
#endif
|
||||
};
|
||||
unsigned long event;
|
||||
};
|
||||
|
||||
unsigned long user_r25;
|
||||
ecr_reg ecr;
|
||||
};
|
||||
|
||||
#define MAX_REG_OFFSET offsetof(struct pt_regs, user_r25)
|
||||
#define MAX_REG_OFFSET offsetof(struct pt_regs, ecr)
|
||||
|
||||
#else
|
||||
|
||||
@@ -64,28 +62,14 @@ struct pt_regs {
|
||||
|
||||
unsigned long orig_r0;
|
||||
|
||||
union {
|
||||
struct {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned long state:8, ecr_vec:8,
|
||||
ecr_cause:8, ecr_param:8;
|
||||
#else
|
||||
unsigned long ecr_param:8, ecr_cause:8,
|
||||
ecr_vec:8, state:8;
|
||||
#endif
|
||||
};
|
||||
unsigned long event;
|
||||
};
|
||||
ecr_reg ecr; /* Exception Cause Reg */
|
||||
|
||||
unsigned long bta; /* bta_l1, bta_l2, erbta */
|
||||
unsigned long bta; /* erbta */
|
||||
|
||||
unsigned long user_r25;
|
||||
|
||||
unsigned long r26; /* gp */
|
||||
unsigned long fp;
|
||||
unsigned long sp; /* user/kernel sp depending on where we came from */
|
||||
|
||||
unsigned long r12, r30;
|
||||
unsigned long r30;
|
||||
unsigned long r12;
|
||||
unsigned long r26; /* gp */
|
||||
|
||||
#ifdef CONFIG_ARC_HAS_ACCL_REGS
|
||||
unsigned long r58, r59; /* ACCL/ACCH used by FPU / DSP MPY */
|
||||
@@ -94,6 +78,8 @@ struct pt_regs {
|
||||
unsigned long DSP_CTRL;
|
||||
#endif
|
||||
|
||||
unsigned long sp; /* user/kernel sp depending on entry */
|
||||
|
||||
/*------- Below list auto saved by h/w -----------*/
|
||||
unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
|
||||
|
||||
@@ -134,13 +120,13 @@ struct callee_regs {
|
||||
/* return 1 if PC in delay slot */
|
||||
#define delay_mode(regs) ((regs->status32 & STATUS_DE_MASK) == STATUS_DE_MASK)
|
||||
|
||||
#define in_syscall(regs) ((regs->ecr_vec == ECR_V_TRAP) && !regs->ecr_param)
|
||||
#define in_brkpt_trap(regs) ((regs->ecr_vec == ECR_V_TRAP) && regs->ecr_param)
|
||||
#define in_syscall(regs) ((regs->ecr.vec == ECR_V_TRAP) && !regs->ecr.param)
|
||||
#define in_brkpt_trap(regs) ((regs->ecr.vec == ECR_V_TRAP) && regs->ecr.param)
|
||||
|
||||
#define STATE_SCALL_RESTARTED 0x01
|
||||
|
||||
#define syscall_wont_restart(reg) (reg->state |= STATE_SCALL_RESTARTED)
|
||||
#define syscall_restartable(reg) !(reg->state & STATE_SCALL_RESTARTED)
|
||||
#define syscall_wont_restart(regs) (regs->ecr.state |= STATE_SCALL_RESTARTED)
|
||||
#define syscall_restartable(regs) !(regs->ecr.state & STATE_SCALL_RESTARTED)
|
||||
|
||||
#define current_pt_regs() \
|
||||
({ \
|
||||
@@ -181,6 +167,9 @@ static inline unsigned long regs_get_register(struct pt_regs *regs,
|
||||
return *(unsigned long *)((unsigned long)regs + offset);
|
||||
}
|
||||
|
||||
extern int syscall_trace_entry(struct pt_regs *);
|
||||
extern void syscall_trace_exit(struct pt_regs *);
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_PTRACE_H */
|
||||
|
||||
@@ -35,11 +35,11 @@ long __init arc_get_mem_sz(void);
|
||||
#define IS_AVAIL3(v, v2, s) IS_AVAIL1(v, s), IS_AVAIL1(v, IS_DISABLED_RUN(v2))
|
||||
|
||||
extern void arc_mmu_init(void);
|
||||
extern char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len);
|
||||
extern void read_decode_mmu_bcr(void);
|
||||
extern int arc_mmu_mumbojumbo(int cpu_id, char *buf, int len);
|
||||
|
||||
extern void arc_cache_init(void);
|
||||
extern char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len);
|
||||
extern void read_decode_cache_bcr(void);
|
||||
extern int arc_cache_mumbojumbo(int cpu_id, char *buf, int len);
|
||||
|
||||
extern void __init handle_uboot_args(void);
|
||||
|
||||
#endif /* __ASMARC_SETUP_H */
|
||||
|
||||
@@ -29,6 +29,8 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
|
||||
extern void __init smp_init_cpus(void);
|
||||
extern void first_lines_of_secondary(void);
|
||||
extern const char *arc_platform_smp_cpuinfo(void);
|
||||
extern void arc_platform_smp_wait_to_boot(int);
|
||||
extern void start_kernel_secondary(void);
|
||||
|
||||
/*
|
||||
* API expected BY platform smp code (FROM arch smp code)
|
||||
|
||||
@@ -37,16 +37,16 @@
|
||||
*/
|
||||
struct thread_info {
|
||||
unsigned long flags; /* low level flags */
|
||||
unsigned long ksp; /* kernel mode stack top in __switch_to */
|
||||
int preempt_count; /* 0 => preemptable, <0 => BUG */
|
||||
struct task_struct *task; /* main task structure */
|
||||
__u32 cpu; /* current CPU */
|
||||
int cpu; /* current CPU */
|
||||
unsigned long thr_ptr; /* TLS ptr */
|
||||
struct task_struct *task; /* main task structure */
|
||||
};
|
||||
|
||||
/*
|
||||
* macros/functions for gaining access to the thread information structure
|
||||
*
|
||||
* preempt_count needs to be 1 initially, until the scheduler is functional.
|
||||
* initilaize thread_info for any @tsk
|
||||
* - this is not related to init_task per se
|
||||
*/
|
||||
#define INIT_THREAD_INFO(tsk) \
|
||||
{ \
|
||||
|
||||
@@ -146,8 +146,9 @@ raw_copy_from_user(void *to, const void __user *from, unsigned long n)
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
/* unaligned */
|
||||
if (((unsigned long)to & 0x3) || ((unsigned long)from & 0x3)) {
|
||||
/* fallback for unaligned access when hardware doesn't support */
|
||||
if (!IS_ENABLED(CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS) &&
|
||||
(((unsigned long)to & 0x3) || ((unsigned long)from & 0x3))) {
|
||||
|
||||
unsigned char tmp;
|
||||
|
||||
@@ -373,8 +374,9 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
/* unaligned */
|
||||
if (((unsigned long)to & 0x3) || ((unsigned long)from & 0x3)) {
|
||||
/* fallback for unaligned access when hardware doesn't support */
|
||||
if (!IS_ENABLED(CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS) &&
|
||||
(((unsigned long)to & 0x3) || ((unsigned long)from & 0x3))) {
|
||||
|
||||
unsigned char tmp;
|
||||
|
||||
@@ -584,7 +586,7 @@ raw_copy_to_user(void __user *to, const void *from, unsigned long n)
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline unsigned long __arc_clear_user(void __user *to, unsigned long n)
|
||||
static inline unsigned long __clear_user(void __user *to, unsigned long n)
|
||||
{
|
||||
long res = n;
|
||||
unsigned char *d_char = to;
|
||||
@@ -626,17 +628,10 @@ static inline unsigned long __arc_clear_user(void __user *to, unsigned long n)
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||
|
||||
#define INLINE_COPY_TO_USER
|
||||
#define INLINE_COPY_FROM_USER
|
||||
|
||||
#define __clear_user(d, n) __arc_clear_user(d, n)
|
||||
#else
|
||||
extern unsigned long arc_clear_user_noinline(void __user *to,
|
||||
unsigned long n);
|
||||
#define __clear_user(d, n) arc_clear_user_noinline(d, n)
|
||||
#endif
|
||||
#define __clear_user __clear_user
|
||||
|
||||
#include <asm-generic/uaccess.h>
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
obj-y := head.o arcksyms.o setup.o irq.o reset.o ptrace.o process.o devtree.o
|
||||
obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o
|
||||
obj-y += ctx_sw_asm.o
|
||||
|
||||
obj-$(CONFIG_ISA_ARCOMPACT) += entry-compact.o intc-compact.o
|
||||
obj-$(CONFIG_ISA_ARCV2) += entry-arcv2.o intc-arcv2.o
|
||||
|
||||
@@ -24,11 +26,4 @@ ifdef CONFIG_ISA_ARCOMPACT
|
||||
CFLAGS_fpu.o += -mdpfp
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARC_DW2_UNWIND
|
||||
CFLAGS_ctx_sw.o += -fno-omit-frame-pointer
|
||||
obj-y += ctx_sw.o
|
||||
else
|
||||
obj-y += ctx_sw_asm.o
|
||||
endif
|
||||
|
||||
extra-y := vmlinux.lds
|
||||
|
||||
@@ -20,13 +20,13 @@ int main(void)
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
|
||||
DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg));
|
||||
DEFINE(THREAD_FAULT_ADDR,
|
||||
offsetof(struct thread_struct, fault_address));
|
||||
|
||||
BLANK();
|
||||
|
||||
DEFINE(THREAD_INFO_KSP, offsetof(struct thread_info, ksp));
|
||||
DEFINE(THREAD_INFO_FLAGS, offsetof(struct thread_info, flags));
|
||||
DEFINE(THREAD_INFO_PREEMPT_COUNT,
|
||||
offsetof(struct thread_info, preempt_count));
|
||||
@@ -46,7 +46,8 @@ int main(void)
|
||||
BLANK();
|
||||
|
||||
DEFINE(PT_status32, offsetof(struct pt_regs, status32));
|
||||
DEFINE(PT_event, offsetof(struct pt_regs, event));
|
||||
DEFINE(PT_event, offsetof(struct pt_regs, ecr));
|
||||
DEFINE(PT_bta, offsetof(struct pt_regs, bta));
|
||||
DEFINE(PT_sp, offsetof(struct pt_regs, sp));
|
||||
DEFINE(PT_r0, offsetof(struct pt_regs, r0));
|
||||
DEFINE(PT_r1, offsetof(struct pt_regs, r1));
|
||||
@@ -61,13 +62,9 @@ int main(void)
|
||||
DEFINE(PT_r26, offsetof(struct pt_regs, r26));
|
||||
DEFINE(PT_ret, offsetof(struct pt_regs, ret));
|
||||
DEFINE(PT_blink, offsetof(struct pt_regs, blink));
|
||||
OFFSET(PT_fp, pt_regs, fp);
|
||||
DEFINE(PT_lpe, offsetof(struct pt_regs, lp_end));
|
||||
DEFINE(PT_lpc, offsetof(struct pt_regs, lp_count));
|
||||
DEFINE(PT_user_r25, offsetof(struct pt_regs, user_r25));
|
||||
|
||||
DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
|
||||
DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
|
||||
|
||||
#ifdef CONFIG_ISA_ARCV2
|
||||
OFFSET(PT_r12, pt_regs, r12);
|
||||
OFFSET(PT_r30, pt_regs, r30);
|
||||
@@ -80,5 +77,8 @@ int main(void)
|
||||
OFFSET(PT_DSP_CTRL, pt_regs, DSP_CTRL);
|
||||
#endif
|
||||
|
||||
DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
|
||||
DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
|
||||
*
|
||||
* Vineetg: Aug 2009
|
||||
* -"C" version of lowest level context switch asm macro called by schedular
|
||||
* gcc doesn't generate the dward CFI info for hand written asm, hence can't
|
||||
* backtrace out of it (e.g. tasks sleeping in kernel).
|
||||
* So we cheat a bit by writing almost similar code in inline-asm.
|
||||
* -This is a hacky way of doing things, but there is no other simple way.
|
||||
* I don't want/intend to extend unwinding code to understand raw asm
|
||||
*/
|
||||
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/debug.h>
|
||||
|
||||
#define KSP_WORD_OFF ((TASK_THREAD + THREAD_KSP) / 4)
|
||||
|
||||
struct task_struct *__sched
|
||||
__switch_to(struct task_struct *prev_task, struct task_struct *next_task)
|
||||
{
|
||||
unsigned int tmp;
|
||||
unsigned int prev = (unsigned int)prev_task;
|
||||
unsigned int next = (unsigned int)next_task;
|
||||
|
||||
__asm__ __volatile__(
|
||||
/* FP/BLINK save generated by gcc (standard function prologue */
|
||||
"st.a r13, [sp, -4] \n\t"
|
||||
"st.a r14, [sp, -4] \n\t"
|
||||
"st.a r15, [sp, -4] \n\t"
|
||||
"st.a r16, [sp, -4] \n\t"
|
||||
"st.a r17, [sp, -4] \n\t"
|
||||
"st.a r18, [sp, -4] \n\t"
|
||||
"st.a r19, [sp, -4] \n\t"
|
||||
"st.a r20, [sp, -4] \n\t"
|
||||
"st.a r21, [sp, -4] \n\t"
|
||||
"st.a r22, [sp, -4] \n\t"
|
||||
"st.a r23, [sp, -4] \n\t"
|
||||
"st.a r24, [sp, -4] \n\t"
|
||||
#ifndef CONFIG_ARC_CURR_IN_REG
|
||||
"st.a r25, [sp, -4] \n\t"
|
||||
#else
|
||||
"sub sp, sp, 4 \n\t" /* usual r25 placeholder */
|
||||
#endif
|
||||
|
||||
/* set ksp of outgoing task in tsk->thread.ksp */
|
||||
#if KSP_WORD_OFF <= 255
|
||||
"st.as sp, [%3, %1] \n\t"
|
||||
#else
|
||||
/*
|
||||
* Workaround for NR_CPUS=4k
|
||||
* %1 is bigger than 255 (S9 offset for st.as)
|
||||
*/
|
||||
"add2 r24, %3, %1 \n\t"
|
||||
"st sp, [r24] \n\t"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* setup _current_task with incoming tsk.
|
||||
* optionally, set r25 to that as well
|
||||
* For SMP extra work to get to &_current_task[cpu]
|
||||
* (open coded SET_CURR_TASK_ON_CPU)
|
||||
*/
|
||||
#ifndef CONFIG_SMP
|
||||
"st %2, [@_current_task] \n\t"
|
||||
#else
|
||||
"lr r24, [identity] \n\t"
|
||||
"lsr r24, r24, 8 \n\t"
|
||||
"bmsk r24, r24, 7 \n\t"
|
||||
"add2 r24, @_current_task, r24 \n\t"
|
||||
"st %2, [r24] \n\t"
|
||||
#endif
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
"mov r25, %2 \n\t"
|
||||
#endif
|
||||
|
||||
/* get ksp of incoming task from tsk->thread.ksp */
|
||||
"ld.as sp, [%2, %1] \n\t"
|
||||
|
||||
/* start loading it's CALLEE reg file */
|
||||
|
||||
#ifndef CONFIG_ARC_CURR_IN_REG
|
||||
"ld.ab r25, [sp, 4] \n\t"
|
||||
#else
|
||||
"add sp, sp, 4 \n\t"
|
||||
#endif
|
||||
"ld.ab r24, [sp, 4] \n\t"
|
||||
"ld.ab r23, [sp, 4] \n\t"
|
||||
"ld.ab r22, [sp, 4] \n\t"
|
||||
"ld.ab r21, [sp, 4] \n\t"
|
||||
"ld.ab r20, [sp, 4] \n\t"
|
||||
"ld.ab r19, [sp, 4] \n\t"
|
||||
"ld.ab r18, [sp, 4] \n\t"
|
||||
"ld.ab r17, [sp, 4] \n\t"
|
||||
"ld.ab r16, [sp, 4] \n\t"
|
||||
"ld.ab r15, [sp, 4] \n\t"
|
||||
"ld.ab r14, [sp, 4] \n\t"
|
||||
"ld.ab r13, [sp, 4] \n\t"
|
||||
|
||||
/* last (ret value) = prev : although for ARC it mov r0, r0 */
|
||||
"mov %0, %3 \n\t"
|
||||
|
||||
/* FP/BLINK restore generated by gcc (standard func epilogue */
|
||||
|
||||
: "=r"(tmp)
|
||||
: "n"(KSP_WORD_OFF), "r"(next), "r"(prev)
|
||||
: "blink"
|
||||
);
|
||||
|
||||
return (struct task_struct *)tmp;
|
||||
}
|
||||
@@ -11,50 +11,54 @@
|
||||
#include <asm/entry.h> /* For the SAVE_* macros */
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
#define KSP_WORD_OFF ((TASK_THREAD + THREAD_KSP) / 4)
|
||||
|
||||
;################### Low Level Context Switch ##########################
|
||||
; IN
|
||||
; - r0: prev task (also current)
|
||||
; - r1: next task
|
||||
; OUT
|
||||
; - r0: prev task (so r0 not touched)
|
||||
|
||||
.section .sched.text,"ax",@progbits
|
||||
.align 4
|
||||
.global __switch_to
|
||||
.type __switch_to, @function
|
||||
__switch_to:
|
||||
CFI_STARTPROC
|
||||
ENTRY_CFI(__switch_to)
|
||||
|
||||
/* Save regs on kernel mode stack of task */
|
||||
st.a blink, [sp, -4]
|
||||
st.a fp, [sp, -4]
|
||||
/* save kernel stack frame regs of @prev task */
|
||||
push blink
|
||||
CFI_DEF_CFA_OFFSET 4
|
||||
CFI_OFFSET r31, -4
|
||||
|
||||
push fp
|
||||
CFI_DEF_CFA_OFFSET 8
|
||||
CFI_OFFSET r27, -8
|
||||
|
||||
mov fp, sp
|
||||
CFI_DEF_CFA_REGISTER r27
|
||||
|
||||
/* kernel mode callee regs of @prev */
|
||||
SAVE_CALLEE_SAVED_KERNEL
|
||||
|
||||
/* Save the now KSP in task->thread.ksp */
|
||||
#if KSP_WORD_OFF <= 255
|
||||
st.as sp, [r0, KSP_WORD_OFF]
|
||||
#else
|
||||
/* Workaround for NR_CPUS=4k as ST.as can only take s9 offset */
|
||||
add2 r24, r0, KSP_WORD_OFF
|
||||
st sp, [r24]
|
||||
#endif
|
||||
/*
|
||||
* Return last task in r0 (return reg)
|
||||
* On ARC, Return reg = First Arg reg = r0.
|
||||
* Since we already have last task in r0,
|
||||
* don't need to do anything special to return it
|
||||
*/
|
||||
|
||||
/*
|
||||
* switch to new task, contained in r1
|
||||
* Temp reg r3 is required to get the ptr to store val
|
||||
* save final SP to @prev->thread_info.ksp
|
||||
* @prev is "current" so thread_info derived from SP
|
||||
*/
|
||||
SET_CURR_TASK_ON_CPU r1, r3
|
||||
GET_CURR_THR_INFO_FROM_SP r10
|
||||
st sp, [r10, THREAD_INFO_KSP]
|
||||
|
||||
/* reload SP with kernel mode stack pointer in task->thread.ksp */
|
||||
ld.as sp, [r1, (TASK_THREAD + THREAD_KSP)/4]
|
||||
/* update @next in _current_task[] and GP register caching it */
|
||||
SET_CURR_TASK_ON_CPU r1, r10
|
||||
|
||||
/* restore the registers */
|
||||
/* load SP from @next->thread_info.ksp */
|
||||
ld r10, [r1, TASK_THREAD_INFO]
|
||||
ld sp, [r10, THREAD_INFO_KSP]
|
||||
|
||||
/* restore callee regs, stack frame regs of @next */
|
||||
RESTORE_CALLEE_SAVED_KERNEL
|
||||
ld.ab fp, [sp, 4]
|
||||
ld.ab blink, [sp, 4]
|
||||
j [blink]
|
||||
|
||||
pop fp
|
||||
CFI_RESTORE r27
|
||||
CFI_DEF_CFA r28, 4
|
||||
|
||||
pop blink
|
||||
CFI_RESTORE r31
|
||||
CFI_DEF_CFA_OFFSET 0
|
||||
|
||||
j [blink]
|
||||
END_CFI(__switch_to)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <asm/mach_desc.h>
|
||||
#include <asm/serial.h>
|
||||
|
||||
#ifdef CONFIG_SERIAL_EARLYCON
|
||||
|
||||
|
||||
@@ -125,11 +125,6 @@ ENTRY(mem_service)
|
||||
|
||||
EXCEPTION_PROLOGUE
|
||||
|
||||
lr r0, [efa]
|
||||
mov r1, sp
|
||||
|
||||
FAKE_RET_FROM_EXCPN
|
||||
|
||||
bl do_memory_error
|
||||
b ret_from_exception
|
||||
END(mem_service)
|
||||
@@ -138,11 +133,6 @@ ENTRY(EV_Misaligned)
|
||||
|
||||
EXCEPTION_PROLOGUE
|
||||
|
||||
lr r0, [efa] ; Faulting Data address
|
||||
mov r1, sp
|
||||
|
||||
FAKE_RET_FROM_EXCPN
|
||||
|
||||
SAVE_CALLEE_SAVED_USER
|
||||
mov r2, sp ; callee_regs
|
||||
|
||||
@@ -163,11 +153,6 @@ ENTRY(EV_TLBProtV)
|
||||
|
||||
EXCEPTION_PROLOGUE
|
||||
|
||||
lr r0, [efa] ; Faulting Data address
|
||||
mov r1, sp ; pt_regs
|
||||
|
||||
FAKE_RET_FROM_EXCPN
|
||||
|
||||
mov blink, ret_from_exception
|
||||
b do_page_fault
|
||||
|
||||
|
||||
@@ -254,18 +254,7 @@ END(handle_interrupt_level1)
|
||||
|
||||
ENTRY(EV_TLBProtV)
|
||||
|
||||
EXCEPTION_PROLOGUE
|
||||
|
||||
mov r2, r10 ; ECR set into r10 already
|
||||
lr r0, [efa] ; Faulting Data address (not part of pt_regs saved above)
|
||||
|
||||
; Exception auto-disables further Intr/exceptions.
|
||||
; Re-enable them by pretending to return from exception
|
||||
; (so rest of handler executes in pure K mode)
|
||||
|
||||
FAKE_RET_FROM_EXCPN
|
||||
|
||||
mov r1, sp ; Handle to pt_regs
|
||||
EXCEPTION_PROLOGUE ; ECR returned in r10
|
||||
|
||||
;------ (5) Type of Protection Violation? ----------
|
||||
;
|
||||
@@ -273,8 +262,7 @@ ENTRY(EV_TLBProtV)
|
||||
; -Access Violation : 00_23_(00|01|02|03)_00
|
||||
; x r w r+w
|
||||
; -Unaligned Access : 00_23_04_00
|
||||
;
|
||||
bbit1 r2, ECR_C_BIT_PROTV_MISALIG_DATA, 4f
|
||||
bbit1 r10, ECR_C_BIT_PROTV_MISALIG_DATA, 4f
|
||||
|
||||
;========= (6a) Access Violation Processing ========
|
||||
bl do_page_fault
|
||||
@@ -303,9 +291,6 @@ END(EV_TLBProtV)
|
||||
ENTRY(call_do_page_fault)
|
||||
|
||||
EXCEPTION_PROLOGUE
|
||||
lr r0, [efa] ; Faulting Data address
|
||||
mov r1, sp
|
||||
FAKE_RET_FROM_EXCPN
|
||||
|
||||
mov blink, ret_from_exception
|
||||
b do_page_fault
|
||||
|
||||
+24
-46
@@ -80,11 +80,6 @@ ENTRY(instr_service)
|
||||
|
||||
EXCEPTION_PROLOGUE
|
||||
|
||||
lr r0, [efa]
|
||||
mov r1, sp
|
||||
|
||||
FAKE_RET_FROM_EXCPN
|
||||
|
||||
bl do_insterror_or_kprobe
|
||||
b ret_from_exception
|
||||
END(instr_service)
|
||||
@@ -95,16 +90,15 @@ END(instr_service)
|
||||
|
||||
ENTRY(EV_MachineCheck)
|
||||
|
||||
EXCEPTION_PROLOGUE
|
||||
EXCEPTION_PROLOGUE_KEEP_AE ; ECR returned in r10
|
||||
|
||||
lr r2, [ecr]
|
||||
lr r0, [efa]
|
||||
mov r1, sp
|
||||
|
||||
; MC excpetions disable MMU
|
||||
ARC_MMU_REENABLE r3
|
||||
|
||||
lsr r3, r2, 8
|
||||
lsr r3, r10, 8
|
||||
bmsk r3, r3, 7
|
||||
brne r3, ECR_C_MCHK_DUP_TLB, 1f
|
||||
|
||||
@@ -129,11 +123,6 @@ ENTRY(EV_PrivilegeV)
|
||||
|
||||
EXCEPTION_PROLOGUE
|
||||
|
||||
lr r0, [efa]
|
||||
mov r1, sp
|
||||
|
||||
FAKE_RET_FROM_EXCPN
|
||||
|
||||
bl do_privilege_fault
|
||||
b ret_from_exception
|
||||
END(EV_PrivilegeV)
|
||||
@@ -145,11 +134,6 @@ ENTRY(EV_Extension)
|
||||
|
||||
EXCEPTION_PROLOGUE
|
||||
|
||||
lr r0, [efa]
|
||||
mov r1, sp
|
||||
|
||||
FAKE_RET_FROM_EXCPN
|
||||
|
||||
bl do_extension_fault
|
||||
b ret_from_exception
|
||||
END(EV_Extension)
|
||||
@@ -160,20 +144,19 @@ END(EV_Extension)
|
||||
; syscall Tracing
|
||||
; ---------------------------------------------
|
||||
tracesys:
|
||||
; save EFA in case tracer wants the PC of traced task
|
||||
; using ERET won't work since next-PC has already committed
|
||||
; safekeep EFA (r12) if syscall tracer wanted PC
|
||||
; for traps, ERET is pre-commit so points to next-PC
|
||||
GET_CURR_TASK_FIELD_PTR TASK_THREAD, r11
|
||||
st r12, [r11, THREAD_FAULT_ADDR] ; thread.fault_address
|
||||
|
||||
; PRE Sys Call Ptrace hook
|
||||
mov r0, sp ; pt_regs needed
|
||||
bl @syscall_trace_entry
|
||||
; PRE syscall trace hook
|
||||
mov r0, sp ; pt_regs
|
||||
bl @syscall_trace_enter
|
||||
|
||||
; Tracing code now returns the syscall num (orig or modif)
|
||||
mov r8, r0
|
||||
|
||||
; Do the Sys Call as we normally would.
|
||||
; Validate the Sys Call number
|
||||
cmp r8, NR_syscalls - 1
|
||||
mov.hi r0, -ENOSYS
|
||||
bhi tracesys_exit
|
||||
@@ -190,37 +173,36 @@ tracesys:
|
||||
ld r6, [sp, PT_r6]
|
||||
ld r7, [sp, PT_r7]
|
||||
ld.as r9, [sys_call_table, r8]
|
||||
jl [r9] ; Entry into Sys Call Handler
|
||||
jl [r9]
|
||||
|
||||
tracesys_exit:
|
||||
st r0, [sp, PT_r0] ; sys call return value in pt_regs
|
||||
st r0, [sp, PT_r0]
|
||||
|
||||
;POST Sys Call Ptrace Hook
|
||||
; POST syscall trace hook
|
||||
mov r0, sp ; pt_regs needed
|
||||
bl @syscall_trace_exit
|
||||
b ret_from_exception ; NOT ret_from_system_call at is saves r0 which
|
||||
; we'd done before calling post hook above
|
||||
|
||||
; don't call ret_from_system_call as it saves r0, already done above
|
||||
b ret_from_exception
|
||||
|
||||
; ---------------------------------------------
|
||||
; Breakpoint TRAP
|
||||
; ---------------------------------------------
|
||||
trap_with_param:
|
||||
mov r0, r12 ; EFA in case ptracer/gdb wants stop_pc
|
||||
mov r1, sp
|
||||
mov r1, sp ; pt_regs
|
||||
|
||||
; Save callee regs in case gdb wants to have a look
|
||||
; SP will grow up by size of CALLEE Reg-File
|
||||
; NOTE: clobbers r12
|
||||
; save callee regs in case tracer/gdb wants to peek
|
||||
SAVE_CALLEE_SAVED_USER
|
||||
|
||||
; save location of saved Callee Regs @ thread_struct->pc
|
||||
; safekeep ref to callee regs
|
||||
GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10
|
||||
st sp, [r10, THREAD_CALLEE_REG]
|
||||
|
||||
; Call the trap handler
|
||||
; call the non syscall trap handler
|
||||
bl do_non_swi_trap
|
||||
|
||||
; unwind stack to discard Callee saved Regs
|
||||
; unwind stack to discard callee regs
|
||||
DISCARD_CALLEE_SAVED_USER
|
||||
|
||||
b ret_from_exception
|
||||
@@ -232,37 +214,33 @@ trap_with_param:
|
||||
|
||||
ENTRY(EV_Trap)
|
||||
|
||||
EXCEPTION_PROLOGUE
|
||||
EXCEPTION_PROLOGUE_KEEP_AE
|
||||
|
||||
lr r12, [efa]
|
||||
|
||||
FAKE_RET_FROM_EXCPN
|
||||
|
||||
;============ TRAP 1 :breakpoints
|
||||
; Check ECR for trap with arg (PROLOGUE ensures r10 has ECR)
|
||||
;============ TRAP N : breakpoints, kprobes etc
|
||||
bmsk.f 0, r10, 7
|
||||
bnz trap_with_param
|
||||
|
||||
;============ TRAP (no param): syscall top level
|
||||
;============ TRAP 0 (no param): syscall
|
||||
|
||||
; If syscall tracing ongoing, invoke pre-post-hooks
|
||||
; syscall tracing ongoing, invoke pre-post-hooks around syscall
|
||||
GET_CURR_THR_INFO_FLAGS r10
|
||||
and.f 0, r10, _TIF_SYSCALL_WORK
|
||||
bnz tracesys ; this never comes back
|
||||
|
||||
;============ Normal syscall case
|
||||
|
||||
; syscall num shd not exceed the total system calls avail
|
||||
cmp r8, NR_syscalls - 1
|
||||
mov.hi r0, -ENOSYS
|
||||
bhi .Lret_from_system_call
|
||||
|
||||
; Offset into the syscall_table and call handler
|
||||
ld.as r9,[sys_call_table, r8]
|
||||
jl [r9] ; Entry into Sys Call Handler
|
||||
jl [r9]
|
||||
|
||||
.Lret_from_system_call:
|
||||
|
||||
st r0, [sp, PT_r0] ; sys call return value in pt_regs
|
||||
|
||||
; fall through to ret_from_exception
|
||||
@@ -318,7 +296,7 @@ resume_user_mode_begin:
|
||||
; tracer might call PEEKUSR(CALLEE reg)
|
||||
;
|
||||
; NOTE: SP will grow up by size of CALLEE Reg-File
|
||||
SAVE_CALLEE_SAVED_USER ; clobbers r12
|
||||
SAVE_CALLEE_SAVED_USER
|
||||
|
||||
; save location of saved Callee Regs @ thread_struct->callee
|
||||
GET_CURR_TASK_FIELD_PTR TASK_THREAD, r10
|
||||
|
||||
@@ -108,7 +108,7 @@ static void arcv2_irq_unmask(struct irq_data *data)
|
||||
write_aux_reg(AUX_IRQ_ENABLE, 1);
|
||||
}
|
||||
|
||||
void arcv2_irq_enable(struct irq_data *data)
|
||||
static void arcv2_irq_enable(struct irq_data *data)
|
||||
{
|
||||
/* set default priority */
|
||||
write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
|
||||
|
||||
@@ -175,7 +175,7 @@ void kgdb_trap(struct pt_regs *regs)
|
||||
* with trap_s 4 (compiled) breakpoints, continuation needs to
|
||||
* start after the breakpoint.
|
||||
*/
|
||||
if (regs->ecr_param == 3)
|
||||
if (regs->ecr.param == 3)
|
||||
instruction_pointer(regs) -= BREAK_INSTR_SIZE;
|
||||
|
||||
kgdb_handle_exception(1, SIGTRAP, 0, regs);
|
||||
|
||||
@@ -165,8 +165,6 @@ static void mcip_probe_n_setup(void)
|
||||
IS_AVAIL1(mp.idu, "IDU "),
|
||||
IS_AVAIL1(mp.dbg, "DEBUG "),
|
||||
IS_AVAIL1(mp.gfrc, "GFRC"));
|
||||
|
||||
cpuinfo_arc700[0].extn.gfrc = mp.gfrc;
|
||||
}
|
||||
|
||||
struct plat_smp_ops plat_smp_ops = {
|
||||
|
||||
@@ -141,7 +141,7 @@ asmlinkage void ret_from_fork(void);
|
||||
* | unused |
|
||||
* | |
|
||||
* ------------------
|
||||
* | r25 | <==== top of Stack (thread.ksp)
|
||||
* | r25 | <==== top of Stack (thread_info.ksp)
|
||||
* ~ ~
|
||||
* | --to-- | (CALLEE Regs of kernel mode)
|
||||
* | r13 |
|
||||
@@ -162,7 +162,6 @@ asmlinkage void ret_from_fork(void);
|
||||
* | SP |
|
||||
* | orig_r0 |
|
||||
* | event/ECR |
|
||||
* | user_r25 |
|
||||
* ------------------ <===== END of PAGE
|
||||
*/
|
||||
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
|
||||
@@ -182,14 +181,14 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
|
||||
c_callee = ((struct callee_regs *)childksp) - 1;
|
||||
|
||||
/*
|
||||
* __switch_to() uses thread.ksp to start unwinding stack
|
||||
* __switch_to() uses thread_info.ksp to start unwinding stack
|
||||
* For kernel threads we don't need to create callee regs, the
|
||||
* stack layout nevertheless needs to remain the same.
|
||||
* Also, since __switch_to anyways unwinds callee regs, we use
|
||||
* this to populate kernel thread entry-pt/args into callee regs,
|
||||
* so that ret_from_kernel_thread() becomes simpler.
|
||||
*/
|
||||
p->thread.ksp = (unsigned long)c_callee; /* THREAD_KSP */
|
||||
task_thread_info(p)->ksp = (unsigned long)c_callee; /* THREAD_INFO_KSP */
|
||||
|
||||
/* __switch_to expects FP(0), BLINK(return addr) at top */
|
||||
childksp[0] = 0; /* fp */
|
||||
@@ -243,16 +242,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
|
||||
*/
|
||||
c_callee->r25 = task_thread_info(p)->thr_ptr;
|
||||
|
||||
#ifdef CONFIG_ARC_CURR_IN_REG
|
||||
/*
|
||||
* setup usermode thread pointer #2:
|
||||
* however for this special use of r25 in kernel, __switch_to() sets
|
||||
* r25 for kernel needs and only in the final return path is usermode
|
||||
* r25 setup, from pt_regs->user_r25. So set that up as well
|
||||
*/
|
||||
c_regs->user_r25 = c_callee->r25;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,8 +46,7 @@ static const struct pt_regs_offset regoffset_table[] = {
|
||||
REG_OFFSET_NAME(r0),
|
||||
REG_OFFSET_NAME(sp),
|
||||
REG_OFFSET_NAME(orig_r0),
|
||||
REG_OFFSET_NAME(event),
|
||||
REG_OFFSET_NAME(user_r25),
|
||||
REG_OFFSET_NAME(ecr),
|
||||
REG_OFFSET_END,
|
||||
};
|
||||
|
||||
@@ -55,9 +54,8 @@ static const struct pt_regs_offset regoffset_table[] = {
|
||||
|
||||
static const struct pt_regs_offset regoffset_table[] = {
|
||||
REG_OFFSET_NAME(orig_r0),
|
||||
REG_OFFSET_NAME(event),
|
||||
REG_OFFSET_NAME(ecr),
|
||||
REG_OFFSET_NAME(bta),
|
||||
REG_OFFSET_NAME(user_r25),
|
||||
REG_OFFSET_NAME(r26),
|
||||
REG_OFFSET_NAME(fp),
|
||||
REG_OFFSET_NAME(sp),
|
||||
@@ -341,7 +339,7 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
return ret;
|
||||
}
|
||||
|
||||
asmlinkage int syscall_trace_entry(struct pt_regs *regs)
|
||||
asmlinkage int syscall_trace_enter(struct pt_regs *regs)
|
||||
{
|
||||
if (test_thread_flag(TIF_SYSCALL_TRACE))
|
||||
if (ptrace_report_syscall_entry(regs))
|
||||
|
||||
+279
-324
@@ -29,6 +29,7 @@
|
||||
#include <asm/mach_desc.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/dsp-impl.h>
|
||||
#include <soc/arc/mcip.h>
|
||||
|
||||
#define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x))
|
||||
|
||||
@@ -43,19 +44,22 @@ const struct machine_desc *machine_desc;
|
||||
|
||||
struct task_struct *_current_task[NR_CPUS]; /* For stack switching */
|
||||
|
||||
struct cpuinfo_arc cpuinfo_arc700[NR_CPUS];
|
||||
struct cpuinfo_arc {
|
||||
int arcver;
|
||||
unsigned int t0:1, t1:1;
|
||||
struct {
|
||||
unsigned long base;
|
||||
unsigned int sz;
|
||||
} iccm, dccm;
|
||||
};
|
||||
|
||||
static const struct id_to_str arc_legacy_rel[] = {
|
||||
#ifdef CONFIG_ISA_ARCV2
|
||||
|
||||
static const struct id_to_str arc_hs_rel[] = {
|
||||
/* ID.ARCVER, Release */
|
||||
#ifdef CONFIG_ISA_ARCOMPACT
|
||||
{ 0x34, "R4.10"},
|
||||
{ 0x35, "R4.11"},
|
||||
#else
|
||||
{ 0x51, "R2.0" },
|
||||
{ 0x52, "R2.1" },
|
||||
{ 0x53, "R3.0" },
|
||||
#endif
|
||||
{ 0x00, NULL }
|
||||
};
|
||||
|
||||
static const struct id_to_str arc_hs_ver54_rel[] = {
|
||||
@@ -66,324 +70,297 @@ static const struct id_to_str arc_hs_ver54_rel[] = {
|
||||
{ 3, "R4.00a"},
|
||||
{ 0xFF, NULL }
|
||||
};
|
||||
#endif
|
||||
|
||||
static void read_decode_ccm_bcr(struct cpuinfo_arc *cpu)
|
||||
static int
|
||||
arcompact_mumbojumbo(int c, struct cpuinfo_arc *info, char *buf, int len)
|
||||
{
|
||||
if (is_isa_arcompact()) {
|
||||
struct bcr_iccm_arcompact iccm;
|
||||
struct bcr_dccm_arcompact dccm;
|
||||
int n = 0;
|
||||
#ifdef CONFIG_ISA_ARCOMPACT
|
||||
char *cpu_nm, *isa_nm = "ARCompact";
|
||||
struct bcr_fp_arcompact fpu_sp, fpu_dp;
|
||||
int atomic = 0, be, present;
|
||||
int bpu_full, bpu_cache, bpu_pred;
|
||||
struct bcr_bpu_arcompact bpu;
|
||||
struct bcr_iccm_arcompact iccm;
|
||||
struct bcr_dccm_arcompact dccm;
|
||||
struct bcr_generic isa;
|
||||
|
||||
READ_BCR(ARC_REG_ICCM_BUILD, iccm);
|
||||
if (iccm.ver) {
|
||||
cpu->iccm.sz = 4096 << iccm.sz; /* 8K to 512K */
|
||||
cpu->iccm.base_addr = iccm.base << 16;
|
||||
}
|
||||
READ_BCR(ARC_REG_ISA_CFG_BCR, isa);
|
||||
|
||||
READ_BCR(ARC_REG_DCCM_BUILD, dccm);
|
||||
if (dccm.ver) {
|
||||
unsigned long base;
|
||||
cpu->dccm.sz = 2048 << dccm.sz; /* 2K to 256K */
|
||||
|
||||
base = read_aux_reg(ARC_REG_DCCM_BASE_BUILD);
|
||||
cpu->dccm.base_addr = base & ~0xF;
|
||||
}
|
||||
} else {
|
||||
struct bcr_iccm_arcv2 iccm;
|
||||
struct bcr_dccm_arcv2 dccm;
|
||||
unsigned long region;
|
||||
|
||||
READ_BCR(ARC_REG_ICCM_BUILD, iccm);
|
||||
if (iccm.ver) {
|
||||
cpu->iccm.sz = 256 << iccm.sz00; /* 512B to 16M */
|
||||
if (iccm.sz00 == 0xF && iccm.sz01 > 0)
|
||||
cpu->iccm.sz <<= iccm.sz01;
|
||||
|
||||
region = read_aux_reg(ARC_REG_AUX_ICCM);
|
||||
cpu->iccm.base_addr = region & 0xF0000000;
|
||||
}
|
||||
|
||||
READ_BCR(ARC_REG_DCCM_BUILD, dccm);
|
||||
if (dccm.ver) {
|
||||
cpu->dccm.sz = 256 << dccm.sz0;
|
||||
if (dccm.sz0 == 0xF && dccm.sz1 > 0)
|
||||
cpu->dccm.sz <<= dccm.sz1;
|
||||
|
||||
region = read_aux_reg(ARC_REG_AUX_DCCM);
|
||||
cpu->dccm.base_addr = region & 0xF0000000;
|
||||
}
|
||||
if (!isa.ver) /* ISA BCR absent, use Kconfig info */
|
||||
atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC);
|
||||
else {
|
||||
/* ARC700_BUILD only has 2 bits of isa info */
|
||||
atomic = isa.info & 1;
|
||||
}
|
||||
|
||||
be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
|
||||
|
||||
if (info->arcver < 0x34)
|
||||
cpu_nm = "ARC750";
|
||||
else
|
||||
cpu_nm = "ARC770";
|
||||
|
||||
n += scnprintf(buf + n, len - n, "processor [%d]\t: %s (%s ISA) %s%s%s\n",
|
||||
c, cpu_nm, isa_nm,
|
||||
IS_AVAIL2(atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
|
||||
IS_AVAIL1(be, "[Big-Endian]"));
|
||||
|
||||
READ_BCR(ARC_REG_FP_BCR, fpu_sp);
|
||||
READ_BCR(ARC_REG_DPFP_BCR, fpu_dp);
|
||||
|
||||
if (fpu_sp.ver | fpu_dp.ver)
|
||||
n += scnprintf(buf + n, len - n, "FPU\t\t: %s%s\n",
|
||||
IS_AVAIL1(fpu_sp.ver, "SP "),
|
||||
IS_AVAIL1(fpu_dp.ver, "DP "));
|
||||
|
||||
READ_BCR(ARC_REG_BPU_BCR, bpu);
|
||||
bpu_full = bpu.fam ? 1 : 0;
|
||||
bpu_cache = 256 << (bpu.ent - 1);
|
||||
bpu_pred = 256 << (bpu.ent - 1);
|
||||
|
||||
n += scnprintf(buf + n, len - n,
|
||||
"BPU\t\t: %s%s match, cache:%d, Predict Table:%d\n",
|
||||
IS_AVAIL1(bpu_full, "full"),
|
||||
IS_AVAIL1(!bpu_full, "partial"),
|
||||
bpu_cache, bpu_pred);
|
||||
|
||||
READ_BCR(ARC_REG_ICCM_BUILD, iccm);
|
||||
if (iccm.ver) {
|
||||
info->iccm.sz = 4096 << iccm.sz; /* 8K to 512K */
|
||||
info->iccm.base = iccm.base << 16;
|
||||
}
|
||||
|
||||
READ_BCR(ARC_REG_DCCM_BUILD, dccm);
|
||||
if (dccm.ver) {
|
||||
unsigned long base;
|
||||
info->dccm.sz = 2048 << dccm.sz; /* 2K to 256K */
|
||||
|
||||
base = read_aux_reg(ARC_REG_DCCM_BASE_BUILD);
|
||||
info->dccm.base = base & ~0xF;
|
||||
}
|
||||
|
||||
/* ARCompact ISA specific sanity checks */
|
||||
present = fpu_dp.ver; /* SP has no arch visible regs */
|
||||
CHK_OPT_STRICT(CONFIG_ARC_FPU_SAVE_RESTORE, present);
|
||||
#endif
|
||||
return n;
|
||||
|
||||
}
|
||||
|
||||
static void decode_arc_core(struct cpuinfo_arc *cpu)
|
||||
static int arcv2_mumbojumbo(int c, struct cpuinfo_arc *info, char *buf, int len)
|
||||
{
|
||||
struct bcr_uarch_build_arcv2 uarch;
|
||||
const struct id_to_str *tbl;
|
||||
|
||||
if (cpu->core.family < 0x54) { /* includes arc700 */
|
||||
|
||||
for (tbl = &arc_legacy_rel[0]; tbl->id != 0; tbl++) {
|
||||
if (cpu->core.family == tbl->id) {
|
||||
cpu->release = tbl->str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_isa_arcompact())
|
||||
cpu->name = "ARC700";
|
||||
else if (tbl->str)
|
||||
cpu->name = "HS38";
|
||||
else
|
||||
cpu->name = cpu->release = "Unknown";
|
||||
|
||||
return;
|
||||
}
|
||||
int n = 0;
|
||||
#ifdef CONFIG_ISA_ARCV2
|
||||
const char *release, *cpu_nm, *isa_nm = "ARCv2";
|
||||
int dual_issue = 0, dual_enb = 0, mpy_opt, present;
|
||||
int bpu_full, bpu_cache, bpu_pred, bpu_ret_stk;
|
||||
char mpy_nm[16], lpb_nm[32];
|
||||
struct bcr_isa_arcv2 isa;
|
||||
struct bcr_mpy mpy;
|
||||
struct bcr_fp_arcv2 fpu;
|
||||
struct bcr_bpu_arcv2 bpu;
|
||||
struct bcr_lpb lpb;
|
||||
struct bcr_iccm_arcv2 iccm;
|
||||
struct bcr_dccm_arcv2 dccm;
|
||||
struct bcr_erp erp;
|
||||
|
||||
/*
|
||||
* Initial HS cores bumped AUX IDENTITY.ARCVER for each release until
|
||||
* ARCVER 0x54 which introduced AUX MICRO_ARCH_BUILD and subsequent
|
||||
* releases only update it.
|
||||
*/
|
||||
READ_BCR(ARC_REG_MICRO_ARCH_BCR, uarch);
|
||||
|
||||
if (uarch.prod == 4) {
|
||||
cpu->name = "HS48";
|
||||
cpu->extn.dual = 1;
|
||||
cpu_nm = "HS38";
|
||||
|
||||
if (info->arcver > 0x50 && info->arcver <= 0x53) {
|
||||
release = arc_hs_rel[info->arcver - 0x51].str;
|
||||
} else {
|
||||
cpu->name = "HS38";
|
||||
}
|
||||
const struct id_to_str *tbl;
|
||||
struct bcr_uarch_build uarch;
|
||||
|
||||
for (tbl = &arc_hs_ver54_rel[0]; tbl->id != 0xFF; tbl++) {
|
||||
if (uarch.maj == tbl->id) {
|
||||
cpu->release = tbl->str;
|
||||
break;
|
||||
READ_BCR(ARC_REG_MICRO_ARCH_BCR, uarch);
|
||||
|
||||
for (tbl = &arc_hs_ver54_rel[0]; tbl->id != 0xFF; tbl++) {
|
||||
if (uarch.maj == tbl->id) {
|
||||
release = tbl->str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void read_arc_build_cfg_regs(void)
|
||||
{
|
||||
struct bcr_timer timer;
|
||||
struct bcr_generic bcr;
|
||||
struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
|
||||
struct bcr_isa_arcv2 isa;
|
||||
struct bcr_actionpoint ap;
|
||||
|
||||
FIX_PTR(cpu);
|
||||
|
||||
READ_BCR(AUX_IDENTITY, cpu->core);
|
||||
decode_arc_core(cpu);
|
||||
|
||||
READ_BCR(ARC_REG_TIMERS_BCR, timer);
|
||||
cpu->extn.timer0 = timer.t0;
|
||||
cpu->extn.timer1 = timer.t1;
|
||||
cpu->extn.rtc = timer.rtc;
|
||||
|
||||
cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
|
||||
|
||||
READ_BCR(ARC_REG_MUL_BCR, cpu->extn_mpy);
|
||||
|
||||
/* Read CCM BCRs for boot reporting even if not enabled in Kconfig */
|
||||
read_decode_ccm_bcr(cpu);
|
||||
|
||||
read_decode_mmu_bcr();
|
||||
read_decode_cache_bcr();
|
||||
|
||||
if (is_isa_arcompact()) {
|
||||
struct bcr_fp_arcompact sp, dp;
|
||||
struct bcr_bpu_arcompact bpu;
|
||||
|
||||
READ_BCR(ARC_REG_FP_BCR, sp);
|
||||
READ_BCR(ARC_REG_DPFP_BCR, dp);
|
||||
cpu->extn.fpu_sp = sp.ver ? 1 : 0;
|
||||
cpu->extn.fpu_dp = dp.ver ? 1 : 0;
|
||||
|
||||
READ_BCR(ARC_REG_BPU_BCR, bpu);
|
||||
cpu->bpu.ver = bpu.ver;
|
||||
cpu->bpu.full = bpu.fam ? 1 : 0;
|
||||
if (bpu.ent) {
|
||||
cpu->bpu.num_cache = 256 << (bpu.ent - 1);
|
||||
cpu->bpu.num_pred = 256 << (bpu.ent - 1);
|
||||
}
|
||||
} else {
|
||||
struct bcr_fp_arcv2 spdp;
|
||||
struct bcr_bpu_arcv2 bpu;
|
||||
|
||||
READ_BCR(ARC_REG_FP_V2_BCR, spdp);
|
||||
cpu->extn.fpu_sp = spdp.sp ? 1 : 0;
|
||||
cpu->extn.fpu_dp = spdp.dp ? 1 : 0;
|
||||
|
||||
READ_BCR(ARC_REG_BPU_BCR, bpu);
|
||||
cpu->bpu.ver = bpu.ver;
|
||||
cpu->bpu.full = bpu.ft;
|
||||
cpu->bpu.num_cache = 256 << bpu.bce;
|
||||
cpu->bpu.num_pred = 2048 << bpu.pte;
|
||||
cpu->bpu.ret_stk = 4 << bpu.rse;
|
||||
|
||||
/* if dual issue hardware, is it enabled ? */
|
||||
if (cpu->extn.dual) {
|
||||
if (uarch.prod == 4) {
|
||||
unsigned int exec_ctrl;
|
||||
|
||||
cpu_nm = "HS48";
|
||||
dual_issue = 1;
|
||||
/* if dual issue hardware, is it enabled ? */
|
||||
READ_BCR(AUX_EXEC_CTRL, exec_ctrl);
|
||||
cpu->extn.dual_enb = !(exec_ctrl & 1);
|
||||
dual_enb = !(exec_ctrl & 1);
|
||||
}
|
||||
}
|
||||
|
||||
READ_BCR(ARC_REG_AP_BCR, ap);
|
||||
if (ap.ver) {
|
||||
cpu->extn.ap_num = 2 << ap.num;
|
||||
cpu->extn.ap_full = !ap.min;
|
||||
}
|
||||
|
||||
READ_BCR(ARC_REG_SMART_BCR, bcr);
|
||||
cpu->extn.smart = bcr.ver ? 1 : 0;
|
||||
|
||||
READ_BCR(ARC_REG_RTT_BCR, bcr);
|
||||
cpu->extn.rtt = bcr.ver ? 1 : 0;
|
||||
|
||||
READ_BCR(ARC_REG_ISA_CFG_BCR, isa);
|
||||
|
||||
/* some hacks for lack of feature BCR info in old ARC700 cores */
|
||||
if (is_isa_arcompact()) {
|
||||
if (!isa.ver) /* ISA BCR absent, use Kconfig info */
|
||||
cpu->isa.atomic = IS_ENABLED(CONFIG_ARC_HAS_LLSC);
|
||||
else {
|
||||
/* ARC700_BUILD only has 2 bits of isa info */
|
||||
struct bcr_generic bcr = *(struct bcr_generic *)&isa;
|
||||
cpu->isa.atomic = bcr.info & 1;
|
||||
}
|
||||
n += scnprintf(buf + n, len - n, "processor [%d]\t: %s %s (%s ISA) %s%s%s\n",
|
||||
c, cpu_nm, release, isa_nm,
|
||||
IS_AVAIL1(isa.be, "[Big-Endian]"),
|
||||
IS_AVAIL3(dual_issue, dual_enb, " Dual-Issue "));
|
||||
|
||||
cpu->isa.be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
|
||||
READ_BCR(ARC_REG_MPY_BCR, mpy);
|
||||
mpy_opt = 2; /* stock MPY/MPYH */
|
||||
if (mpy.dsp) /* OPT 7-9 */
|
||||
mpy_opt = mpy.dsp + 6;
|
||||
|
||||
/* there's no direct way to distinguish 750 vs. 770 */
|
||||
if (unlikely(cpu->core.family < 0x34 || cpu->mmu.ver < 3))
|
||||
cpu->name = "ARC750";
|
||||
} else {
|
||||
cpu->isa = isa;
|
||||
scnprintf(mpy_nm, 16, "mpy[opt %d] ", mpy_opt);
|
||||
|
||||
READ_BCR(ARC_REG_FP_V2_BCR, fpu);
|
||||
|
||||
n += scnprintf(buf + n, len - n, "ISA Extn\t: %s%s%s%s%s%s%s%s%s%s%s\n",
|
||||
IS_AVAIL2(isa.atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
|
||||
IS_AVAIL2(isa.ldd, "ll64 ", CONFIG_ARC_HAS_LL64),
|
||||
IS_AVAIL2(isa.unalign, "unalign ", CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS),
|
||||
IS_AVAIL1(mpy.ver, mpy_nm),
|
||||
IS_AVAIL1(isa.div_rem, "div_rem "),
|
||||
IS_AVAIL1((fpu.sp | fpu.dp), " FPU:"),
|
||||
IS_AVAIL1(fpu.sp, " sp"),
|
||||
IS_AVAIL1(fpu.dp, " dp"));
|
||||
|
||||
READ_BCR(ARC_REG_BPU_BCR, bpu);
|
||||
bpu_full = bpu.ft;
|
||||
bpu_cache = 256 << bpu.bce;
|
||||
bpu_pred = 2048 << bpu.pte;
|
||||
bpu_ret_stk = 4 << bpu.rse;
|
||||
|
||||
READ_BCR(ARC_REG_LPB_BUILD, lpb);
|
||||
if (lpb.ver) {
|
||||
unsigned int ctl;
|
||||
ctl = read_aux_reg(ARC_REG_LPB_CTRL);
|
||||
|
||||
scnprintf(lpb_nm, sizeof(lpb_nm), " Loop Buffer:%d %s",
|
||||
lpb.entries, IS_DISABLED_RUN(!ctl));
|
||||
}
|
||||
}
|
||||
|
||||
static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
|
||||
{
|
||||
struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id];
|
||||
struct bcr_identity *core = &cpu->core;
|
||||
char mpy_opt[16];
|
||||
int n = 0;
|
||||
|
||||
FIX_PTR(cpu);
|
||||
|
||||
n += scnprintf(buf + n, len - n,
|
||||
"\nIDENTITY\t: ARCVER [%#02x] ARCNUM [%#02x] CHIPID [%#4x]\n",
|
||||
core->family, core->cpu_id, core->chip_id);
|
||||
"BPU\t\t: %s%s match, cache:%d, Predict Table:%d Return stk: %d%s\n",
|
||||
IS_AVAIL1(bpu_full, "full"),
|
||||
IS_AVAIL1(!bpu_full, "partial"),
|
||||
bpu_cache, bpu_pred, bpu_ret_stk,
|
||||
lpb_nm);
|
||||
|
||||
n += scnprintf(buf + n, len - n, "processor [%d]\t: %s %s (%s ISA) %s%s%s\n",
|
||||
cpu_id, cpu->name, cpu->release,
|
||||
is_isa_arcompact() ? "ARCompact" : "ARCv2",
|
||||
IS_AVAIL1(cpu->isa.be, "[Big-Endian]"),
|
||||
IS_AVAIL3(cpu->extn.dual, cpu->extn.dual_enb, " Dual-Issue "));
|
||||
|
||||
n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s%s%s\nISA Extn\t: ",
|
||||
IS_AVAIL1(cpu->extn.timer0, "Timer0 "),
|
||||
IS_AVAIL1(cpu->extn.timer1, "Timer1 "),
|
||||
IS_AVAIL2(cpu->extn.rtc, "RTC [UP 64-bit] ", CONFIG_ARC_TIMERS_64BIT),
|
||||
IS_AVAIL2(cpu->extn.gfrc, "GFRC [SMP 64-bit] ", CONFIG_ARC_TIMERS_64BIT));
|
||||
|
||||
if (cpu->extn_mpy.ver) {
|
||||
if (is_isa_arcompact()) {
|
||||
scnprintf(mpy_opt, 16, "mpy");
|
||||
} else {
|
||||
|
||||
int opt = 2; /* stock MPY/MPYH */
|
||||
|
||||
if (cpu->extn_mpy.dsp) /* OPT 7-9 */
|
||||
opt = cpu->extn_mpy.dsp + 6;
|
||||
|
||||
scnprintf(mpy_opt, 16, "mpy[opt %d] ", opt);
|
||||
}
|
||||
READ_BCR(ARC_REG_ICCM_BUILD, iccm);
|
||||
if (iccm.ver) {
|
||||
unsigned long base;
|
||||
info->iccm.sz = 256 << iccm.sz00; /* 512B to 16M */
|
||||
if (iccm.sz00 == 0xF && iccm.sz01 > 0)
|
||||
info->iccm.sz <<= iccm.sz01;
|
||||
base = read_aux_reg(ARC_REG_AUX_ICCM);
|
||||
info->iccm.base = base & 0xF0000000;
|
||||
}
|
||||
|
||||
n += scnprintf(buf + n, len - n, "%s%s%s%s%s%s%s%s\n",
|
||||
IS_AVAIL2(cpu->isa.atomic, "atomic ", CONFIG_ARC_HAS_LLSC),
|
||||
IS_AVAIL2(cpu->isa.ldd, "ll64 ", CONFIG_ARC_HAS_LL64),
|
||||
IS_AVAIL2(cpu->isa.unalign, "unalign ", CONFIG_ARC_USE_UNALIGNED_MEM_ACCESS),
|
||||
IS_AVAIL1(cpu->extn_mpy.ver, mpy_opt),
|
||||
IS_AVAIL1(cpu->isa.div_rem, "div_rem "));
|
||||
|
||||
if (cpu->bpu.ver) {
|
||||
n += scnprintf(buf + n, len - n,
|
||||
"BPU\t\t: %s%s match, cache:%d, Predict Table:%d Return stk: %d",
|
||||
IS_AVAIL1(cpu->bpu.full, "full"),
|
||||
IS_AVAIL1(!cpu->bpu.full, "partial"),
|
||||
cpu->bpu.num_cache, cpu->bpu.num_pred, cpu->bpu.ret_stk);
|
||||
|
||||
if (is_isa_arcv2()) {
|
||||
struct bcr_lpb lpb;
|
||||
|
||||
READ_BCR(ARC_REG_LPB_BUILD, lpb);
|
||||
if (lpb.ver) {
|
||||
unsigned int ctl;
|
||||
ctl = read_aux_reg(ARC_REG_LPB_CTRL);
|
||||
|
||||
n += scnprintf(buf + n, len - n, " Loop Buffer:%d %s",
|
||||
lpb.entries,
|
||||
IS_DISABLED_RUN(!ctl));
|
||||
}
|
||||
}
|
||||
n += scnprintf(buf + n, len - n, "\n");
|
||||
READ_BCR(ARC_REG_DCCM_BUILD, dccm);
|
||||
if (dccm.ver) {
|
||||
unsigned long base;
|
||||
info->dccm.sz = 256 << dccm.sz0;
|
||||
if (dccm.sz0 == 0xF && dccm.sz1 > 0)
|
||||
info->dccm.sz <<= dccm.sz1;
|
||||
base = read_aux_reg(ARC_REG_AUX_DCCM);
|
||||
info->dccm.base = base & 0xF0000000;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
|
||||
{
|
||||
int n = 0;
|
||||
struct cpuinfo_arc *cpu = &cpuinfo_arc700[cpu_id];
|
||||
|
||||
FIX_PTR(cpu);
|
||||
|
||||
n += scnprintf(buf + n, len - n, "Vector Table\t: %#x\n", cpu->vec_base);
|
||||
|
||||
if (cpu->extn.fpu_sp || cpu->extn.fpu_dp)
|
||||
n += scnprintf(buf + n, len - n, "FPU\t\t: %s%s\n",
|
||||
IS_AVAIL1(cpu->extn.fpu_sp, "SP "),
|
||||
IS_AVAIL1(cpu->extn.fpu_dp, "DP "));
|
||||
|
||||
if (cpu->extn.ap_num | cpu->extn.smart | cpu->extn.rtt) {
|
||||
n += scnprintf(buf + n, len - n, "DEBUG\t\t: %s%s",
|
||||
IS_AVAIL1(cpu->extn.smart, "smaRT "),
|
||||
IS_AVAIL1(cpu->extn.rtt, "RTT "));
|
||||
if (cpu->extn.ap_num) {
|
||||
n += scnprintf(buf + n, len - n, "ActionPoint %d/%s",
|
||||
cpu->extn.ap_num,
|
||||
cpu->extn.ap_full ? "full":"min");
|
||||
}
|
||||
n += scnprintf(buf + n, len - n, "\n");
|
||||
}
|
||||
|
||||
if (cpu->dccm.sz || cpu->iccm.sz)
|
||||
n += scnprintf(buf + n, len - n, "Extn [CCM]\t: DCCM @ %x, %d KB / ICCM: @ %x, %d KB\n",
|
||||
cpu->dccm.base_addr, TO_KB(cpu->dccm.sz),
|
||||
cpu->iccm.base_addr, TO_KB(cpu->iccm.sz));
|
||||
|
||||
if (is_isa_arcv2()) {
|
||||
|
||||
/* Error Protection: ECC/Parity */
|
||||
struct bcr_erp erp;
|
||||
READ_BCR(ARC_REG_ERP_BUILD, erp);
|
||||
|
||||
if (erp.ver) {
|
||||
struct ctl_erp ctl;
|
||||
READ_BCR(ARC_REG_ERP_CTRL, ctl);
|
||||
|
||||
/* inverted bits: 0 means enabled */
|
||||
n += scnprintf(buf + n, len - n, "Extn [ECC]\t: %s%s%s%s%s%s\n",
|
||||
/* Error Protection: ECC/Parity */
|
||||
READ_BCR(ARC_REG_ERP_BUILD, erp);
|
||||
if (erp.ver) {
|
||||
struct ctl_erp ctl;
|
||||
READ_BCR(ARC_REG_ERP_CTRL, ctl);
|
||||
/* inverted bits: 0 means enabled */
|
||||
n += scnprintf(buf + n, len - n, "Extn [ECC]\t: %s%s%s%s%s%s\n",
|
||||
IS_AVAIL3(erp.ic, !ctl.dpi, "IC "),
|
||||
IS_AVAIL3(erp.dc, !ctl.dpd, "DC "),
|
||||
IS_AVAIL3(erp.mmu, !ctl.mpd, "MMU "));
|
||||
}
|
||||
}
|
||||
|
||||
/* ARCv2 ISA specific sanity checks */
|
||||
present = fpu.sp | fpu.dp | mpy.dsp; /* DSP and/or FPU */
|
||||
CHK_OPT_STRICT(CONFIG_ARC_HAS_ACCL_REGS, present);
|
||||
|
||||
dsp_config_check();
|
||||
#endif
|
||||
return n;
|
||||
}
|
||||
|
||||
static char *arc_cpu_mumbojumbo(int c, struct cpuinfo_arc *info, char *buf, int len)
|
||||
{
|
||||
struct bcr_identity ident;
|
||||
struct bcr_timer timer;
|
||||
struct bcr_generic bcr;
|
||||
struct mcip_bcr mp;
|
||||
struct bcr_actionpoint ap;
|
||||
unsigned long vec_base;
|
||||
int ap_num, ap_full, smart, rtt, n;
|
||||
|
||||
memset(info, 0, sizeof(struct cpuinfo_arc));
|
||||
|
||||
READ_BCR(AUX_IDENTITY, ident);
|
||||
info->arcver = ident.family;
|
||||
|
||||
n = scnprintf(buf, len,
|
||||
"\nIDENTITY\t: ARCVER [%#02x] ARCNUM [%#02x] CHIPID [%#4x]\n",
|
||||
ident.family, ident.cpu_id, ident.chip_id);
|
||||
|
||||
if (is_isa_arcompact()) {
|
||||
n += arcompact_mumbojumbo(c, info, buf + n, len - n);
|
||||
} else if (is_isa_arcv2()){
|
||||
n += arcv2_mumbojumbo(c, info, buf + n, len - n);
|
||||
}
|
||||
|
||||
n += arc_mmu_mumbojumbo(c, buf + n, len - n);
|
||||
n += arc_cache_mumbojumbo(c, buf + n, len - n);
|
||||
|
||||
READ_BCR(ARC_REG_TIMERS_BCR, timer);
|
||||
info->t0 = timer.t0;
|
||||
info->t1 = timer.t1;
|
||||
|
||||
READ_BCR(ARC_REG_MCIP_BCR, mp);
|
||||
vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
|
||||
|
||||
n += scnprintf(buf + n, len - n,
|
||||
"Timers\t\t: %s%s%s%s%s%s\nVector Table\t: %#lx\n",
|
||||
IS_AVAIL1(timer.t0, "Timer0 "),
|
||||
IS_AVAIL1(timer.t1, "Timer1 "),
|
||||
IS_AVAIL2(timer.rtc, "RTC [UP 64-bit] ", CONFIG_ARC_TIMERS_64BIT),
|
||||
IS_AVAIL2(mp.gfrc, "GFRC [SMP 64-bit] ", CONFIG_ARC_TIMERS_64BIT),
|
||||
vec_base);
|
||||
|
||||
READ_BCR(ARC_REG_AP_BCR, ap);
|
||||
if (ap.ver) {
|
||||
ap_num = 2 << ap.num;
|
||||
ap_full = !ap.min;
|
||||
}
|
||||
|
||||
READ_BCR(ARC_REG_SMART_BCR, bcr);
|
||||
smart = bcr.ver ? 1 : 0;
|
||||
|
||||
READ_BCR(ARC_REG_RTT_BCR, bcr);
|
||||
rtt = bcr.ver ? 1 : 0;
|
||||
|
||||
if (ap.ver | smart | rtt) {
|
||||
n += scnprintf(buf + n, len - n, "DEBUG\t\t: %s%s",
|
||||
IS_AVAIL1(smart, "smaRT "),
|
||||
IS_AVAIL1(rtt, "RTT "));
|
||||
if (ap.ver) {
|
||||
n += scnprintf(buf + n, len - n, "ActionPoint %d/%s",
|
||||
ap_num,
|
||||
ap_full ? "full":"min");
|
||||
}
|
||||
n += scnprintf(buf + n, len - n, "\n");
|
||||
}
|
||||
|
||||
if (info->dccm.sz || info->iccm.sz)
|
||||
n += scnprintf(buf + n, len - n,
|
||||
"Extn [CCM]\t: DCCM @ %lx, %d KB / ICCM: @ %lx, %d KB\n",
|
||||
info->dccm.base, TO_KB(info->dccm.sz),
|
||||
info->iccm.base, TO_KB(info->iccm.sz));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -401,15 +378,15 @@ void chk_opt_weak(char *opt_name, bool hw_exists, bool opt_ena)
|
||||
panic("Disable %s, hardware NOT present\n", opt_name);
|
||||
}
|
||||
|
||||
static void arc_chk_core_config(void)
|
||||
/*
|
||||
* ISA agnostic sanity checks
|
||||
*/
|
||||
static void arc_chk_core_config(struct cpuinfo_arc *info)
|
||||
{
|
||||
struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
|
||||
int present = 0;
|
||||
|
||||
if (!cpu->extn.timer0)
|
||||
if (!info->t0)
|
||||
panic("Timer0 is not present!\n");
|
||||
|
||||
if (!cpu->extn.timer1)
|
||||
if (!info->t1)
|
||||
panic("Timer1 is not present!\n");
|
||||
|
||||
#ifdef CONFIG_ARC_HAS_DCCM
|
||||
@@ -417,35 +394,17 @@ static void arc_chk_core_config(void)
|
||||
* DCCM can be arbit placed in hardware.
|
||||
* Make sure it's placement/sz matches what Linux is built with
|
||||
*/
|
||||
if ((unsigned int)__arc_dccm_base != cpu->dccm.base_addr)
|
||||
if ((unsigned int)__arc_dccm_base != info->dccm.base)
|
||||
panic("Linux built with incorrect DCCM Base address\n");
|
||||
|
||||
if (CONFIG_ARC_DCCM_SZ * SZ_1K != cpu->dccm.sz)
|
||||
if (CONFIG_ARC_DCCM_SZ * SZ_1K != info->dccm.sz)
|
||||
panic("Linux built with incorrect DCCM Size\n");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARC_HAS_ICCM
|
||||
if (CONFIG_ARC_ICCM_SZ * SZ_1K != cpu->iccm.sz)
|
||||
if (CONFIG_ARC_ICCM_SZ * SZ_1K != info->iccm.sz)
|
||||
panic("Linux built with incorrect ICCM Size\n");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FP hardware/software config sanity
|
||||
* -If hardware present, kernel needs to save/restore FPU state
|
||||
* -If not, it will crash trying to save/restore the non-existant regs
|
||||
*/
|
||||
|
||||
if (is_isa_arcompact()) {
|
||||
/* only DPDP checked since SP has no arch visible regs */
|
||||
present = cpu->extn.fpu_dp;
|
||||
CHK_OPT_STRICT(CONFIG_ARC_FPU_SAVE_RESTORE, present);
|
||||
} else {
|
||||
/* Accumulator Low:High pair (r58:59) present if DSP MPY or FPU */
|
||||
present = cpu->extn_mpy.dsp | cpu->extn.fpu_sp | cpu->extn.fpu_dp;
|
||||
CHK_OPT_STRICT(CONFIG_ARC_HAS_ACCL_REGS, present);
|
||||
|
||||
dsp_config_check();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -456,21 +415,19 @@ static void arc_chk_core_config(void)
|
||||
|
||||
void setup_processor(void)
|
||||
{
|
||||
struct cpuinfo_arc info;
|
||||
int c = smp_processor_id();
|
||||
char str[512];
|
||||
int cpu_id = smp_processor_id();
|
||||
|
||||
read_arc_build_cfg_regs();
|
||||
pr_info("%s", arc_cpu_mumbojumbo(c, &info, str, sizeof(str)));
|
||||
pr_info("%s", arc_platform_smp_cpuinfo());
|
||||
|
||||
arc_chk_core_config(&info);
|
||||
|
||||
arc_init_IRQ();
|
||||
|
||||
pr_info("%s", arc_cpu_mumbojumbo(cpu_id, str, sizeof(str)));
|
||||
|
||||
arc_mmu_init();
|
||||
arc_cache_init();
|
||||
|
||||
pr_info("%s", arc_extn_mumbojumbo(cpu_id, str, sizeof(str)));
|
||||
pr_info("%s", arc_platform_smp_cpuinfo());
|
||||
|
||||
arc_chk_core_config();
|
||||
}
|
||||
|
||||
static inline bool uboot_arg_invalid(unsigned long addr)
|
||||
@@ -617,6 +574,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
||||
char *str;
|
||||
int cpu_id = ptr_to_cpu(v);
|
||||
struct device *cpu_dev = get_cpu_device(cpu_id);
|
||||
struct cpuinfo_arc info;
|
||||
struct clk *cpu_clk;
|
||||
unsigned long freq = 0;
|
||||
|
||||
@@ -629,7 +587,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
||||
if (!str)
|
||||
goto done;
|
||||
|
||||
seq_printf(m, arc_cpu_mumbojumbo(cpu_id, str, PAGE_SIZE));
|
||||
seq_printf(m, arc_cpu_mumbojumbo(cpu_id, &info, str, PAGE_SIZE));
|
||||
|
||||
cpu_clk = clk_get(cpu_dev, NULL);
|
||||
if (IS_ERR(cpu_clk)) {
|
||||
@@ -646,9 +604,6 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
||||
loops_per_jiffy / (500000 / HZ),
|
||||
(loops_per_jiffy / (5000 / HZ)) % 100);
|
||||
|
||||
seq_printf(m, arc_mmu_mumbojumbo(cpu_id, str, PAGE_SIZE));
|
||||
seq_printf(m, arc_cache_mumbojumbo(cpu_id, str, PAGE_SIZE));
|
||||
seq_printf(m, arc_extn_mumbojumbo(cpu_id, str, PAGE_SIZE));
|
||||
seq_printf(m, arc_platform_smp_cpuinfo());
|
||||
|
||||
free_page((unsigned long)str);
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include <linux/sched/task_stack.h>
|
||||
|
||||
#include <asm/ucontext.h>
|
||||
#include <asm/entry.h>
|
||||
|
||||
struct rt_sigframe {
|
||||
struct siginfo info;
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/of_fdt.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/mach_desc.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/smp.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#ifndef CONFIG_ARC_HAS_LLSC
|
||||
arch_spinlock_t smp_atomic_ops_lock = __ARCH_SPIN_LOCK_UNLOCKED;
|
||||
@@ -351,7 +352,7 @@ static inline int __do_IPI(unsigned long msg)
|
||||
* arch-common ISR to handle for inter-processor interrupts
|
||||
* Has hooks for platform specific IPI
|
||||
*/
|
||||
irqreturn_t do_IPI(int irq, void *dev_id)
|
||||
static irqreturn_t do_IPI(int irq, void *dev_id)
|
||||
{
|
||||
unsigned long pending;
|
||||
unsigned long __maybe_unused copy;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <asm/arcregs.h>
|
||||
#include <asm/unwind.h>
|
||||
#include <asm/stacktrace.h>
|
||||
#include <asm/switch_to.h>
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/kgdb.h>
|
||||
#include <asm/entry.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <asm/kprobes.h>
|
||||
@@ -109,9 +110,7 @@ void do_machine_check_fault(unsigned long address, struct pt_regs *regs)
|
||||
*/
|
||||
void do_non_swi_trap(unsigned long address, struct pt_regs *regs)
|
||||
{
|
||||
unsigned int param = regs->ecr_param;
|
||||
|
||||
switch (param) {
|
||||
switch (regs->ecr.param) {
|
||||
case 1:
|
||||
trap_is_brkpt(address, regs);
|
||||
break;
|
||||
|
||||
@@ -115,8 +115,8 @@ static void show_ecr_verbose(struct pt_regs *regs)
|
||||
/* For Data fault, this is data address not instruction addr */
|
||||
address = current->thread.fault_address;
|
||||
|
||||
vec = regs->ecr_vec;
|
||||
cause_code = regs->ecr_cause;
|
||||
vec = regs->ecr.vec;
|
||||
cause_code = regs->ecr.cause;
|
||||
|
||||
/* For DTLB Miss or ProtV, display the memory involved too */
|
||||
if (vec == ECR_V_DTLB_MISS) {
|
||||
@@ -154,7 +154,7 @@ static void show_ecr_verbose(struct pt_regs *regs)
|
||||
pr_cont("Misaligned r/w from 0x%08lx\n", address);
|
||||
#endif
|
||||
} else if (vec == ECR_V_TRAP) {
|
||||
if (regs->ecr_param == 5)
|
||||
if (regs->ecr.param == 5)
|
||||
pr_cont("gcc generated __builtin_trap\n");
|
||||
} else {
|
||||
pr_cont("Check Programmer's Manual\n");
|
||||
@@ -184,9 +184,10 @@ void show_regs(struct pt_regs *regs)
|
||||
if (user_mode(regs))
|
||||
show_faulting_vma(regs->ret); /* faulting code, not data */
|
||||
|
||||
pr_info("ECR: 0x%08lx EFA: 0x%08lx ERET: 0x%08lx\nSTAT: 0x%08lx",
|
||||
regs->event, current->thread.fault_address, regs->ret,
|
||||
regs->status32);
|
||||
pr_info("ECR: 0x%08lx EFA: 0x%08lx ERET: 0x%08lx\n",
|
||||
regs->ecr.full, current->thread.fault_address, regs->ret);
|
||||
|
||||
pr_info("STAT32: 0x%08lx", regs->status32);
|
||||
|
||||
#define STS_BIT(r, bit) r->status32 & STATUS_##bit##_MASK ? #bit" " : ""
|
||||
|
||||
|
||||
@@ -36,12 +36,13 @@
|
||||
#endif
|
||||
|
||||
ENTRY_CFI(memset)
|
||||
PREFETCHW_INSTR r0, 0 ; Prefetch the first write location
|
||||
mov.f 0, r2
|
||||
;;; if size is zero
|
||||
jz.d [blink]
|
||||
mov r3, r0 ; don't clobber ret val
|
||||
|
||||
PREFETCHW_INSTR r0, 0 ; Prefetch the first write location
|
||||
|
||||
;;; if length < 8
|
||||
brls.d.nt r2, 8, .Lsmallchunk
|
||||
mov.f lp_count,r2
|
||||
|
||||
+68
-111
@@ -28,6 +28,10 @@ int slc_enable = 1, ioc_enable = 1;
|
||||
unsigned long perip_base = ARC_UNCACHED_ADDR_SPACE; /* legacy value for boot */
|
||||
unsigned long perip_end = 0xFFFFFFFF; /* legacy value */
|
||||
|
||||
static struct cpuinfo_arc_cache {
|
||||
unsigned int sz_k, line_len, colors;
|
||||
} ic_info, dc_info, slc_info;
|
||||
|
||||
void (*_cache_line_loop_ic_fn)(phys_addr_t paddr, unsigned long vaddr,
|
||||
unsigned long sz, const int op, const int full_page);
|
||||
|
||||
@@ -35,78 +39,24 @@ void (*__dma_cache_wback_inv)(phys_addr_t start, unsigned long sz);
|
||||
void (*__dma_cache_inv)(phys_addr_t start, unsigned long sz);
|
||||
void (*__dma_cache_wback)(phys_addr_t start, unsigned long sz);
|
||||
|
||||
char *arc_cache_mumbojumbo(int c, char *buf, int len)
|
||||
static int read_decode_cache_bcr_arcv2(int c, char *buf, int len)
|
||||
{
|
||||
int n = 0;
|
||||
struct cpuinfo_arc_cache *p;
|
||||
|
||||
#define PR_CACHE(p, cfg, str) \
|
||||
if (!(p)->line_len) \
|
||||
n += scnprintf(buf + n, len - n, str"\t\t: N/A\n"); \
|
||||
else \
|
||||
n += scnprintf(buf + n, len - n, \
|
||||
str"\t\t: %uK, %dway/set, %uB Line, %s%s%s\n", \
|
||||
(p)->sz_k, (p)->assoc, (p)->line_len, \
|
||||
(p)->vipt ? "VIPT" : "PIPT", \
|
||||
(p)->alias ? " aliasing" : "", \
|
||||
IS_USED_CFG(cfg));
|
||||
|
||||
PR_CACHE(&cpuinfo_arc700[c].icache, CONFIG_ARC_HAS_ICACHE, "I-Cache");
|
||||
PR_CACHE(&cpuinfo_arc700[c].dcache, CONFIG_ARC_HAS_DCACHE, "D-Cache");
|
||||
|
||||
p = &cpuinfo_arc700[c].slc;
|
||||
if (p->line_len)
|
||||
n += scnprintf(buf + n, len - n,
|
||||
"SLC\t\t: %uK, %uB Line%s\n",
|
||||
p->sz_k, p->line_len, IS_USED_RUN(slc_enable));
|
||||
|
||||
n += scnprintf(buf + n, len - n, "Peripherals\t: %#lx%s%s\n",
|
||||
perip_base,
|
||||
IS_AVAIL3(ioc_exists, ioc_enable, ", IO-Coherency (per-device) "));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the Cache Build Confuration Registers, Decode them and save into
|
||||
* the cpuinfo structure for later use.
|
||||
* No Validation done here, simply read/convert the BCRs
|
||||
*/
|
||||
static void read_decode_cache_bcr_arcv2(int cpu)
|
||||
{
|
||||
struct cpuinfo_arc_cache *p_slc = &cpuinfo_arc700[cpu].slc;
|
||||
struct cpuinfo_arc_cache *p_slc = &slc_info;
|
||||
struct bcr_identity ident;
|
||||
struct bcr_generic sbcr;
|
||||
|
||||
struct bcr_slc_cfg {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int pad:24, way:2, lsz:2, sz:4;
|
||||
#else
|
||||
unsigned int sz:4, lsz:2, way:2, pad:24;
|
||||
#endif
|
||||
} slc_cfg;
|
||||
|
||||
struct bcr_clust_cfg {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int pad:7, c:1, num_entries:8, num_cores:8, ver:8;
|
||||
#else
|
||||
unsigned int ver:8, num_cores:8, num_entries:8, c:1, pad:7;
|
||||
#endif
|
||||
} cbcr;
|
||||
|
||||
struct bcr_volatile {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int start:4, limit:4, pad:22, order:1, disable:1;
|
||||
#else
|
||||
unsigned int disable:1, order:1, pad:22, limit:4, start:4;
|
||||
#endif
|
||||
} vol;
|
||||
|
||||
struct bcr_clust_cfg cbcr;
|
||||
struct bcr_volatile vol;
|
||||
int n = 0;
|
||||
|
||||
READ_BCR(ARC_REG_SLC_BCR, sbcr);
|
||||
if (sbcr.ver) {
|
||||
struct bcr_slc_cfg slc_cfg;
|
||||
READ_BCR(ARC_REG_SLC_CFG, slc_cfg);
|
||||
p_slc->sz_k = 128 << slc_cfg.sz;
|
||||
l2_line_sz = p_slc->line_len = (slc_cfg.lsz == 0) ? 128 : 64;
|
||||
n += scnprintf(buf + n, len - n,
|
||||
"SLC\t\t: %uK, %uB Line%s\n",
|
||||
p_slc->sz_k, p_slc->line_len, IS_USED_RUN(slc_enable));
|
||||
}
|
||||
|
||||
READ_BCR(ARC_REG_CLUSTER_BCR, cbcr);
|
||||
@@ -129,70 +79,83 @@ static void read_decode_cache_bcr_arcv2(int cpu)
|
||||
ioc_enable = 0;
|
||||
}
|
||||
|
||||
READ_BCR(AUX_IDENTITY, ident);
|
||||
|
||||
/* HS 2.0 didn't have AUX_VOL */
|
||||
if (cpuinfo_arc700[cpu].core.family > 0x51) {
|
||||
if (ident.family > 0x51) {
|
||||
READ_BCR(AUX_VOL, vol);
|
||||
perip_base = vol.start << 28;
|
||||
/* HS 3.0 has limit and strict-ordering fields */
|
||||
if (cpuinfo_arc700[cpu].core.family > 0x52)
|
||||
if (ident.family > 0x52)
|
||||
perip_end = (vol.limit << 28) - 1;
|
||||
}
|
||||
|
||||
n += scnprintf(buf + n, len - n, "Peripherals\t: %#lx%s%s\n",
|
||||
perip_base,
|
||||
IS_AVAIL3(ioc_exists, ioc_enable, ", IO-Coherency (per-device) "));
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void read_decode_cache_bcr(void)
|
||||
int arc_cache_mumbojumbo(int c, char *buf, int len)
|
||||
{
|
||||
struct cpuinfo_arc_cache *p_ic, *p_dc;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct bcr_cache {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
|
||||
#else
|
||||
unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
|
||||
#endif
|
||||
} ibcr, dbcr;
|
||||
struct cpuinfo_arc_cache *p_ic = &ic_info, *p_dc = &dc_info;
|
||||
struct bcr_cache ibcr, dbcr;
|
||||
int vipt, assoc;
|
||||
int n = 0;
|
||||
|
||||
p_ic = &cpuinfo_arc700[cpu].icache;
|
||||
READ_BCR(ARC_REG_IC_BCR, ibcr);
|
||||
|
||||
if (!ibcr.ver)
|
||||
goto dc_chk;
|
||||
|
||||
if (ibcr.ver <= 3) {
|
||||
if (is_isa_arcompact() && (ibcr.ver <= 3)) {
|
||||
BUG_ON(ibcr.config != 3);
|
||||
p_ic->assoc = 2; /* Fixed to 2w set assoc */
|
||||
} else if (ibcr.ver >= 4) {
|
||||
p_ic->assoc = 1 << ibcr.config; /* 1,2,4,8 */
|
||||
assoc = 2; /* Fixed to 2w set assoc */
|
||||
} else if (is_isa_arcv2() && (ibcr.ver >= 4)) {
|
||||
assoc = 1 << ibcr.config; /* 1,2,4,8 */
|
||||
}
|
||||
|
||||
p_ic->line_len = 8 << ibcr.line_len;
|
||||
p_ic->sz_k = 1 << (ibcr.sz - 1);
|
||||
p_ic->vipt = 1;
|
||||
p_ic->alias = p_ic->sz_k/p_ic->assoc/TO_KB(PAGE_SIZE) > 1;
|
||||
p_ic->colors = p_ic->sz_k/assoc/TO_KB(PAGE_SIZE);
|
||||
|
||||
n += scnprintf(buf + n, len - n,
|
||||
"I-Cache\t\t: %uK, %dway/set, %uB Line, VIPT%s%s\n",
|
||||
p_ic->sz_k, assoc, p_ic->line_len,
|
||||
p_ic->colors > 1 ? " aliasing" : "",
|
||||
IS_USED_CFG(CONFIG_ARC_HAS_ICACHE));
|
||||
|
||||
dc_chk:
|
||||
p_dc = &cpuinfo_arc700[cpu].dcache;
|
||||
READ_BCR(ARC_REG_DC_BCR, dbcr);
|
||||
|
||||
if (!dbcr.ver)
|
||||
goto slc_chk;
|
||||
|
||||
if (dbcr.ver <= 3) {
|
||||
if (is_isa_arcompact() && (dbcr.ver <= 3)) {
|
||||
BUG_ON(dbcr.config != 2);
|
||||
p_dc->assoc = 4; /* Fixed to 4w set assoc */
|
||||
p_dc->vipt = 1;
|
||||
p_dc->alias = p_dc->sz_k/p_dc->assoc/TO_KB(PAGE_SIZE) > 1;
|
||||
} else if (dbcr.ver >= 4) {
|
||||
p_dc->assoc = 1 << dbcr.config; /* 1,2,4,8 */
|
||||
p_dc->vipt = 0;
|
||||
p_dc->alias = 0; /* PIPT so can't VIPT alias */
|
||||
vipt = 1;
|
||||
assoc = 4; /* Fixed to 4w set assoc */
|
||||
p_dc->colors = p_dc->sz_k/assoc/TO_KB(PAGE_SIZE);
|
||||
} else if (is_isa_arcv2() && (dbcr.ver >= 4)) {
|
||||
vipt = 0;
|
||||
assoc = 1 << dbcr.config; /* 1,2,4,8 */
|
||||
p_dc->colors = 1; /* PIPT so can't VIPT alias */
|
||||
}
|
||||
|
||||
p_dc->line_len = 16 << dbcr.line_len;
|
||||
p_dc->sz_k = 1 << (dbcr.sz - 1);
|
||||
|
||||
n += scnprintf(buf + n, len - n,
|
||||
"D-Cache\t\t: %uK, %dway/set, %uB Line, %s%s%s\n",
|
||||
p_dc->sz_k, assoc, p_dc->line_len,
|
||||
vipt ? "VIPT" : "PIPT",
|
||||
p_dc->colors > 1 ? " aliasing" : "",
|
||||
IS_USED_CFG(CONFIG_ARC_HAS_DCACHE));
|
||||
|
||||
slc_chk:
|
||||
if (is_isa_arcv2())
|
||||
read_decode_cache_bcr_arcv2(cpu);
|
||||
n += read_decode_cache_bcr_arcv2(c, buf + n, len - n);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -581,7 +544,7 @@ static void __ic_line_inv_vaddr(phys_addr_t paddr, unsigned long vaddr,
|
||||
|
||||
#endif /* CONFIG_ARC_HAS_ICACHE */
|
||||
|
||||
noinline void slc_op_rgn(phys_addr_t paddr, unsigned long sz, const int op)
|
||||
static noinline void slc_op_rgn(phys_addr_t paddr, unsigned long sz, const int op)
|
||||
{
|
||||
#ifdef CONFIG_ISA_ARCV2
|
||||
/*
|
||||
@@ -644,7 +607,7 @@ noinline void slc_op_rgn(phys_addr_t paddr, unsigned long sz, const int op)
|
||||
#endif
|
||||
}
|
||||
|
||||
noinline void slc_op_line(phys_addr_t paddr, unsigned long sz, const int op)
|
||||
static __maybe_unused noinline void slc_op_line(phys_addr_t paddr, unsigned long sz, const int op)
|
||||
{
|
||||
#ifdef CONFIG_ISA_ARCV2
|
||||
/*
|
||||
@@ -1082,7 +1045,7 @@ SYSCALL_DEFINE3(cacheflush, uint32_t, start, uint32_t, sz, uint32_t, flags)
|
||||
* 3. All Caches need to be disabled when setting up IOC to elide any in-flight
|
||||
* Coherency transactions
|
||||
*/
|
||||
noinline void __init arc_ioc_setup(void)
|
||||
static noinline void __init arc_ioc_setup(void)
|
||||
{
|
||||
unsigned int ioc_base, mem_sz;
|
||||
|
||||
@@ -1144,12 +1107,10 @@ noinline void __init arc_ioc_setup(void)
|
||||
* one core suffices for all
|
||||
* - IOC setup / dma callbacks only need to be done once
|
||||
*/
|
||||
void __init arc_cache_init_master(void)
|
||||
static noinline void __init arc_cache_init_master(void)
|
||||
{
|
||||
unsigned int __maybe_unused cpu = smp_processor_id();
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE)) {
|
||||
struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache;
|
||||
struct cpuinfo_arc_cache *ic = &ic_info;
|
||||
|
||||
if (!ic->line_len)
|
||||
panic("cache support enabled but non-existent cache\n");
|
||||
@@ -1162,14 +1123,14 @@ void __init arc_cache_init_master(void)
|
||||
* In MMU v4 (HS38x) the aliasing icache config uses IVIL/PTAG
|
||||
* pair to provide vaddr/paddr respectively, just as in MMU v3
|
||||
*/
|
||||
if (is_isa_arcv2() && ic->alias)
|
||||
if (is_isa_arcv2() && ic->colors > 1)
|
||||
_cache_line_loop_ic_fn = __cache_line_loop_v3;
|
||||
else
|
||||
_cache_line_loop_ic_fn = __cache_line_loop;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARC_HAS_DCACHE)) {
|
||||
struct cpuinfo_arc_cache *dc = &cpuinfo_arc700[cpu].dcache;
|
||||
struct cpuinfo_arc_cache *dc = &dc_info;
|
||||
|
||||
if (!dc->line_len)
|
||||
panic("cache support enabled but non-existent cache\n");
|
||||
@@ -1181,14 +1142,13 @@ void __init arc_cache_init_master(void)
|
||||
/* check for D-Cache aliasing on ARCompact: ARCv2 has PIPT */
|
||||
if (is_isa_arcompact()) {
|
||||
int handled = IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING);
|
||||
int num_colors = dc->sz_k/dc->assoc/TO_KB(PAGE_SIZE);
|
||||
|
||||
if (dc->alias) {
|
||||
if (dc->colors > 1) {
|
||||
if (!handled)
|
||||
panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
|
||||
if (CACHE_COLORS_NUM != num_colors)
|
||||
if (CACHE_COLORS_NUM != dc->colors)
|
||||
panic("CACHE_COLORS_NUM not optimized for config\n");
|
||||
} else if (!dc->alias && handled) {
|
||||
} else if (handled && dc->colors == 1) {
|
||||
panic("Disable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
|
||||
}
|
||||
}
|
||||
@@ -1231,9 +1191,6 @@ void __init arc_cache_init_master(void)
|
||||
void __ref arc_cache_init(void)
|
||||
{
|
||||
unsigned int __maybe_unused cpu = smp_processor_id();
|
||||
char str[256];
|
||||
|
||||
pr_info("%s", arc_cache_mumbojumbo(0, str, sizeof(str)));
|
||||
|
||||
if (!cpu)
|
||||
arc_cache_init_master();
|
||||
|
||||
@@ -22,14 +22,3 @@ int fixup_exception(struct pt_regs *regs)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||
|
||||
unsigned long arc_clear_user_noinline(void __user *to,
|
||||
unsigned long n)
|
||||
{
|
||||
return __arc_clear_user(to, n);
|
||||
}
|
||||
EXPORT_SYMBOL(arc_clear_user_noinline);
|
||||
|
||||
#endif
|
||||
|
||||
+4
-3
@@ -13,6 +13,7 @@
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/mm_types.h>
|
||||
#include <asm/entry.h>
|
||||
#include <asm/mmu.h>
|
||||
|
||||
/*
|
||||
@@ -99,10 +100,10 @@ void do_page_fault(unsigned long address, struct pt_regs *regs)
|
||||
if (faulthandler_disabled() || !mm)
|
||||
goto no_context;
|
||||
|
||||
if (regs->ecr_cause & ECR_C_PROTV_STORE) /* ST/EX */
|
||||
if (regs->ecr.cause & ECR_C_PROTV_STORE) /* ST/EX */
|
||||
write = 1;
|
||||
else if ((regs->ecr_vec == ECR_V_PROTV) &&
|
||||
(regs->ecr_cause == ECR_C_PROTV_INST_FETCH))
|
||||
else if ((regs->ecr.vec == ECR_V_PROTV) &&
|
||||
(regs->ecr.cause == ECR_C_PROTV_INST_FETCH))
|
||||
exec = 1;
|
||||
|
||||
flags = FAULT_FLAG_DEFAULT;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/highmem.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/arcregs.h>
|
||||
|
||||
pgd_t swapper_pg_dir[PTRS_PER_PGD] __aligned(PAGE_SIZE);
|
||||
|
||||
+37
-60
@@ -18,7 +18,9 @@
|
||||
/* A copy of the ASID from the PID reg is kept in asid_cache */
|
||||
DEFINE_PER_CPU(unsigned int, asid_cache) = MM_CTXT_FIRST_CYCLE;
|
||||
|
||||
static int __read_mostly pae_exists;
|
||||
static struct cpuinfo_arc_mmu {
|
||||
unsigned int ver, pg_sz_k, s_pg_sz_m, pae, sets, ways;
|
||||
} mmuinfo;
|
||||
|
||||
/*
|
||||
* Utility Routine to erase a J-TLB entry
|
||||
@@ -131,7 +133,7 @@ static void tlb_entry_insert(unsigned int pd0, phys_addr_t pd1)
|
||||
|
||||
noinline void local_flush_tlb_all(void)
|
||||
{
|
||||
struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
|
||||
struct cpuinfo_arc_mmu *mmu = &mmuinfo;
|
||||
unsigned long flags;
|
||||
unsigned int entry;
|
||||
int num_tlb = mmu->sets * mmu->ways;
|
||||
@@ -389,7 +391,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
|
||||
/*
|
||||
* Routine to create a TLB entry
|
||||
*/
|
||||
void create_tlb(struct vm_area_struct *vma, unsigned long vaddr, pte_t *ptep)
|
||||
static void create_tlb(struct vm_area_struct *vma, unsigned long vaddr, pte_t *ptep)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int asid_or_sasid, rwx;
|
||||
@@ -564,89 +566,64 @@ void local_flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start,
|
||||
* the cpuinfo structure for later use.
|
||||
* No Validation is done here, simply read/convert the BCRs
|
||||
*/
|
||||
void read_decode_mmu_bcr(void)
|
||||
int arc_mmu_mumbojumbo(int c, char *buf, int len)
|
||||
{
|
||||
struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
|
||||
unsigned int tmp;
|
||||
struct bcr_mmu_3 {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int ver:8, ways:4, sets:4, res:3, sasid:1, pg_sz:4,
|
||||
u_itlb:4, u_dtlb:4;
|
||||
#else
|
||||
unsigned int u_dtlb:4, u_itlb:4, pg_sz:4, sasid:1, res:3, sets:4,
|
||||
ways:4, ver:8;
|
||||
#endif
|
||||
} *mmu3;
|
||||
struct cpuinfo_arc_mmu *mmu = &mmuinfo;
|
||||
unsigned int bcr, u_dtlb, u_itlb, sasid;
|
||||
struct bcr_mmu_3 *mmu3;
|
||||
struct bcr_mmu_4 *mmu4;
|
||||
char super_pg[64] = "";
|
||||
int n = 0;
|
||||
|
||||
struct bcr_mmu_4 {
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
unsigned int ver:8, sasid:1, sz1:4, sz0:4, res:2, pae:1,
|
||||
n_ways:2, n_entry:2, n_super:2, u_itlb:3, u_dtlb:3;
|
||||
#else
|
||||
/* DTLB ITLB JES JE JA */
|
||||
unsigned int u_dtlb:3, u_itlb:3, n_super:2, n_entry:2, n_ways:2,
|
||||
pae:1, res:2, sz0:4, sz1:4, sasid:1, ver:8;
|
||||
#endif
|
||||
} *mmu4;
|
||||
|
||||
tmp = read_aux_reg(ARC_REG_MMU_BCR);
|
||||
mmu->ver = (tmp >> 24);
|
||||
bcr = read_aux_reg(ARC_REG_MMU_BCR);
|
||||
mmu->ver = (bcr >> 24);
|
||||
|
||||
if (is_isa_arcompact() && mmu->ver == 3) {
|
||||
mmu3 = (struct bcr_mmu_3 *)&tmp;
|
||||
mmu3 = (struct bcr_mmu_3 *)&bcr;
|
||||
mmu->pg_sz_k = 1 << (mmu3->pg_sz - 1);
|
||||
mmu->sets = 1 << mmu3->sets;
|
||||
mmu->ways = 1 << mmu3->ways;
|
||||
mmu->u_dtlb = mmu3->u_dtlb;
|
||||
mmu->u_itlb = mmu3->u_itlb;
|
||||
mmu->sasid = mmu3->sasid;
|
||||
u_dtlb = mmu3->u_dtlb;
|
||||
u_itlb = mmu3->u_itlb;
|
||||
sasid = mmu3->sasid;
|
||||
} else {
|
||||
mmu4 = (struct bcr_mmu_4 *)&tmp;
|
||||
mmu4 = (struct bcr_mmu_4 *)&bcr;
|
||||
mmu->pg_sz_k = 1 << (mmu4->sz0 - 1);
|
||||
mmu->s_pg_sz_m = 1 << (mmu4->sz1 - 11);
|
||||
mmu->sets = 64 << mmu4->n_entry;
|
||||
mmu->ways = mmu4->n_ways * 2;
|
||||
mmu->u_dtlb = mmu4->u_dtlb * 4;
|
||||
mmu->u_itlb = mmu4->u_itlb * 4;
|
||||
mmu->sasid = mmu4->sasid;
|
||||
pae_exists = mmu->pae = mmu4->pae;
|
||||
u_dtlb = mmu4->u_dtlb * 4;
|
||||
u_itlb = mmu4->u_itlb * 4;
|
||||
sasid = mmu4->sasid;
|
||||
mmu->pae = mmu4->pae;
|
||||
}
|
||||
}
|
||||
|
||||
char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len)
|
||||
{
|
||||
int n = 0;
|
||||
struct cpuinfo_arc_mmu *p_mmu = &cpuinfo_arc700[cpu_id].mmu;
|
||||
char super_pg[64] = "";
|
||||
|
||||
if (p_mmu->s_pg_sz_m)
|
||||
scnprintf(super_pg, 64, "%dM Super Page %s",
|
||||
p_mmu->s_pg_sz_m,
|
||||
IS_USED_CFG(CONFIG_TRANSPARENT_HUGEPAGE));
|
||||
if (mmu->s_pg_sz_m)
|
||||
scnprintf(super_pg, 64, "/%dM%s",
|
||||
mmu->s_pg_sz_m,
|
||||
IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) ? " (THP enabled)":"");
|
||||
|
||||
n += scnprintf(buf + n, len - n,
|
||||
"MMU [v%x]\t: %dk PAGE, %s, swalk %d lvl, JTLB %d (%dx%d), uDTLB %d, uITLB %d%s%s\n",
|
||||
p_mmu->ver, p_mmu->pg_sz_k, super_pg, CONFIG_PGTABLE_LEVELS,
|
||||
p_mmu->sets * p_mmu->ways, p_mmu->sets, p_mmu->ways,
|
||||
p_mmu->u_dtlb, p_mmu->u_itlb,
|
||||
IS_AVAIL2(p_mmu->pae, ", PAE40 ", CONFIG_ARC_HAS_PAE40));
|
||||
"MMU [v%x]\t: %dk%s, swalk %d lvl, JTLB %dx%d, uDTLB %d, uITLB %d%s%s%s\n",
|
||||
mmu->ver, mmu->pg_sz_k, super_pg, CONFIG_PGTABLE_LEVELS,
|
||||
mmu->sets, mmu->ways,
|
||||
u_dtlb, u_itlb,
|
||||
IS_AVAIL1(sasid, ", SASID"),
|
||||
IS_AVAIL2(mmu->pae, ", PAE40 ", CONFIG_ARC_HAS_PAE40));
|
||||
|
||||
return buf;
|
||||
return n;
|
||||
}
|
||||
|
||||
int pae40_exist_but_not_enab(void)
|
||||
{
|
||||
return pae_exists && !is_pae40_enabled();
|
||||
return mmuinfo.pae && !is_pae40_enabled();
|
||||
}
|
||||
|
||||
void arc_mmu_init(void)
|
||||
{
|
||||
struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
|
||||
char str[256];
|
||||
struct cpuinfo_arc_mmu *mmu = &mmuinfo;
|
||||
int compat = 0;
|
||||
|
||||
pr_info("%s", arc_mmu_mumbojumbo(0, str, sizeof(str)));
|
||||
|
||||
/*
|
||||
* Can't be done in processor.h due to header include dependencies
|
||||
*/
|
||||
@@ -723,7 +700,7 @@ volatile int dup_pd_silent; /* Be silent abt it or complain (default) */
|
||||
void do_tlb_overlap_fault(unsigned long cause, unsigned long address,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
|
||||
struct cpuinfo_arc_mmu *mmu = &mmuinfo;
|
||||
unsigned long flags;
|
||||
int set, n_ways = mmu->ways;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/libfdt.h>
|
||||
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
@@ -99,9 +99,6 @@ extern int page_is_ram(unsigned long pfn);
|
||||
# define phys_to_pfn(phys) (PFN_DOWN(phys))
|
||||
# define pfn_to_phys(pfn) (PFN_PHYS(pfn))
|
||||
|
||||
# define virt_to_pfn(vaddr) (phys_to_pfn((__pa(vaddr))))
|
||||
# define pfn_to_virt(pfn) __va(pfn_to_phys((pfn)))
|
||||
|
||||
# define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT))
|
||||
# define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT)
|
||||
# define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
|
||||
@@ -109,11 +106,6 @@ extern int page_is_ram(unsigned long pfn);
|
||||
# define ARCH_PFN_OFFSET (memory_start >> PAGE_SHIFT)
|
||||
# endif /* __ASSEMBLY__ */
|
||||
|
||||
#define virt_addr_valid(vaddr) (pfn_valid(virt_to_pfn(vaddr)))
|
||||
|
||||
# define __pa(x) __virt_to_phys((unsigned long)(x))
|
||||
# define __va(x) ((void *)__phys_to_virt((unsigned long)(x)))
|
||||
|
||||
/* Convert between virtual and physical address for MMU. */
|
||||
/* Handle MicroBlaze processor with virtual memory. */
|
||||
#define __virt_to_phys(addr) \
|
||||
@@ -125,6 +117,25 @@ extern int page_is_ram(unsigned long pfn);
|
||||
#define tovirt(rd, rs) \
|
||||
addik rd, rs, (CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
# define __pa(x) __virt_to_phys((unsigned long)(x))
|
||||
# define __va(x) ((void *)__phys_to_virt((unsigned long)(x)))
|
||||
|
||||
static inline unsigned long virt_to_pfn(const void *vaddr)
|
||||
{
|
||||
return phys_to_pfn(__pa(vaddr));
|
||||
}
|
||||
|
||||
static inline const void *pfn_to_virt(unsigned long pfn)
|
||||
{
|
||||
return __va(pfn_to_phys((pfn)));
|
||||
}
|
||||
|
||||
#define virt_addr_valid(vaddr) (pfn_valid(virt_to_pfn(vaddr)))
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#define TOPHYS(addr) __virt_to_phys(addr)
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
@@ -25,7 +25,5 @@ void machine_shutdown(void);
|
||||
void machine_halt(void);
|
||||
void machine_power_off(void);
|
||||
|
||||
extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
|
||||
|
||||
# endif /* __ASSEMBLY__ */
|
||||
#endif /* _ASM_MICROBLAZE_SETUP_H */
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
void machine_shutdown(void)
|
||||
|
||||
@@ -270,22 +270,6 @@ asmlinkage void __init mmu_init(void)
|
||||
memblock_dump_all();
|
||||
}
|
||||
|
||||
void * __ref zalloc_maybe_bootmem(size_t size, gfp_t mask)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if (mem_init_done) {
|
||||
p = kzalloc(size, mask);
|
||||
} else {
|
||||
p = memblock_alloc(size, SMP_CACHE_BYTES);
|
||||
if (!p)
|
||||
panic("%s: Failed to allocate %zu bytes\n",
|
||||
__func__, size);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static const pgprot_t protection_map[16] = {
|
||||
[VM_NONE] = PAGE_NONE,
|
||||
[VM_READ] = PAGE_READONLY_X,
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef __ASM_OPENRISC_BUG_H
|
||||
#define __ASM_OPENRISC_BUG_H
|
||||
|
||||
#include <asm-generic/bug.h>
|
||||
|
||||
struct pt_regs;
|
||||
|
||||
void __noreturn die(const char *str, struct pt_regs *regs, long err);
|
||||
|
||||
#endif /* __ASM_OPENRISC_BUG_H */
|
||||
@@ -72,8 +72,15 @@ typedef struct page *pgtable_t;
|
||||
#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET))
|
||||
#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET)
|
||||
|
||||
#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
|
||||
#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT)
|
||||
static inline unsigned long virt_to_pfn(const void *kaddr)
|
||||
{
|
||||
return __pa(kaddr) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
static inline void * pfn_to_virt(unsigned long pfn)
|
||||
{
|
||||
return (void *)((unsigned long)__va(pfn) << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
#define virt_to_page(addr) \
|
||||
(mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
|
||||
|
||||
@@ -73,6 +73,7 @@ struct thread_struct {
|
||||
|
||||
void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp);
|
||||
unsigned long __get_wchan(struct task_struct *p);
|
||||
void show_registers(struct pt_regs *regs);
|
||||
|
||||
#define cpu_relax() barrier()
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#define __KERNEL_SYSCALLS__
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/debug.h>
|
||||
@@ -38,6 +39,7 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/spr_defs.h>
|
||||
#include <asm/switch_to.h>
|
||||
|
||||
#include <linux/smp.h>
|
||||
|
||||
@@ -119,8 +121,6 @@ void flush_thread(void)
|
||||
|
||||
void show_regs(struct pt_regs *regs)
|
||||
{
|
||||
extern void show_registers(struct pt_regs *regs);
|
||||
|
||||
show_regs_print_info(KERN_DEFAULT);
|
||||
/* __PHX__ cleanup this mess */
|
||||
show_registers(regs);
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
|
||||
|
||||
asmlinkage void do_syscall_trace_leave(struct pt_regs *regs);
|
||||
|
||||
/*
|
||||
* Copy the thread state to a regset that can be interpreted by userspace.
|
||||
*
|
||||
|
||||
@@ -34,6 +34,11 @@ struct rt_sigframe {
|
||||
unsigned char retcode[16]; /* trampoline code */
|
||||
};
|
||||
|
||||
asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs);
|
||||
|
||||
asmlinkage int do_work_pending(struct pt_regs *regs, unsigned int thread_flags,
|
||||
int syscall);
|
||||
|
||||
static int restore_sigcontext(struct pt_regs *regs,
|
||||
struct sigcontext __user *sc)
|
||||
{
|
||||
@@ -224,7 +229,7 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
|
||||
* mode below.
|
||||
*/
|
||||
|
||||
int do_signal(struct pt_regs *regs, int syscall)
|
||||
static int do_signal(struct pt_regs *regs, int syscall)
|
||||
{
|
||||
struct ksignal ksig;
|
||||
unsigned long continue_addr = 0;
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/time.h>
|
||||
|
||||
asmlinkage __init void secondary_start_kernel(void);
|
||||
|
||||
static void (*smp_cross_call)(const struct cpumask *, unsigned int);
|
||||
|
||||
unsigned long secondary_release = -1;
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <asm/cpuinfo.h>
|
||||
#include <asm/time.h>
|
||||
|
||||
irqreturn_t __irq_entry timer_interrupt(struct pt_regs *regs);
|
||||
|
||||
/* Test the timer ticks to count, used in sync routine */
|
||||
inline void openrisc_timer_set(unsigned long count)
|
||||
{
|
||||
|
||||
@@ -30,14 +30,23 @@
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/bug.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/unwinder.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
static int kstack_depth_to_print = 0x180;
|
||||
int lwa_flag;
|
||||
static unsigned long __user *lwa_addr;
|
||||
|
||||
asmlinkage void unhandled_exception(struct pt_regs *regs, int ea, int vector);
|
||||
asmlinkage void do_trap(struct pt_regs *regs, unsigned long address);
|
||||
asmlinkage void do_fpe_trap(struct pt_regs *regs, unsigned long address);
|
||||
asmlinkage void do_unaligned_access(struct pt_regs *regs, unsigned long address);
|
||||
asmlinkage void do_bus_fault(struct pt_regs *regs, unsigned long address);
|
||||
asmlinkage void do_illegal_instruction(struct pt_regs *regs,
|
||||
unsigned long address);
|
||||
|
||||
static void print_trace(void *data, unsigned long addr, int reliable)
|
||||
{
|
||||
const char *loglvl = data;
|
||||
@@ -143,80 +152,6 @@ bad:
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
void nommu_dump_state(struct pt_regs *regs,
|
||||
unsigned long ea, unsigned long vector)
|
||||
{
|
||||
int i;
|
||||
unsigned long addr, stack = regs->sp;
|
||||
|
||||
printk("\n\r[nommu_dump_state] :: ea %lx, vector %lx\n\r", ea, vector);
|
||||
|
||||
printk("CPU #: %d\n"
|
||||
" PC: %08lx SR: %08lx SP: %08lx\n",
|
||||
0, regs->pc, regs->sr, regs->sp);
|
||||
printk("GPR00: %08lx GPR01: %08lx GPR02: %08lx GPR03: %08lx\n",
|
||||
0L, regs->gpr[1], regs->gpr[2], regs->gpr[3]);
|
||||
printk("GPR04: %08lx GPR05: %08lx GPR06: %08lx GPR07: %08lx\n",
|
||||
regs->gpr[4], regs->gpr[5], regs->gpr[6], regs->gpr[7]);
|
||||
printk("GPR08: %08lx GPR09: %08lx GPR10: %08lx GPR11: %08lx\n",
|
||||
regs->gpr[8], regs->gpr[9], regs->gpr[10], regs->gpr[11]);
|
||||
printk("GPR12: %08lx GPR13: %08lx GPR14: %08lx GPR15: %08lx\n",
|
||||
regs->gpr[12], regs->gpr[13], regs->gpr[14], regs->gpr[15]);
|
||||
printk("GPR16: %08lx GPR17: %08lx GPR18: %08lx GPR19: %08lx\n",
|
||||
regs->gpr[16], regs->gpr[17], regs->gpr[18], regs->gpr[19]);
|
||||
printk("GPR20: %08lx GPR21: %08lx GPR22: %08lx GPR23: %08lx\n",
|
||||
regs->gpr[20], regs->gpr[21], regs->gpr[22], regs->gpr[23]);
|
||||
printk("GPR24: %08lx GPR25: %08lx GPR26: %08lx GPR27: %08lx\n",
|
||||
regs->gpr[24], regs->gpr[25], regs->gpr[26], regs->gpr[27]);
|
||||
printk("GPR28: %08lx GPR29: %08lx GPR30: %08lx GPR31: %08lx\n",
|
||||
regs->gpr[28], regs->gpr[29], regs->gpr[30], regs->gpr[31]);
|
||||
printk(" RES: %08lx oGPR11: %08lx\n",
|
||||
regs->gpr[11], regs->orig_gpr11);
|
||||
|
||||
printk("Process %s (pid: %d, stackpage=%08lx)\n",
|
||||
((struct task_struct *)(__pa(current)))->comm,
|
||||
((struct task_struct *)(__pa(current)))->pid,
|
||||
(unsigned long)current);
|
||||
|
||||
printk("\nStack: ");
|
||||
printk("Stack dump [0x%08lx]:\n", (unsigned long)stack);
|
||||
for (i = 0; i < kstack_depth_to_print; i++) {
|
||||
if (((long)stack & (THREAD_SIZE - 1)) == 0)
|
||||
break;
|
||||
stack++;
|
||||
|
||||
printk("%lx :: sp + %02d: 0x%08lx\n", stack, i * 4,
|
||||
*((unsigned long *)(__pa(stack))));
|
||||
}
|
||||
printk("\n");
|
||||
|
||||
printk("Call Trace: ");
|
||||
i = 1;
|
||||
while (((long)stack & (THREAD_SIZE - 1)) != 0) {
|
||||
addr = *((unsigned long *)__pa(stack));
|
||||
stack++;
|
||||
|
||||
if (kernel_text_address(addr)) {
|
||||
if (i && ((i % 6) == 0))
|
||||
printk("\n ");
|
||||
printk(" [<%08lx>]", addr);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
printk("\n");
|
||||
|
||||
printk("\nCode: ");
|
||||
|
||||
for (i = -24; i < 24; i++) {
|
||||
unsigned long word;
|
||||
|
||||
word = ((unsigned long *)(__pa(regs->pc)))[i];
|
||||
|
||||
print_data(regs->pc, word, i);
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
/* This is normally the 'Oops' routine */
|
||||
void __noreturn die(const char *str, struct pt_regs *regs, long err)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/perf_event.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/bug.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/siginfo.h>
|
||||
#include <asm/signal.h>
|
||||
@@ -30,7 +31,8 @@
|
||||
*/
|
||||
volatile pgd_t *current_pgd[NR_CPUS];
|
||||
|
||||
extern void __noreturn die(char *, struct pt_regs *, long);
|
||||
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long address,
|
||||
unsigned long vector, int write_acc);
|
||||
|
||||
/*
|
||||
* This routine handles page faults. It determines the address,
|
||||
|
||||
@@ -123,8 +123,6 @@ static void __init map_ram(void)
|
||||
|
||||
void __init paging_init(void)
|
||||
{
|
||||
extern void tlb_init(void);
|
||||
|
||||
int i;
|
||||
|
||||
printk(KERN_INFO "Setting up paging and PTEs.\n");
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
extern int mem_init_done;
|
||||
|
||||
/**
|
||||
/*
|
||||
* OK, this one's a bit tricky... ioremap can get called before memory is
|
||||
* initialized (early serial console does this) and will want to alloc a page
|
||||
* for its mapping. No userspace pages will ever get allocated before memory
|
||||
|
||||
@@ -182,12 +182,3 @@ void destroy_context(struct mm_struct *mm)
|
||||
flush_tlb_mm(mm);
|
||||
|
||||
}
|
||||
|
||||
/* called once during VM initialization, from init.c */
|
||||
|
||||
void __init tlb_init(void)
|
||||
{
|
||||
/* Do nothing... */
|
||||
/* invalidate the entire TLB */
|
||||
/* flush_tlb_all(); */
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy);
|
||||
static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
struct cpufreq_governor *new_gov,
|
||||
unsigned int new_pol);
|
||||
static bool cpufreq_boost_supported(void);
|
||||
|
||||
/*
|
||||
* Two notifier lists: the "policy" list is involved in the
|
||||
@@ -458,8 +459,10 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
|
||||
policy->cur,
|
||||
policy->cpuinfo.max_freq);
|
||||
|
||||
spin_lock(&policy->transition_lock);
|
||||
policy->transition_ongoing = false;
|
||||
policy->transition_task = NULL;
|
||||
spin_unlock(&policy->transition_lock);
|
||||
|
||||
wake_up(&policy->transition_wait);
|
||||
}
|
||||
@@ -624,6 +627,40 @@ static ssize_t store_boost(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
}
|
||||
define_one_global_rw(boost);
|
||||
|
||||
static ssize_t show_local_boost(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%d\n", policy->boost_enabled);
|
||||
}
|
||||
|
||||
static ssize_t store_local_boost(struct cpufreq_policy *policy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret, enable;
|
||||
|
||||
ret = kstrtoint(buf, 10, &enable);
|
||||
if (ret || enable < 0 || enable > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (!cpufreq_driver->boost_enabled)
|
||||
return -EINVAL;
|
||||
|
||||
if (policy->boost_enabled == enable)
|
||||
return count;
|
||||
|
||||
cpus_read_lock();
|
||||
ret = cpufreq_driver->set_boost(policy, enable);
|
||||
cpus_read_unlock();
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
policy->boost_enabled = enable;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct freq_attr local_boost = __ATTR(boost, 0644, show_local_boost, store_local_boost);
|
||||
|
||||
static struct cpufreq_governor *find_governor(const char *str_governor)
|
||||
{
|
||||
struct cpufreq_governor *t;
|
||||
@@ -1065,6 +1102,12 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cpufreq_boost_supported()) {
|
||||
ret = sysfs_create_file(&policy->kobj, &local_boost.attr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1954,16 +1997,16 @@ void cpufreq_resume(void)
|
||||
|
||||
for_each_active_policy(policy) {
|
||||
if (cpufreq_driver->resume && cpufreq_driver->resume(policy)) {
|
||||
pr_err("%s: Failed to resume driver: %p\n", __func__,
|
||||
policy);
|
||||
pr_err("%s: Failed to resume driver: %s\n", __func__,
|
||||
cpufreq_driver->name);
|
||||
} else if (has_target()) {
|
||||
down_write(&policy->rwsem);
|
||||
ret = cpufreq_start_governor(policy);
|
||||
up_write(&policy->rwsem);
|
||||
|
||||
if (ret)
|
||||
pr_err("%s: Failed to start governor for policy: %p\n",
|
||||
__func__, policy);
|
||||
pr_err("%s: Failed to start governor for CPU%u's policy\n",
|
||||
__func__, policy->cpu);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2727,6 +2770,8 @@ int cpufreq_boost_trigger_state(int state)
|
||||
ret = cpufreq_driver->set_boost(policy, state);
|
||||
if (ret)
|
||||
goto err_reset_state;
|
||||
|
||||
policy->boost_enabled = state;
|
||||
}
|
||||
cpus_read_unlock();
|
||||
|
||||
|
||||
@@ -439,7 +439,7 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)
|
||||
|
||||
ret = gov->init(dbs_data);
|
||||
if (ret)
|
||||
goto free_policy_dbs_info;
|
||||
goto free_dbs_data;
|
||||
|
||||
/*
|
||||
* The sampling interval should not be less than the transition latency
|
||||
@@ -474,6 +474,8 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)
|
||||
if (!have_governor_per_policy())
|
||||
gov->gdbs_data = NULL;
|
||||
gov->exit(dbs_data);
|
||||
|
||||
free_dbs_data:
|
||||
kfree(dbs_data);
|
||||
|
||||
free_policy_dbs_info:
|
||||
|
||||
@@ -232,8 +232,8 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
|
||||
status = ioread16(&pcch_hdr->status);
|
||||
iowrite16(0, &pcch_hdr->status);
|
||||
|
||||
cpufreq_freq_transition_end(policy, &freqs, status != CMD_COMPLETE);
|
||||
spin_unlock(&pcc_lock);
|
||||
cpufreq_freq_transition_end(policy, &freqs, status != CMD_COMPLETE);
|
||||
|
||||
if (status != CMD_COMPLETE) {
|
||||
pr_debug("target: FAILED for cpu %d, with status: 0x%x\n",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <linux/hugetlb.h>
|
||||
#include <linux/huge_mm.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/ksm.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/ptrace.h>
|
||||
@@ -396,6 +397,7 @@ struct mem_size_stats {
|
||||
unsigned long swap;
|
||||
unsigned long shared_hugetlb;
|
||||
unsigned long private_hugetlb;
|
||||
unsigned long ksm;
|
||||
u64 pss;
|
||||
u64 pss_anon;
|
||||
u64 pss_file;
|
||||
@@ -452,6 +454,9 @@ static void smaps_account(struct mem_size_stats *mss, struct page *page,
|
||||
mss->lazyfree += size;
|
||||
}
|
||||
|
||||
if (PageKsm(page))
|
||||
mss->ksm += size;
|
||||
|
||||
mss->resident += size;
|
||||
/* Accumulate the size in pages that have been accessed. */
|
||||
if (young || page_is_young(page) || PageReferenced(page))
|
||||
@@ -825,6 +830,7 @@ static void __show_smap(struct seq_file *m, const struct mem_size_stats *mss,
|
||||
SEQ_PUT_DEC(" kB\nPrivate_Dirty: ", mss->private_dirty);
|
||||
SEQ_PUT_DEC(" kB\nReferenced: ", mss->referenced);
|
||||
SEQ_PUT_DEC(" kB\nAnonymous: ", mss->anonymous);
|
||||
SEQ_PUT_DEC(" kB\nKSM: ", mss->ksm);
|
||||
SEQ_PUT_DEC(" kB\nLazyFree: ", mss->lazyfree);
|
||||
SEQ_PUT_DEC(" kB\nAnonHugePages: ", mss->anonymous_thp);
|
||||
SEQ_PUT_DEC(" kB\nShmemPmdMapped: ", mss->shmem_thp);
|
||||
|
||||
@@ -141,6 +141,9 @@ struct cpufreq_policy {
|
||||
*/
|
||||
bool dvfs_possible_from_any_cpu;
|
||||
|
||||
/* Per policy boost enabled flag. */
|
||||
bool boost_enabled;
|
||||
|
||||
/* Cached frequency lookup from cpufreq_driver_resolve_freq. */
|
||||
unsigned int cached_target_freq;
|
||||
unsigned int cached_resolved_idx;
|
||||
|
||||
@@ -479,7 +479,6 @@ struct anon_vma *folio_lock_anon_vma_read(struct folio *folio,
|
||||
|
||||
#define anon_vma_init() do {} while (0)
|
||||
#define anon_vma_prepare(vma) (0)
|
||||
#define anon_vma_link(vma) do {} while (0)
|
||||
|
||||
static inline int folio_referenced(struct folio *folio, int is_locked,
|
||||
struct mem_cgroup *memcg,
|
||||
|
||||
+3
-2
@@ -1584,6 +1584,9 @@ static void kmemleak_scan(void)
|
||||
for (pfn = start_pfn; pfn < end_pfn; pfn++) {
|
||||
struct page *page = pfn_to_online_page(pfn);
|
||||
|
||||
if (!(pfn & 63))
|
||||
cond_resched();
|
||||
|
||||
if (!page)
|
||||
continue;
|
||||
|
||||
@@ -1594,8 +1597,6 @@ static void kmemleak_scan(void)
|
||||
if (page_count(page) == 0)
|
||||
continue;
|
||||
scan_block(page, page + 1, NULL);
|
||||
if (!(pfn & 63))
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
put_online_mems();
|
||||
|
||||
+11
-10
@@ -717,7 +717,7 @@ static void collect_procs(struct page *page, struct list_head *tokill,
|
||||
collect_procs_file(page, tokill, force_early);
|
||||
}
|
||||
|
||||
struct hwp_walk {
|
||||
struct hwpoison_walk {
|
||||
struct to_kill tk;
|
||||
unsigned long pfn;
|
||||
int flags;
|
||||
@@ -752,7 +752,7 @@ static int check_hwpoisoned_entry(pte_t pte, unsigned long addr, short shift,
|
||||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
static int check_hwpoisoned_pmd_entry(pmd_t *pmdp, unsigned long addr,
|
||||
struct hwp_walk *hwp)
|
||||
struct hwpoison_walk *hwp)
|
||||
{
|
||||
pmd_t pmd = *pmdp;
|
||||
unsigned long pfn;
|
||||
@@ -770,7 +770,7 @@ static int check_hwpoisoned_pmd_entry(pmd_t *pmdp, unsigned long addr,
|
||||
}
|
||||
#else
|
||||
static int check_hwpoisoned_pmd_entry(pmd_t *pmdp, unsigned long addr,
|
||||
struct hwp_walk *hwp)
|
||||
struct hwpoison_walk *hwp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -779,7 +779,7 @@ static int check_hwpoisoned_pmd_entry(pmd_t *pmdp, unsigned long addr,
|
||||
static int hwpoison_pte_range(pmd_t *pmdp, unsigned long addr,
|
||||
unsigned long end, struct mm_walk *walk)
|
||||
{
|
||||
struct hwp_walk *hwp = walk->private;
|
||||
struct hwpoison_walk *hwp = walk->private;
|
||||
int ret = 0;
|
||||
pte_t *ptep, *mapped_pte;
|
||||
spinlock_t *ptl;
|
||||
@@ -813,7 +813,7 @@ static int hwpoison_hugetlb_range(pte_t *ptep, unsigned long hmask,
|
||||
unsigned long addr, unsigned long end,
|
||||
struct mm_walk *walk)
|
||||
{
|
||||
struct hwp_walk *hwp = walk->private;
|
||||
struct hwpoison_walk *hwp = walk->private;
|
||||
pte_t pte = huge_ptep_get(ptep);
|
||||
struct hstate *h = hstate_vma(walk->vma);
|
||||
|
||||
@@ -824,7 +824,7 @@ static int hwpoison_hugetlb_range(pte_t *ptep, unsigned long hmask,
|
||||
#define hwpoison_hugetlb_range NULL
|
||||
#endif
|
||||
|
||||
static const struct mm_walk_ops hwp_walk_ops = {
|
||||
static const struct mm_walk_ops hwpoison_walk_ops = {
|
||||
.pmd_entry = hwpoison_pte_range,
|
||||
.hugetlb_entry = hwpoison_hugetlb_range,
|
||||
.walk_lock = PGWALK_RDLOCK,
|
||||
@@ -847,7 +847,7 @@ static int kill_accessing_process(struct task_struct *p, unsigned long pfn,
|
||||
int flags)
|
||||
{
|
||||
int ret;
|
||||
struct hwp_walk priv = {
|
||||
struct hwpoison_walk priv = {
|
||||
.pfn = pfn,
|
||||
};
|
||||
priv.tk.tsk = p;
|
||||
@@ -856,7 +856,7 @@ static int kill_accessing_process(struct task_struct *p, unsigned long pfn,
|
||||
return -EFAULT;
|
||||
|
||||
mmap_read_lock(p->mm);
|
||||
ret = walk_page_range(p->mm, 0, TASK_SIZE, &hwp_walk_ops,
|
||||
ret = walk_page_range(p->mm, 0, TASK_SIZE, &hwpoison_walk_ops,
|
||||
(void *)&priv);
|
||||
if (ret == 1 && priv.tk.addr)
|
||||
kill_proc(&priv.tk, pfn, flags);
|
||||
@@ -1562,7 +1562,7 @@ static bool hwpoison_user_mappings(struct page *p, unsigned long pfn,
|
||||
* Here we are interested only in user-mapped pages, so skip any
|
||||
* other types of pages.
|
||||
*/
|
||||
if (PageReserved(p) || PageSlab(p) || PageTable(p))
|
||||
if (PageReserved(p) || PageSlab(p) || PageTable(p) || PageOffline(p))
|
||||
return true;
|
||||
if (!(PageLRU(hpage) || PageHuge(p)))
|
||||
return true;
|
||||
@@ -2533,7 +2533,8 @@ int unpoison_memory(unsigned long pfn)
|
||||
goto unlock_mutex;
|
||||
}
|
||||
|
||||
if (folio_test_slab(folio) || PageTable(&folio->page) || folio_test_reserved(folio))
|
||||
if (folio_test_slab(folio) || PageTable(&folio->page) ||
|
||||
folio_test_reserved(folio) || PageOffline(&folio->page))
|
||||
goto unlock_mutex;
|
||||
|
||||
/*
|
||||
|
||||
+4
-17
@@ -2641,12 +2641,6 @@ struct page *rmqueue_buddy(struct zone *preferred_zone, struct zone *zone,
|
||||
do {
|
||||
page = NULL;
|
||||
spin_lock_irqsave(&zone->lock, flags);
|
||||
/*
|
||||
* order-0 request can reach here when the pcplist is skipped
|
||||
* due to non-CMA allocation context. HIGHATOMIC area is
|
||||
* reserved for high-order atomic allocation, so order-0
|
||||
* request should skip it.
|
||||
*/
|
||||
if (alloc_flags & ALLOC_HIGHATOMIC)
|
||||
page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC);
|
||||
if (!page) {
|
||||
@@ -2780,17 +2774,10 @@ struct page *rmqueue(struct zone *preferred_zone,
|
||||
WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1));
|
||||
|
||||
if (likely(pcp_allowed_order(order))) {
|
||||
/*
|
||||
* MIGRATE_MOVABLE pcplist could have the pages on CMA area and
|
||||
* we need to skip it when CMA area isn't allowed.
|
||||
*/
|
||||
if (!IS_ENABLED(CONFIG_CMA) || alloc_flags & ALLOC_CMA ||
|
||||
migratetype != MIGRATE_MOVABLE) {
|
||||
page = rmqueue_pcplist(preferred_zone, zone, order,
|
||||
migratetype, alloc_flags);
|
||||
if (likely(page))
|
||||
goto out;
|
||||
}
|
||||
page = rmqueue_pcplist(preferred_zone, zone, order,
|
||||
migratetype, alloc_flags);
|
||||
if (likely(page))
|
||||
goto out;
|
||||
}
|
||||
|
||||
page = rmqueue_buddy(preferred_zone, zone, order, alloc_flags,
|
||||
|
||||
@@ -57,7 +57,7 @@ LIB_MIN= 1
|
||||
|
||||
PACKAGE = cpupower
|
||||
PACKAGE_BUGREPORT = linux-pm@vger.kernel.org
|
||||
LANGUAGES = de fr it cs pt
|
||||
LANGUAGES = de fr it cs pt ka
|
||||
|
||||
|
||||
# Directory definitions. These are default and most probably
|
||||
|
||||
Reference in New Issue
Block a user