aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/tile/Kconfig1
-rw-r--r--arch/tile/include/asm/setup.h3
-rw-r--r--arch/tile/include/hv/hypervisor.h29
-rw-r--r--arch/tile/kernel/early_printk.c47
-rw-r--r--arch/tile/kernel/hvglue.lds3
-rw-r--r--arch/tile/kernel/reboot.c2
-rw-r--r--drivers/tty/hvc/hvc_tile.c149
7 files changed, 186 insertions, 48 deletions
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index e41a3818b240..0576e1d8c4f9 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -112,6 +112,7 @@ config SMP
112config HVC_TILE 112config HVC_TILE
113 depends on TTY 113 depends on TTY
114 select HVC_DRIVER 114 select HVC_DRIVER
115 select HVC_IRQ if TILEGX
115 def_bool y 116 def_bool y
116 117
117config TILEGX 118config TILEGX
diff --git a/arch/tile/include/asm/setup.h b/arch/tile/include/asm/setup.h
index d048888c5d9a..e98909033e5b 100644
--- a/arch/tile/include/asm/setup.h
+++ b/arch/tile/include/asm/setup.h
@@ -24,9 +24,8 @@
24 */ 24 */
25#define MAXMEM_PFN PFN_DOWN(MAXMEM) 25#define MAXMEM_PFN PFN_DOWN(MAXMEM)
26 26
27int tile_console_write(const char *buf, int count);
27void early_panic(const char *fmt, ...); 28void early_panic(const char *fmt, ...);
28void warn_early_printk(void);
29void __init disable_early_printk(void);
30 29
31/* Init-time routine to do tile-specific per-cpu setup. */ 30/* Init-time routine to do tile-specific per-cpu setup. */
32void setup_cpu(int boot); 31void setup_cpu(int boot);
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h
index 837dca5328c2..f882ebcf43a9 100644
--- a/arch/tile/include/hv/hypervisor.h
+++ b/arch/tile/include/hv/hypervisor.h
@@ -318,8 +318,11 @@
318/** hv_set_pte_super_shift */ 318/** hv_set_pte_super_shift */
319#define HV_DISPATCH_SET_PTE_SUPER_SHIFT 57 319#define HV_DISPATCH_SET_PTE_SUPER_SHIFT 57
320 320
321/** hv_console_set_ipi */
322#define HV_DISPATCH_CONSOLE_SET_IPI 63
323
321/** One more than the largest dispatch value */ 324/** One more than the largest dispatch value */
322#define _HV_DISPATCH_END 58 325#define _HV_DISPATCH_END 64
323 326
324 327
325#ifndef __ASSEMBLER__ 328#ifndef __ASSEMBLER__
@@ -585,6 +588,30 @@ typedef struct
585 */ 588 */
586int hv_get_ipi_pte(HV_Coord tile, int pl, HV_PTE* pte); 589int hv_get_ipi_pte(HV_Coord tile, int pl, HV_PTE* pte);
587 590
591/** Configure the console interrupt.
592 *
593 * When the console client interrupt is enabled, the hypervisor will
594 * deliver the specified IPI to the client in the following situations:
595 *
596 * - The console has at least one character available for input.
597 *
598 * - The console can accept new characters for output, and the last call
599 * to hv_console_write() did not write all of the characters requested
600 * by the client.
601 *
602 * Note that in some system configurations, console interrupt will not
603 * be available; clients should be prepared for this routine to fail and
604 * to fall back to periodic console polling in that case.
605 *
606 * @param ipi Index of the IPI register which will receive the interrupt.
607 * @param event IPI event number for console interrupt. If less than 0,
608 * disable the console IPI interrupt.
609 * @param coord Tile to be targeted for console interrupt.
610 * @return 0 on success, otherwise, HV_EINVAL if illegal parameter,
611 * HV_ENOTSUP if console interrupt are not available.
612 */
613int hv_console_set_ipi(int ipi, int event, HV_Coord coord);
614
588#else /* !CHIP_HAS_IPI() */ 615#else /* !CHIP_HAS_IPI() */
589 616
590/** A set of interrupts. */ 617/** A set of interrupts. */
diff --git a/arch/tile/kernel/early_printk.c b/arch/tile/kernel/early_printk.c
index 34d72a151bf3..b608e00e7f6d 100644
--- a/arch/tile/kernel/early_printk.c
+++ b/arch/tile/kernel/early_printk.c
@@ -23,19 +23,24 @@
23 23
24static void early_hv_write(struct console *con, const char *s, unsigned n) 24static void early_hv_write(struct console *con, const char *s, unsigned n)
25{ 25{
26 hv_console_write((HV_VirtAddr) s, n); 26 tile_console_write(s, n);
27
28 /*
29 * Convert NL to NLCR (close enough to CRNL) during early boot.
30 * We assume newlines are at the ends of strings, which turns out
31 * to be good enough for early boot console output.
32 */
33 if (n && s[n-1] == '\n')
34 tile_console_write("\r", 1);
27} 35}
28 36
29static struct console early_hv_console = { 37static struct console early_hv_console = {
30 .name = "earlyhv", 38 .name = "earlyhv",
31 .write = early_hv_write, 39 .write = early_hv_write,
32 .flags = CON_PRINTBUFFER, 40 .flags = CON_PRINTBUFFER | CON_BOOT,
33 .index = -1, 41 .index = -1,
34}; 42};
35 43
36/* Direct interface for emergencies */
37static int early_console_complete;
38
39void early_panic(const char *fmt, ...) 44void early_panic(const char *fmt, ...)
40{ 45{
41 va_list ap; 46 va_list ap;
@@ -43,51 +48,21 @@ void early_panic(const char *fmt, ...)
43 va_start(ap, fmt); 48 va_start(ap, fmt);
44 early_printk("Kernel panic - not syncing: "); 49 early_printk("Kernel panic - not syncing: ");
45 early_vprintk(fmt, ap); 50 early_vprintk(fmt, ap);
46 early_console->write(early_console, "\n", 1); 51 early_printk("\n");
47 va_end(ap); 52 va_end(ap);
48 dump_stack(); 53 dump_stack();
49 hv_halt(); 54 hv_halt();
50} 55}
51 56
52static int __initdata keep_early;
53
54static int __init setup_early_printk(char *str) 57static int __init setup_early_printk(char *str)
55{ 58{
56 if (early_console) 59 if (early_console)
57 return 1; 60 return 1;
58 61
59 if (str != NULL && strncmp(str, "keep", 4) == 0)
60 keep_early = 1;
61
62 early_console = &early_hv_console; 62 early_console = &early_hv_console;
63 register_console(early_console); 63 register_console(early_console);
64 64
65 return 0; 65 return 0;
66} 66}
67 67
68void __init disable_early_printk(void)
69{
70 early_console_complete = 1;
71 if (!early_console)
72 return;
73 if (!keep_early) {
74 early_printk("disabling early console\n");
75 unregister_console(early_console);
76 early_console = NULL;
77 } else {
78 early_printk("keeping early console\n");
79 }
80}
81
82void warn_early_printk(void)
83{
84 if (early_console_complete || early_console)
85 return;
86 early_printk("\
87Machine shutting down before console output is fully initialized.\n\
88You may wish to reboot and add the option 'earlyprintk' to your\n\
89boot command line to see any diagnostic early console output.\n\
90");
91}
92
93early_param("earlyprintk", setup_early_printk); 68early_param("earlyprintk", setup_early_printk);
diff --git a/arch/tile/kernel/hvglue.lds b/arch/tile/kernel/hvglue.lds
index d44c5a67a1ed..ef522900633a 100644
--- a/arch/tile/kernel/hvglue.lds
+++ b/arch/tile/kernel/hvglue.lds
@@ -56,4 +56,5 @@ hv_inquire_realpa = TEXT_OFFSET + 0x106c0;
56hv_flush_all = TEXT_OFFSET + 0x106e0; 56hv_flush_all = TEXT_OFFSET + 0x106e0;
57hv_get_ipi_pte = TEXT_OFFSET + 0x10700; 57hv_get_ipi_pte = TEXT_OFFSET + 0x10700;
58hv_set_pte_super_shift = TEXT_OFFSET + 0x10720; 58hv_set_pte_super_shift = TEXT_OFFSET + 0x10720;
59hv_glue_internals = TEXT_OFFSET + 0x10740; 59hv_console_set_ipi = TEXT_OFFSET + 0x107e0;
60hv_glue_internals = TEXT_OFFSET + 0x10800;
diff --git a/arch/tile/kernel/reboot.c b/arch/tile/kernel/reboot.c
index d1b5c913ae72..6c5d2c070a12 100644
--- a/arch/tile/kernel/reboot.c
+++ b/arch/tile/kernel/reboot.c
@@ -27,7 +27,6 @@
27 27
28void machine_halt(void) 28void machine_halt(void)
29{ 29{
30 warn_early_printk();
31 arch_local_irq_disable_all(); 30 arch_local_irq_disable_all();
32 smp_send_stop(); 31 smp_send_stop();
33 hv_halt(); 32 hv_halt();
@@ -35,7 +34,6 @@ void machine_halt(void)
35 34
36void machine_power_off(void) 35void machine_power_off(void)
37{ 36{
38 warn_early_printk();
39 arch_local_irq_disable_all(); 37 arch_local_irq_disable_all();
40 smp_send_stop(); 38 smp_send_stop();
41 hv_power_off(); 39 hv_power_off();
diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c
index 7a84a0595477..af8cdaa1dcb9 100644
--- a/drivers/tty/hvc/hvc_tile.c
+++ b/drivers/tty/hvc/hvc_tile.c
@@ -18,16 +18,46 @@
18#include <linux/delay.h> 18#include <linux/delay.h>
19#include <linux/err.h> 19#include <linux/err.h>
20#include <linux/init.h> 20#include <linux/init.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
21#include <linux/moduleparam.h> 23#include <linux/moduleparam.h>
24#include <linux/platform_device.h>
22#include <linux/types.h> 25#include <linux/types.h>
23 26
27#include <asm/setup.h>
28#include <arch/sim_def.h>
29
24#include <hv/hypervisor.h> 30#include <hv/hypervisor.h>
25 31
26#include "hvc_console.h" 32#include "hvc_console.h"
27 33
34static int use_sim_console;
35static int __init sim_console(char *str)
36{
37 use_sim_console = 1;
38 return 0;
39}
40early_param("sim_console", sim_console);
41
42int tile_console_write(const char *buf, int count)
43{
44 if (unlikely(use_sim_console)) {
45 int i;
46 for (i = 0; i < count; ++i)
47 __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
48 (buf[i] << _SIM_CONTROL_OPERATOR_BITS));
49 __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
50 (SIM_PUTC_FLUSH_BINARY <<
51 _SIM_CONTROL_OPERATOR_BITS));
52 return 0;
53 } else {
54 return hv_console_write((HV_VirtAddr)buf, count);
55 }
56}
57
28static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count) 58static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count)
29{ 59{
30 return hv_console_write((HV_VirtAddr)buf, count); 60 return tile_console_write(buf, count);
31} 61}
32 62
33static int hvc_tile_get_chars(uint32_t vt, char *buf, int count) 63static int hvc_tile_get_chars(uint32_t vt, char *buf, int count)
@@ -44,25 +74,132 @@ static int hvc_tile_get_chars(uint32_t vt, char *buf, int count)
44 return i; 74 return i;
45} 75}
46 76
77#ifdef __tilegx__
78/*
79 * IRQ based callbacks.
80 */
81static int hvc_tile_notifier_add_irq(struct hvc_struct *hp, int irq)
82{
83 int rc;
84 int cpu = raw_smp_processor_id(); /* Choose an arbitrary cpu */
85 HV_Coord coord = { .x = cpu_x(cpu), .y = cpu_y(cpu) };
86
87 rc = notifier_add_irq(hp, irq);
88 if (rc)
89 return rc;
90
91 /*
92 * Request that the hypervisor start sending us interrupts.
93 * If the hypervisor returns an error, we still return 0, so that
94 * we can fall back to polling.
95 */
96 if (hv_console_set_ipi(KERNEL_PL, irq, coord) < 0)
97 notifier_del_irq(hp, irq);
98
99 return 0;
100}
101
102static void hvc_tile_notifier_del_irq(struct hvc_struct *hp, int irq)
103{
104 HV_Coord coord = { 0, 0 };
105
106 /* Tell the hypervisor to stop sending us interrupts. */
107 hv_console_set_ipi(KERNEL_PL, -1, coord);
108
109 notifier_del_irq(hp, irq);
110}
111
112static void hvc_tile_notifier_hangup_irq(struct hvc_struct *hp, int irq)
113{
114 hvc_tile_notifier_del_irq(hp, irq);
115}
116#endif
117
47static const struct hv_ops hvc_tile_get_put_ops = { 118static const struct hv_ops hvc_tile_get_put_ops = {
48 .get_chars = hvc_tile_get_chars, 119 .get_chars = hvc_tile_get_chars,
49 .put_chars = hvc_tile_put_chars, 120 .put_chars = hvc_tile_put_chars,
121#ifdef __tilegx__
122 .notifier_add = hvc_tile_notifier_add_irq,
123 .notifier_del = hvc_tile_notifier_del_irq,
124 .notifier_hangup = hvc_tile_notifier_hangup_irq,
125#endif
126};
127
128
129#ifdef __tilegx__
130static int hvc_tile_probe(struct platform_device *pdev)
131{
132 struct hvc_struct *hp;
133 int tile_hvc_irq;
134
135 /* Create our IRQ and register it. */
136 tile_hvc_irq = create_irq();
137 if (tile_hvc_irq < 0)
138 return -ENXIO;
139
140 tile_irq_activate(tile_hvc_irq, TILE_IRQ_PERCPU);
141 hp = hvc_alloc(0, tile_hvc_irq, &hvc_tile_get_put_ops, 128);
142 if (IS_ERR(hp)) {
143 destroy_irq(tile_hvc_irq);
144 return PTR_ERR(hp);
145 }
146 dev_set_drvdata(&pdev->dev, hp);
147
148 return 0;
149}
150
151static int hvc_tile_remove(struct platform_device *pdev)
152{
153 int rc;
154 struct hvc_struct *hp = dev_get_drvdata(&pdev->dev);
155
156 rc = hvc_remove(hp);
157 if (rc == 0)
158 destroy_irq(hp->data);
159
160 return rc;
161}
162
163static void hvc_tile_shutdown(struct platform_device *pdev)
164{
165 struct hvc_struct *hp = dev_get_drvdata(&pdev->dev);
166
167 hvc_tile_notifier_del_irq(hp, hp->data);
168}
169
170static struct platform_device hvc_tile_pdev = {
171 .name = "hvc-tile",
172 .id = 0,
173};
174
175static struct platform_driver hvc_tile_driver = {
176 .probe = hvc_tile_probe,
177 .remove = hvc_tile_remove,
178 .shutdown = hvc_tile_shutdown,
179 .driver = {
180 .name = "hvc-tile",
181 .owner = THIS_MODULE,
182 }
50}; 183};
184#endif
51 185
52static int __init hvc_tile_console_init(void) 186static int __init hvc_tile_console_init(void)
53{ 187{
54 extern void disable_early_printk(void);
55 hvc_instantiate(0, 0, &hvc_tile_get_put_ops); 188 hvc_instantiate(0, 0, &hvc_tile_get_put_ops);
56 add_preferred_console("hvc", 0, NULL); 189 add_preferred_console("hvc", 0, NULL);
57 disable_early_printk();
58 return 0; 190 return 0;
59} 191}
60console_initcall(hvc_tile_console_init); 192console_initcall(hvc_tile_console_init);
61 193
62static int __init hvc_tile_init(void) 194static int __init hvc_tile_init(void)
63{ 195{
64 struct hvc_struct *s; 196#ifndef __tilegx__
65 s = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128); 197 struct hvc_struct *hp;
66 return IS_ERR(s) ? PTR_ERR(s) : 0; 198 hp = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
199 return IS_ERR(hp) ? PTR_ERR(hp) : 0;
200#else
201 platform_device_register(&hvc_tile_pdev);
202 return platform_driver_register(&hvc_tile_driver);
203#endif
67} 204}
68device_initcall(hvc_tile_init); 205device_initcall(hvc_tile_init);