aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/platforms/iseries/Kconfig8
-rw-r--r--arch/powerpc/platforms/iseries/dt.c3
-rw-r--r--drivers/char/Kconfig7
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/hvc_console.c14
-rw-r--r--drivers/char/hvc_console.h2
-rw-r--r--drivers/char/hvc_iseries.c594
-rw-r--r--drivers/char/hvc_rtas.c2
-rw-r--r--drivers/char/hvc_vio.c3
-rw-r--r--drivers/char/viocons.c31
-rw-r--r--include/asm-powerpc/iseries/vio.h28
11 files changed, 652 insertions, 41 deletions
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
index 3d957a30c8c2..887b68804e6d 100644
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -3,13 +3,17 @@ menu "iSeries device drivers"
3 depends on PPC_ISERIES 3 depends on PPC_ISERIES
4 4
5config VIOCONS 5config VIOCONS
6 tristate "iSeries Virtual Console Support" 6 tristate "iSeries Virtual Console Support (Obsolete)"
7 help
8 This is the old virtual console driver for legacy iSeries.
9 You should use the iSeries Hypervisor Virtual Console
10 support instead.
7 11
8config VIODASD 12config VIODASD
9 tristate "iSeries Virtual I/O disk support" 13 tristate "iSeries Virtual I/O disk support"
10 help 14 help
11 If you are running on an iSeries system and you want to use 15 If you are running on an iSeries system and you want to use
12 virtual disks created and managed by OS/400, say Y. 16 virtual disks created and managed by OS/400, say Y.
13 17
14config VIOCD 18config VIOCD
15 tristate "iSeries Virtual I/O CD support" 19 tristate "iSeries Virtual I/O CD support"
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c
index d194140c1ebf..894b534669d0 100644
--- a/arch/powerpc/platforms/iseries/dt.c
+++ b/arch/powerpc/platforms/iseries/dt.c
@@ -298,7 +298,8 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt)
298 dt_prop_u32(dt, "#address-cells", 1); 298 dt_prop_u32(dt, "#address-cells", 1);
299 dt_prop_u32(dt, "#size-cells", 0); 299 dt_prop_u32(dt, "#size-cells", 0);
300 300
301 dt_do_vdevice(dt, "vty", reg, -1, device_type_serial, NULL, 1); 301 dt_do_vdevice(dt, "vty", reg, -1, device_type_serial,
302 "IBM,iSeries-vty", 1);
302 reg++; 303 reg++;
303 304
304 dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi, 305 dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi,
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 11de59ff4229..a7ef542afbc2 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -610,6 +610,13 @@ config HVC_CONSOLE
610 console. This driver allows each pSeries partition to have a console 610 console. This driver allows each pSeries partition to have a console
611 which is accessed via the HMC. 611 which is accessed via the HMC.
612 612
613config HVC_ISERIES
614 bool "iSeries Hypervisor Virtual Console support"
615 depends on PPC_ISERIES && !VIOCONS
616 select HVC_DRIVER
617 help
618 iSeries machines support a hypervisor virtual console.
619
613config HVC_RTAS 620config HVC_RTAS
614 bool "IBM RTAS Console support" 621 bool "IBM RTAS Console support"
615 depends on PPC_RTAS 622 depends on PPC_RTAS
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 7a7ee5721279..8c6dfc621520 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
42obj-$(CONFIG_SX) += sx.o generic_serial.o 42obj-$(CONFIG_SX) += sx.o generic_serial.o
43obj-$(CONFIG_RIO) += rio/ generic_serial.o 43obj-$(CONFIG_RIO) += rio/ generic_serial.o
44obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o 44obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
45obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
45obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o 46obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
46obj-$(CONFIG_HVC_DRIVER) += hvc_console.o 47obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
47obj-$(CONFIG_RAW_DRIVER) += raw.o 48obj-$(CONFIG_RAW_DRIVER) += raw.o
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index ca2f538e549e..dbee8bed0530 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -80,7 +80,8 @@ struct hvc_struct {
80 struct tty_struct *tty; 80 struct tty_struct *tty;
81 unsigned int count; 81 unsigned int count;
82 int do_wakeup; 82 int do_wakeup;
83 char outbuf[N_OUTBUF] __ALIGNED__; 83 char *outbuf;
84 int outbuf_size;
84 int n_outbuf; 85 int n_outbuf;
85 uint32_t vtermno; 86 uint32_t vtermno;
86 struct hv_ops *ops; 87 struct hv_ops *ops;
@@ -505,7 +506,7 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
505 if (hp->n_outbuf > 0) 506 if (hp->n_outbuf > 0)
506 hvc_push(hp); 507 hvc_push(hp);
507 508
508 while (count > 0 && (rsize = N_OUTBUF - hp->n_outbuf) > 0) { 509 while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) {
509 if (rsize > count) 510 if (rsize > count)
510 rsize = count; 511 rsize = count;
511 memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); 512 memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
@@ -538,7 +539,7 @@ static int hvc_write_room(struct tty_struct *tty)
538 if (!hp) 539 if (!hp)
539 return -1; 540 return -1;
540 541
541 return N_OUTBUF - hp->n_outbuf; 542 return hp->outbuf_size - hp->n_outbuf;
542} 543}
543 544
544static int hvc_chars_in_buffer(struct tty_struct *tty) 545static int hvc_chars_in_buffer(struct tty_struct *tty)
@@ -728,12 +729,13 @@ static struct kobj_type hvc_kobj_type = {
728}; 729};
729 730
730struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, 731struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
731 struct hv_ops *ops) 732 struct hv_ops *ops, int outbuf_size)
732{ 733{
733 struct hvc_struct *hp; 734 struct hvc_struct *hp;
734 int i; 735 int i;
735 736
736 hp = kmalloc(sizeof(*hp), GFP_KERNEL); 737 hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
738 GFP_KERNEL);
737 if (!hp) 739 if (!hp)
738 return ERR_PTR(-ENOMEM); 740 return ERR_PTR(-ENOMEM);
739 741
@@ -742,6 +744,8 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
742 hp->vtermno = vtermno; 744 hp->vtermno = vtermno;
743 hp->irq = irq; 745 hp->irq = irq;
744 hp->ops = ops; 746 hp->ops = ops;
747 hp->outbuf_size = outbuf_size;
748 hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
745 749
746 kobject_init(&hp->kobj); 750 kobject_init(&hp->kobj);
747 hp->kobj.ktype = &hvc_kobj_type; 751 hp->kobj.ktype = &hvc_kobj_type;
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
index 96b7401319c1..8c59818050e6 100644
--- a/drivers/char/hvc_console.h
+++ b/drivers/char/hvc_console.h
@@ -56,7 +56,7 @@ extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
56 56
57/* register a vterm for hvc tty operation (module_init or hotplug add) */ 57/* register a vterm for hvc tty operation (module_init or hotplug add) */
58extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq, 58extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq,
59 struct hv_ops *ops); 59 struct hv_ops *ops, int outbuf_size);
60/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ 60/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
61extern int __devexit hvc_remove(struct hvc_struct *hp); 61extern int __devexit hvc_remove(struct hvc_struct *hp);
62 62
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
new file mode 100644
index 000000000000..4747729459c7
--- /dev/null
+++ b/drivers/char/hvc_iseries.c
@@ -0,0 +1,594 @@
1/*
2 * iSeries vio driver interface to hvc_console.c
3 *
4 * This code is based heavily on hvc_vio.c and viocons.c
5 *
6 * Copyright (C) 2006 Stephen Rothwell, IBM Corporation
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22#include <stdarg.h>
23#include <linux/types.h>
24#include <linux/init.h>
25#include <linux/kernel.h>
26#include <linux/spinlock.h>
27#include <linux/console.h>
28
29#include <asm/hvconsole.h>
30#include <asm/vio.h>
31#include <asm/prom.h>
32#include <asm/iseries/vio.h>
33#include <asm/iseries/hv_call.h>
34#include <asm/iseries/hv_lp_config.h>
35#include <asm/iseries/hv_lp_event.h>
36
37#include "hvc_console.h"
38
39#define VTTY_PORTS 10
40
41static DEFINE_SPINLOCK(consolelock);
42static DEFINE_SPINLOCK(consoleloglock);
43
44static const char hvc_driver_name[] = "hvc_console";
45
46#define IN_BUF_SIZE 200
47
48/*
49 * Our port information.
50 */
51static struct port_info {
52 HvLpIndex lp;
53 u64 seq; /* sequence number of last HV send */
54 u64 ack; /* last ack from HV */
55 struct hvc_struct *hp;
56 int in_start;
57 int in_end;
58 unsigned char in_buf[IN_BUF_SIZE];
59} port_info[VTTY_PORTS] = {
60 [ 0 ... VTTY_PORTS - 1 ] = {
61 .lp = HvLpIndexInvalid
62 }
63};
64
65#define viochar_is_console(pi) ((pi) == &port_info[0])
66
67static struct vio_device_id hvc_driver_table[] __devinitdata = {
68 {"serial", "IBM,iSeries-vty"},
69 { "", "" }
70};
71MODULE_DEVICE_TABLE(vio, hvc_driver_table);
72
73static void hvlog(char *fmt, ...)
74{
75 int i;
76 unsigned long flags;
77 va_list args;
78 static char buf[256];
79
80 spin_lock_irqsave(&consoleloglock, flags);
81 va_start(args, fmt);
82 i = vscnprintf(buf, sizeof(buf) - 1, fmt, args);
83 va_end(args);
84 buf[i++] = '\r';
85 HvCall_writeLogBuffer(buf, i);
86 spin_unlock_irqrestore(&consoleloglock, flags);
87}
88
89/*
90 * Initialize the common fields in a charLpEvent
91 */
92static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp)
93{
94 struct HvLpEvent *hev = &viochar->event;
95
96 memset(viochar, 0, sizeof(struct viocharlpevent));
97
98 hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK |
99 HV_LP_EVENT_INT;
100 hev->xType = HvLpEvent_Type_VirtualIo;
101 hev->xSubtype = viomajorsubtype_chario | viochardata;
102 hev->xSourceLp = HvLpConfig_getLpIndex();
103 hev->xTargetLp = lp;
104 hev->xSizeMinus1 = sizeof(struct viocharlpevent);
105 hev->xSourceInstanceId = viopath_sourceinst(lp);
106 hev->xTargetInstanceId = viopath_targetinst(lp);
107}
108
109static int get_chars(uint32_t vtermno, char *buf, int count)
110{
111 struct port_info *pi;
112 int n = 0;
113 unsigned long flags;
114
115 if (vtermno >= VTTY_PORTS)
116 return -EINVAL;
117 if (count == 0)
118 return 0;
119
120 pi = &port_info[vtermno];
121 spin_lock_irqsave(&consolelock, flags);
122
123 if (pi->in_end == 0)
124 goto done;
125
126 n = pi->in_end - pi->in_start;
127 if (n > count)
128 n = count;
129 memcpy(buf, &pi->in_buf[pi->in_start], n);
130 pi->in_start += n;
131 if (pi->in_start == pi->in_end) {
132 pi->in_start = 0;
133 pi->in_end = 0;
134 }
135done:
136 spin_unlock_irqrestore(&consolelock, flags);
137 return n;
138}
139
140static int put_chars(uint32_t vtermno, const char *buf, int count)
141{
142 struct viocharlpevent *viochar;
143 struct port_info *pi;
144 HvLpEvent_Rc hvrc;
145 unsigned long flags;
146 int sent = 0;
147
148 if (vtermno >= VTTY_PORTS)
149 return -EINVAL;
150
151 pi = &port_info[vtermno];
152
153 spin_lock_irqsave(&consolelock, flags);
154
155 if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) {
156 spin_lock_irqsave(&consoleloglock, flags);
157 HvCall_writeLogBuffer(buf, count);
158 spin_unlock_irqrestore(&consoleloglock, flags);
159 sent = count;
160 goto done;
161 }
162
163 viochar = vio_get_event_buffer(viomajorsubtype_chario);
164 if (viochar == NULL) {
165 hvlog("\n\rviocons: Can't get viochar buffer.");
166 goto done;
167 }
168
169 while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
170 int len;
171
172 len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count;
173
174 if (viochar_is_console(pi)) {
175 spin_lock_irqsave(&consoleloglock, flags);
176 HvCall_writeLogBuffer(buf, len);
177 spin_unlock_irqrestore(&consoleloglock, flags);
178 }
179
180 init_data_event(viochar, pi->lp);
181
182 viochar->len = len;
183 viochar->event.xCorrelationToken = pi->seq++;
184 viochar->event.xSizeMinus1 =
185 offsetof(struct viocharlpevent, data) + len;
186
187 memcpy(viochar->data, buf, len);
188
189 hvrc = HvCallEvent_signalLpEvent(&viochar->event);
190 if (hvrc)
191 hvlog("\n\rerror sending event! return code %d\n\r",
192 (int)hvrc);
193 sent += len;
194 count -= len;
195 buf += len;
196 }
197
198 vio_free_event_buffer(viomajorsubtype_chario, viochar);
199done:
200 spin_unlock_irqrestore(&consolelock, flags);
201 return sent;
202}
203
204static struct hv_ops hvc_get_put_ops = {
205 .get_chars = get_chars,
206 .put_chars = put_chars,
207};
208
209static int __devinit hvc_vio_probe(struct vio_dev *vdev,
210 const struct vio_device_id *id)
211{
212 struct hvc_struct *hp;
213 struct port_info *pi;
214
215 /* probed with invalid parameters. */
216 if (!vdev || !id)
217 return -EPERM;
218
219 if (vdev->unit_address >= VTTY_PORTS)
220 return -ENODEV;
221
222 pi = &port_info[vdev->unit_address];
223
224 hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
225 VIOCHAR_MAX_DATA);
226 if (IS_ERR(hp))
227 return PTR_ERR(hp);
228 pi->hp = hp;
229 dev_set_drvdata(&vdev->dev, pi);
230
231 return 0;
232}
233
234static int __devexit hvc_vio_remove(struct vio_dev *vdev)
235{
236 struct port_info *pi = dev_get_drvdata(&vdev->dev);
237 struct hvc_struct *hp = pi->hp;
238
239 return hvc_remove(hp);
240}
241
242static struct vio_driver hvc_vio_driver = {
243 .id_table = hvc_driver_table,
244 .probe = hvc_vio_probe,
245 .remove = hvc_vio_remove,
246 .driver = {
247 .name = hvc_driver_name,
248 .owner = THIS_MODULE,
249 }
250};
251
252static void hvc_open_event(struct HvLpEvent *event)
253{
254 unsigned long flags;
255 struct viocharlpevent *cevent = (struct viocharlpevent *)event;
256 u8 port = cevent->virtual_device;
257 struct port_info *pi;
258 int reject = 0;
259
260 if (hvlpevent_is_ack(event)) {
261 if (port >= VTTY_PORTS)
262 return;
263
264 spin_lock_irqsave(&consolelock, flags);
265
266 pi = &port_info[port];
267 if (event->xRc == HvLpEvent_Rc_Good) {
268 pi->seq = pi->ack = 0;
269 /*
270 * This line allows connections from the primary
271 * partition but once one is connected from the
272 * primary partition nothing short of a reboot
273 * of linux will allow access from the hosting
274 * partition again without a required iSeries fix.
275 */
276 pi->lp = event->xTargetLp;
277 }
278
279 spin_unlock_irqrestore(&consolelock, flags);
280 if (event->xRc != HvLpEvent_Rc_Good)
281 printk(KERN_WARNING
282 "hvc: handle_open_event: event->xRc == (%d).\n",
283 event->xRc);
284
285 if (event->xCorrelationToken != 0) {
286 atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
287 atomic_set(aptr, 1);
288 } else
289 printk(KERN_WARNING
290 "hvc: weird...got open ack without atomic\n");
291 return;
292 }
293
294 /* This had better require an ack, otherwise complain */
295 if (!hvlpevent_need_ack(event)) {
296 printk(KERN_WARNING "hvc: viocharopen without ack bit!\n");
297 return;
298 }
299
300 spin_lock_irqsave(&consolelock, flags);
301
302 /* Make sure this is a good virtual tty */
303 if (port >= VTTY_PORTS) {
304 event->xRc = HvLpEvent_Rc_SubtypeError;
305 cevent->subtype_result_code = viorc_openRejected;
306 /*
307 * Flag state here since we can't printk while holding
308 * the consolelock spinlock.
309 */
310 reject = 1;
311 } else {
312 pi = &port_info[port];
313 if ((pi->lp != HvLpIndexInvalid) &&
314 (pi->lp != event->xSourceLp)) {
315 /*
316 * If this is tty is already connected to a different
317 * partition, fail.
318 */
319 event->xRc = HvLpEvent_Rc_SubtypeError;
320 cevent->subtype_result_code = viorc_openRejected;
321 reject = 2;
322 } else {
323 pi->lp = event->xSourceLp;
324 event->xRc = HvLpEvent_Rc_Good;
325 cevent->subtype_result_code = viorc_good;
326 pi->seq = pi->ack = 0;
327 }
328 }
329
330 spin_unlock_irqrestore(&consolelock, flags);
331
332 if (reject == 1)
333 printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n");
334 else if (reject == 2)
335 printk(KERN_WARNING "hvc: open rejected: console in exclusive "
336 "use by another partition.\n");
337
338 /* Return the acknowledgement */
339 HvCallEvent_ackLpEvent(event);
340}
341
342/*
343 * Handle a close charLpEvent. This should ONLY be an Interrupt because the
344 * virtual console should never actually issue a close event to the hypervisor
345 * because the virtual console never goes away. A close event coming from the
346 * hypervisor simply means that there are no client consoles connected to the
347 * virtual console.
348 */
349static void hvc_close_event(struct HvLpEvent *event)
350{
351 unsigned long flags;
352 struct viocharlpevent *cevent = (struct viocharlpevent *)event;
353 u8 port = cevent->virtual_device;
354
355 if (!hvlpevent_is_int(event)) {
356 printk(KERN_WARNING
357 "hvc: got unexpected close acknowlegement\n");
358 return;
359 }
360
361 if (port >= VTTY_PORTS) {
362 printk(KERN_WARNING
363 "hvc: close message from invalid virtual device.\n");
364 return;
365 }
366
367 /* For closes, just mark the console partition invalid */
368 spin_lock_irqsave(&consolelock, flags);
369
370 if (port_info[port].lp == event->xSourceLp)
371 port_info[port].lp = HvLpIndexInvalid;
372
373 spin_unlock_irqrestore(&consolelock, flags);
374}
375
376static void hvc_data_event(struct HvLpEvent *event)
377{
378 unsigned long flags;
379 struct viocharlpevent *cevent = (struct viocharlpevent *)event;
380 struct port_info *pi;
381 int n;
382 u8 port = cevent->virtual_device;
383
384 if (port >= VTTY_PORTS) {
385 printk(KERN_WARNING "hvc: data on invalid virtual device %d\n",
386 port);
387 return;
388 }
389 if (cevent->len == 0)
390 return;
391
392 /*
393 * Change 05/01/2003 - Ryan Arnold: If a partition other than
394 * the current exclusive partition tries to send us data
395 * events then just drop them on the floor because we don't
396 * want his stinking data. He isn't authorized to receive
397 * data because he wasn't the first one to get the console,
398 * therefore he shouldn't be allowed to send data either.
399 * This will work without an iSeries fix.
400 */
401 pi = &port_info[port];
402 if (pi->lp != event->xSourceLp)
403 return;
404
405 spin_lock_irqsave(&consolelock, flags);
406
407 n = IN_BUF_SIZE - pi->in_end;
408 if (n > cevent->len)
409 n = cevent->len;
410 if (n > 0) {
411 memcpy(&pi->in_buf[pi->in_end], cevent->data, n);
412 pi->in_end += n;
413 }
414 spin_unlock_irqrestore(&consolelock, flags);
415 if (n == 0)
416 printk(KERN_WARNING "hvc: input buffer overflow\n");
417}
418
419static void hvc_ack_event(struct HvLpEvent *event)
420{
421 struct viocharlpevent *cevent = (struct viocharlpevent *)event;
422 unsigned long flags;
423 u8 port = cevent->virtual_device;
424
425 if (port >= VTTY_PORTS) {
426 printk(KERN_WARNING "hvc: data on invalid virtual device\n");
427 return;
428 }
429
430 spin_lock_irqsave(&consolelock, flags);
431 port_info[port].ack = event->xCorrelationToken;
432 spin_unlock_irqrestore(&consolelock, flags);
433}
434
435static void hvc_config_event(struct HvLpEvent *event)
436{
437 struct viocharlpevent *cevent = (struct viocharlpevent *)event;
438
439 if (cevent->data[0] == 0x01)
440 printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n",
441 cevent->data[1], cevent->data[2],
442 cevent->data[3], cevent->data[4]);
443 else
444 printk(KERN_WARNING "hvc: unknown config event\n");
445}
446
447static void hvc_handle_event(struct HvLpEvent *event)
448{
449 int charminor;
450
451 if (event == NULL)
452 return;
453
454 charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
455 switch (charminor) {
456 case viocharopen:
457 hvc_open_event(event);
458 break;
459 case viocharclose:
460 hvc_close_event(event);
461 break;
462 case viochardata:
463 hvc_data_event(event);
464 break;
465 case viocharack:
466 hvc_ack_event(event);
467 break;
468 case viocharconfig:
469 hvc_config_event(event);
470 break;
471 default:
472 if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
473 event->xRc = HvLpEvent_Rc_InvalidSubtype;
474 HvCallEvent_ackLpEvent(event);
475 }
476 }
477}
478
479static int send_open(HvLpIndex remoteLp, void *sem)
480{
481 return HvCallEvent_signalLpEventFast(remoteLp,
482 HvLpEvent_Type_VirtualIo,
483 viomajorsubtype_chario | viocharopen,
484 HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
485 viopath_sourceinst(remoteLp),
486 viopath_targetinst(remoteLp),
487 (u64)(unsigned long)sem, VIOVERSION << 16,
488 0, 0, 0, 0);
489}
490
491static int hvc_vio_init(void)
492{
493 atomic_t wait_flag;
494 int rc;
495
496 /* +2 for fudge */
497 rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
498 viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
499 if (rc)
500 printk(KERN_WARNING "hvc: error opening to primary %d\n", rc);
501
502 if (viopath_hostLp == HvLpIndexInvalid)
503 vio_set_hostlp();
504
505 /*
506 * And if the primary is not the same as the hosting LP, open to the
507 * hosting lp
508 */
509 if ((viopath_hostLp != HvLpIndexInvalid) &&
510 (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
511 printk(KERN_INFO "hvc: open path to hosting (%d)\n",
512 viopath_hostLp);
513 rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
514 VIOCHAR_WINDOW + 2); /* +2 for fudge */
515 if (rc)
516 printk(KERN_WARNING
517 "error opening to partition %d: %d\n",
518 viopath_hostLp, rc);
519 }
520
521 if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0)
522 printk(KERN_WARNING
523 "hvc: error seting handler for console events!\n");
524
525 /*
526 * First, try to open the console to the hosting lp.
527 * Wait on a semaphore for the response.
528 */
529 atomic_set(&wait_flag, 0);
530 if ((viopath_isactive(viopath_hostLp)) &&
531 (send_open(viopath_hostLp, &wait_flag) == 0)) {
532 printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp);
533 while (atomic_read(&wait_flag) == 0)
534 mb();
535 atomic_set(&wait_flag, 0);
536 }
537
538 /*
539 * If we don't have an active console, try the primary
540 */
541 if ((!viopath_isactive(port_info[0].lp)) &&
542 (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
543 (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) {
544 printk(KERN_INFO "hvc: opening console to primary partition\n");
545 while (atomic_read(&wait_flag) == 0)
546 mb();
547 }
548
549 /* Register as a vio device to receive callbacks */
550 rc = vio_register_driver(&hvc_vio_driver);
551
552 return rc;
553}
554module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
555
556static void hvc_vio_exit(void)
557{
558 vio_unregister_driver(&hvc_vio_driver);
559}
560module_exit(hvc_vio_exit);
561
562/* the device tree order defines our numbering */
563static int hvc_find_vtys(void)
564{
565 struct device_node *vty;
566 int num_found = 0;
567
568 for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
569 vty = of_find_node_by_name(vty, "vty")) {
570 uint32_t *vtermno;
571
572 /* We have statically defined space for only a certain number
573 * of console adapters.
574 */
575 if ((num_found >= MAX_NR_HVC_CONSOLES) ||
576 (num_found >= VTTY_PORTS))
577 break;
578
579 vtermno = (uint32_t *)get_property(vty, "reg", NULL);
580 if (!vtermno)
581 continue;
582
583 if (!device_is_compatible(vty, "IBM,iSeries-vty"))
584 continue;
585
586 if (num_found == 0)
587 add_preferred_console("hvc", 0, NULL);
588 hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
589 ++num_found;
590 }
591
592 return num_found;
593}
594console_initcall(hvc_find_vtys);
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c
index 57106e02fd2e..4b97eaf18602 100644
--- a/drivers/char/hvc_rtas.c
+++ b/drivers/char/hvc_rtas.c
@@ -94,7 +94,7 @@ static int hvc_rtas_init(void)
94 94
95 /* Allocate an hvc_struct for the console device we instantiated 95 /* Allocate an hvc_struct for the console device we instantiated
96 * earlier. Save off hp so that we can return it on exit */ 96 * earlier. Save off hp so that we can return it on exit */
97 hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops); 97 hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16);
98 if (IS_ERR(hp)) 98 if (IS_ERR(hp))
99 return PTR_ERR(hp); 99 return PTR_ERR(hp);
100 100
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index 9add81ceb440..651e5d25f58b 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -90,7 +90,8 @@ static int __devinit hvc_vio_probe(struct vio_dev *vdev,
90 if (!vdev || !id) 90 if (!vdev || !id)
91 return -EPERM; 91 return -EPERM;
92 92
93 hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops); 93 hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
94 MAX_VIO_PUT_CHARS);
94 if (IS_ERR(hp)) 95 if (IS_ERR(hp))
95 return PTR_ERR(hp); 96 return PTR_ERR(hp);
96 dev_set_drvdata(&vdev->dev, hp); 97 dev_set_drvdata(&vdev->dev, hp);
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
index 766f7864c6c6..f3efeaf2826e 100644
--- a/drivers/char/viocons.c
+++ b/drivers/char/viocons.c
@@ -43,7 +43,6 @@
43#include <linux/sysrq.h> 43#include <linux/sysrq.h>
44 44
45#include <asm/iseries/vio.h> 45#include <asm/iseries/vio.h>
46
47#include <asm/iseries/hv_lp_event.h> 46#include <asm/iseries/hv_lp_event.h>
48#include <asm/iseries/hv_call_event.h> 47#include <asm/iseries/hv_call_event.h>
49#include <asm/iseries/hv_lp_config.h> 48#include <asm/iseries/hv_lp_config.h>
@@ -67,35 +66,6 @@ static int vio_sysrq_pressed;
67extern int sysrq_enabled; 66extern int sysrq_enabled;
68#endif 67#endif
69 68
70/*
71 * The structure of the events that flow between us and OS/400. You can't
72 * mess with this unless the OS/400 side changes too
73 */
74struct viocharlpevent {
75 struct HvLpEvent event;
76 u32 reserved;
77 u16 version;
78 u16 subtype_result_code;
79 u8 virtual_device;
80 u8 len;
81 u8 data[VIOCHAR_MAX_DATA];
82};
83
84#define VIOCHAR_WINDOW 10
85#define VIOCHAR_HIGHWATERMARK 3
86
87enum viocharsubtype {
88 viocharopen = 0x0001,
89 viocharclose = 0x0002,
90 viochardata = 0x0003,
91 viocharack = 0x0004,
92 viocharconfig = 0x0005
93};
94
95enum viochar_rc {
96 viochar_rc_ebusy = 1
97};
98
99#define VIOCHAR_NUM_BUF 16 69#define VIOCHAR_NUM_BUF 16
100 70
101/* 71/*
@@ -1183,6 +1153,7 @@ static int __init viocons_init(void)
1183 port_info[i].magic = VIOTTY_MAGIC; 1153 port_info[i].magic = VIOTTY_MAGIC;
1184 } 1154 }
1185 HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437); 1155 HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437);
1156 add_preferred_console("viocons", 0, NULL);
1186 register_console(&viocons_early); 1157 register_console(&viocons_early);
1187 return 0; 1158 return 0;
1188} 1159}
diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h
index 72a97d37aac3..7a95d296abd1 100644
--- a/include/asm-powerpc/iseries/vio.h
+++ b/include/asm-powerpc/iseries/vio.h
@@ -122,6 +122,34 @@ enum viorc {
122 viorc_openRejected = 0x0301 122 viorc_openRejected = 0x0301
123}; 123};
124 124
125/*
126 * The structure of the events that flow between us and OS/400 for chario
127 * events. You can't mess with this unless the OS/400 side changes too.
128 */
129struct viocharlpevent {
130 struct HvLpEvent event;
131 u32 reserved;
132 u16 version;
133 u16 subtype_result_code;
134 u8 virtual_device;
135 u8 len;
136 u8 data[VIOCHAR_MAX_DATA];
137};
138
139#define VIOCHAR_WINDOW 10
140
141enum viocharsubtype {
142 viocharopen = 0x0001,
143 viocharclose = 0x0002,
144 viochardata = 0x0003,
145 viocharack = 0x0004,
146 viocharconfig = 0x0005
147};
148
149enum viochar_rc {
150 viochar_rc_ebusy = 1
151};
152
125struct device; 153struct device;
126 154
127extern struct device *iSeries_vio_dev; 155extern struct device *iSeries_vio_dev;