diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-22 07:43:48 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-06-22 07:43:48 -0700 |
| commit | 2580f89860460f38bcc13fce75db8626d555c0cd (patch) | |
| tree | 896d08f70dbfcea9b94c225334b597c740dda652 /arch | |
| parent | ef0c9f75a19532d7675384708fc8621e10850104 (diff) | |
| parent | 1ac287e2af9a9112fe271427ef45eceb26bce8b4 (diff) | |
| download | ath-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.c | 32 | ||||
| -rw-r--r-- | arch/s390/include/asm/hugetlb.h | 2 | ||||
| -rw-r--r-- | arch/s390/include/asm/idle.h | 14 | ||||
| -rw-r--r-- | arch/s390/include/asm/lowcore.h | 4 | ||||
| -rw-r--r-- | arch/s390/include/asm/pgtable.h | 60 | ||||
| -rw-r--r-- | arch/s390/include/asm/timex.h | 20 | ||||
| -rw-r--r-- | arch/s390/include/asm/tod_types.h | 30 | ||||
| -rw-r--r-- | arch/s390/include/asm/vtime.h | 4 | ||||
| -rw-r--r-- | arch/s390/kernel/asm-offsets.c | 7 | ||||
| -rw-r--r-- | arch/s390/kernel/entry.S | 14 | ||||
| -rw-r--r-- | arch/s390/kernel/idle.c | 128 | ||||
| -rw-r--r-- | arch/s390/kernel/irq.c | 7 | ||||
| -rw-r--r-- | arch/s390/kernel/smp.c | 33 | ||||
| -rw-r--r-- | arch/s390/kernel/vtime.c | 55 | ||||
| -rw-r--r-- | arch/s390/mm/hugetlbpage.c | 12 | ||||
| -rw-r--r-- | arch/s390/mm/pageattr.c | 45 | ||||
| -rw-r--r-- | arch/s390/mm/vmem.c | 82 |
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); |
