[S390] store indication fault optimization
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 25 Oct 2010 14:10:13 +0000 (16:10 +0200)
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>
Mon, 25 Oct 2010 14:10:15 +0000 (16:10 +0200)
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>
arch/s390/include/asm/pgtable.h
arch/s390/mm/fault.c
arch/s390/mm/init.c

index 785229ae39cba424fd523feb556c2c54123ab498..85cd4b039de6b90e998185566e8b2f0c78252ac9 100644 (file)
@@ -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
index 2505b2ea0ef187803033c096bab3cff8eac45f02..b49d12073f1046b062876ae2a79edc0faa8c3940 100644 (file)
 #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;
 
index 852a3fec1ecef7b493fb5c64dd19a8a8155f7202..bb409332a484add0f68a1c20734d81968273f0e6 100644 (file)
@@ -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)