| /* | 
 |  * arch/blackfin/lib/ins.S - ins{bwl} using hardware loops | 
 |  * | 
 |  * Copyright 2004-2008 Analog Devices Inc. | 
 |  * Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl> | 
 |  * Licensed under the GPL-2 or later. | 
 |  */ | 
 |  | 
 | #include <linux/linkage.h> | 
 | #include <asm/blackfin.h> | 
 |  | 
 | .align 2 | 
 |  | 
 | #ifdef CONFIG_IPIPE | 
 | # define DO_CLI \ | 
 | 	[--sp] = rets; \ | 
 | 	[--sp] = (P5:0); \ | 
 | 	sp += -12; \ | 
 | 	call ___ipipe_disable_root_irqs_hw; \ | 
 | 	sp += 12; \ | 
 | 	(P5:0) = [sp++]; | 
 | # define CLI_INNER_NOP | 
 | #else | 
 | # define DO_CLI cli R3; | 
 | # define CLI_INNER_NOP nop; nop; nop; | 
 | #endif | 
 |  | 
 | #ifdef CONFIG_IPIPE | 
 | # define DO_STI \ | 
 | 	sp += -12; \ | 
 | 	call ___ipipe_enable_root_irqs_hw; \ | 
 | 	sp += 12; \ | 
 | 2:	rets = [sp++]; | 
 | #else | 
 | # define DO_STI 2: sti R3; | 
 | #endif | 
 |  | 
 | #ifdef CONFIG_BFIN_INS_LOWOVERHEAD | 
 | # define CLI_OUTER DO_CLI; | 
 | # define STI_OUTER DO_STI; | 
 | # define CLI_INNER 1: | 
 | # if ANOMALY_05000416 | 
 | #  define STI_INNER nop; 2: nop; | 
 | # else | 
 | #  define STI_INNER 2: | 
 | # endif | 
 | #else | 
 | # define CLI_OUTER | 
 | # define STI_OUTER | 
 | # define CLI_INNER 1: DO_CLI; CLI_INNER_NOP; | 
 | # define STI_INNER DO_STI; | 
 | #endif | 
 |  | 
 | /* | 
 |  * Reads on the Blackfin are speculative. In Blackfin terms, this means they | 
 |  * can be interrupted at any time (even after they have been issued on to the | 
 |  * external bus), and re-issued after the interrupt occurs. | 
 |  * | 
 |  * If a FIFO is sitting on the end of the read, it will see two reads, | 
 |  * when the core only sees one. The FIFO receives the read which is cancelled, | 
 |  * and not delivered to the core. | 
 |  * | 
 |  * To solve this, interrupts are turned off before reads occur to I/O space. | 
 |  * There are 3 versions of all these functions | 
 |  *  - turns interrupts off every read (higher overhead, but lower latency) | 
 |  *  - turns interrupts off every loop (low overhead, but longer latency) | 
 |  *  - DMA version, which do not suffer from this issue. DMA versions have | 
 |  *      different name (prefixed by dma_ ), and are located in | 
 |  *      ../kernel/bfin_dma_5xx.c | 
 |  * Using the dma related functions are recommended for transferring large | 
 |  * buffers in/out of FIFOs. | 
 |  */ | 
 |  | 
 | #define COMMON_INS(func, ops) \ | 
 | ENTRY(_ins##func) \ | 
 | 	P0 = R0;	/* P0 = port */ \ | 
 | 	CLI_OUTER;	/* 3 instructions before first read access */ \ | 
 | 	P1 = R1;	/* P1 = address */ \ | 
 | 	P2 = R2;	/* P2 = count */ \ | 
 | 	SSYNC; \ | 
 |  \ | 
 | 	LSETUP(1f, 2f) LC0 = P2; \ | 
 | 	CLI_INNER; \ | 
 | 	ops; \ | 
 | 	STI_INNER; \ | 
 |  \ | 
 | 	STI_OUTER; \ | 
 | 	RTS; \ | 
 | ENDPROC(_ins##func) | 
 |  | 
 | COMMON_INS(l, \ | 
 | 	R0 = [P0]; \ | 
 | 	[P1++] = R0; \ | 
 | ) | 
 |  | 
 | COMMON_INS(w, \ | 
 | 	R0 = W[P0]; \ | 
 | 	W[P1++] = R0; \ | 
 | ) | 
 |  | 
 | COMMON_INS(w_8, \ | 
 | 	R0 = W[P0]; \ | 
 | 	B[P1++] = R0; \ | 
 | 	R0 = R0 >> 8; \ | 
 | 	B[P1++] = R0; \ | 
 | ) | 
 |  | 
 | COMMON_INS(b, \ | 
 | 	R0 = B[P0]; \ | 
 | 	B[P1++] = R0; \ | 
 | ) | 
 |  | 
 | COMMON_INS(l_16, \ | 
 | 	R0 = [P0]; \ | 
 | 	W[P1++] = R0; \ | 
 | 	R0 = R0 >> 16; \ | 
 | 	W[P1++] = R0; \ | 
 | ) |