diff options
author | Anton Blanchard <anton@samba.org> | 2014-03-28 02:01:23 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-04-08 22:53:28 -0400 |
commit | f83319d71002aec03bd87bc9aabce5f549680f0a (patch) | |
tree | b028e016fe0eaf36809700798fd7d9b05698b299 | |
parent | e28b05e7ae8ba09e030ffe891ba154df5791cb76 (diff) |
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>
-rw-r--r-- | arch/powerpc/include/asm/emulated_ops.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/align.c | 52 | ||||
-rw-r--r-- | arch/powerpc/kernel/traps.c | 1 |
3 files changed, 46 insertions, 8 deletions
diff --git a/arch/powerpc/include/asm/emulated_ops.h b/arch/powerpc/include/asm/emulated_ops.h index 4358e3002f35..f00e10e2a335 100644 --- a/arch/powerpc/include/asm/emulated_ops.h +++ b/arch/powerpc/include/asm/emulated_ops.h | |||
@@ -54,6 +54,7 @@ extern struct ppc_emulated { | |||
54 | #ifdef CONFIG_PPC64 | 54 | #ifdef CONFIG_PPC64 |
55 | struct ppc_emulated_entry mfdscr; | 55 | struct ppc_emulated_entry mfdscr; |
56 | struct ppc_emulated_entry mtdscr; | 56 | struct ppc_emulated_entry mtdscr; |
57 | struct ppc_emulated_entry lq_stq; | ||
57 | #endif | 58 | #endif |
58 | } ppc_emulated; | 59 | } ppc_emulated; |
59 | 60 | ||
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index de91f3ae631e..94908af308d8 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c | |||
@@ -73,7 +73,7 @@ static struct aligninfo aligninfo[128] = { | |||
73 | { 8, LD+F }, /* 00 0 1001: lfd */ | 73 | { 8, LD+F }, /* 00 0 1001: lfd */ |
74 | { 4, ST+F+S }, /* 00 0 1010: stfs */ | 74 | { 4, ST+F+S }, /* 00 0 1010: stfs */ |
75 | { 8, ST+F }, /* 00 0 1011: stfd */ | 75 | { 8, ST+F }, /* 00 0 1011: stfd */ |
76 | INVALID, /* 00 0 1100 */ | 76 | { 16, LD }, /* 00 0 1100: lq */ |
77 | { 8, LD }, /* 00 0 1101: ld/ldu/lwa */ | 77 | { 8, LD }, /* 00 0 1101: ld/ldu/lwa */ |
78 | INVALID, /* 00 0 1110 */ | 78 | INVALID, /* 00 0 1110 */ |
79 | { 8, ST }, /* 00 0 1111: std/stdu */ | 79 | { 8, ST }, /* 00 0 1111: std/stdu */ |
@@ -140,7 +140,7 @@ static struct aligninfo aligninfo[128] = { | |||
140 | { 2, LD+SW }, /* 10 0 1100: lhbrx */ | 140 | { 2, LD+SW }, /* 10 0 1100: lhbrx */ |
141 | { 4, LD+SE }, /* 10 0 1101 lwa */ | 141 | { 4, LD+SE }, /* 10 0 1101 lwa */ |
142 | { 2, ST+SW }, /* 10 0 1110: sthbrx */ | 142 | { 2, ST+SW }, /* 10 0 1110: sthbrx */ |
143 | INVALID, /* 10 0 1111 */ | 143 | { 16, ST }, /* 10 0 1111: stq */ |
144 | INVALID, /* 10 1 0000 */ | 144 | INVALID, /* 10 1 0000 */ |
145 | INVALID, /* 10 1 0001 */ | 145 | INVALID, /* 10 1 0001 */ |
146 | INVALID, /* 10 1 0010 */ | 146 | INVALID, /* 10 1 0010 */ |
@@ -385,8 +385,6 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg, | |||
385 | char *ptr1 = (char *) ¤t->thread.TS_FPR(reg+1); | 385 | char *ptr1 = (char *) ¤t->thread.TS_FPR(reg+1); |
386 | int i, ret, sw = 0; | 386 | int i, ret, sw = 0; |
387 | 387 | ||
388 | if (!(flags & F)) | ||
389 | return 0; | ||
390 | if (reg & 1) | 388 | if (reg & 1) |
391 | return 0; /* invalid form: FRS/FRT must be even */ | 389 | return 0; /* invalid form: FRS/FRT must be even */ |
392 | if (flags & SW) | 390 | if (flags & SW) |
@@ -406,6 +404,34 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg, | |||
406 | return 1; /* exception handled and fixed up */ | 404 | return 1; /* exception handled and fixed up */ |
407 | } | 405 | } |
408 | 406 | ||
407 | #ifdef CONFIG_PPC64 | ||
408 | static int emulate_lq_stq(struct pt_regs *regs, unsigned char __user *addr, | ||
409 | unsigned int reg, unsigned int flags) | ||
410 | { | ||
411 | char *ptr0 = (char *)®s->gpr[reg]; | ||
412 | char *ptr1 = (char *)®s->gpr[reg+1]; | ||
413 | int i, ret, sw = 0; | ||
414 | |||
415 | if (reg & 1) | ||
416 | return 0; /* invalid form: GPR must be even */ | ||
417 | if (flags & SW) | ||
418 | sw = 7; | ||
419 | ret = 0; | ||
420 | for (i = 0; i < 8; ++i) { | ||
421 | if (!(flags & ST)) { | ||
422 | ret |= __get_user(ptr0[i^sw], addr + i); | ||
423 | ret |= __get_user(ptr1[i^sw], addr + i + 8); | ||
424 | } else { | ||
425 | ret |= __put_user(ptr0[i^sw], addr + i); | ||
426 | ret |= __put_user(ptr1[i^sw], addr + i + 8); | ||
427 | } | ||
428 | } | ||
429 | if (ret) | ||
430 | return -EFAULT; | ||
431 | return 1; /* exception handled and fixed up */ | ||
432 | } | ||
433 | #endif /* CONFIG_PPC64 */ | ||
434 | |||
409 | #ifdef CONFIG_SPE | 435 | #ifdef CONFIG_SPE |
410 | 436 | ||
411 | static struct aligninfo spe_aligninfo[32] = { | 437 | static struct aligninfo spe_aligninfo[32] = { |
@@ -914,10 +940,20 @@ int fix_alignment(struct pt_regs *regs) | |||
914 | flush_fp_to_thread(current); | 940 | flush_fp_to_thread(current); |
915 | } | 941 | } |
916 | 942 | ||
917 | /* Special case for 16-byte FP loads and stores */ | 943 | if ((nb == 16)) { |
918 | if (nb == 16) { | 944 | if (flags & F) { |
919 | PPC_WARN_ALIGNMENT(fp_pair, regs); | 945 | /* Special case for 16-byte FP loads and stores */ |
920 | return emulate_fp_pair(addr, reg, flags); | 946 | PPC_WARN_ALIGNMENT(fp_pair, regs); |
947 | return emulate_fp_pair(addr, reg, flags); | ||
948 | } else { | ||
949 | #ifdef CONFIG_PPC64 | ||
950 | /* Special case for 16-byte loads and stores */ | ||
951 | PPC_WARN_ALIGNMENT(lq_stq, regs); | ||
952 | return emulate_lq_stq(regs, addr, reg, flags); | ||
953 | #else | ||
954 | return 0; | ||
955 | #endif | ||
956 | } | ||
921 | } | 957 | } |
922 | 958 | ||
923 | PPC_WARN_ALIGNMENT(unaligned, regs); | 959 | PPC_WARN_ALIGNMENT(unaligned, regs); |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index df86f0ce2d36..1bd7ca298fa1 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -1868,6 +1868,7 @@ struct ppc_emulated ppc_emulated = { | |||
1868 | #ifdef CONFIG_PPC64 | 1868 | #ifdef CONFIG_PPC64 |
1869 | WARN_EMULATED_SETUP(mfdscr), | 1869 | WARN_EMULATED_SETUP(mfdscr), |
1870 | WARN_EMULATED_SETUP(mtdscr), | 1870 | WARN_EMULATED_SETUP(mtdscr), |
1871 | WARN_EMULATED_SETUP(lq_stq), | ||
1871 | #endif | 1872 | #endif |
1872 | }; | 1873 | }; |
1873 | 1874 | ||