Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f83319d7 authored by Anton Blanchard's avatar Anton Blanchard Committed by Benjamin Herrenschmidt
Browse files

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: default avatarAnton Blanchard <anton@samba.org>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent e28b05e7
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -54,6 +54,7 @@ extern struct ppc_emulated {
#ifdef CONFIG_PPC64
#ifdef CONFIG_PPC64
	struct ppc_emulated_entry mfdscr;
	struct ppc_emulated_entry mfdscr;
	struct ppc_emulated_entry mtdscr;
	struct ppc_emulated_entry mtdscr;
	struct ppc_emulated_entry lq_stq;
#endif
#endif
} ppc_emulated;
} ppc_emulated;


+44 −8
Original line number Original line Diff line number Diff line
@@ -73,7 +73,7 @@ static struct aligninfo aligninfo[128] = {
	{ 8, LD+F },		/* 00 0 1001: lfd */
	{ 8, LD+F },		/* 00 0 1001: lfd */
	{ 4, ST+F+S },		/* 00 0 1010: stfs */
	{ 4, ST+F+S },		/* 00 0 1010: stfs */
	{ 8, ST+F },		/* 00 0 1011: stfd */
	{ 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 */
	{ 8, LD },		/* 00 0 1101: ld/ldu/lwa */
	INVALID,		/* 00 0 1110 */
	INVALID,		/* 00 0 1110 */
	{ 8, ST },		/* 00 0 1111: std/stdu */
	{ 8, ST },		/* 00 0 1111: std/stdu */
@@ -140,7 +140,7 @@ static struct aligninfo aligninfo[128] = {
	{ 2, LD+SW },		/* 10 0 1100: lhbrx */
	{ 2, LD+SW },		/* 10 0 1100: lhbrx */
	{ 4, LD+SE },		/* 10 0 1101  lwa */
	{ 4, LD+SE },		/* 10 0 1101  lwa */
	{ 2, ST+SW },		/* 10 0 1110: sthbrx */
	{ 2, ST+SW },		/* 10 0 1110: sthbrx */
	INVALID,		/* 10 0 1111 */
	{ 16, ST },		/* 10 0 1111: stq */
	INVALID,		/* 10 1 0000 */
	INVALID,		/* 10 1 0000 */
	INVALID,		/* 10 1 0001 */
	INVALID,		/* 10 1 0001 */
	INVALID,		/* 10 1 0010 */
	INVALID,		/* 10 1 0010 */
@@ -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);
	char *ptr1 = (char *) &current->thread.TS_FPR(reg+1);
	int i, ret, sw = 0;
	int i, ret, sw = 0;


	if (!(flags & F))
		return 0;
	if (reg & 1)
	if (reg & 1)
		return 0;	/* invalid form: FRS/FRT must be even */
		return 0;	/* invalid form: FRS/FRT must be even */
	if (flags & SW)
	if (flags & SW)
@@ -406,6 +404,34 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
	return 1;	/* exception handled and fixed up */
	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
#ifdef CONFIG_SPE


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


	if ((nb == 16)) {
		if (flags & F) {
			/* Special case for 16-byte FP loads and stores */
			/* Special case for 16-byte FP loads and stores */
	if (nb == 16) {
			PPC_WARN_ALIGNMENT(fp_pair, regs);
			PPC_WARN_ALIGNMENT(fp_pair, regs);
			return emulate_fp_pair(addr, reg, flags);
			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);
	PPC_WARN_ALIGNMENT(unaligned, regs);
+1 −0
Original line number Original line Diff line number Diff line
@@ -1868,6 +1868,7 @@ struct ppc_emulated ppc_emulated = {
#ifdef CONFIG_PPC64
#ifdef CONFIG_PPC64
	WARN_EMULATED_SETUP(mfdscr),
	WARN_EMULATED_SETUP(mfdscr),
	WARN_EMULATED_SETUP(mtdscr),
	WARN_EMULATED_SETUP(mtdscr),
	WARN_EMULATED_SETUP(lq_stq),
#endif
#endif
};
};