s390: add support for DCACHE_WORD_ACCESS
authorHeiko Carstens <hca@linux.ibm.com>
Fri, 6 Oct 2023 13:42:42 +0000 (15:42 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Mon, 16 Oct 2023 11:04:09 +0000 (13:04 +0200)
Implement load_unaligned_zeropad() and enable DCACHE_WORD_ACCESS to
speed up string operations in fs/dcache.c and fs/namei.c.

Reviewed-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/Kconfig
arch/s390/include/asm/asm-extable.h
arch/s390/include/asm/word-at-a-time.h
arch/s390/mm/extable.c

index ae29e43..b0d67ac 100644 (file)
@@ -131,6 +131,7 @@ config S390
        select ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP
        select BUILDTIME_TABLE_SORT
        select CLONE_BACKWARDS2
+       select DCACHE_WORD_ACCESS if !KMSAN
        select DMA_OPS if PCI
        select DYNAMIC_FTRACE if FUNCTION_TRACER
        select FUNCTION_ALIGNMENT_8B if CC_IS_GCC
index d1ecc2b..4a6b0a8 100644 (file)
@@ -13,6 +13,7 @@
 #define EX_TYPE_UA_LOAD_MEM    4
 #define EX_TYPE_UA_LOAD_REG    5
 #define EX_TYPE_UA_LOAD_REGPAIR        6
+#define EX_TYPE_ZEROPAD                7
 
 #define EX_DATA_REG_ERR_SHIFT  0
 #define EX_DATA_REG_ERR                GENMASK(3, 0)
@@ -80,4 +81,7 @@
 #define EX_TABLE_UA_LOAD_REGPAIR(_fault, _target, _regerr, _regzero)   \
        __EX_TABLE(__ex_table, _fault, _target, EX_TYPE_UA_LOAD_REGPAIR, _regerr, _regzero, 0)
 
+#define EX_TABLE_ZEROPAD(_fault, _target, _regdata, _regaddr)          \
+       __EX_TABLE(__ex_table, _fault, _target, EX_TYPE_ZEROPAD, _regdata, _regaddr, 0)
+
 #endif /* __ASM_EXTABLE_H */
index 09b3754..2579f16 100644 (file)
@@ -3,6 +3,7 @@
 #define _ASM_WORD_AT_A_TIME_H
 
 #include <linux/kernel.h>
+#include <asm/asm-extable.h>
 #include <asm/bitsperlong.h>
 
 struct word_at_a_time {
@@ -39,4 +40,25 @@ static inline unsigned long zero_bytemask(unsigned long data)
        return ~1UL << data;
 }
 
+/*
+ * Load an unaligned word from kernel space.
+ *
+ * In the (very unlikely) case of the word being a page-crosser
+ * and the next page not being mapped, take the exception and
+ * return zeroes in the non-existing part.
+ */
+static inline unsigned long load_unaligned_zeropad(const void *addr)
+{
+       unsigned long data;
+
+       asm volatile(
+               "0:     lg      %[data],0(%[addr])\n"
+               "1:     nopr    %%r7\n"
+               EX_TABLE_ZEROPAD(0b, 1b, %[data], %[addr])
+               EX_TABLE_ZEROPAD(1b, 1b, %[data], %[addr])
+               : [data] "=d" (data)
+               : [addr] "a" (addr), "m" (*(unsigned long *)addr));
+       return data;
+}
+
 #endif /* _ASM_WORD_AT_A_TIME_H */
index fe87291..0a0738a 100644 (file)
@@ -61,6 +61,22 @@ static bool ex_handler_ua_load_reg(const struct exception_table_entry *ex,
        return true;
 }
 
+static bool ex_handler_zeropad(const struct exception_table_entry *ex, struct pt_regs *regs)
+{
+       unsigned int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data);
+       unsigned int reg_data = FIELD_GET(EX_DATA_REG_ERR, ex->data);
+       unsigned long data, addr, offset;
+
+       addr = regs->gprs[reg_addr];
+       offset = addr & (sizeof(unsigned long) - 1);
+       addr &= ~(sizeof(unsigned long) - 1);
+       data = *(unsigned long *)addr;
+       data <<= BITS_PER_BYTE * offset;
+       regs->gprs[reg_data] = data;
+       regs->psw.addr = extable_fixup(ex);
+       return true;
+}
+
 bool fixup_exception(struct pt_regs *regs)
 {
        const struct exception_table_entry *ex;
@@ -81,6 +97,8 @@ bool fixup_exception(struct pt_regs *regs)
                return ex_handler_ua_load_reg(ex, false, regs);
        case EX_TYPE_UA_LOAD_REGPAIR:
                return ex_handler_ua_load_reg(ex, true, regs);
+       case EX_TYPE_ZEROPAD:
+               return ex_handler_zeropad(ex, regs);
        }
        panic("invalid exception table entry");
 }