diff options
author | Kyle McMartin <kyle@shortfin.cabal.ca> | 2008-02-19 02:34:34 -0500 |
---|---|---|
committer | Kyle McMartin <kyle@shortfin.cabal.ca> | 2008-03-15 22:12:03 -0400 |
commit | ef1afd4d79f0479960ff36bb5fe6ec6eba1ebff2 (patch) | |
tree | 71351cd3150e87a2d5a5c2ae06ea143e7345cf14 /arch/parisc | |
parent | d0347b49c9a877a33c59f80de1a9dbabd5244205 (diff) |
[PARISC] pdc_console: fix bizarre panic on boot
Commit 721fdf34167580ff98263c74cead8871d76936e6 introduced a subtle bug
by accidently removing the "static" from iodc_dbuf. This resulted in, what
appeared to be, a trap without *current set to a task. Probably the result of
a trap in real mode while calling firmware.
Also do other misc clean ups. Since the only input from firmware is non
blocking, share iodc_dbuf between input and output, and spinlock the
only callers.
Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
Diffstat (limited to 'arch/parisc')
-rw-r--r-- | arch/parisc/kernel/firmware.c | 27 | ||||
-rw-r--r-- | arch/parisc/kernel/pdc_cons.c | 19 |
2 files changed, 34 insertions, 12 deletions
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index 4ab83d56974d..7177a6cd1b7f 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c | |||
@@ -1080,6 +1080,9 @@ void pdc_io_reset_devices(void) | |||
1080 | spin_unlock_irqrestore(&pdc_lock, flags); | 1080 | spin_unlock_irqrestore(&pdc_lock, flags); |
1081 | } | 1081 | } |
1082 | 1082 | ||
1083 | /* locked by pdc_console_lock */ | ||
1084 | static int __attribute__((aligned(8))) iodc_retbuf[32]; | ||
1085 | static char __attribute__((aligned(64))) iodc_dbuf[4096]; | ||
1083 | 1086 | ||
1084 | /** | 1087 | /** |
1085 | * pdc_iodc_print - Console print using IODC. | 1088 | * pdc_iodc_print - Console print using IODC. |
@@ -1091,24 +1094,20 @@ void pdc_io_reset_devices(void) | |||
1091 | * Since the HP console requires CR+LF to perform a 'newline', we translate | 1094 | * Since the HP console requires CR+LF to perform a 'newline', we translate |
1092 | * "\n" to "\r\n". | 1095 | * "\n" to "\r\n". |
1093 | */ | 1096 | */ |
1094 | int pdc_iodc_print(unsigned char *str, unsigned count) | 1097 | int pdc_iodc_print(const unsigned char *str, unsigned count) |
1095 | { | 1098 | { |
1096 | /* XXX Should we spinlock posx usage */ | ||
1097 | static int posx; /* for simple TAB-Simulation... */ | 1099 | static int posx; /* for simple TAB-Simulation... */ |
1098 | int __attribute__((aligned(8))) iodc_retbuf[32]; | ||
1099 | char __attribute__((aligned(64))) iodc_dbuf[4096]; | ||
1100 | unsigned int i; | 1100 | unsigned int i; |
1101 | unsigned long flags; | 1101 | unsigned long flags; |
1102 | 1102 | ||
1103 | memset(iodc_dbuf, 0, 4096); | 1103 | for (i = 0; i < count && i < 79;) { |
1104 | for (i = 0; i < count && i < 2048;) { | ||
1105 | switch(str[i]) { | 1104 | switch(str[i]) { |
1106 | case '\n': | 1105 | case '\n': |
1107 | iodc_dbuf[i+0] = '\r'; | 1106 | iodc_dbuf[i+0] = '\r'; |
1108 | iodc_dbuf[i+1] = '\n'; | 1107 | iodc_dbuf[i+1] = '\n'; |
1109 | i += 2; | 1108 | i += 2; |
1110 | posx = 0; | 1109 | posx = 0; |
1111 | break; | 1110 | goto print; |
1112 | case '\t': | 1111 | case '\t': |
1113 | while (posx & 7) { | 1112 | while (posx & 7) { |
1114 | iodc_dbuf[i] = ' '; | 1113 | iodc_dbuf[i] = ' '; |
@@ -1124,6 +1123,16 @@ int pdc_iodc_print(unsigned char *str, unsigned count) | |||
1124 | } | 1123 | } |
1125 | } | 1124 | } |
1126 | 1125 | ||
1126 | /* if we're at the end of line, and not already inserting a newline, | ||
1127 | * insert one anyway. iodc console doesn't claim to support >79 char | ||
1128 | * lines. don't account for this in the return value. | ||
1129 | */ | ||
1130 | if (i == 79 && iodc_dbuf[i-1] != '\n') { | ||
1131 | iodc_dbuf[i+0] = '\r'; | ||
1132 | iodc_dbuf[i+1] = '\n'; | ||
1133 | } | ||
1134 | |||
1135 | print: | ||
1127 | spin_lock_irqsave(&pdc_lock, flags); | 1136 | spin_lock_irqsave(&pdc_lock, flags); |
1128 | real32_call(PAGE0->mem_cons.iodc_io, | 1137 | real32_call(PAGE0->mem_cons.iodc_io, |
1129 | (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT, | 1138 | (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT, |
@@ -1142,11 +1151,9 @@ int pdc_iodc_print(unsigned char *str, unsigned count) | |||
1142 | */ | 1151 | */ |
1143 | int pdc_iodc_getc(void) | 1152 | int pdc_iodc_getc(void) |
1144 | { | 1153 | { |
1145 | unsigned long flags; | ||
1146 | static int __attribute__((aligned(8))) iodc_retbuf[32]; | ||
1147 | static char __attribute__((aligned(64))) iodc_dbuf[4096]; | ||
1148 | int ch; | 1154 | int ch; |
1149 | int status; | 1155 | int status; |
1156 | unsigned long flags; | ||
1150 | 1157 | ||
1151 | /* Bail if no console input device. */ | 1158 | /* Bail if no console input device. */ |
1152 | if (!PAGE0->mem_kbd.iodc_io) | 1159 | if (!PAGE0->mem_kbd.iodc_io) |
diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index e7afc899d717..ccb68090781e 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c | |||
@@ -52,15 +52,30 @@ | |||
52 | #include <linux/tty.h> | 52 | #include <linux/tty.h> |
53 | #include <asm/pdc.h> /* for iodc_call() proto and friends */ | 53 | #include <asm/pdc.h> /* for iodc_call() proto and friends */ |
54 | 54 | ||
55 | static spinlock_t pdc_console_lock = SPIN_LOCK_UNLOCKED; | ||
55 | 56 | ||
56 | static void pdc_console_write(struct console *co, const char *s, unsigned count) | 57 | static void pdc_console_write(struct console *co, const char *s, unsigned count) |
57 | { | 58 | { |
58 | pdc_iodc_print(s, count); | 59 | int i = 0; |
60 | unsigned long flags; | ||
61 | |||
62 | spin_lock_irqsave(&pdc_console_lock, flags); | ||
63 | do { | ||
64 | i += pdc_iodc_print(s + i, count - i); | ||
65 | } while (i < count); | ||
66 | spin_unlock_irqrestore(&pdc_console_lock, flags); | ||
59 | } | 67 | } |
60 | 68 | ||
61 | int pdc_console_poll_key(struct console *co) | 69 | int pdc_console_poll_key(struct console *co) |
62 | { | 70 | { |
63 | return pdc_iodc_getc(); | 71 | int c; |
72 | unsigned long flags; | ||
73 | |||
74 | spin_lock_irqsave(&pdc_console_lock, flags); | ||
75 | c = pdc_iodc_getc(); | ||
76 | spin_unlock_irqrestore(&pdc_console_lock, flags); | ||
77 | |||
78 | return c; | ||
64 | } | 79 | } |
65 | 80 | ||
66 | static int pdc_console_setup(struct console *co, char *options) | 81 | static int pdc_console_setup(struct console *co, char *options) |