diff options
author | David S. Miller <davem@davemloft.net> | 2017-02-23 11:27:30 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-02-23 11:27:30 -0500 |
commit | 0d88b86694e0b176c1b9ca10cee95863065e2471 (patch) | |
tree | 9637fa692398887c369983b5fba391b3c83c199a | |
parent | f41e54616ca1a199f6c17228f26082ccdaaab3de (diff) | |
parent | 4cfe140618b99e653134598de9f18b48743549ec (diff) |
Merge branch 'sparc64-jump-to-boot-prom'
Vijay Kumar says:
====================
sparc64: Jump to boot prom from console on panic
V3 changes:
- patch 02/04: Added SERIAL_SUNHV conditional group for
sunhv_migrate_hvcons_irq in smp_send_stop().
V2 changes:
- Added cover letter patch
Currently Stop-A (L1A) does not make the kernel switch to OBP on panic. This
patchset addresses this issue. Also, now we can cause a jump to OBP by sending
'break' twice from sunhv console. On bare metal, one can send a break by
typing Esc + 'B' + Sysrq (or whatever). On LDOM, press Ctrl + ] in telnet,
and then "send break" at the telnet prompt.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/sparc/console.txt | 9 | ||||
-rw-r--r-- | arch/sparc/include/asm/setup.h | 5 | ||||
-rw-r--r-- | arch/sparc/kernel/smp_64.c | 9 | ||||
-rw-r--r-- | drivers/tty/serial/sunhv.c | 12 | ||||
-rw-r--r-- | kernel/panic.c | 3 |
5 files changed, 34 insertions, 4 deletions
diff --git a/Documentation/sparc/console.txt b/Documentation/sparc/console.txt new file mode 100644 index 000000000000..5aa735a44e02 --- /dev/null +++ b/Documentation/sparc/console.txt | |||
@@ -0,0 +1,9 @@ | |||
1 | Steps for sending 'break' on sunhv console: | ||
2 | =========================================== | ||
3 | |||
4 | On Baremetal: | ||
5 | 1. press Esc + 'B' | ||
6 | |||
7 | On LDOM: | ||
8 | 1. press Ctrl + ']' | ||
9 | 2. telnet> send break | ||
diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h index 29d64b1758ed..478bf6bb4598 100644 --- a/arch/sparc/include/asm/setup.h +++ b/arch/sparc/include/asm/setup.h | |||
@@ -59,8 +59,11 @@ extern atomic_t dcpage_flushes; | |||
59 | extern atomic_t dcpage_flushes_xcall; | 59 | extern atomic_t dcpage_flushes_xcall; |
60 | 60 | ||
61 | extern int sysctl_tsb_ratio; | 61 | extern int sysctl_tsb_ratio; |
62 | #endif | ||
63 | 62 | ||
63 | #ifdef CONFIG_SERIAL_SUNHV | ||
64 | void sunhv_migrate_hvcons_irq(int cpu); | ||
65 | #endif | ||
66 | #endif | ||
64 | void sun_do_break(void); | 67 | void sun_do_break(void); |
65 | extern int stop_a_enabled; | 68 | extern int stop_a_enabled; |
66 | extern int scons_pwroff; | 69 | extern int scons_pwroff; |
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 0ce347f8e4cc..90a02cb64e20 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c | |||
@@ -1443,6 +1443,7 @@ void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs) | |||
1443 | 1443 | ||
1444 | static void stop_this_cpu(void *dummy) | 1444 | static void stop_this_cpu(void *dummy) |
1445 | { | 1445 | { |
1446 | set_cpu_online(smp_processor_id(), false); | ||
1446 | prom_stopself(); | 1447 | prom_stopself(); |
1447 | } | 1448 | } |
1448 | 1449 | ||
@@ -1451,9 +1452,15 @@ void smp_send_stop(void) | |||
1451 | int cpu; | 1452 | int cpu; |
1452 | 1453 | ||
1453 | if (tlb_type == hypervisor) { | 1454 | if (tlb_type == hypervisor) { |
1455 | int this_cpu = smp_processor_id(); | ||
1456 | #ifdef CONFIG_SERIAL_SUNHV | ||
1457 | sunhv_migrate_hvcons_irq(this_cpu); | ||
1458 | #endif | ||
1454 | for_each_online_cpu(cpu) { | 1459 | for_each_online_cpu(cpu) { |
1455 | if (cpu == smp_processor_id()) | 1460 | if (cpu == this_cpu) |
1456 | continue; | 1461 | continue; |
1462 | |||
1463 | set_cpu_online(cpu, false); | ||
1457 | #ifdef CONFIG_SUN_LDOMS | 1464 | #ifdef CONFIG_SUN_LDOMS |
1458 | if (ldom_domaining_enabled) { | 1465 | if (ldom_domaining_enabled) { |
1459 | unsigned long hv_err; | 1466 | unsigned long hv_err; |
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c index 73abd89c0108..46e46894e918 100644 --- a/drivers/tty/serial/sunhv.c +++ b/drivers/tty/serial/sunhv.c | |||
@@ -116,7 +116,7 @@ static int receive_chars_getchar(struct uart_port *port) | |||
116 | 116 | ||
117 | static int receive_chars_read(struct uart_port *port) | 117 | static int receive_chars_read(struct uart_port *port) |
118 | { | 118 | { |
119 | int saw_console_brk = 0; | 119 | static int saw_console_brk; |
120 | int limit = 10000; | 120 | int limit = 10000; |
121 | 121 | ||
122 | while (limit-- > 0) { | 122 | while (limit-- > 0) { |
@@ -128,6 +128,9 @@ static int receive_chars_read(struct uart_port *port) | |||
128 | bytes_read = 0; | 128 | bytes_read = 0; |
129 | 129 | ||
130 | if (stat == CON_BREAK) { | 130 | if (stat == CON_BREAK) { |
131 | if (saw_console_brk) | ||
132 | sun_do_break(); | ||
133 | |||
131 | if (uart_handle_break(port)) | 134 | if (uart_handle_break(port)) |
132 | continue; | 135 | continue; |
133 | saw_console_brk = 1; | 136 | saw_console_brk = 1; |
@@ -151,6 +154,7 @@ static int receive_chars_read(struct uart_port *port) | |||
151 | if (port->sysrq != 0 && *con_read_page) { | 154 | if (port->sysrq != 0 && *con_read_page) { |
152 | for (i = 0; i < bytes_read; i++) | 155 | for (i = 0; i < bytes_read; i++) |
153 | uart_handle_sysrq_char(port, con_read_page[i]); | 156 | uart_handle_sysrq_char(port, con_read_page[i]); |
157 | saw_console_brk = 0; | ||
154 | } | 158 | } |
155 | 159 | ||
156 | if (port->state == NULL) | 160 | if (port->state == NULL) |
@@ -398,6 +402,12 @@ static struct uart_driver sunhv_reg = { | |||
398 | 402 | ||
399 | static struct uart_port *sunhv_port; | 403 | static struct uart_port *sunhv_port; |
400 | 404 | ||
405 | void sunhv_migrate_hvcons_irq(int cpu) | ||
406 | { | ||
407 | /* Migrate hvcons irq to param cpu */ | ||
408 | irq_force_affinity(sunhv_port->irq, cpumask_of(cpu)); | ||
409 | } | ||
410 | |||
401 | /* Copy 's' into the con_write_page, decoding "\n" into | 411 | /* Copy 's' into the con_write_page, decoding "\n" into |
402 | * "\r\n" along the way. We have to return two lengths | 412 | * "\r\n" along the way. We have to return two lengths |
403 | * because the caller needs to know how much to advance | 413 | * because the caller needs to know how much to advance |
diff --git a/kernel/panic.c b/kernel/panic.c index b95959733ce0..3ec16e603e88 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
@@ -273,7 +273,8 @@ void panic(const char *fmt, ...) | |||
273 | extern int stop_a_enabled; | 273 | extern int stop_a_enabled; |
274 | /* Make sure the user can actually press Stop-A (L1-A) */ | 274 | /* Make sure the user can actually press Stop-A (L1-A) */ |
275 | stop_a_enabled = 1; | 275 | stop_a_enabled = 1; |
276 | pr_emerg("Press Stop-A (L1-A) to return to the boot prom\n"); | 276 | pr_emerg("Press Stop-A (L1-A) from sun keyboard or send break\n" |
277 | "twice on console to return to the boot prom\n"); | ||
277 | } | 278 | } |
278 | #endif | 279 | #endif |
279 | #if defined(CONFIG_S390) | 280 | #if defined(CONFIG_S390) |