aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
authorLinus Torvalds <torvalds@linux-foundation.org>2026-06-22 07:43:48 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-06-22 07:43:48 -0700
commit2580f89860460f38bcc13fce75db8626d555c0cd (patch)
tree896d08f70dbfcea9b94c225334b597c740dda652 /arch
parentef0c9f75a19532d7675384708fc8621e10850104 (diff)
parent1ac287e2af9a9112fe271427ef45eceb26bce8b4 (diff)
downloadath-2580f89860460f38bcc13fce75db8626d555c0cd.tar.gz
Merge tag 's390-7.2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull more s390 updates from Alexander Gordeev: - consolidate s390 idle time accounting by moving all CPU time tracking to the architecture backend and eliminate the mix of architecture- specific and common code accounting - Add missing EXPORT_SYMBOL_GPL() to kcpustat_field_idle() and kcpustat_field_iowait() functions - Finalize ptep_get() conversion by replacing direct page table entry dereferencing with proper accessors (ptep_get(), pmdp_get(), etc.) - Explicitly check the buffer length in PKEY_VERIFYPROTK ioctl and pkey_pckmo implementations and fail if the length is exceeded * tag 's390-7.2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/pkey: Check length in pkey_pckmo handler implementation s390/pkey: Check length in PKEY_VERIFYPROTK ioctl s390/idle: Add missing EXPORT_SYMBOL_GPL() s390/mm: Complete ptep_get() conversion s390/idle: Remove idle time and count sysfs files s390/idle: Provide arch specific kcpustat_field_idle()/kcpustat_field_iowait() s390/irq/idle: Use stcke instead of stckf for time stamps s390/timex: Move union tod_clock type to separate header
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/boot/vmem.c32
-rw-r--r--arch/s390/include/asm/hugetlb.h2
-rw-r--r--arch/s390/include/asm/idle.h14
-rw-r--r--arch/s390/include/asm/lowcore.h4
-rw-r--r--arch/s390/include/asm/pgtable.h60
-rw-r--r--arch/s390/include/asm/timex.h20
-rw-r--r--arch/s390/include/asm/tod_types.h30
-rw-r--r--arch/s390/include/asm/vtime.h4
-rw-r--r--arch/s390/kernel/asm-offsets.c7
-rw-r--r--arch/s390/kernel/entry.S14
-rw-r--r--arch/s390/kernel/idle.c128
-rw-r--r--arch/s390/kernel/irq.c7
-rw-r--r--arch/s390/kernel/smp.c33
-rw-r--r--arch/s390/kernel/vtime.c55
-rw-r--r--arch/s390/mm/hugetlbpage.c12
-rw-r--r--arch/s390/mm/pageattr.c45
-rw-r--r--arch/s390/mm/vmem.c82
17 files changed, 307 insertions, 242 deletions
diff --git a/arch/s390/boot/vmem.c b/arch/s390/boot/vmem.c
index 7d6cc4c85af05..ff6d58a476bae 100644
--- a/arch/s390/boot/vmem.c
+++ b/arch/s390/boot/vmem.c
@@ -338,7 +338,7 @@ static void pgtable_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long e
pte = pte_offset_kernel(pmd, addr);
for (; addr < end; addr += PAGE_SIZE, pte++) {
- if (pte_none(*pte)) {
+ if (pte_none(ptep_get(pte))) {
if (kasan_pte_populate_zero_shadow(pte, mode))
continue;
entry = __pte(resolve_pa_may_alloc(addr, PAGE_SIZE, mode));
@@ -355,26 +355,27 @@ static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long e
enum populate_mode mode)
{
unsigned long pa, next, pages = 0;
- pmd_t *pmd, entry;
+ pmd_t *pmd, entry, large_entry;
pte_t *pte;
pmd = pmd_offset(pud, addr);
for (; addr < end; addr = next, pmd++) {
next = pmd_addr_end(addr, end);
- if (pmd_none(*pmd)) {
+ entry = pmdp_get(pmd);
+ if (pmd_none(entry)) {
if (kasan_pmd_populate_zero_shadow(pmd, addr, next, mode))
continue;
pa = try_get_large_pmd_pa(pmd, addr, next, mode);
if (pa != INVALID_PHYS_ADDR) {
- entry = __pmd(pa);
- entry = set_pmd_bit(entry, SEGMENT_KERNEL);
- set_pmd(pmd, entry);
+ large_entry = __pmd(pa);
+ large_entry = set_pmd_bit(large_entry, SEGMENT_KERNEL);
+ set_pmd(pmd, large_entry);
pages++;
continue;
}
pte = boot_pte_alloc();
pmd_populate(&init_mm, pmd, pte);
- } else if (pmd_leaf(*pmd)) {
+ } else if (pmd_leaf(entry)) {
continue;
}
pgtable_pte_populate(pmd, addr, next, mode);
@@ -387,26 +388,27 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e
enum populate_mode mode)
{
unsigned long pa, next, pages = 0;
- pud_t *pud, entry;
+ pud_t *pud, entry, large_entry;
pmd_t *pmd;
pud = pud_offset(p4d, addr);
for (; addr < end; addr = next, pud++) {
next = pud_addr_end(addr, end);
- if (pud_none(*pud)) {
+ entry = pudp_get(pud);
+ if (pud_none(entry)) {
if (kasan_pud_populate_zero_shadow(pud, addr, next, mode))
continue;
pa = try_get_large_pud_pa(pud, addr, next, mode);
if (pa != INVALID_PHYS_ADDR) {
- entry = __pud(pa);
- entry = set_pud_bit(entry, REGION3_KERNEL);
- set_pud(pud, entry);
+ large_entry = __pud(pa);
+ large_entry = set_pud_bit(large_entry, REGION3_KERNEL);
+ set_pud(pud, large_entry);
pages++;
continue;
}
pmd = boot_crst_alloc(_SEGMENT_ENTRY_EMPTY);
pud_populate(&init_mm, pud, pmd);
- } else if (pud_leaf(*pud)) {
+ } else if (pud_leaf(entry)) {
continue;
}
pgtable_pmd_populate(pud, addr, next, mode);
@@ -425,7 +427,7 @@ static void pgtable_p4d_populate(pgd_t *pgd, unsigned long addr, unsigned long e
p4d = p4d_offset(pgd, addr);
for (; addr < end; addr = next, p4d++) {
next = p4d_addr_end(addr, end);
- if (p4d_none(*p4d)) {
+ if (p4d_none(p4dp_get(p4d))) {
if (kasan_p4d_populate_zero_shadow(p4d, addr, next, mode))
continue;
pud = boot_crst_alloc(_REGION3_ENTRY_EMPTY);
@@ -451,7 +453,7 @@ static void pgtable_populate(unsigned long addr, unsigned long end, enum populat
pgd = pgd_offset(&init_mm, addr);
for (; addr < end; addr = next, pgd++) {
next = pgd_addr_end(addr, end);
- if (pgd_none(*pgd)) {
+ if (pgd_none(pgdp_get(pgd))) {
if (kasan_pgd_populate_zero_shadow(pgd, addr, next, mode))
continue;
p4d = boot_crst_alloc(_REGION2_ENTRY_EMPTY);
diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h
index 6983e52eaf819..e33a5b587ee4e 100644
--- a/arch/s390/include/asm/hugetlb.h
+++ b/arch/s390/include/asm/hugetlb.h
@@ -41,7 +41,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, unsigned long sz)
{
- if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
+ if ((pte_val(ptep_get(ptep)) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
set_pte(ptep, __pte(_REGION3_ENTRY_EMPTY));
else
set_pte(ptep, __pte(_SEGMENT_ENTRY_EMPTY));
diff --git a/arch/s390/include/asm/idle.h b/arch/s390/include/asm/idle.h
index e4ad09a22400b..07819f11987cc 100644
--- a/arch/s390/include/asm/idle.h
+++ b/arch/s390/include/asm/idle.h
@@ -10,20 +10,18 @@
#include <linux/percpu-defs.h>
#include <linux/types.h>
-#include <linux/device.h>
+#include <asm/tod_types.h>
struct s390_idle_data {
- bool idle_dyntick;
- unsigned long idle_count;
- unsigned long idle_time;
- unsigned long clock_idle_enter;
+#ifdef CONFIG_NO_HZ_COMMON
+ bool in_idle;
+#endif
unsigned long timer_idle_enter;
unsigned long mt_cycles_enter[8];
+ union tod_clock clock_idle_enter;
+ union tod_clock clock_idle_exit;
};
DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
-extern struct device_attribute dev_attr_idle_count;
-extern struct device_attribute dev_attr_idle_time_us;
-
#endif /* _S390_IDLE_H */
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index cd1ddfdb5d35d..3b3ecc647993f 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -10,6 +10,7 @@
#define _ASM_S390_LOWCORE_H
#include <linux/types.h>
+#include <asm/tod_types.h>
#include <asm/machine.h>
#include <asm/ptrace.h>
#include <asm/ctlreg.h>
@@ -125,8 +126,7 @@ struct lowcore {
__u64 avg_steal_timer; /* 0x0300 */
__u64 last_update_timer; /* 0x0308 */
__u64 last_update_clock; /* 0x0310 */
- __u64 int_clock; /* 0x0318 */
- __u8 pad_0x0320[0x0328-0x0320]; /* 0x0320 */
+ union tod_clock int_clock; /* 0x0318 */
__u64 clock_comparator; /* 0x0328 */
__u8 pad_0x0330[0x0340-0x0330]; /* 0x0330 */
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 3197b8b372a2a..f9a8a92fa160d 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -983,27 +983,34 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
WRITE_ONCE(*ptep, pte);
}
-static inline void pgd_clear(pgd_t *pgd)
+#define ptep_get ptep_get
+static inline pte_t ptep_get(pte_t *ptep)
{
- if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R1)
- set_pgd(pgd, __pgd(_REGION1_ENTRY_EMPTY));
+ return READ_ONCE(*ptep);
}
-static inline void p4d_clear(p4d_t *p4d)
+#define pmdp_get pmdp_get
+static inline pmd_t pmdp_get(pmd_t *pmdp)
{
- if ((p4d_val(*p4d) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2)
- set_p4d(p4d, __p4d(_REGION2_ENTRY_EMPTY));
+ return READ_ONCE(*pmdp);
}
-static inline void pud_clear(pud_t *pud)
+#define pudp_get pudp_get
+static inline pud_t pudp_get(pud_t *pudp)
{
- if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
- set_pud(pud, __pud(_REGION3_ENTRY_EMPTY));
+ return READ_ONCE(*pudp);
}
-static inline void pmd_clear(pmd_t *pmdp)
+#define p4dp_get p4dp_get
+static inline p4d_t p4dp_get(p4d_t *p4dp)
{
- set_pmd(pmdp, __pmd(_SEGMENT_ENTRY_EMPTY));
+ return READ_ONCE(*p4dp);
+}
+
+#define pgdp_get pgdp_get
+static inline pgd_t pgdp_get(pgd_t *pgdp)
+{
+ return READ_ONCE(*pgdp);
}
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
@@ -1011,6 +1018,29 @@ static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *pt
set_pte(ptep, __pte(_PAGE_INVALID));
}
+static inline void pmd_clear(pmd_t *pmdp)
+{
+ set_pmd(pmdp, __pmd(_SEGMENT_ENTRY_EMPTY));
+}
+
+static inline void pud_clear(pud_t *pud)
+{
+ if ((pud_val(pudp_get(pud)) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
+ set_pud(pud, __pud(_REGION3_ENTRY_EMPTY));
+}
+
+static inline void p4d_clear(p4d_t *p4d)
+{
+ if ((p4d_val(p4dp_get(p4d)) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2)
+ set_p4d(p4d, __p4d(_REGION2_ENTRY_EMPTY));
+}
+
+static inline void pgd_clear(pgd_t *pgd)
+{
+ if ((pgd_val(pgdp_get(pgd)) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R1)
+ set_pgd(pgd, __pgd(_REGION1_ENTRY_EMPTY));
+}
+
/*
* The following pte modification functions only work if
* pte_present() is true. Undefined behaviour if not..
@@ -1169,7 +1199,7 @@ pte_t ptep_xchg_lazy(struct mm_struct *, unsigned long, pte_t *, pte_t);
static inline bool ptep_test_and_clear_young(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep)
{
- pte_t pte = *ptep;
+ pte_t pte = ptep_get(ptep);
pte = ptep_xchg_direct(vma->vm_mm, addr, ptep, pte_mkold(pte));
return pte_young(pte);
@@ -1230,7 +1260,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
pte_t res;
if (full) {
- res = *ptep;
+ res = ptep_get(ptep);
set_pte(ptep, __pte(_PAGE_INVALID));
} else {
res = ptep_xchg_lazy(mm, addr, ptep, __pte(_PAGE_INVALID));
@@ -1259,7 +1289,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
static inline void ptep_set_wrprotect(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
- pte_t pte = *ptep;
+ pte_t pte = ptep_get(ptep);
if (pte_write(pte))
ptep_xchg_lazy(mm, addr, ptep, pte_wrprotect(pte));
@@ -1295,7 +1325,7 @@ static inline void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma,
* PTE does not have _PAGE_PROTECT set, to avoid unnecessary overhead.
* A local RDP can be used to do the flush.
*/
- if (cpu_has_rdp() && !(pte_val(*ptep) & _PAGE_PROTECT))
+ if (cpu_has_rdp() && !(pte_val(ptep_get(ptep)) & _PAGE_PROTECT))
__ptep_rdp(address, ptep, 1);
}
#define flush_tlb_fix_spurious_fault flush_tlb_fix_spurious_fault
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h
index 49447b40f0385..ac3ab6c299127 100644
--- a/arch/s390/include/asm/timex.h
+++ b/arch/s390/include/asm/timex.h
@@ -12,6 +12,7 @@
#include <linux/preempt.h>
#include <linux/time64.h>
+#include <asm/tod_types.h>
#include <asm/lowcore.h>
#include <asm/machine.h>
#include <asm/asm.h>
@@ -21,25 +22,6 @@
extern u64 clock_comparator_max;
-union tod_clock {
- __uint128_t val;
- struct {
- __uint128_t ei : 8; /* epoch index */
- __uint128_t tod : 64; /* bits 0-63 of tod clock */
- __uint128_t : 40;
- __uint128_t pf : 16; /* programmable field */
- };
- struct {
- __uint128_t eitod : 72; /* epoch index + bits 0-63 tod clock */
- __uint128_t : 56;
- };
- struct {
- __uint128_t us : 60; /* micro-seconds */
- __uint128_t sus : 12; /* sub-microseconds */
- __uint128_t : 56;
- };
-} __packed;
-
/* Inline functions for clock register access. */
static inline int set_tod_clock(__u64 time)
{
diff --git a/arch/s390/include/asm/tod_types.h b/arch/s390/include/asm/tod_types.h
new file mode 100644
index 0000000000000..976fa0a1e8959
--- /dev/null
+++ b/arch/s390/include/asm/tod_types.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_S390_TOD_TYPES_H
+#define _ASM_S390_TOD_TYPES_H
+
+#include <linux/types.h>
+
+#ifndef __ASSEMBLER__
+
+union tod_clock {
+ __uint128_t val;
+ struct {
+ __uint128_t ei : 8; /* epoch index */
+ __uint128_t tod : 64; /* bits 0-63 of tod clock */
+ __uint128_t : 40;
+ __uint128_t pf : 16; /* programmable field */
+ };
+ struct {
+ __uint128_t eitod : 72; /* epoch index + bits 0-63 tod clock */
+ __uint128_t : 56;
+ };
+ struct {
+ __uint128_t us : 60; /* micro-seconds */
+ __uint128_t sus : 12; /* sub-microseconds */
+ __uint128_t : 56;
+ };
+} __packed;
+
+#endif
+#endif
diff --git a/arch/s390/include/asm/vtime.h b/arch/s390/include/asm/vtime.h
index b1db75d14e9dc..da116a93d3b6c 100644
--- a/arch/s390/include/asm/vtime.h
+++ b/arch/s390/include/asm/vtime.h
@@ -48,8 +48,8 @@ static inline void update_timer_idle(void)
* The accounted CPU times will be subtracted again from steal_timer
* when accumulated steal time is calculated in do_account_vtime().
*/
- lc->steal_timer += idle->clock_idle_enter - lc->last_update_clock;
- lc->last_update_clock = lc->int_clock;
+ lc->steal_timer += idle->clock_idle_enter.tod - lc->last_update_clock;
+ lc->last_update_clock = lc->int_clock.tod;
lc->system_timer += lc->last_update_timer - idle->timer_idle_enter;
lc->last_update_timer = lc->sys_enter_timer;
}
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index fbd26f3e9f96b..f6dd2b67dcee7 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -11,9 +11,11 @@
#include <linux/purgatory.h>
#include <linux/pgtable.h>
#include <linux/ftrace_regs.h>
+#include <linux/kernel_stat.h>
#include <asm/kvm_host_types.h>
#include <asm/stacktrace.h>
#include <asm/ptrace.h>
+#include <asm/idle.h>
int main(void)
{
@@ -128,6 +130,7 @@ int main(void)
OFFSET(__LC_LAST_UPDATE_CLOCK, lowcore, last_update_clock);
OFFSET(__LC_INT_CLOCK, lowcore, int_clock);
OFFSET(__LC_CURRENT, lowcore, current_task);
+ OFFSET(__LC_PERCPU_OFFSET, lowcore, percpu_offset);
OFFSET(__LC_KERNEL_STACK, lowcore, kernel_stack);
OFFSET(__LC_ASYNC_STACK, lowcore, async_stack);
OFFSET(__LC_NODAT_STACK, lowcore, nodat_stack);
@@ -180,6 +183,10 @@ int main(void)
DEFINE(OLDMEM_SIZE, PARMAREA + offsetof(struct parmarea, oldmem_size));
DEFINE(COMMAND_LINE, PARMAREA + offsetof(struct parmarea, command_line));
DEFINE(MAX_COMMAND_LINE_SIZE, PARMAREA + offsetof(struct parmarea, max_command_line_size));
+ OFFSET(__IDLE_CLOCK_EXIT, s390_idle_data, clock_idle_exit);
+#ifdef CONFIG_NO_HZ_COMMON
+ OFFSET(__KCPUSTAT_SEQUENCE, kernel_cpustat, idle_sleeptime_seq);
+#endif
OFFSET(__FTRACE_REGS_PT_REGS, __arch_ftrace_regs, regs);
DEFINE(__FTRACE_REGS_SIZE, sizeof(struct __arch_ftrace_regs));
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index bb806d1ddae01..79a45efae23d0 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -379,8 +379,19 @@ SYM_CODE_END(pgm_check_handler)
SYM_CODE_START(\name)
STMG_LC %r8,%r15,__LC_SAVE_AREA
GET_LC %r13
- stckf __LC_INT_CLOCK(%r13)
+#ifdef CONFIG_NO_HZ_COMMON
+ larl %r12,kernel_cpustat
+ ag %r12,__LC_PERCPU_OFFSET(%r13)
+ asi __KCPUSTAT_SEQUENCE(%r12),1
+#endif
+ stcke __LC_INT_CLOCK(%r13)
stpt __LC_SYS_ENTER_TIMER(%r13)
+ larl %r10,s390_idle
+ ag %r10,__LC_PERCPU_OFFSET(%r13)
+ mvc __IDLE_CLOCK_EXIT(16,%r10),__LC_INT_CLOCK(%r13)
+#ifdef CONFIG_NO_HZ_COMMON
+ asi __KCPUSTAT_SEQUENCE(%r12),1
+#endif
STBEAR __LC_LAST_BREAK(%r13)
BPOFF
lmg %r8,%r9,\lc_old_psw(%r13)
@@ -407,7 +418,6 @@ SYM_CODE_START(\name)
xgr %r5,%r5
xgr %r6,%r6
xgr %r7,%r7
- xgr %r10,%r10
xgr %r12,%r12
xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA(%r13)
diff --git a/arch/s390/kernel/idle.c b/arch/s390/kernel/idle.c
index 4685d7c5bc518..08f3520c67853 100644
--- a/arch/s390/kernel/idle.c
+++ b/arch/s390/kernel/idle.c
@@ -9,9 +9,11 @@
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
+#include <linux/sched/stat.h>
#include <linux/notifier.h>
#include <linux/init.h>
#include <linux/cpu.h>
+#include <linux/export.h>
#include <trace/events/power.h>
#include <asm/cpu_mf.h>
#include <asm/cputime.h>
@@ -21,22 +23,111 @@
DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
-void account_idle_time_irq(void)
+static __always_inline void __account_idle_time_irq(void)
{
struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
unsigned long idle_time;
- idle_time = get_lowcore()->int_clock - idle->clock_idle_enter;
+ idle_time = idle->clock_idle_exit.tod - idle->clock_idle_enter.tod;
+ account_idle_time(cputime_to_nsecs(idle_time));
+}
- /* Account time spent with enabled wait psw loaded as idle time. */
- __atomic64_add(idle_time, &idle->idle_time);
- __atomic64_add_const(1, &idle->idle_count);
+static __always_inline void __account_idle_time_setup(void)
+{
+ struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
- /* Dyntick idle time accounted by nohz/scheduler */
- if (!idle->idle_dyntick)
- account_idle_time(cputime_to_nsecs(idle_time));
+ store_tod_clock_ext(&idle->clock_idle_enter);
+ idle->timer_idle_enter = get_cpu_timer();
+ idle->clock_idle_exit = idle->clock_idle_enter;
}
+#ifdef CONFIG_NO_HZ_COMMON
+
+static u64 arch_cpu_in_idle_time(int cpu)
+{
+ struct s390_idle_data *idle = &per_cpu(s390_idle, cpu);
+ union tod_clock now;
+ u64 idle_time;
+
+ if (!idle->in_idle)
+ return 0;
+ store_tod_clock_ext(&now);
+ if (tod_after(idle->clock_idle_exit.tod, idle->clock_idle_enter.tod))
+ idle_time = idle->clock_idle_exit.tod - idle->clock_idle_enter.tod;
+ else
+ idle_time = now.tod - idle->clock_idle_enter.tod;
+ return cputime_to_nsecs(idle_time);
+}
+
+static u64 arch_cpu_idle_time(int cpu, enum cpu_usage_stat idx, bool compute_delta)
+{
+ struct kernel_cpustat *kc = &kcpustat_cpu(cpu);
+ u64 *cpustat = kc->cpustat;
+ unsigned int seq;
+ u64 idle_time;
+
+ /*
+ * The open coded seqcount writer in entry.S relies on the
+ * raw counting mechanism without any writer protection.
+ */
+ typecheck(typeof(kc->idle_sleeptime_seq), seqcount_t);
+ do {
+ seq = read_seqcount_begin(&kc->idle_sleeptime_seq);
+ idle_time = cpustat[idx];
+ if (compute_delta)
+ idle_time += arch_cpu_in_idle_time(cpu);
+ } while (read_seqcount_retry(&kc->idle_sleeptime_seq, seq));
+ return idle_time;
+}
+
+u64 arch_kcpustat_field_idle(int cpu)
+{
+ return arch_cpu_idle_time(cpu, CPUTIME_IDLE, !nr_iowait_cpu(cpu));
+}
+EXPORT_SYMBOL_GPL(arch_kcpustat_field_idle);
+
+u64 arch_kcpustat_field_iowait(int cpu)
+{
+ return arch_cpu_idle_time(cpu, CPUTIME_IOWAIT, nr_iowait_cpu(cpu));
+}
+EXPORT_SYMBOL_GPL(arch_kcpustat_field_iowait);
+
+void account_idle_time_irq(void)
+{
+ struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
+ struct kernel_cpustat *kc = kcpustat_this_cpu;
+
+ write_seqcount_begin(&kc->idle_sleeptime_seq);
+ idle->in_idle = false;
+ __account_idle_time_irq();
+ write_seqcount_end(&kc->idle_sleeptime_seq);
+}
+
+static __always_inline void account_idle_time_setup(void)
+{
+ struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
+ struct kernel_cpustat *kc = kcpustat_this_cpu;
+
+ raw_write_seqcount_begin(&kc->idle_sleeptime_seq);
+ idle->in_idle = true;
+ __account_idle_time_setup();
+ raw_write_seqcount_end(&kc->idle_sleeptime_seq);
+}
+
+#else /* CONFIG_NO_HZ_COMMON */
+
+void account_idle_time_irq(void)
+{
+ __account_idle_time_irq();
+}
+
+static __always_inline void account_idle_time_setup(void)
+{
+ __account_idle_time_setup();
+}
+
+#endif /* CONFIG_NO_HZ_COMMON */
+
void noinstr arch_cpu_idle(void)
{
struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
@@ -49,30 +140,11 @@ void noinstr arch_cpu_idle(void)
set_cpu_flag(CIF_ENABLED_WAIT);
if (smp_cpu_mtid)
stcctm(MT_DIAG, smp_cpu_mtid, (u64 *)&idle->mt_cycles_enter);
- idle->clock_idle_enter = get_tod_clock_fast();
- idle->timer_idle_enter = get_cpu_timer();
+ account_idle_time_setup();
bpon();
__load_psw_mask(psw_mask);
}
-static ssize_t show_idle_count(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
-
- return sysfs_emit(buf, "%lu\n", READ_ONCE(idle->idle_count));
-}
-DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL);
-
-static ssize_t show_idle_time(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id);
-
- return sysfs_emit(buf, "%lu\n", READ_ONCE(idle->idle_time) >> 12);
-}
-DEVICE_ATTR(idle_time_us, 0444, show_idle_time, NULL);
-
void arch_cpu_idle_enter(void)
{
}
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index efb988833c88d..04d528639b946 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -104,9 +104,10 @@ static const struct irq_class irqclass_sub_desc[] = {
static void do_IRQ(struct pt_regs *regs, int irq)
{
- if (tod_after_eq(get_lowcore()->int_clock,
- get_lowcore()->clock_comparator))
- /* Serve timer interrupts first. */
+ struct lowcore *lc = get_lowcore();
+
+ /* Serve timer interrupts first */
+ if (tod_after_eq(lc->int_clock.tod, lc->clock_comparator))
clock_comparator_work();
generic_handle_irq(irq);
}
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 50bb499cf3e50..0ba7f89b81611 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -54,7 +54,6 @@
#include <asm/debug.h>
#include <asm/os_info.h>
#include <asm/sigp.h>
-#include <asm/idle.h>
#include <asm/nmi.h>
#include <asm/stacktrace.h>
#include <asm/topology.h>
@@ -1085,31 +1084,6 @@ static struct attribute_group cpu_common_attr_group = {
.attrs = cpu_common_attrs,
};
-static struct attribute *cpu_online_attrs[] = {
- &dev_attr_idle_count.attr,
- &dev_attr_idle_time_us.attr,
- NULL,
-};
-
-static struct attribute_group cpu_online_attr_group = {
- .attrs = cpu_online_attrs,
-};
-
-static int smp_cpu_online(unsigned int cpu)
-{
- struct cpu *c = per_cpu_ptr(&cpu_devices, cpu);
-
- return sysfs_create_group(&c->dev.kobj, &cpu_online_attr_group);
-}
-
-static int smp_cpu_pre_down(unsigned int cpu)
-{
- struct cpu *c = per_cpu_ptr(&cpu_devices, cpu);
-
- sysfs_remove_group(&c->dev.kobj, &cpu_online_attr_group);
- return 0;
-}
-
bool arch_cpu_is_hotpluggable(int cpu)
{
return !!cpu;
@@ -1175,18 +1149,13 @@ static DEVICE_ATTR_WO(rescan);
static int __init s390_smp_init(void)
{
struct device *dev_root;
- int rc;
+ int rc = 0;
dev_root = bus_get_dev_root(&cpu_subsys);
if (dev_root) {
rc = device_create_file(dev_root, &dev_attr_rescan);
put_device(dev_root);
- if (rc)
- return rc;
}
- rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "s390/smp:online",
- smp_cpu_online, smp_cpu_pre_down);
- rc = rc <= 0 ? rc : 0;
return rc;
}
subsys_initcall(s390_smp_init);
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index d1102a6f80bda..d804e1140c2e9 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -140,8 +140,6 @@ static int do_account_vtime(struct task_struct *tsk)
if (hardirq_count())
lc->hardirq_timer += timer;
- else if (in_serving_softirq())
- lc->softirq_timer += timer;
else
lc->system_timer += timer;
@@ -241,62 +239,13 @@ EXPORT_SYMBOL_GPL(vtime_account_kernel);
void vtime_account_softirq(struct task_struct *tsk)
{
- if (!__this_cpu_read(s390_idle.idle_dyntick))
- get_lowcore()->softirq_timer += vtime_delta();
- else
- vtime_flush(tsk);
+ get_lowcore()->softirq_timer += vtime_delta();
}
void vtime_account_hardirq(struct task_struct *tsk)
{
- if (!__this_cpu_read(s390_idle.idle_dyntick)) {
- get_lowcore()->hardirq_timer += vtime_delta();
- } else {
- /*
- * In dynticks mode, the idle cputime is accounted by the nohz
- * subsystem. Therefore the s390 timer/clocks are reset on IRQ
- * entry and steal time must be accounted now.
- */
- vtime_flush(tsk);
- }
-}
-
-#ifdef CONFIG_NO_HZ_COMMON
-/**
- * vtime_reset - Fast forward vtime entry clocks
- *
- * Called from dynticks idle IRQ entry to fast-forward the clocks to current time
- * so that the IRQ time is still accounted by vtime while nohz cputime is paused.
- */
-void vtime_reset(void)
-{
- vtime_reset_last_update(get_lowcore());
-}
-
-/**
- * vtime_dyntick_start - Inform vtime about entry to idle-dynticks
- *
- * Called when idle enters in dyntick mode. The idle cputime that elapsed so far
- * is flushed and the tick subsystem takes over the idle cputime accounting.
- */
-void vtime_dyntick_start(void)
-{
- __this_cpu_write(s390_idle.idle_dyntick, true);
- vtime_flush(current);
-}
-
-/**
- * vtime_dyntick_stop - Inform vtime about exit from idle-dynticks
- *
- * Called when idle exits from dyntick mode. The vtime entry clocks are
- * fast-forward to current time and idle accounting resumes.
- */
-void vtime_dyntick_stop(void)
-{
- vtime_reset_last_update(get_lowcore());
- __this_cpu_write(s390_idle.idle_dyntick, false);
+ get_lowcore()->hardirq_timer += vtime_delta();
}
-#endif /* CONFIG_NO_HZ_COMMON */
/*
* Sorted add to a list. List is linear searched until first bigger
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c
index 302ef5781b656..db35d8fe86090 100644
--- a/arch/s390/mm/hugetlbpage.c
+++ b/arch/s390/mm/hugetlbpage.c
@@ -143,7 +143,7 @@ void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
rste = __pte_to_rste(pte);
/* Set correct table type for 2G hugepages */
- if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) {
+ if ((pte_val(ptep_get(ptep)) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) {
if (likely(pte_present(pte)))
rste |= _REGION3_ENTRY_LARGE;
rste |= _REGION_ENTRY_TYPE_R3;
@@ -161,7 +161,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t huge_ptep_get(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
- return __rste_to_pte(pte_val(*ptep));
+ return __rste_to_pte(pte_val(ptep_get(ptep)));
}
pte_t __huge_ptep_get_and_clear(struct mm_struct *mm,
@@ -171,7 +171,7 @@ pte_t __huge_ptep_get_and_clear(struct mm_struct *mm,
pmd_t *pmdp = (pmd_t *) ptep;
pud_t *pudp = (pud_t *) ptep;
- if ((pte_val(*ptep) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
+ if ((pte_val(ptep_get(ptep)) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
pudp_xchg_direct(mm, addr, pudp, __pud(_REGION3_ENTRY_EMPTY));
else
pmdp_xchg_direct(mm, addr, pmdp, __pmd(_SEGMENT_ENTRY_EMPTY));
@@ -209,13 +209,13 @@ pte_t *huge_pte_offset(struct mm_struct *mm,
pmd_t *pmdp = NULL;
pgdp = pgd_offset(mm, addr);
- if (pgd_present(*pgdp)) {
+ if (pgd_present(pgdp_get(pgdp))) {
p4dp = p4d_offset(pgdp, addr);
- if (p4d_present(*p4dp)) {
+ if (p4d_present(p4dp_get(p4dp))) {
pudp = pud_offset(p4dp, addr);
if (sz == PUD_SIZE)
return (pte_t *)pudp;
- if (pud_present(*pudp))
+ if (pud_present(pudp_get(pudp)))
pmdp = pmd_offset(pudp, addr);
}
}
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c
index bb29c38ae6241..e6f788696dd1a 100644
--- a/arch/s390/mm/pageattr.c
+++ b/arch/s390/mm/pageattr.c
@@ -85,7 +85,7 @@ static int walk_pte_level(pmd_t *pmdp, unsigned long addr, unsigned long end,
return 0;
ptep = pte_offset_kernel(pmdp, addr);
do {
- new = *ptep;
+ new = ptep_get(ptep);
if (pte_none(new))
return -EINVAL;
if (flags & SET_MEMORY_RO)
@@ -114,15 +114,16 @@ static int split_pmd_page(pmd_t *pmdp, unsigned long addr)
{
unsigned long pte_addr, prot;
pte_t *pt_dir, *ptep;
- pmd_t new;
+ pmd_t new, pmd;
int i, ro, nx;
pt_dir = vmem_pte_alloc();
if (!pt_dir)
return -ENOMEM;
- pte_addr = pmd_pfn(*pmdp) << PAGE_SHIFT;
- ro = !!(pmd_val(*pmdp) & _SEGMENT_ENTRY_PROTECT);
- nx = !!(pmd_val(*pmdp) & _SEGMENT_ENTRY_NOEXEC);
+ pmd = pmdp_get(pmdp);
+ pte_addr = pmd_pfn(pmd) << PAGE_SHIFT;
+ ro = !!(pmd_val(pmd) & _SEGMENT_ENTRY_PROTECT);
+ nx = !!(pmd_val(pmd) & _SEGMENT_ENTRY_NOEXEC);
prot = pgprot_val(ro ? PAGE_KERNEL_RO : PAGE_KERNEL);
if (!nx)
prot &= ~_PAGE_NOEXEC;
@@ -142,7 +143,7 @@ static int split_pmd_page(pmd_t *pmdp, unsigned long addr)
static void modify_pmd_page(pmd_t *pmdp, unsigned long addr,
unsigned long flags)
{
- pmd_t new = *pmdp;
+ pmd_t new = pmdp_get(pmdp);
if (flags & SET_MEMORY_RO)
new = pmd_wrprotect(new);
@@ -165,16 +166,17 @@ static int walk_pmd_level(pud_t *pudp, unsigned long addr, unsigned long end,
unsigned long flags)
{
unsigned long next;
+ pmd_t *pmdp, pmd;
int need_split;
- pmd_t *pmdp;
int rc = 0;
pmdp = pmd_offset(pudp, addr);
do {
- if (pmd_none(*pmdp))
+ pmd = pmdp_get(pmdp);
+ if (pmd_none(pmd))
return -EINVAL;
next = pmd_addr_end(addr, end);
- if (pmd_leaf(*pmdp)) {
+ if (pmd_leaf(pmd)) {
need_split = !!(flags & SET_MEMORY_4K);
need_split |= !!(addr & ~PMD_MASK);
need_split |= !!(addr + PMD_SIZE > next);
@@ -201,15 +203,16 @@ int split_pud_page(pud_t *pudp, unsigned long addr)
{
unsigned long pmd_addr, prot;
pmd_t *pm_dir, *pmdp;
- pud_t new;
+ pud_t new, pud;
int i, ro, nx;
pm_dir = vmem_crst_alloc(_SEGMENT_ENTRY_EMPTY);
if (!pm_dir)
return -ENOMEM;
- pmd_addr = pud_pfn(*pudp) << PAGE_SHIFT;
- ro = !!(pud_val(*pudp) & _REGION_ENTRY_PROTECT);
- nx = !!(pud_val(*pudp) & _REGION_ENTRY_NOEXEC);
+ pud = pudp_get(pudp);
+ pmd_addr = pud_pfn(pud) << PAGE_SHIFT;
+ ro = !!(pud_val(pud) & _REGION_ENTRY_PROTECT);
+ nx = !!(pud_val(pud) & _REGION_ENTRY_NOEXEC);
prot = pgprot_val(ro ? SEGMENT_KERNEL_RO : SEGMENT_KERNEL);
if (!nx)
prot &= ~_SEGMENT_ENTRY_NOEXEC;
@@ -229,7 +232,7 @@ int split_pud_page(pud_t *pudp, unsigned long addr)
static void modify_pud_page(pud_t *pudp, unsigned long addr,
unsigned long flags)
{
- pud_t new = *pudp;
+ pud_t new = pudp_get(pudp);
if (flags & SET_MEMORY_RO)
new = pud_wrprotect(new);
@@ -252,16 +255,17 @@ static int walk_pud_level(p4d_t *p4d, unsigned long addr, unsigned long end,
unsigned long flags)
{
unsigned long next;
+ pud_t *pudp, pud;
int need_split;
- pud_t *pudp;
int rc = 0;
pudp = pud_offset(p4d, addr);
do {
- if (pud_none(*pudp))
+ pud = pudp_get(pudp);
+ if (pud_none(pud))
return -EINVAL;
next = pud_addr_end(addr, end);
- if (pud_leaf(*pudp)) {
+ if (pud_leaf(pud)) {
need_split = !!(flags & SET_MEMORY_4K);
need_split |= !!(addr & ~PUD_MASK);
need_split |= !!(addr + PUD_SIZE > next);
@@ -291,7 +295,7 @@ static int walk_p4d_level(pgd_t *pgd, unsigned long addr, unsigned long end,
p4dp = p4d_offset(pgd, addr);
do {
- if (p4d_none(*p4dp))
+ if (p4d_none(p4dp_get(p4dp)))
return -EINVAL;
next = p4d_addr_end(addr, end);
rc = walk_pud_level(p4dp, addr, next, flags);
@@ -313,7 +317,7 @@ static int change_page_attr(unsigned long addr, unsigned long end,
pgdp = pgd_offset_k(addr);
do {
- if (pgd_none(*pgdp))
+ if (pgd_none(pgdp_get(pgdp)))
break;
next = pgd_addr_end(addr, end);
rc = walk_p4d_level(pgdp, addr, next, flags);
@@ -451,7 +455,8 @@ void __kernel_map_pages(struct page *page, int numpages, int enable)
nr = min(numpages - i, nr);
if (enable) {
for (j = 0; j < nr; j++) {
- pte = clear_pte_bit(*ptep, __pgprot(_PAGE_INVALID));
+ pte = ptep_get(ptep);
+ pte = clear_pte_bit(pte, __pgprot(_PAGE_INVALID));
set_pte(ptep, pte);
address += PAGE_SIZE;
ptep++;
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index d8b2a60e0c33b..94ee06ae89134 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -170,18 +170,19 @@ static int __ref modify_pte_table(pmd_t *pmd, unsigned long addr,
{
unsigned long prot, pages = 0;
int ret = -ENOMEM;
- pte_t *pte;
+ pte_t *pte, entry;
prot = pgprot_val(PAGE_KERNEL);
pte = pte_offset_kernel(pmd, addr);
for (; addr < end; addr += PAGE_SIZE, pte++) {
+ entry = ptep_get(pte);
if (!add) {
- if (pte_none(*pte))
+ if (pte_none(entry))
continue;
if (!direct)
- vmem_free_pages((unsigned long)pfn_to_virt(pte_pfn(*pte)), get_order(PAGE_SIZE), altmap);
+ vmem_free_pages((unsigned long)pfn_to_virt(pte_pfn(entry)), get_order(PAGE_SIZE), altmap);
pte_clear(&init_mm, addr, pte);
- } else if (pte_none(*pte)) {
+ } else if (pte_none(entry)) {
if (!direct) {
void *new_page = vmemmap_alloc_block_buf(PAGE_SIZE, NUMA_NO_NODE, altmap);
@@ -211,10 +212,10 @@ static void try_free_pte_table(pmd_t *pmd, unsigned long start)
/* We can safely assume this is fully in 1:1 mapping & vmemmap area */
pte = pte_offset_kernel(pmd, start);
for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
- if (!pte_none(*pte))
+ if (!pte_none(ptep_get(pte)))
return;
}
- vmem_pte_free((unsigned long *) pmd_deref(*pmd));
+ vmem_pte_free((unsigned long *)pmd_deref(pmdp_get(pmd)));
pmd_clear(pmd);
}
@@ -225,6 +226,7 @@ static int __ref modify_pmd_table(pud_t *pud, unsigned long addr,
{
unsigned long next, prot, pages = 0;
int ret = -ENOMEM;
+ pmd_t entry;
pmd_t *pmd;
pte_t *pte;
@@ -232,23 +234,24 @@ static int __ref modify_pmd_table(pud_t *pud, unsigned long addr,
pmd = pmd_offset(pud, addr);
for (; addr < end; addr = next, pmd++) {
next = pmd_addr_end(addr, end);
+ entry = pmdp_get(pmd);
if (!add) {
- if (pmd_none(*pmd))
+ if (pmd_none(entry))
continue;
- if (pmd_leaf(*pmd)) {
+ if (pmd_leaf(entry)) {
if (IS_ALIGNED(addr, PMD_SIZE) &&
IS_ALIGNED(next, PMD_SIZE)) {
if (!direct)
- vmem_free_pages(pmd_deref(*pmd), get_order(PMD_SIZE), altmap);
+ vmem_free_pages(pmd_deref(entry), get_order(PMD_SIZE), altmap);
pmd_clear(pmd);
pages++;
} else if (!direct && vmemmap_unuse_sub_pmd(addr, next)) {
- vmem_free_pages(pmd_deref(*pmd), get_order(PMD_SIZE), altmap);
+ vmem_free_pages(pmd_deref(entry), get_order(PMD_SIZE), altmap);
pmd_clear(pmd);
}
continue;
}
- } else if (pmd_none(*pmd)) {
+ } else if (pmd_none(entry)) {
if (IS_ALIGNED(addr, PMD_SIZE) &&
IS_ALIGNED(next, PMD_SIZE) &&
cpu_has_edat1() && direct &&
@@ -280,7 +283,7 @@ static int __ref modify_pmd_table(pud_t *pud, unsigned long addr,
if (!pte)
goto out;
pmd_populate(&init_mm, pmd, pte);
- } else if (pmd_leaf(*pmd)) {
+ } else if (pmd_leaf(entry)) {
if (!direct)
vmemmap_use_sub_pmd(addr, next);
continue;
@@ -305,9 +308,9 @@ static void try_free_pmd_table(pud_t *pud, unsigned long start)
pmd = pmd_offset(pud, start);
for (i = 0; i < PTRS_PER_PMD; i++, pmd++)
- if (!pmd_none(*pmd))
+ if (!pmd_none(pmdp_get(pmd)))
return;
- vmem_free_pages(pud_deref(*pud), CRST_ALLOC_ORDER, NULL);
+ vmem_free_pages(pud_deref(pudp_get(pud)), CRST_ALLOC_ORDER, NULL);
pud_clear(pud);
}
@@ -316,21 +319,22 @@ static int modify_pud_table(p4d_t *p4d, unsigned long addr, unsigned long end,
{
unsigned long next, prot, pages = 0;
int ret = -ENOMEM;
- pud_t *pud;
+ pud_t *pud, entry;
pmd_t *pmd;
prot = pgprot_val(REGION3_KERNEL);
pud = pud_offset(p4d, addr);
for (; addr < end; addr = next, pud++) {
next = pud_addr_end(addr, end);
+ entry = pudp_get(pud);
if (!add) {
- if (pud_none(*pud))
+ if (pud_none(entry))
continue;
- if (pud_leaf(*pud)) {
+ if (pud_leaf(entry)) {
if (IS_ALIGNED(addr, PUD_SIZE) &&
IS_ALIGNED(next, PUD_SIZE)) {
if (!direct)
- vmem_free_pages(pud_deref(*pud), get_order(PUD_SIZE), altmap);
+ vmem_free_pages(pud_deref(entry), get_order(PUD_SIZE), altmap);
pud_clear(pud);
pages++;
continue;
@@ -338,7 +342,7 @@ static int modify_pud_table(p4d_t *p4d, unsigned long addr, unsigned long end,
split_pud_page(pud, addr & PUD_MASK);
}
}
- } else if (pud_none(*pud)) {
+ } else if (pud_none(entry)) {
if (IS_ALIGNED(addr, PUD_SIZE) &&
IS_ALIGNED(next, PUD_SIZE) &&
cpu_has_edat2() && direct &&
@@ -351,7 +355,7 @@ static int modify_pud_table(p4d_t *p4d, unsigned long addr, unsigned long end,
if (!pmd)
goto out;
pud_populate(&init_mm, pud, pmd);
- } else if (pud_leaf(*pud)) {
+ } else if (pud_leaf(entry)) {
continue;
}
ret = modify_pmd_table(pud, addr, next, add, direct, altmap);
@@ -374,10 +378,10 @@ static void try_free_pud_table(p4d_t *p4d, unsigned long start)
pud = pud_offset(p4d, start);
for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
- if (!pud_none(*pud))
+ if (!pud_none(pudp_get(pud)))
return;
}
- vmem_free_pages(p4d_deref(*p4d), CRST_ALLOC_ORDER, NULL);
+ vmem_free_pages(p4d_deref(p4dp_get(p4d)), CRST_ALLOC_ORDER, NULL);
p4d_clear(p4d);
}
@@ -386,16 +390,17 @@ static int modify_p4d_table(pgd_t *pgd, unsigned long addr, unsigned long end,
{
unsigned long next;
int ret = -ENOMEM;
- p4d_t *p4d;
+ p4d_t *p4d, entry;
pud_t *pud;
p4d = p4d_offset(pgd, addr);
for (; addr < end; addr = next, p4d++) {
next = p4d_addr_end(addr, end);
+ entry = p4dp_get(p4d);
if (!add) {
- if (p4d_none(*p4d))
+ if (p4d_none(entry))
continue;
- } else if (p4d_none(*p4d)) {
+ } else if (p4d_none(entry)) {
pud = vmem_crst_alloc(_REGION3_ENTRY_EMPTY);
if (!pud)
goto out;
@@ -419,10 +424,10 @@ static void try_free_p4d_table(pgd_t *pgd, unsigned long start)
p4d = p4d_offset(pgd, start);
for (i = 0; i < PTRS_PER_P4D; i++, p4d++) {
- if (!p4d_none(*p4d))
+ if (!p4d_none(p4dp_get(p4d)))
return;
}
- vmem_free_pages(pgd_deref(*pgd), CRST_ALLOC_ORDER, NULL);
+ vmem_free_pages(pgd_deref(pgdp_get(pgd)), CRST_ALLOC_ORDER, NULL);
pgd_clear(pgd);
}
@@ -431,7 +436,7 @@ static int modify_pagetable(unsigned long start, unsigned long end, bool add,
{
unsigned long addr, next;
int ret = -ENOMEM;
- pgd_t *pgd;
+ pgd_t *pgd, entry;
p4d_t *p4d;
if (WARN_ON_ONCE(!PAGE_ALIGNED(start | end)))
@@ -448,11 +453,12 @@ static int modify_pagetable(unsigned long start, unsigned long end, bool add,
for (addr = start; addr < end; addr = next) {
next = pgd_addr_end(addr, end);
pgd = pgd_offset_k(addr);
+ entry = pgdp_get(pgd);
if (!add) {
- if (pgd_none(*pgd))
+ if (pgd_none(entry))
continue;
- } else if (pgd_none(*pgd)) {
+ } else if (pgd_none(entry)) {
p4d = vmem_crst_alloc(_REGION2_ENTRY_EMPTY);
if (!p4d)
goto out;
@@ -574,6 +580,8 @@ int vmem_add_mapping(unsigned long start, unsigned long size)
pte_t *vmem_get_alloc_pte(unsigned long addr, bool alloc)
{
pte_t *ptep = NULL;
+ pud_t pud_entry;
+ pmd_t pmd_entry;
pgd_t *pgd;
p4d_t *p4d;
pud_t *pud;
@@ -581,7 +589,7 @@ pte_t *vmem_get_alloc_pte(unsigned long addr, bool alloc)
pte_t *pte;
pgd = pgd_offset_k(addr);
- if (pgd_none(*pgd)) {
+ if (pgd_none(pgdp_get(pgd))) {
if (!alloc)
goto out;
p4d = vmem_crst_alloc(_REGION2_ENTRY_EMPTY);
@@ -590,7 +598,7 @@ pte_t *vmem_get_alloc_pte(unsigned long addr, bool alloc)
pgd_populate(&init_mm, pgd, p4d);
}
p4d = p4d_offset(pgd, addr);
- if (p4d_none(*p4d)) {
+ if (p4d_none(p4dp_get(p4d))) {
if (!alloc)
goto out;
pud = vmem_crst_alloc(_REGION3_ENTRY_EMPTY);
@@ -599,25 +607,27 @@ pte_t *vmem_get_alloc_pte(unsigned long addr, bool alloc)
p4d_populate(&init_mm, p4d, pud);
}
pud = pud_offset(p4d, addr);
- if (pud_none(*pud)) {
+ pud_entry = pudp_get(pud);
+ if (pud_none(pud_entry)) {
if (!alloc)
goto out;
pmd = vmem_crst_alloc(_SEGMENT_ENTRY_EMPTY);
if (!pmd)
goto out;
pud_populate(&init_mm, pud, pmd);
- } else if (WARN_ON_ONCE(pud_leaf(*pud))) {
+ } else if (WARN_ON_ONCE(pud_leaf(pud_entry))) {
goto out;
}
pmd = pmd_offset(pud, addr);
- if (pmd_none(*pmd)) {
+ pmd_entry = pmdp_get(pmd);
+ if (pmd_none(pmd_entry)) {
if (!alloc)
goto out;
pte = vmem_pte_alloc();
if (!pte)
goto out;
pmd_populate(&init_mm, pmd, pte);
- } else if (WARN_ON_ONCE(pmd_leaf(*pmd))) {
+ } else if (WARN_ON_ONCE(pmd_leaf(pmd_entry))) {
goto out;
}
ptep = pte_offset_kernel(pmd, addr);