aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-05-15 20:03:54 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-05-15 23:23:02 -0400
commitc7754d465b1feade85b5f1c4492781a30f6652a2 (patch)
tree9a3b6ccb18983c1ea389377028ca51c8170730ef
parent7b104bcb8e460e45a1aebe3da9b86aacdb4cab12 (diff)
[SPARC64]: Add hypervisor API negotiation and fix console bugs.
Hypervisor interfaces need to be negotiated in order to use some API calls reliably. So add a small set of interfaces to request API versions and query current settings. This allows us to fix some bugs in the hypervisor console: 1) If we can negotiate API group CORE of at least major 1 minor 1 we can use con_read and con_write which can improve console performance quite a bit. 2) When we do a console write request, we should hold the spinlock around the whole request, not a byte at a time. What would happen is that it's easy for output from different cpus to get mixed with each other. 3) Use consistent udelay() based polling, udelay(1) each loop with a limit of 1000 polls to handle stuck hypervisor console. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc64/kernel/Makefile2
-rw-r--r--arch/sparc64/kernel/entry.S94
-rw-r--r--arch/sparc64/kernel/hvapi.c189
-rw-r--r--arch/sparc64/kernel/setup.c3
-rw-r--r--drivers/serial/sunhv.c276
-rw-r--r--include/asm-sparc64/hypervisor.h83
6 files changed, 574 insertions, 73 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 6bf6fb65bc20..c749dccacc32 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -12,7 +12,7 @@ obj-y := process.o setup.o cpu.o idprom.o \
12 irq.o ptrace.o time.o sys_sparc.o signal.o \ 12 irq.o ptrace.o time.o sys_sparc.o signal.o \
13 unaligned.o central.o pci.o starfire.o semaphore.o \ 13 unaligned.o central.o pci.o starfire.o semaphore.o \
14 power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ 14 power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
15 visemul.o prom.o of_device.o 15 visemul.o prom.o of_device.o hvapi.o
16 16
17obj-$(CONFIG_STACKTRACE) += stacktrace.o 17obj-$(CONFIG_STACKTRACE) += stacktrace.o
18obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \ 18obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index c15a3edcb826..732b77cb71f8 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1843,3 +1843,97 @@ sun4v_cpu_state:
1843 mov %o1, %o0 1843 mov %o1, %o0
18441: retl 18441: retl
1845 nop 1845 nop
1846
1847 /* %o0: API group number
1848 * %o1: pointer to unsigned long major number storage
1849 * %o2: pointer to unsigned long minor number storage
1850 *
1851 * returns %o0: status
1852 */
1853 .globl sun4v_get_version
1854sun4v_get_version:
1855 mov HV_CORE_GET_VER, %o5
1856 mov %o1, %o3
1857 mov %o2, %o4
1858 ta HV_CORE_TRAP
1859 stx %o1, [%o3]
1860 retl
1861 stx %o2, [%o4]
1862
1863 /* %o0: API group number
1864 * %o1: desired major number
1865 * %o2: desired minor number
1866 * %o3: pointer to unsigned long actual minor number storage
1867 *
1868 * returns %o0: status
1869 */
1870 .globl sun4v_set_version
1871sun4v_set_version:
1872 mov HV_CORE_SET_VER, %o5
1873 mov %o3, %o4
1874 ta HV_CORE_TRAP
1875 retl
1876 stx %o1, [%o4]
1877
1878 /* %o0: pointer to unsigned long status
1879 *
1880 * returns %o0: signed character
1881 */
1882 .globl sun4v_con_getchar
1883sun4v_con_getchar:
1884 mov %o0, %o4
1885 mov HV_FAST_CONS_GETCHAR, %o5
1886 clr %o0
1887 clr %o1
1888 ta HV_FAST_TRAP
1889 stx %o0, [%o4]
1890 retl
1891 sra %o1, 0, %o0
1892
1893 /* %o0: signed long character
1894 *
1895 * returns %o0: status
1896 */
1897 .globl sun4v_con_putchar
1898sun4v_con_putchar:
1899 mov HV_FAST_CONS_PUTCHAR, %o5
1900 ta HV_FAST_TRAP
1901 retl
1902 sra %o0, 0, %o0
1903
1904 /* %o0: buffer real address
1905 * %o1: buffer size
1906 * %o2: pointer to unsigned long bytes_read
1907 *
1908 * returns %o0: status
1909 */
1910 .globl sun4v_con_read
1911sun4v_con_read:
1912 mov %o2, %o4
1913 mov HV_FAST_CONS_READ, %o5
1914 ta HV_FAST_TRAP
1915 brnz %o0, 1f
1916 cmp %o1, -1 /* break */
1917 be,a,pn %icc, 1f
1918 mov %o1, %o0
1919 cmp %o1, -2 /* hup */
1920 be,a,pn %icc, 1f
1921 mov %o1, %o0
1922 stx %o1, [%o4]
19231: retl
1924 nop
1925
1926 /* %o0: buffer real address
1927 * %o1: buffer size
1928 * %o2: pointer to unsigned long bytes_written
1929 *
1930 * returns %o0: status
1931 */
1932 .globl sun4v_con_write
1933sun4v_con_write:
1934 mov %o2, %o4
1935 mov HV_FAST_CONS_WRITE, %o5
1936 ta HV_FAST_TRAP
1937 stx %o1, [%o4]
1938 retl
1939 nop
diff --git a/arch/sparc64/kernel/hvapi.c b/arch/sparc64/kernel/hvapi.c
new file mode 100644
index 000000000000..f03ffc829c7a
--- /dev/null
+++ b/arch/sparc64/kernel/hvapi.c
@@ -0,0 +1,189 @@
1/* hvapi.c: Hypervisor API management.
2 *
3 * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
4 */
5#include <linux/kernel.h>
6#include <linux/module.h>
7#include <linux/init.h>
8#include <linux/slab.h>
9
10#include <asm/hypervisor.h>
11#include <asm/oplib.h>
12
13/* If the hypervisor indicates that the API setting
14 * calls are unsupported, by returning HV_EBADTRAP or
15 * HV_ENOTSUPPORTED, we assume that API groups with the
16 * PRE_API flag set are major 1 minor 0.
17 */
18struct api_info {
19 unsigned long group;
20 unsigned long major;
21 unsigned long minor;
22 unsigned int refcnt;
23 unsigned int flags;
24#define FLAG_PRE_API 0x00000001
25};
26
27static struct api_info api_table[] = {
28 { .group = HV_GRP_SUN4V, .flags = FLAG_PRE_API },
29 { .group = HV_GRP_CORE, .flags = FLAG_PRE_API },
30 { .group = HV_GRP_INTR, },
31 { .group = HV_GRP_SOFT_STATE, },
32 { .group = HV_GRP_PCI, .flags = FLAG_PRE_API },
33 { .group = HV_GRP_LDOM, },
34 { .group = HV_GRP_SVC_CHAN, .flags = FLAG_PRE_API },
35 { .group = HV_GRP_NCS, .flags = FLAG_PRE_API },
36 { .group = HV_GRP_NIAG_PERF, .flags = FLAG_PRE_API },
37 { .group = HV_GRP_FIRE_PERF, },
38 { .group = HV_GRP_DIAG, .flags = FLAG_PRE_API },
39};
40
41static DEFINE_SPINLOCK(hvapi_lock);
42
43static struct api_info *__get_info(unsigned long group)
44{
45 int i;
46
47 for (i = 0; i < ARRAY_SIZE(api_table); i++) {
48 if (api_table[i].group == group)
49 return &api_table[i];
50 }
51 return NULL;
52}
53
54static void __get_ref(struct api_info *p)
55{
56 p->refcnt++;
57}
58
59static void __put_ref(struct api_info *p)
60{
61 if (--p->refcnt == 0) {
62 unsigned long ignore;
63
64 sun4v_set_version(p->group, 0, 0, &ignore);
65 p->major = p->minor = 0;
66 }
67}
68
69/* Register a hypervisor API specification. It indicates the
70 * API group and desired major+minor.
71 *
72 * If an existing API registration exists '0' (success) will
73 * be returned if it is compatible with the one being registered.
74 * Otherwise a negative error code will be returned.
75 *
76 * Otherwise an attempt will be made to negotiate the requested
77 * API group/major/minor with the hypervisor, and errors returned
78 * if that does not succeed.
79 */
80int sun4v_hvapi_register(unsigned long group, unsigned long major,
81 unsigned long *minor)
82{
83 struct api_info *p;
84 unsigned long flags;
85 int ret;
86
87 spin_lock_irqsave(&hvapi_lock, flags);
88 p = __get_info(group);
89 ret = -EINVAL;
90 if (p) {
91 if (p->refcnt) {
92 ret = -EINVAL;
93 if (p->major == major) {
94 *minor = p->minor;
95 ret = 0;
96 }
97 } else {
98 unsigned long actual_minor;
99 unsigned long hv_ret;
100
101 hv_ret = sun4v_set_version(group, major, *minor,
102 &actual_minor);
103 ret = -EINVAL;
104 if (hv_ret == HV_EOK) {
105 *minor = actual_minor;
106 p->major = major;
107 p->minor = actual_minor;
108 ret = 0;
109 } else if (hv_ret == HV_EBADTRAP ||
110 HV_ENOTSUPPORTED) {
111 if (p->flags & FLAG_PRE_API) {
112 if (major == 1) {
113 p->major = 1;
114 p->minor = 0;
115 *minor = 0;
116 ret = 0;
117 }
118 }
119 }
120 }
121
122 if (ret == 0)
123 __get_ref(p);
124 }
125 spin_unlock_irqrestore(&hvapi_lock, flags);
126
127 return ret;
128}
129EXPORT_SYMBOL(sun4v_hvapi_register);
130
131void sun4v_hvapi_unregister(unsigned long group)
132{
133 struct api_info *p;
134 unsigned long flags;
135
136 spin_lock_irqsave(&hvapi_lock, flags);
137 p = __get_info(group);
138 if (p)
139 __put_ref(p);
140 spin_unlock_irqrestore(&hvapi_lock, flags);
141}
142EXPORT_SYMBOL(sun4v_hvapi_unregister);
143
144int sun4v_hvapi_get(unsigned long group,
145 unsigned long *major,
146 unsigned long *minor)
147{
148 struct api_info *p;
149 unsigned long flags;
150 int ret;
151
152 spin_lock_irqsave(&hvapi_lock, flags);
153 ret = -EINVAL;
154 p = __get_info(group);
155 if (p && p->refcnt) {
156 *major = p->major;
157 *minor = p->minor;
158 ret = 0;
159 }
160 spin_unlock_irqrestore(&hvapi_lock, flags);
161
162 return ret;
163}
164EXPORT_SYMBOL(sun4v_hvapi_get);
165
166void __init sun4v_hvapi_init(void)
167{
168 unsigned long group, major, minor;
169
170 group = HV_GRP_SUN4V;
171 major = 1;
172 minor = 0;
173 if (sun4v_hvapi_register(group, major, &minor))
174 goto bad;
175
176 group = HV_GRP_CORE;
177 major = 1;
178 minor = 1;
179 if (sun4v_hvapi_register(group, major, &minor))
180 goto bad;
181
182 return;
183
184bad:
185 prom_printf("HVAPI: Cannot register API group "
186 "%lx with major(%u) minor(%u)\n",
187 group, major, minor);
188 prom_halt();
189}
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 451028341c75..dea9c3c9ec5f 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -269,6 +269,7 @@ void __init per_cpu_patch(void)
269 269
270void __init sun4v_patch(void) 270void __init sun4v_patch(void)
271{ 271{
272 extern void sun4v_hvapi_init(void);
272 struct sun4v_1insn_patch_entry *p1; 273 struct sun4v_1insn_patch_entry *p1;
273 struct sun4v_2insn_patch_entry *p2; 274 struct sun4v_2insn_patch_entry *p2;
274 275
@@ -300,6 +301,8 @@ void __init sun4v_patch(void)
300 301
301 p2++; 302 p2++;
302 } 303 }
304
305 sun4v_hvapi_init();
303} 306}
304 307
305#ifdef CONFIG_SMP 308#ifdef CONFIG_SMP
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index c3a6bd2e7950..96557e6dba60 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -1,6 +1,6 @@
1/* sunhv.c: Serial driver for SUN4V hypervisor console. 1/* sunhv.c: Serial driver for SUN4V hypervisor console.
2 * 2 *
3 * Copyright (C) 2006 David S. Miller (davem@davemloft.net) 3 * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
4 */ 4 */
5 5
6#include <linux/module.h> 6#include <linux/module.h>
@@ -35,57 +35,51 @@
35#define CON_BREAK ((long)-1) 35#define CON_BREAK ((long)-1)
36#define CON_HUP ((long)-2) 36#define CON_HUP ((long)-2)
37 37
38static inline long hypervisor_con_getchar(long *status) 38#define IGNORE_BREAK 0x1
39{ 39#define IGNORE_ALL 0x2
40 register unsigned long func asm("%o5");
41 register unsigned long arg0 asm("%o0");
42 register unsigned long arg1 asm("%o1");
43
44 func = HV_FAST_CONS_GETCHAR;
45 arg0 = 0;
46 arg1 = 0;
47 __asm__ __volatile__("ta %6"
48 : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
49 : "0" (func), "1" (arg0), "2" (arg1),
50 "i" (HV_FAST_TRAP));
51 40
52 *status = arg0; 41static char *con_write_page;
42static char *con_read_page;
53 43
54 return (long) arg1; 44static int hung_up = 0;
55}
56 45
57static inline long hypervisor_con_putchar(long ch) 46static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
58{ 47{
59 register unsigned long func asm("%o5"); 48 while (!uart_circ_empty(xmit)) {
60 register unsigned long arg0 asm("%o0"); 49 long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
61 50
62 func = HV_FAST_CONS_PUTCHAR; 51 if (status != HV_EOK)
63 arg0 = ch; 52 break;
64 __asm__ __volatile__("ta %4"
65 : "=&r" (func), "=&r" (arg0)
66 : "0" (func), "1" (arg0), "i" (HV_FAST_TRAP));
67 53
68 return (long) arg0; 54 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
55 port->icount.tx++;
56 }
69} 57}
70 58
71#define IGNORE_BREAK 0x1 59static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
72#define IGNORE_ALL 0x2 60{
61 while (!uart_circ_empty(xmit)) {
62 unsigned long ra = __pa(xmit->buf + xmit->tail);
63 unsigned long len, status, sent;
73 64
74static int hung_up = 0; 65 len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
66 UART_XMIT_SIZE);
67 status = sun4v_con_write(ra, len, &sent);
68 if (status != HV_EOK)
69 break;
70 xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
71 port->icount.tx += sent;
72 }
73}
75 74
76static struct tty_struct *receive_chars(struct uart_port *port) 75static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
77{ 76{
78 struct tty_struct *tty = NULL;
79 int saw_console_brk = 0; 77 int saw_console_brk = 0;
80 int limit = 10000; 78 int limit = 10000;
81 79
82 if (port->info != NULL) /* Unopened serial console */
83 tty = port->info->tty;
84
85 while (limit-- > 0) { 80 while (limit-- > 0) {
86 long status; 81 long status;
87 long c = hypervisor_con_getchar(&status); 82 long c = sun4v_con_getchar(&status);
88 unsigned char flag;
89 83
90 if (status == HV_EWOULDBLOCK) 84 if (status == HV_EWOULDBLOCK)
91 break; 85 break;
@@ -110,27 +104,90 @@ static struct tty_struct *receive_chars(struct uart_port *port)
110 continue; 104 continue;
111 } 105 }
112 106
113 flag = TTY_NORMAL;
114 port->icount.rx++; 107 port->icount.rx++;
115 if (c == CON_BREAK) {
116 port->icount.brk++;
117 if (uart_handle_break(port))
118 continue;
119 flag = TTY_BREAK;
120 }
121 108
122 if (uart_handle_sysrq_char(port, c)) 109 if (uart_handle_sysrq_char(port, c))
123 continue; 110 continue;
124 111
125 if ((port->ignore_status_mask & IGNORE_ALL) || 112 tty_insert_flip_char(tty, c, TTY_NORMAL);
126 ((port->ignore_status_mask & IGNORE_BREAK) && 113 }
127 (c == CON_BREAK))) 114
115 return saw_console_brk;
116}
117
118static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
119{
120 int saw_console_brk = 0;
121 int limit = 10000;
122
123 while (limit-- > 0) {
124 unsigned long ra = __pa(con_read_page);
125 unsigned long bytes_read, i;
126 long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
127
128 if (stat != HV_EOK) {
129 bytes_read = 0;
130
131 if (stat == CON_BREAK) {
132 if (uart_handle_break(port))
133 continue;
134 saw_console_brk = 1;
135 *con_read_page = 0;
136 bytes_read = 1;
137 } else if (stat == CON_HUP) {
138 hung_up = 1;
139 uart_handle_dcd_change(port, 0);
140 continue;
141 } else {
142 /* HV_EWOULDBLOCK, etc. */
143 break;
144 }
145 }
146
147 if (hung_up) {
148 hung_up = 0;
149 uart_handle_dcd_change(port, 1);
150 }
151
152 for (i = 0; i < bytes_read; i++)
153 uart_handle_sysrq_char(port, con_read_page[i]);
154
155 if (tty == NULL)
128 continue; 156 continue;
129 157
130 tty_insert_flip_char(tty, c, flag); 158 port->icount.rx += bytes_read;
159
160 tty_insert_flip_string(tty, con_read_page, bytes_read);
131 } 161 }
132 162
133 if (saw_console_brk) 163 return saw_console_brk;
164}
165
166struct sunhv_ops {
167 void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
168 int (*receive_chars)(struct uart_port *port, struct tty_struct *tty);
169};
170
171static struct sunhv_ops bychar_ops = {
172 .transmit_chars = transmit_chars_putchar,
173 .receive_chars = receive_chars_getchar,
174};
175
176static struct sunhv_ops bywrite_ops = {
177 .transmit_chars = transmit_chars_write,
178 .receive_chars = receive_chars_read,
179};
180
181static struct sunhv_ops *sunhv_ops = &bychar_ops;
182
183static struct tty_struct *receive_chars(struct uart_port *port)
184{
185 struct tty_struct *tty = NULL;
186
187 if (port->info != NULL) /* Unopened serial console */
188 tty = port->info->tty;
189
190 if (sunhv_ops->receive_chars(port, tty))
134 sun_do_break(); 191 sun_do_break();
135 192
136 return tty; 193 return tty;
@@ -147,15 +204,7 @@ static void transmit_chars(struct uart_port *port)
147 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) 204 if (uart_circ_empty(xmit) || uart_tx_stopped(port))
148 return; 205 return;
149 206
150 while (!uart_circ_empty(xmit)) { 207 sunhv_ops->transmit_chars(port, xmit);
151 long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
152
153 if (status != HV_EOK)
154 break;
155
156 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
157 port->icount.tx++;
158 }
159 208
160 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 209 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
161 uart_write_wakeup(port); 210 uart_write_wakeup(port);
@@ -212,7 +261,7 @@ static void sunhv_start_tx(struct uart_port *port)
212 struct circ_buf *xmit = &port->info->xmit; 261 struct circ_buf *xmit = &port->info->xmit;
213 262
214 while (!uart_circ_empty(xmit)) { 263 while (!uart_circ_empty(xmit)) {
215 long status = hypervisor_con_putchar(xmit->buf[xmit->tail]); 264 long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
216 265
217 if (status != HV_EOK) 266 if (status != HV_EOK)
218 break; 267 break;
@@ -231,9 +280,10 @@ static void sunhv_send_xchar(struct uart_port *port, char ch)
231 spin_lock_irqsave(&port->lock, flags); 280 spin_lock_irqsave(&port->lock, flags);
232 281
233 while (limit-- > 0) { 282 while (limit-- > 0) {
234 long status = hypervisor_con_putchar(ch); 283 long status = sun4v_con_putchar(ch);
235 if (status == HV_EOK) 284 if (status == HV_EOK)
236 break; 285 break;
286 udelay(1);
237 } 287 }
238 288
239 spin_unlock_irqrestore(&port->lock, flags); 289 spin_unlock_irqrestore(&port->lock, flags);
@@ -254,15 +304,15 @@ static void sunhv_break_ctl(struct uart_port *port, int break_state)
254{ 304{
255 if (break_state) { 305 if (break_state) {
256 unsigned long flags; 306 unsigned long flags;
257 int limit = 1000000; 307 int limit = 10000;
258 308
259 spin_lock_irqsave(&port->lock, flags); 309 spin_lock_irqsave(&port->lock, flags);
260 310
261 while (limit-- > 0) { 311 while (limit-- > 0) {
262 long status = hypervisor_con_putchar(CON_BREAK); 312 long status = sun4v_con_putchar(CON_BREAK);
263 if (status == HV_EOK) 313 if (status == HV_EOK)
264 break; 314 break;
265 udelay(2); 315 udelay(1);
266 } 316 }
267 317
268 spin_unlock_irqrestore(&port->lock, flags); 318 spin_unlock_irqrestore(&port->lock, flags);
@@ -359,38 +409,99 @@ static struct uart_driver sunhv_reg = {
359 409
360static struct uart_port *sunhv_port; 410static struct uart_port *sunhv_port;
361 411
362static inline void sunhv_console_putchar(struct uart_port *port, char c) 412/* Copy 's' into the con_write_page, decoding "\n" into
413 * "\r\n" along the way. We have to return two lengths
414 * because the caller needs to know how much to advance
415 * 's' and also how many bytes to output via con_write_page.
416 */
417static int fill_con_write_page(const char *s, unsigned int n,
418 unsigned long *page_bytes)
419{
420 const char *orig_s = s;
421 char *p = con_write_page;
422 int left = PAGE_SIZE;
423
424 while (n--) {
425 if (*s == '\n') {
426 if (left < 2)
427 break;
428 *p++ = '\r';
429 left--;
430 } else if (left < 1)
431 break;
432 *p++ = *s++;
433 left--;
434 }
435 *page_bytes = p - con_write_page;
436 return s - orig_s;
437}
438
439static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
363{ 440{
441 struct uart_port *port = sunhv_port;
364 unsigned long flags; 442 unsigned long flags;
365 int limit = 1000000;
366 443
367 spin_lock_irqsave(&port->lock, flags); 444 spin_lock_irqsave(&port->lock, flags);
445 while (n > 0) {
446 unsigned long ra = __pa(con_write_page);
447 unsigned long page_bytes;
448 unsigned int cpy = fill_con_write_page(s, n,
449 &page_bytes);
450
451 n -= cpy;
452 s += cpy;
453 while (page_bytes > 0) {
454 unsigned long written;
455 int limit = 1000000;
456
457 while (limit--) {
458 unsigned long stat;
459
460 stat = sun4v_con_write(ra, page_bytes,
461 &written);
462 if (stat == HV_EOK)
463 break;
464 udelay(1);
465 }
466 if (limit <= 0)
467 break;
468 page_bytes -= written;
469 ra += written;
470 }
471 }
472 spin_unlock_irqrestore(&port->lock, flags);
473}
474
475static inline void sunhv_console_putchar(struct uart_port *port, char c)
476{
477 int limit = 1000000;
368 478
369 while (limit-- > 0) { 479 while (limit-- > 0) {
370 long status = hypervisor_con_putchar(c); 480 long status = sun4v_con_putchar(c);
371 if (status == HV_EOK) 481 if (status == HV_EOK)
372 break; 482 break;
373 udelay(2); 483 udelay(1);
374 } 484 }
375
376 spin_unlock_irqrestore(&port->lock, flags);
377} 485}
378 486
379static void sunhv_console_write(struct console *con, const char *s, unsigned n) 487static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
380{ 488{
381 struct uart_port *port = sunhv_port; 489 struct uart_port *port = sunhv_port;
490 unsigned long flags;
382 int i; 491 int i;
383 492
493 spin_lock_irqsave(&port->lock, flags);
384 for (i = 0; i < n; i++) { 494 for (i = 0; i < n; i++) {
385 if (*s == '\n') 495 if (*s == '\n')
386 sunhv_console_putchar(port, '\r'); 496 sunhv_console_putchar(port, '\r');
387 sunhv_console_putchar(port, *s++); 497 sunhv_console_putchar(port, *s++);
388 } 498 }
499 spin_unlock_irqrestore(&port->lock, flags);
389} 500}
390 501
391static struct console sunhv_console = { 502static struct console sunhv_console = {
392 .name = "ttyHV", 503 .name = "ttyHV",
393 .write = sunhv_console_write, 504 .write = sunhv_console_write_bychar,
394 .device = uart_console_device, 505 .device = uart_console_device,
395 .flags = CON_PRINTBUFFER, 506 .flags = CON_PRINTBUFFER,
396 .index = -1, 507 .index = -1,
@@ -410,6 +521,7 @@ static inline struct console *SUNHV_CONSOLE(void)
410static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match) 521static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
411{ 522{
412 struct uart_port *port; 523 struct uart_port *port;
524 unsigned long minor;
413 int err; 525 int err;
414 526
415 if (op->irqs[0] == 0xffffffff) 527 if (op->irqs[0] == 0xffffffff)
@@ -419,6 +531,22 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
419 if (unlikely(!port)) 531 if (unlikely(!port))
420 return -ENOMEM; 532 return -ENOMEM;
421 533
534 minor = 1;
535 if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
536 minor >= 1) {
537 err = -ENOMEM;
538 con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
539 if (!con_write_page)
540 goto out_free_port;
541
542 con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
543 if (!con_read_page)
544 goto out_free_con_write_page;
545
546 sunhv_console.write = sunhv_console_write_paged;
547 sunhv_ops = &bywrite_ops;
548 }
549
422 sunhv_port = port; 550 sunhv_port = port;
423 551
424 port->line = 0; 552 port->line = 0;
@@ -437,7 +565,7 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
437 565
438 err = uart_register_driver(&sunhv_reg); 566 err = uart_register_driver(&sunhv_reg);
439 if (err) 567 if (err)
440 goto out_free_port; 568 goto out_free_con_read_page;
441 569
442 sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64; 570 sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
443 sunserial_current_minor += 1; 571 sunserial_current_minor += 1;
@@ -463,6 +591,12 @@ out_unregister_driver:
463 sunserial_current_minor -= 1; 591 sunserial_current_minor -= 1;
464 uart_unregister_driver(&sunhv_reg); 592 uart_unregister_driver(&sunhv_reg);
465 593
594out_free_con_read_page:
595 kfree(con_read_page);
596
597out_free_con_write_page:
598 kfree(con_write_page);
599
466out_free_port: 600out_free_port:
467 kfree(port); 601 kfree(port);
468 sunhv_port = NULL; 602 sunhv_port = NULL;
diff --git a/include/asm-sparc64/hypervisor.h b/include/asm-sparc64/hypervisor.h
index 612bf319753f..a5558c87556d 100644
--- a/include/asm-sparc64/hypervisor.h
+++ b/include/asm-sparc64/hypervisor.h
@@ -940,6 +940,54 @@ struct hv_fault_status {
940 */ 940 */
941#define HV_FAST_CONS_PUTCHAR 0x61 941#define HV_FAST_CONS_PUTCHAR 0x61
942 942
943/* con_read()
944 * TRAP: HV_FAST_TRAP
945 * FUNCTION: HV_FAST_CONS_READ
946 * ARG0: buffer real address
947 * ARG1: buffer size in bytes
948 * RET0: status
949 * RET1: bytes read or BREAK or HUP
950 * ERRORS: EWOULDBLOCK No character available.
951 *
952 * Reads characters into a buffer from the console device. If no
953 * character is available then an EWOULDBLOCK error is returned.
954 * If a character is available, then the returned status is EOK
955 * and the number of bytes read into the given buffer is provided
956 * in RET1.
957 *
958 * A virtual BREAK is represented by the 64-bit RET1 value -1.
959 *
960 * A virtual HUP signal is represented by the 64-bit RET1 value -2.
961 *
962 * If BREAK or HUP are indicated, no bytes were read into buffer.
963 */
964#define HV_FAST_CONS_READ 0x62
965
966/* con_write()
967 * TRAP: HV_FAST_TRAP
968 * FUNCTION: HV_FAST_CONS_WRITE
969 * ARG0: buffer real address
970 * ARG1: buffer size in bytes
971 * RET0: status
972 * RET1: bytes written
973 * ERRORS: EWOULDBLOCK Output buffer currently full, would block
974 *
975 * Send a characters in buffer to the console device. Breaks must be
976 * sent using con_putchar().
977 */
978#define HV_FAST_CONS_WRITE 0x63
979
980#ifndef __ASSEMBLY__
981extern long sun4v_con_getchar(long *status);
982extern long sun4v_con_putchar(long c);
983extern long sun4v_con_read(unsigned long buffer,
984 unsigned long size,
985 unsigned long *bytes_read);
986extern unsigned long sun4v_con_write(unsigned long buffer,
987 unsigned long size,
988 unsigned long *bytes_written);
989#endif
990
943/* Trap trace services. 991/* Trap trace services.
944 * 992 *
945 * The hypervisor provides a trap tracing capability for privileged 993 * The hypervisor provides a trap tracing capability for privileged
@@ -2121,8 +2169,41 @@ struct hv_mmu_statistics {
2121#define HV_FAST_MMUSTAT_INFO 0x103 2169#define HV_FAST_MMUSTAT_INFO 0x103
2122 2170
2123/* Function numbers for HV_CORE_TRAP. */ 2171/* Function numbers for HV_CORE_TRAP. */
2124#define HV_CORE_VER 0x00 2172#define HV_CORE_SET_VER 0x00
2125#define HV_CORE_PUTCHAR 0x01 2173#define HV_CORE_PUTCHAR 0x01
2126#define HV_CORE_EXIT 0x02 2174#define HV_CORE_EXIT 0x02
2175#define HV_CORE_GET_VER 0x03
2176
2177/* Hypervisor API groups for use with HV_CORE_SET_VER and
2178 * HV_CORE_GET_VER.
2179 */
2180#define HV_GRP_SUN4V 0x0000
2181#define HV_GRP_CORE 0x0001
2182#define HV_GRP_INTR 0x0002
2183#define HV_GRP_SOFT_STATE 0x0003
2184#define HV_GRP_PCI 0x0100
2185#define HV_GRP_LDOM 0x0101
2186#define HV_GRP_SVC_CHAN 0x0102
2187#define HV_GRP_NCS 0x0103
2188#define HV_GRP_NIAG_PERF 0x0200
2189#define HV_GRP_FIRE_PERF 0x0201
2190#define HV_GRP_DIAG 0x0300
2191
2192#ifndef __ASSEMBLY__
2193extern unsigned long sun4v_get_version(unsigned long group,
2194 unsigned long *major,
2195 unsigned long *minor);
2196extern unsigned long sun4v_set_version(unsigned long group,
2197 unsigned long major,
2198 unsigned long minor,
2199 unsigned long *actual_minor);
2200
2201extern int sun4v_hvapi_register(unsigned long group, unsigned long major,
2202 unsigned long *minor);
2203extern void sun4v_hvapi_unregister(unsigned long group);
2204extern int sun4v_hvapi_get(unsigned long group,
2205 unsigned long *major,
2206 unsigned long *minor);
2207#endif
2127 2208
2128#endif /* !(_SPARC64_HYPERVISOR_H) */ 2209#endif /* !(_SPARC64_HYPERVISOR_H) */