aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-11-30 23:15:58 -0500
committerDavid S. Miller <davem@davemloft.net>2010-11-30 23:15:58 -0500
commit595a251c0740785fd3c0d2156d78578c7479811e (patch)
tree513cee9d682b12c2c4e490f7e91422e82530c4b8
parent12c7a35ee6a1c605e740733f2cbd5b5079f09f0f (diff)
sparc: Write to prom console using indirect buffer.
sparc64 systems have a restriction in that passing in buffer addressses above 4GB to prom calls is not reliable. We end up violating this when we do prom console writes, because we use an on-stack buffer to translate '\n' into '\r\n'. So instead, do this translation into an intermediate buffer, which is in the kernel image and thus below 4GB, then pass that to the PROM console write calls. On the 32-bit side we don't have to deal with any of these issues, so the new prom_console_write_buf() uses the existing prom_nbputchar() implementation. However we can now mark those routines static. Since the 64-bit side completely uses new code we can delete the putchar bits as they are now completely unused. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc/include/asm/oplib_32.h4
-rw-r--r--arch/sparc/include/asm/oplib_64.h4
-rw-r--r--arch/sparc/prom/console_32.c14
-rw-r--r--arch/sparc/prom/console_64.c27
-rw-r--r--arch/sparc/prom/printf.c32
5 files changed, 52 insertions, 29 deletions
diff --git a/arch/sparc/include/asm/oplib_32.h b/arch/sparc/include/asm/oplib_32.h
index 40bc9efb1ac4..9e5c64084b86 100644
--- a/arch/sparc/include/asm/oplib_32.h
+++ b/arch/sparc/include/asm/oplib_32.h
@@ -102,8 +102,8 @@ extern int prom_getrev(void);
102/* Get the prom firmware revision. */ 102/* Get the prom firmware revision. */
103extern int prom_getprev(void); 103extern int prom_getprev(void);
104 104
105/* Blocking put character to console. */ 105/* Write a buffer of characters to the console. */
106extern void prom_putchar(const char *buf); 106extern void prom_console_write_buf(const char *buf, int len);
107 107
108/* Prom's internal routines, don't use in kernel/boot code. */ 108/* Prom's internal routines, don't use in kernel/boot code. */
109extern void prom_printf(const char *fmt, ...); 109extern void prom_printf(const char *fmt, ...);
diff --git a/arch/sparc/include/asm/oplib_64.h b/arch/sparc/include/asm/oplib_64.h
index d4613738c537..8cd0df34e82b 100644
--- a/arch/sparc/include/asm/oplib_64.h
+++ b/arch/sparc/include/asm/oplib_64.h
@@ -94,8 +94,8 @@ extern void prom_halt_power_off(void) __attribute__ ((noreturn));
94 */ 94 */
95extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size); 95extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size);
96 96
97/* Blocking put character to console. */ 97/* Write a buffer of characters to the console. */
98extern void prom_putchar(const char *buf); 98extern void prom_console_write_buf(const char *buf, int len);
99 99
100/* Prom's internal routines, don't use in kernel/boot code. */ 100/* Prom's internal routines, don't use in kernel/boot code. */
101extern void prom_printf(const char *fmt, ...); 101extern void prom_printf(const char *fmt, ...);
diff --git a/arch/sparc/prom/console_32.c b/arch/sparc/prom/console_32.c
index 157019e29fd4..48863108a44c 100644
--- a/arch/sparc/prom/console_32.c
+++ b/arch/sparc/prom/console_32.c
@@ -43,12 +43,14 @@ static int prom_nbputchar(const char *buf)
43 return i; /* Ugh, we could spin forever on unsupported proms ;( */ 43 return i; /* Ugh, we could spin forever on unsupported proms ;( */
44} 44}
45 45
46/* Blocking version of put character routine above. */ 46void prom_console_write_buf(const char *buf, int len)
47void prom_putchar(const char *buf)
48{ 47{
49 while (1) { 48 while (len) {
50 int err = prom_nbputchar(buf); 49 int n = prom_nbputchar(buf);
51 if (!err) 50 if (n)
52 break; 51 continue;
52 len--;
53 buf++;
53 } 54 }
54} 55}
56
diff --git a/arch/sparc/prom/console_64.c b/arch/sparc/prom/console_64.c
index 0da88d10beff..ed39e75828bd 100644
--- a/arch/sparc/prom/console_64.c
+++ b/arch/sparc/prom/console_64.c
@@ -15,35 +15,34 @@
15 15
16extern int prom_stdin, prom_stdout; 16extern int prom_stdin, prom_stdout;
17 17
18/* Non blocking put character to console device, returns -1 if 18static int __prom_console_write_buf(const char *buf, int len)
19 * unsuccessful.
20 */
21static int prom_nbputchar(const char *buf)
22{ 19{
23 unsigned long args[7]; 20 unsigned long args[7];
21 int ret;
24 22
25 args[0] = (unsigned long) "write"; 23 args[0] = (unsigned long) "write";
26 args[1] = 3; 24 args[1] = 3;
27 args[2] = 1; 25 args[2] = 1;
28 args[3] = (unsigned int) prom_stdout; 26 args[3] = (unsigned int) prom_stdout;
29 args[4] = (unsigned long) buf; 27 args[4] = (unsigned long) buf;
30 args[5] = 1; 28 args[5] = (unsigned int) len;
31 args[6] = (unsigned long) -1; 29 args[6] = (unsigned long) -1;
32 30
33 p1275_cmd_direct(args); 31 p1275_cmd_direct(args);
34 32
35 if (args[6] == 1) 33 ret = (int) args[6];
36 return 0; 34 if (ret < 0)
37 else
38 return -1; 35 return -1;
36 return ret;
39} 37}
40 38
41/* Blocking version of put character routine above. */ 39void prom_console_write_buf(const char *buf, int len)
42void prom_putchar(const char *buf)
43{ 40{
44 while (1) { 41 while (len) {
45 int err = prom_nbputchar(buf); 42 int n = __prom_console_write_buf(buf, len);
46 if (!err) 43 if (n < 0)
47 break; 44 continue;
45 len -= n;
46 buf += len;
48 } 47 }
49} 48}
diff --git a/arch/sparc/prom/printf.c b/arch/sparc/prom/printf.c
index 24031971f806..d9682f06b3b0 100644
--- a/arch/sparc/prom/printf.c
+++ b/arch/sparc/prom/printf.c
@@ -15,23 +15,45 @@
15 15
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/compiler.h> 17#include <linux/compiler.h>
18#include <linux/spinlock.h>
18 19
19#include <asm/openprom.h> 20#include <asm/openprom.h>
20#include <asm/oplib.h> 21#include <asm/oplib.h>
21 22
23#define CONSOLE_WRITE_BUF_SIZE 1024
24
22static char ppbuf[1024]; 25static char ppbuf[1024];
26static char console_write_buf[CONSOLE_WRITE_BUF_SIZE];
27static DEFINE_RAW_SPINLOCK(console_write_lock);
23 28
24void notrace prom_write(const char *buf, unsigned int n) 29void notrace prom_write(const char *buf, unsigned int n)
25{ 30{
31 unsigned int dest_len;
32 unsigned long flags;
33 char *dest;
34
35 dest = console_write_buf;
36 raw_spin_lock_irqsave(&console_write_lock, flags);
37
38 dest_len = 0;
26 while (n-- != 0) { 39 while (n-- != 0) {
27 char ch = *buf; 40 char ch = *buf++;
28 if (ch == '\n') { 41 if (ch == '\n') {
29 char tmp = '\r'; 42 *dest++ = '\r';
30 prom_putchar(&tmp); 43 dest_len++;
44 }
45 *dest++ = ch;
46 dest_len++;
47 if (dest_len >= CONSOLE_WRITE_BUF_SIZE - 1) {
48 prom_console_write_buf(console_write_buf, dest_len);
49 dest = console_write_buf;
50 dest_len = 0;
31 } 51 }
32 prom_putchar(buf);
33 buf++;
34 } 52 }
53 if (dest_len)
54 prom_console_write_buf(console_write_buf, dest_len);
55
56 raw_spin_unlock_irqrestore(&console_write_lock, flags);
35} 57}
36 58
37void notrace prom_printf(const char *fmt, ...) 59void notrace prom_printf(const char *fmt, ...)