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

Commit 9e83b98a authored by Mike Frysinger's avatar Mike Frysinger Committed by Bryan Wu
Browse files

Blackfin arch: add support for working around anomaly 05000312



Anomaly 05000312 - Errors When SSYNC, CSYNC, or Loads to LT, LB and LC Registers Are Interrupted:

DESCRIPTION:
When instruction cache is enabled, erroneous behavior may occur when any of the following instructions are interrupted:

. CSYNC
• SSYNC
• LCx =
• LTx = (only when LCx is non-zero)
• LBx = (only when LCx is non-zero)

When this problem occurs, a variety of incorrect things could happen, including an illegal instruction exception. Additional errors could
show up as an exception, a hardware error, or an instruction that is valid but different than the one that was expected.

WORKAROUND:
Place a cli before all SSYNC, CSYNC, "LCx =", "LTx =", and "LBx =" instructions to disable interrupts, and place an sti after each of these
instructions to re-enable interrupts. When these instructions are executed in code that is already non-interruptible, the problem will not
occur.

Signed-off-by: default avatarMike Frysinger <michael.frysinger@analog.com>
Signed-off-by: default avatarBryan Wu <bryan.wu@analog.com>
parent b5f87aa4
Loading
Loading
Loading
Loading
+42 −24
Original line number Diff line number Diff line
#ifndef _BLACKFIN_DELAY_H
#define _BLACKFIN_DELAY_H
/*
 * delay.h - delay functions
 *
 * Copyright (c) 2004-2007 Analog Devices Inc.
 *
 * Licensed under the GPL-2 or later.
 */

static inline void __delay(unsigned long loops)
{
#ifndef __ASM_DELAY_H__
#define __ASM_DELAY_H__

/* FIXME: Currently the assembler doesn't recognize Loop Register Clobbers,
   uncomment this as soon those are implemented */
/*
      __asm__ __volatile__ (  "\t LSETUP (1f,1f) LC0= %0\n\t"
                              "1:\t NOP;\n\t"
                              : :"a" (loops)
                              : "LT0","LB0","LC0");
#include <asm/mach/anomaly.h>

static inline void __delay(unsigned long loops)
{
	if (ANOMALY_05000312) {
		/* Interrupted loads to loop registers -> bad */
		unsigned long tmp;
		__asm__ __volatile__(
			"[--SP] = LC0;"
			"[--SP] = LT0;"
			"[--SP] = LB0;"
			"LSETUP (1f,1f) LC0 = %1;"
			"1: NOP;"
			/* We take advantage of the fact that LC0 is 0 at
			 * the end of the loop.  Otherwise we'd need some
			 * NOPs after the CLI here.
			 */

	__asm__ __volatile__("[--SP] = LC0;\n\t"
			     "[--SP] = LT0;\n\t"
			     "[--SP] = LB0;\n\t"
			     "LSETUP (1f,1f) LC0 = %0;\n\t"
			     "1:\t NOP;\n\t"
			     "LB0 = [SP++];\n\t"
				"LT0 = [SP++];\n\t"
				"LC0 = [SP++];\n"
			"CLI %0;"
			"LB0 = [SP++];"
			"LT0 = [SP++];"
			"LC0 = [SP++];"
			"STI %0;"
			: "=d" (tmp)
			: "a" (loops)
		);
	} else
		__asm__ __volatile__ (
			"LSETUP(1f, 1f) LC0 = %0;"
			"1: NOP;"
			:
				:"a" (loops));
			: "a" (loops)
			: "LT0", "LB0", "LC0"
		);
}

#include <linux/param.h>	/* needed for HZ */
@@ -41,4 +59,4 @@ static inline void udelay(unsigned long usecs)
	__delay(usecs * loops_per_jiffy / (1000000 / HZ));
}

#endif				/* defined(_BLACKFIN_DELAY_H) */
#endif