aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2010-10-25 16:10:13 +0200
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-10-25 16:10:15 +0200
commit92f842eac7ee321c8a0749aba2513541b4ac226f (patch)
tree06a9c2302729ecd6d2941f8629da1646c11c714c
parent6931be0803ddae2791f3c646c8e1e0f82ca26013 (diff)
[S390] store indication fault optimization
Use the store indication bit in the translation exception code on page faults to avoid the protection faults that immediatly follow the page fault if the access has been a write. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/pgtable.h1
-rw-r--r--arch/s390/mm/fault.c21
-rw-r--r--arch/s390/mm/init.c1
3 files changed, 20 insertions, 3 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 785229ae39c..85cd4b039de 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -38,6 +38,7 @@
extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
extern void paging_init(void);
extern void vmem_map_init(void);
+extern void fault_init(void);
/*
* The S390 doesn't have any external MMU info: the kernel page
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 2505b2ea0ef..b49d12073f1 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -52,6 +52,19 @@
#define VM_FAULT_BADMAP 0x020000
#define VM_FAULT_BADACCESS 0x040000
+static unsigned long store_indication;
+
+void fault_init(void)
+{
+ unsigned long long facility_list[2];
+
+ if (stfle(facility_list, 2) < 2)
+ return;
+ if ((facility_list[0] & (1ULL << 61)) &&
+ (facility_list[1] & (1ULL << 52)))
+ store_indication = 0xc00;
+}
+
static inline int notify_page_fault(struct pt_regs *regs)
{
int ret = 0;
@@ -294,7 +307,7 @@ static inline int do_exception(struct pt_regs *regs, int access,
struct mm_struct *mm;
struct vm_area_struct *vma;
unsigned long address;
- int fault;
+ int fault, write;
if (notify_page_fault(regs))
return 0;
@@ -348,8 +361,10 @@ static inline int do_exception(struct pt_regs *regs, int access,
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- fault = handle_mm_fault(mm, vma, address,
- (access == VM_WRITE) ? FAULT_FLAG_WRITE : 0);
+ write = (access == VM_WRITE ||
+ (trans_exc_code & store_indication) == 0x400) ?
+ FAULT_FLAG_WRITE : 0;
+ fault = handle_mm_fault(mm, vma, address, write);
if (unlikely(fault & VM_FAULT_ERROR))
goto out_up;
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 852a3fec1ec..bb409332a48 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -124,6 +124,7 @@ void __init paging_init(void)
#endif
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
free_area_init_nodes(max_zone_pfns);
+ fault_init();
}
void __init mem_init(void)