Skip to content

Commit

Permalink
powerpc: Add lq/stq emulation
Browse files Browse the repository at this point in the history
Recent CPUs support quad word load and store instructions. Add
support to the alignment handler for them.

Signed-off-by: Anton Blanchard <[email protected]>
Signed-off-by: Benjamin Herrenschmidt <[email protected]>
  • Loading branch information
antonblanchard authored and ozbenh committed Apr 9, 2014
1 parent e28b05e commit f83319d
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 8 deletions.
1 change: 1 addition & 0 deletions arch/powerpc/include/asm/emulated_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ extern struct ppc_emulated {
#ifdef CONFIG_PPC64
struct ppc_emulated_entry mfdscr;
struct ppc_emulated_entry mtdscr;
struct ppc_emulated_entry lq_stq;
#endif
} ppc_emulated;

Expand Down
52 changes: 44 additions & 8 deletions arch/powerpc/kernel/align.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ static struct aligninfo aligninfo[128] = {
{ 8, LD+F }, /* 00 0 1001: lfd */
{ 4, ST+F+S }, /* 00 0 1010: stfs */
{ 8, ST+F }, /* 00 0 1011: stfd */
INVALID, /* 00 0 1100 */
{ 16, LD }, /* 00 0 1100: lq */
{ 8, LD }, /* 00 0 1101: ld/ldu/lwa */
INVALID, /* 00 0 1110 */
{ 8, ST }, /* 00 0 1111: std/stdu */
Expand Down Expand Up @@ -140,7 +140,7 @@ static struct aligninfo aligninfo[128] = {
{ 2, LD+SW }, /* 10 0 1100: lhbrx */
{ 4, LD+SE }, /* 10 0 1101 lwa */
{ 2, ST+SW }, /* 10 0 1110: sthbrx */
INVALID, /* 10 0 1111 */
{ 16, ST }, /* 10 0 1111: stq */
INVALID, /* 10 1 0000 */
INVALID, /* 10 1 0001 */
INVALID, /* 10 1 0010 */
Expand Down Expand Up @@ -385,8 +385,6 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
char *ptr1 = (char *) &current->thread.TS_FPR(reg+1);
int i, ret, sw = 0;

if (!(flags & F))
return 0;
if (reg & 1)
return 0; /* invalid form: FRS/FRT must be even */
if (flags & SW)
Expand All @@ -406,6 +404,34 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
return 1; /* exception handled and fixed up */
}

#ifdef CONFIG_PPC64
static int emulate_lq_stq(struct pt_regs *regs, unsigned char __user *addr,
unsigned int reg, unsigned int flags)
{
char *ptr0 = (char *)&regs->gpr[reg];
char *ptr1 = (char *)&regs->gpr[reg+1];
int i, ret, sw = 0;

if (reg & 1)
return 0; /* invalid form: GPR must be even */
if (flags & SW)
sw = 7;
ret = 0;
for (i = 0; i < 8; ++i) {
if (!(flags & ST)) {
ret |= __get_user(ptr0[i^sw], addr + i);
ret |= __get_user(ptr1[i^sw], addr + i + 8);
} else {
ret |= __put_user(ptr0[i^sw], addr + i);
ret |= __put_user(ptr1[i^sw], addr + i + 8);
}
}
if (ret)
return -EFAULT;
return 1; /* exception handled and fixed up */
}
#endif /* CONFIG_PPC64 */

#ifdef CONFIG_SPE

static struct aligninfo spe_aligninfo[32] = {
Expand Down Expand Up @@ -914,10 +940,20 @@ int fix_alignment(struct pt_regs *regs)
flush_fp_to_thread(current);
}

/* Special case for 16-byte FP loads and stores */
if (nb == 16) {
PPC_WARN_ALIGNMENT(fp_pair, regs);
return emulate_fp_pair(addr, reg, flags);
if ((nb == 16)) {
if (flags & F) {
/* Special case for 16-byte FP loads and stores */
PPC_WARN_ALIGNMENT(fp_pair, regs);
return emulate_fp_pair(addr, reg, flags);
} else {
#ifdef CONFIG_PPC64
/* Special case for 16-byte loads and stores */
PPC_WARN_ALIGNMENT(lq_stq, regs);
return emulate_lq_stq(regs, addr, reg, flags);
#else
return 0;
#endif
}
}

PPC_WARN_ALIGNMENT(unaligned, regs);
Expand Down
1 change: 1 addition & 0 deletions arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -1868,6 +1868,7 @@ struct ppc_emulated ppc_emulated = {
#ifdef CONFIG_PPC64
WARN_EMULATED_SETUP(mfdscr),
WARN_EMULATED_SETUP(mtdscr),
WARN_EMULATED_SETUP(lq_stq),
#endif
};

Expand Down

0 comments on commit f83319d

Please sign in to comment.