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 | |
| 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>
| -rw-r--r-- | arch/parisc/kernel/firmware.c | 27 | ||||
| -rw-r--r-- | arch/parisc/kernel/pdc_cons.c | 19 | ||||
| -rw-r--r-- | include/asm-parisc/pdc.h | 2 |
3 files changed, 35 insertions, 13 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) |
diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h index b340c42f6bbc..9eaa794c3e4a 100644 --- a/include/asm-parisc/pdc.h +++ b/include/asm-parisc/pdc.h | |||
| @@ -645,7 +645,7 @@ int pdc_soft_power_button(int sw_control); | |||
| 645 | void pdc_io_reset(void); | 645 | void pdc_io_reset(void); |
| 646 | void pdc_io_reset_devices(void); | 646 | void pdc_io_reset_devices(void); |
| 647 | int pdc_iodc_getc(void); | 647 | int pdc_iodc_getc(void); |
| 648 | int pdc_iodc_print(unsigned char *str, unsigned count); | 648 | int pdc_iodc_print(const unsigned char *str, unsigned count); |
| 649 | 649 | ||
| 650 | void pdc_emergency_unlock(void); | 650 | void pdc_emergency_unlock(void); |
| 651 | int pdc_sti_call(unsigned long func, unsigned long flags, | 651 | int pdc_sti_call(unsigned long func, unsigned long flags, |
