summaryrefslogtreecommitdiffstats
path: root/arch/blackfin/lib/ins.S
diff options
context:
space:
mode:
authorRobin Getz <rgetz@blackfin.uclinux.org>2008-08-14 15:12:55 +0800
committerBryan Wu <cooloney@kernel.org>2008-08-14 15:12:55 +0800
commit251383c7c50cf17664a4d7d60d3a52d8827a0e11 (patch)
treef4b8368ddfe748040b80762bfd01d08b7e635bc4 /arch/blackfin/lib/ins.S
parentcd8fb8df1458df7f3b99fd112e722b05f42c64d9 (diff)
downloadblackbird-op-linux-251383c7c50cf17664a4d7d60d3a52d8827a0e11.tar.gz
blackbird-op-linux-251383c7c50cf17664a4d7d60d3a52d8827a0e11.zip
Blackfin arch: Allow ins functions to have a low latency version
Signed-off-by: Robin Getz <rgetz@blackfin.uclinux.org> Signed-off-by: Bryan Wu <cooloney@kernel.org>
Diffstat (limited to 'arch/blackfin/lib/ins.S')
-rw-r--r--arch/blackfin/lib/ins.S109
1 files changed, 109 insertions, 0 deletions
diff --git a/arch/blackfin/lib/ins.S b/arch/blackfin/lib/ins.S
index eba2343b1b59..d60554dce87b 100644
--- a/arch/blackfin/lib/ins.S
+++ b/arch/blackfin/lib/ins.S
@@ -33,7 +33,28 @@
.align 2
+/*
+ * 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 transfering large
+ * buffers in/out of FIFOs.
+ */
+
ENTRY(_insl)
+#ifdef CONFIG_BFIN_INS_LOWOVERHEAD
P0 = R0; /* P0 = port */
cli R3;
P1 = R1; /* P1 = address */
@@ -46,9 +67,26 @@ ENTRY(_insl)
.Llong_loop_e: NOP;
sti R3;
RTS;
+#else
+ P0 = R0; /* P0 = port */
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+ SSYNC;
+ LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
+.Llong_loop_s:
+ CLI R3;
+ NOP; NOP; NOP;
+ R0 = [P0];
+ [P1++] = R0;
+.Llong_loop_e:
+ STI R3;
+
+ RTS;
+#endif
ENDPROC(_insl)
ENTRY(_insw)
+#ifdef CONFIG_BFIN_INS_LOWOVERHEAD
P0 = R0; /* P0 = port */
cli R3;
P1 = R1; /* P1 = address */
@@ -61,9 +99,26 @@ ENTRY(_insw)
.Lword_loop_e: NOP;
sti R3;
RTS;
+#else
+ P0 = R0; /* P0 = port */
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+ SSYNC;
+ LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
+.Lword_loop_s:
+ CLI R3;
+ NOP; NOP; NOP;
+ R0 = W[P0];
+ W[P1++] = R0;
+.Lword_loop_e:
+ STI R3;
+ RTS;
+
+#endif
ENDPROC(_insw)
ENTRY(_insw_8)
+#ifdef CONFIG_BFIN_INS_LOWOVERHEAD
P0 = R0; /* P0 = port */
cli R3;
P1 = R1; /* P1 = address */
@@ -78,9 +133,29 @@ ENTRY(_insw_8)
.Lword8_loop_e: NOP;
sti R3;
RTS;
+#else
+ P0 = R0; /* P0 = port */
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+ SSYNC;
+ LSETUP( .Lword8_loop_s, .Lword8_loop_e) LC0 = P2;
+.Lword8_loop_s:
+ CLI R3;
+ NOP; NOP; NOP;
+ R0 = W[P0];
+ B[P1++] = R0;
+ R0 = R0 >> 8;
+ B[P1++] = R0;
+ NOP;
+.Lword8_loop_e:
+ STI R3;
+
+ RTS;
+#endif
ENDPROC(_insw_8)
ENTRY(_insb)
+#ifdef CONFIG_BFIN_INS_LOWOVERHEAD
P0 = R0; /* P0 = port */
cli R3;
P1 = R1; /* P1 = address */
@@ -93,9 +168,26 @@ ENTRY(_insb)
.Lbyte_loop_e: NOP;
sti R3;
RTS;
+#else
+ P0 = R0; /* P0 = port */
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+ SSYNC;
+ LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
+.Lbyte_loop_s:
+ CLI R3;
+ NOP; NOP; NOP;
+ R0 = B[P0];
+ B[P1++] = R0;
+.Lbyte_loop_e:
+ STI R3;
+
+ RTS;
+#endif
ENDPROC(_insb)
ENTRY(_insl_16)
+#ifdef CONFIG_BFIN_INS_LOWOVERHEAD
P0 = R0; /* P0 = port */
cli R3;
P1 = R1; /* P1 = address */
@@ -110,4 +202,21 @@ ENTRY(_insl_16)
.Llong16_loop_e: NOP;
sti R3;
RTS;
+#else
+ P0 = R0; /* P0 = port */
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+ SSYNC;
+ LSETUP( .Llong16_loop_s, .Llong16_loop_e) LC0 = P2;
+.Llong16_loop_s:
+ CLI R3;
+ NOP; NOP; NOP;
+ R0 = [P0];
+ W[P1++] = R0;
+ R0 = R0 >> 16;
+ W[P1++] = R0;
+.Llong16_loop_e:
+ STI R3;
+ RTS;
+#endif
ENDPROC(_insl_16)
OpenPOWER on IntegriCloud