Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc: Add lq/stq emulation

Recent CPUs support quad word load and store instructions. Add
support to the alignment handler for them.

Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

authored by

Anton Blanchard and committed by
Benjamin Herrenschmidt
f83319d7 e28b05e7

+46 -8
+1
arch/powerpc/include/asm/emulated_ops.h
··· 54 54 #ifdef CONFIG_PPC64 55 55 struct ppc_emulated_entry mfdscr; 56 56 struct ppc_emulated_entry mtdscr; 57 + struct ppc_emulated_entry lq_stq; 57 58 #endif 58 59 } ppc_emulated; 59 60
+44 -8
arch/powerpc/kernel/align.c
··· 73 73 { 8, LD+F }, /* 00 0 1001: lfd */ 74 74 { 4, ST+F+S }, /* 00 0 1010: stfs */ 75 75 { 8, ST+F }, /* 00 0 1011: stfd */ 76 - INVALID, /* 00 0 1100 */ 76 + { 16, LD }, /* 00 0 1100: lq */ 77 77 { 8, LD }, /* 00 0 1101: ld/ldu/lwa */ 78 78 INVALID, /* 00 0 1110 */ 79 79 { 8, ST }, /* 00 0 1111: std/stdu */ ··· 140 140 { 2, LD+SW }, /* 10 0 1100: lhbrx */ 141 141 { 4, LD+SE }, /* 10 0 1101 lwa */ 142 142 { 2, ST+SW }, /* 10 0 1110: sthbrx */ 143 - INVALID, /* 10 0 1111 */ 143 + { 16, ST }, /* 10 0 1111: stq */ 144 144 INVALID, /* 10 1 0000 */ 145 145 INVALID, /* 10 1 0001 */ 146 146 INVALID, /* 10 1 0010 */ ··· 385 385 char *ptr1 = (char *) &current->thread.TS_FPR(reg+1); 386 386 int i, ret, sw = 0; 387 387 388 - if (!(flags & F)) 389 - return 0; 390 388 if (reg & 1) 391 389 return 0; /* invalid form: FRS/FRT must be even */ 392 390 if (flags & SW) ··· 403 405 return -EFAULT; 404 406 return 1; /* exception handled and fixed up */ 405 407 } 408 + 409 + #ifdef CONFIG_PPC64 410 + static int emulate_lq_stq(struct pt_regs *regs, unsigned char __user *addr, 411 + unsigned int reg, unsigned int flags) 412 + { 413 + char *ptr0 = (char *)&regs->gpr[reg]; 414 + char *ptr1 = (char *)&regs->gpr[reg+1]; 415 + int i, ret, sw = 0; 416 + 417 + if (reg & 1) 418 + return 0; /* invalid form: GPR must be even */ 419 + if (flags & SW) 420 + sw = 7; 421 + ret = 0; 422 + for (i = 0; i < 8; ++i) { 423 + if (!(flags & ST)) { 424 + ret |= __get_user(ptr0[i^sw], addr + i); 425 + ret |= __get_user(ptr1[i^sw], addr + i + 8); 426 + } else { 427 + ret |= __put_user(ptr0[i^sw], addr + i); 428 + ret |= __put_user(ptr1[i^sw], addr + i + 8); 429 + } 430 + } 431 + if (ret) 432 + return -EFAULT; 433 + return 1; /* exception handled and fixed up */ 434 + } 435 + #endif /* CONFIG_PPC64 */ 406 436 407 437 #ifdef CONFIG_SPE 408 438 ··· 940 914 flush_fp_to_thread(current); 941 915 } 942 916 943 - /* Special case for 16-byte FP loads and stores */ 944 - if (nb == 16) { 945 - PPC_WARN_ALIGNMENT(fp_pair, regs); 946 - return emulate_fp_pair(addr, reg, flags); 917 + if ((nb == 16)) { 918 + if (flags & F) { 919 + /* Special case for 16-byte FP loads and stores */ 920 + PPC_WARN_ALIGNMENT(fp_pair, regs); 921 + return emulate_fp_pair(addr, reg, flags); 922 + } else { 923 + #ifdef CONFIG_PPC64 924 + /* Special case for 16-byte loads and stores */ 925 + PPC_WARN_ALIGNMENT(lq_stq, regs); 926 + return emulate_lq_stq(regs, addr, reg, flags); 927 + #else 928 + return 0; 929 + #endif 930 + } 947 931 } 948 932 949 933 PPC_WARN_ALIGNMENT(unaligned, regs);
+1
arch/powerpc/kernel/traps.c
··· 1868 1868 #ifdef CONFIG_PPC64 1869 1869 WARN_EMULATED_SETUP(mfdscr), 1870 1870 WARN_EMULATED_SETUP(mtdscr), 1871 + WARN_EMULATED_SETUP(lq_stq), 1871 1872 #endif 1872 1873 }; 1873 1874