Skip to content

Commit cd774b9

Browse files
author
Martin Schwidefsky
committed
s390/mm,kvm: use nodat PGSTE tag to optimize TLB flushing
Signed-off-by: Martin Schwidefsky <[email protected]>
1 parent 28c807e commit cd774b9

File tree

2 files changed

+31
-17
lines changed

2 files changed

+31
-17
lines changed

arch/s390/include/asm/pgtable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ static inline int is_module_addr(void *addr)
376376

377377
/* Guest Page State used for virtualization */
378378
#define _PGSTE_GPS_ZERO 0x0000000080000000UL
379+
#define _PGSTE_GPS_NODAT 0x0000000040000000UL
379380
#define _PGSTE_GPS_USAGE_MASK 0x0000000003000000UL
380381
#define _PGSTE_GPS_USAGE_STABLE 0x0000000000000000UL
381382
#define _PGSTE_GPS_USAGE_UNUSED 0x0000000001000000UL

arch/s390/mm/pgtable.c

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@
2626
#include <asm/page-states.h>
2727

2828
static inline void ptep_ipte_local(struct mm_struct *mm, unsigned long addr,
29-
pte_t *ptep)
29+
pte_t *ptep, int nodat)
3030
{
3131
unsigned long opt, asce;
3232

3333
if (MACHINE_HAS_TLB_GUEST) {
3434
opt = 0;
3535
asce = READ_ONCE(mm->context.gmap_asce);
36-
if (asce == 0UL)
36+
if (asce == 0UL || nodat)
3737
opt |= IPTE_NODAT;
3838
if (asce != -1UL) {
3939
asce = asce ? : mm->context.asce;
@@ -46,14 +46,14 @@ static inline void ptep_ipte_local(struct mm_struct *mm, unsigned long addr,
4646
}
4747

4848
static inline void ptep_ipte_global(struct mm_struct *mm, unsigned long addr,
49-
pte_t *ptep)
49+
pte_t *ptep, int nodat)
5050
{
5151
unsigned long opt, asce;
5252

5353
if (MACHINE_HAS_TLB_GUEST) {
5454
opt = 0;
5555
asce = READ_ONCE(mm->context.gmap_asce);
56-
if (asce == 0UL)
56+
if (asce == 0UL || nodat)
5757
opt |= IPTE_NODAT;
5858
if (asce != -1UL) {
5959
asce = asce ? : mm->context.asce;
@@ -66,7 +66,8 @@ static inline void ptep_ipte_global(struct mm_struct *mm, unsigned long addr,
6666
}
6767

6868
static inline pte_t ptep_flush_direct(struct mm_struct *mm,
69-
unsigned long addr, pte_t *ptep)
69+
unsigned long addr, pte_t *ptep,
70+
int nodat)
7071
{
7172
pte_t old;
7273

@@ -76,15 +77,16 @@ static inline pte_t ptep_flush_direct(struct mm_struct *mm,
7677
atomic_inc(&mm->context.flush_count);
7778
if (MACHINE_HAS_TLB_LC &&
7879
cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
79-
ptep_ipte_local(mm, addr, ptep);
80+
ptep_ipte_local(mm, addr, ptep, nodat);
8081
else
81-
ptep_ipte_global(mm, addr, ptep);
82+
ptep_ipte_global(mm, addr, ptep, nodat);
8283
atomic_dec(&mm->context.flush_count);
8384
return old;
8485
}
8586

8687
static inline pte_t ptep_flush_lazy(struct mm_struct *mm,
87-
unsigned long addr, pte_t *ptep)
88+
unsigned long addr, pte_t *ptep,
89+
int nodat)
8890
{
8991
pte_t old;
9092

@@ -97,7 +99,7 @@ static inline pte_t ptep_flush_lazy(struct mm_struct *mm,
9799
pte_val(*ptep) |= _PAGE_INVALID;
98100
mm->context.flush_mm = 1;
99101
} else
100-
ptep_ipte_global(mm, addr, ptep);
102+
ptep_ipte_global(mm, addr, ptep, nodat);
101103
atomic_dec(&mm->context.flush_count);
102104
return old;
103105
}
@@ -269,10 +271,12 @@ pte_t ptep_xchg_direct(struct mm_struct *mm, unsigned long addr,
269271
{
270272
pgste_t pgste;
271273
pte_t old;
274+
int nodat;
272275

273276
preempt_disable();
274277
pgste = ptep_xchg_start(mm, addr, ptep);
275-
old = ptep_flush_direct(mm, addr, ptep);
278+
nodat = !!(pgste_val(pgste) & _PGSTE_GPS_NODAT);
279+
old = ptep_flush_direct(mm, addr, ptep, nodat);
276280
old = ptep_xchg_commit(mm, addr, ptep, pgste, old, new);
277281
preempt_enable();
278282
return old;
@@ -284,10 +288,12 @@ pte_t ptep_xchg_lazy(struct mm_struct *mm, unsigned long addr,
284288
{
285289
pgste_t pgste;
286290
pte_t old;
291+
int nodat;
287292

288293
preempt_disable();
289294
pgste = ptep_xchg_start(mm, addr, ptep);
290-
old = ptep_flush_lazy(mm, addr, ptep);
295+
nodat = !!(pgste_val(pgste) & _PGSTE_GPS_NODAT);
296+
old = ptep_flush_lazy(mm, addr, ptep, nodat);
291297
old = ptep_xchg_commit(mm, addr, ptep, pgste, old, new);
292298
preempt_enable();
293299
return old;
@@ -299,10 +305,12 @@ pte_t ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr,
299305
{
300306
pgste_t pgste;
301307
pte_t old;
308+
int nodat;
302309

303310
preempt_disable();
304311
pgste = ptep_xchg_start(mm, addr, ptep);
305-
old = ptep_flush_lazy(mm, addr, ptep);
312+
nodat = !!(pgste_val(pgste) & _PGSTE_GPS_NODAT);
313+
old = ptep_flush_lazy(mm, addr, ptep, nodat);
306314
if (mm_has_pgste(mm)) {
307315
pgste = pgste_update_all(old, pgste, mm);
308316
pgste_set(ptep, pgste);
@@ -557,7 +565,7 @@ int ptep_force_prot(struct mm_struct *mm, unsigned long addr,
557565
{
558566
pte_t entry;
559567
pgste_t pgste;
560-
int pte_i, pte_p;
568+
int pte_i, pte_p, nodat;
561569

562570
pgste = pgste_get_lock(ptep);
563571
entry = *ptep;
@@ -570,13 +578,14 @@ int ptep_force_prot(struct mm_struct *mm, unsigned long addr,
570578
return -EAGAIN;
571579
}
572580
/* Change access rights and set pgste bit */
581+
nodat = !!(pgste_val(pgste) & _PGSTE_GPS_NODAT);
573582
if (prot == PROT_NONE && !pte_i) {
574-
ptep_flush_direct(mm, addr, ptep);
583+
ptep_flush_direct(mm, addr, ptep, nodat);
575584
pgste = pgste_update_all(entry, pgste, mm);
576585
pte_val(entry) |= _PAGE_INVALID;
577586
}
578587
if (prot == PROT_READ && !pte_p) {
579-
ptep_flush_direct(mm, addr, ptep);
588+
ptep_flush_direct(mm, addr, ptep, nodat);
580589
pte_val(entry) &= ~_PAGE_INVALID;
581590
pte_val(entry) |= _PAGE_PROTECT;
582591
}
@@ -616,10 +625,12 @@ int ptep_shadow_pte(struct mm_struct *mm, unsigned long saddr,
616625
void ptep_unshadow_pte(struct mm_struct *mm, unsigned long saddr, pte_t *ptep)
617626
{
618627
pgste_t pgste;
628+
int nodat;
619629

620630
pgste = pgste_get_lock(ptep);
621631
/* notifier is called by the caller */
622-
ptep_flush_direct(mm, saddr, ptep);
632+
nodat = !!(pgste_val(pgste) & _PGSTE_GPS_NODAT);
633+
ptep_flush_direct(mm, saddr, ptep, nodat);
623634
/* don't touch the storage key - it belongs to parent pgste */
624635
pgste = pgste_set_pte(ptep, pgste, __pte(_PAGE_INVALID));
625636
pgste_set_unlock(ptep, pgste);
@@ -692,6 +703,7 @@ bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long addr)
692703
pte_t *ptep;
693704
pte_t pte;
694705
bool dirty;
706+
int nodat;
695707

696708
pgd = pgd_offset(mm, addr);
697709
p4d = p4d_alloc(mm, pgd, addr);
@@ -720,7 +732,8 @@ bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long addr)
720732
pte = *ptep;
721733
if (dirty && (pte_val(pte) & _PAGE_PRESENT)) {
722734
pgste = pgste_pte_notify(mm, addr, ptep, pgste);
723-
ptep_ipte_global(mm, addr, ptep);
735+
nodat = !!(pgste_val(pgste) & _PGSTE_GPS_NODAT);
736+
ptep_ipte_global(mm, addr, ptep, nodat);
724737
if (MACHINE_HAS_ESOP || !(pte_val(pte) & _PAGE_WRITE))
725738
pte_val(pte) |= _PAGE_PROTECT;
726739
else

0 commit comments

Comments
 (0)