]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/char/viocons.c
viocons: BKL locking
[linux-2.6-omap-h63xx.git] / drivers / char / viocons.c
1 /* -*- linux-c -*-
2  *
3  *  drivers/char/viocons.c
4  *
5  *  iSeries Virtual Terminal
6  *
7  *  Authors: Dave Boutcher <boutcher@us.ibm.com>
8  *           Ryan Arnold <ryanarn@us.ibm.com>
9  *           Colin Devilbiss <devilbis@us.ibm.com>
10  *           Stephen Rothwell <sfr@au1.ibm.com>
11  *
12  * (C) Copyright 2000, 2001, 2002, 2003, 2004 IBM Corporation
13  *
14  * This program is free software;  you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) anyu later version.
18  *
19  * This program is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27  */
28 #include <linux/kernel.h>
29 #include <linux/proc_fs.h>
30 #include <linux/errno.h>
31 #include <linux/vmalloc.h>
32 #include <linux/mm.h>
33 #include <linux/console.h>
34 #include <linux/module.h>
35 #include <asm/uaccess.h>
36 #include <linux/init.h>
37 #include <linux/wait.h>
38 #include <linux/spinlock.h>
39 #include <asm/ioctls.h>
40 #include <linux/kd.h>
41 #include <linux/tty.h>
42 #include <linux/tty_flip.h>
43 #include <linux/sysrq.h>
44
45 #include <asm/firmware.h>
46 #include <asm/iseries/vio.h>
47 #include <asm/iseries/hv_lp_event.h>
48 #include <asm/iseries/hv_call_event.h>
49 #include <asm/iseries/hv_lp_config.h>
50 #include <asm/iseries/hv_call.h>
51
52 #ifdef CONFIG_VT
53 #error You must turn off CONFIG_VT to use CONFIG_VIOCONS
54 #endif
55
56 #define VIOTTY_MAGIC (0x0DCB)
57 #define VTTY_PORTS 10
58
59 #define VIOCONS_KERN_WARN       KERN_WARNING "viocons: "
60 #define VIOCONS_KERN_INFO       KERN_INFO "viocons: "
61
62 static DEFINE_SPINLOCK(consolelock);
63 static DEFINE_SPINLOCK(consoleloglock);
64
65 static int vio_sysrq_pressed;
66
67 #define VIOCHAR_NUM_BUF         16
68
69 /*
70  * Our port information.  We store a pointer to one entry in the
71  * tty_driver_data
72  */
73 static struct port_info {
74         int magic;
75         struct tty_struct *tty;
76         HvLpIndex lp;
77         u8 vcons;
78         u64 seq;        /* sequence number of last HV send */
79         u64 ack;        /* last ack from HV */
80 /*
81  * When we get writes faster than we can send it to the partition,
82  * buffer the data here. Note that used is a bit map of used buffers.
83  * It had better have enough bits to hold VIOCHAR_NUM_BUF the bitops assume
84  * it is a multiple of unsigned long
85  */
86         unsigned long used;
87         u8 *buffer[VIOCHAR_NUM_BUF];
88         int bufferBytes[VIOCHAR_NUM_BUF];
89         int curbuf;
90         int bufferOverflow;
91         int overflowMessage;
92 } port_info[VTTY_PORTS];
93
94 #define viochar_is_console(pi)  ((pi) == &port_info[0])
95 #define viochar_port(pi)        ((pi) - &port_info[0])
96
97 static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp);
98
99 static struct tty_driver *viotty_driver;
100
101 static void hvlog(char *fmt, ...)
102 {
103         int i;
104         unsigned long flags;
105         va_list args;
106         static char buf[256];
107
108         spin_lock_irqsave(&consoleloglock, flags);
109         va_start(args, fmt);
110         i = vscnprintf(buf, sizeof(buf) - 1, fmt, args);
111         va_end(args);
112         buf[i++] = '\r';
113         HvCall_writeLogBuffer(buf, i);
114         spin_unlock_irqrestore(&consoleloglock, flags);
115 }
116
117 static void hvlogOutput(const char *buf, int count)
118 {
119         unsigned long flags;
120         int begin;
121         int index;
122         static const char cr = '\r';
123
124         begin = 0;
125         spin_lock_irqsave(&consoleloglock, flags);
126         for (index = 0; index < count; index++) {
127                 if (buf[index] == '\n') {
128                         /*
129                          * Start right after the last '\n' or at the zeroth
130                          * array position and output the number of characters
131                          * including the newline.
132                          */
133                         HvCall_writeLogBuffer(&buf[begin], index - begin + 1);
134                         begin = index + 1;
135                         HvCall_writeLogBuffer(&cr, 1);
136                 }
137         }
138         if ((index - begin) > 0)
139                 HvCall_writeLogBuffer(&buf[begin], index - begin);
140         spin_unlock_irqrestore(&consoleloglock, flags);
141 }
142
143 /*
144  * Make sure we're pointing to a valid port_info structure.  Shamelessly
145  * plagerized from serial.c
146  */
147 static inline int viotty_paranoia_check(struct port_info *pi,
148                                         char *name, const char *routine)
149 {
150         static const char *bad_pi_addr = VIOCONS_KERN_WARN
151                 "warning: bad address for port_info struct (%s) in %s\n";
152         static const char *badmagic = VIOCONS_KERN_WARN
153                 "warning: bad magic number for port_info struct (%s) in %s\n";
154
155         if ((pi < &port_info[0]) || (viochar_port(pi) > VTTY_PORTS)) {
156                 printk(bad_pi_addr, name, routine);
157                 return 1;
158         }
159         if (pi->magic != VIOTTY_MAGIC) {
160                 printk(badmagic, name, routine);
161                 return 1;
162         }
163         return 0;
164 }
165
166 /*
167  * Add data to our pending-send buffers.  
168  *
169  * NOTE: Don't use printk in here because it gets nastily recursive.
170  * hvlog can be used to log to the hypervisor buffer
171  */
172 static int buffer_add(struct port_info *pi, const char *buf, size_t len)
173 {
174         size_t bleft;
175         size_t curlen;
176         const char *curbuf;
177         int nextbuf;
178
179         curbuf = buf;
180         bleft = len;
181         while (bleft > 0) {
182                 /*
183                  * If there is no space left in the current buffer, we have
184                  * filled everything up, so return.  If we filled the previous
185                  * buffer we would already have moved to the next one.
186                  */
187                 if (pi->bufferBytes[pi->curbuf] == VIOCHAR_MAX_DATA) {
188                         hvlog ("\n\rviocons: No overflow buffer available for memcpy().\n");
189                         pi->bufferOverflow++;
190                         pi->overflowMessage = 1;
191                         break;
192                 }
193
194                 /*
195                  * Turn on the "used" bit for this buffer.  If it's already on,
196                  * that's fine.
197                  */
198                 set_bit(pi->curbuf, &pi->used);
199
200                 /*
201                  * See if this buffer has been allocated.  If not, allocate it.
202                  */
203                 if (pi->buffer[pi->curbuf] == NULL) {
204                         pi->buffer[pi->curbuf] =
205                             kmalloc(VIOCHAR_MAX_DATA, GFP_ATOMIC);
206                         if (pi->buffer[pi->curbuf] == NULL) {
207                                 hvlog("\n\rviocons: kmalloc failed allocating spaces for buffer %d.",
208                                         pi->curbuf);
209                                 break;
210                         }
211                 }
212
213                 /* Figure out how much we can copy into this buffer. */
214                 if (bleft < (VIOCHAR_MAX_DATA - pi->bufferBytes[pi->curbuf]))
215                         curlen = bleft;
216                 else
217                         curlen = VIOCHAR_MAX_DATA - pi->bufferBytes[pi->curbuf];
218
219                 /* Copy the data into the buffer. */
220                 memcpy(pi->buffer[pi->curbuf] + pi->bufferBytes[pi->curbuf],
221                                 curbuf, curlen);
222
223                 pi->bufferBytes[pi->curbuf] += curlen;
224                 curbuf += curlen;
225                 bleft -= curlen;
226
227                 /*
228                  * Now see if we've filled this buffer.  If not then
229                  * we'll try to use it again later.  If we've filled it
230                  * up then we'll advance the curbuf to the next in the
231                  * circular queue.
232                  */
233                 if (pi->bufferBytes[pi->curbuf] == VIOCHAR_MAX_DATA) {
234                         nextbuf = (pi->curbuf + 1) % VIOCHAR_NUM_BUF;
235                         /*
236                          * Move to the next buffer if it hasn't been used yet
237                          */
238                         if (test_bit(nextbuf, &pi->used) == 0)
239                                 pi->curbuf = nextbuf;
240                 }
241         }
242         return len - bleft;
243 }
244
245 /*
246  * Send pending data
247  *
248  * NOTE: Don't use printk in here because it gets nastily recursive.
249  * hvlog can be used to log to the hypervisor buffer
250  */
251 static void send_buffers(struct port_info *pi)
252 {
253         HvLpEvent_Rc hvrc;
254         int nextbuf;
255         struct viocharlpevent *viochar;
256         unsigned long flags;
257
258         spin_lock_irqsave(&consolelock, flags);
259
260         viochar = (struct viocharlpevent *)
261             vio_get_event_buffer(viomajorsubtype_chario);
262
263         /* Make sure we got a buffer */
264         if (viochar == NULL) {
265                 hvlog("\n\rviocons: Can't get viochar buffer in sendBuffers().");
266                 spin_unlock_irqrestore(&consolelock, flags);
267                 return;
268         }
269
270         if (pi->used == 0) {
271                 hvlog("\n\rviocons: in sendbuffers(), but no buffers used.\n");
272                 vio_free_event_buffer(viomajorsubtype_chario, viochar);
273                 spin_unlock_irqrestore(&consolelock, flags);
274                 return;
275         }
276
277         /*
278          * curbuf points to the buffer we're filling.  We want to
279          * start sending AFTER this one.  
280          */
281         nextbuf = (pi->curbuf + 1) % VIOCHAR_NUM_BUF;
282
283         /*
284          * Loop until we find a buffer with the used bit on
285          */
286         while (test_bit(nextbuf, &pi->used) == 0)
287                 nextbuf = (nextbuf + 1) % VIOCHAR_NUM_BUF;
288
289         initDataEvent(viochar, pi->lp);
290
291         /*
292          * While we have buffers with data, and our send window
293          * is open, send them
294          */
295         while ((test_bit(nextbuf, &pi->used)) &&
296                ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
297                 viochar->len = pi->bufferBytes[nextbuf];
298                 viochar->event.xCorrelationToken = pi->seq++;
299                 viochar->event.xSizeMinus1 =
300                         offsetof(struct viocharlpevent, data) + viochar->len;
301
302                 memcpy(viochar->data, pi->buffer[nextbuf], viochar->len);
303
304                 hvrc = HvCallEvent_signalLpEvent(&viochar->event);
305                 if (hvrc) {
306                         /*
307                          * MUST unlock the spinlock before doing a printk
308                          */
309                         vio_free_event_buffer(viomajorsubtype_chario, viochar);
310                         spin_unlock_irqrestore(&consolelock, flags);
311
312                         printk(VIOCONS_KERN_WARN
313                                "error sending event! return code %d\n",
314                                (int)hvrc);
315                         return;
316                 }
317
318                 /*
319                  * clear the used bit, zero the number of bytes in
320                  * this buffer, and move to the next buffer
321                  */
322                 clear_bit(nextbuf, &pi->used);
323                 pi->bufferBytes[nextbuf] = 0;
324                 nextbuf = (nextbuf + 1) % VIOCHAR_NUM_BUF;
325         }
326
327         /*
328          * If we have emptied all the buffers, start at 0 again.
329          * this will re-use any allocated buffers
330          */
331         if (pi->used == 0) {
332                 pi->curbuf = 0;
333
334                 if (pi->overflowMessage)
335                         pi->overflowMessage = 0;
336
337                 if (pi->tty) {
338                         tty_wakeup(pi->tty);
339                 }
340         }
341
342         vio_free_event_buffer(viomajorsubtype_chario, viochar);
343         spin_unlock_irqrestore(&consolelock, flags);
344 }
345
346 /*
347  * Our internal writer.  Gets called both from the console device and
348  * the tty device.  the tty pointer will be NULL if called from the console.
349  * Return total number of bytes "written".
350  *
351  * NOTE: Don't use printk in here because it gets nastily recursive.  hvlog
352  * can be used to log to the hypervisor buffer
353  */
354 static int internal_write(struct port_info *pi, const char *buf, size_t len)
355 {
356         HvLpEvent_Rc hvrc;
357         size_t bleft;
358         size_t curlen;
359         const char *curbuf;
360         unsigned long flags;
361         struct viocharlpevent *viochar;
362
363         /*
364          * Write to the hvlog of inbound data are now done prior to
365          * calling internal_write() since internal_write() is only called in
366          * the event that an lp event path is active, which isn't the case for
367          * logging attempts prior to console initialization.
368          *
369          * If there is already data queued for this port, send it prior to
370          * attempting to send any new data.
371          */
372         if (pi->used)
373                 send_buffers(pi);
374
375         spin_lock_irqsave(&consolelock, flags);
376
377         viochar = vio_get_event_buffer(viomajorsubtype_chario);
378         if (viochar == NULL) {
379                 spin_unlock_irqrestore(&consolelock, flags);
380                 hvlog("\n\rviocons: Can't get vio buffer in internal_write().");
381                 return -EAGAIN;
382         }
383         initDataEvent(viochar, pi->lp);
384
385         curbuf = buf;
386         bleft = len;
387
388         while ((bleft > 0) && (pi->used == 0) &&
389                ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
390                 if (bleft > VIOCHAR_MAX_DATA)
391                         curlen = VIOCHAR_MAX_DATA;
392                 else
393                         curlen = bleft;
394
395                 viochar->event.xCorrelationToken = pi->seq++;
396                 memcpy(viochar->data, curbuf, curlen);
397                 viochar->len = curlen;
398                 viochar->event.xSizeMinus1 =
399                     offsetof(struct viocharlpevent, data) + curlen;
400
401                 hvrc = HvCallEvent_signalLpEvent(&viochar->event);
402                 if (hvrc) {
403                         hvlog("viocons: error sending event! %d\n", (int)hvrc);
404                         goto out;
405                 }
406                 curbuf += curlen;
407                 bleft -= curlen;
408         }
409
410         /* If we didn't send it all, buffer as much of it as we can. */
411         if (bleft > 0)
412                 bleft -= buffer_add(pi, curbuf, bleft);
413 out:
414         vio_free_event_buffer(viomajorsubtype_chario, viochar);
415         spin_unlock_irqrestore(&consolelock, flags);
416         return len - bleft;
417 }
418
419 static struct port_info *get_port_data(struct tty_struct *tty)
420 {
421         unsigned long flags;
422         struct port_info *pi;
423
424         spin_lock_irqsave(&consolelock, flags);
425         if (tty) {
426                 pi = (struct port_info *)tty->driver_data;
427                 if (!pi || viotty_paranoia_check(pi, tty->name,
428                                              "get_port_data")) {
429                         pi = NULL;
430                 }
431         } else
432                 /*
433                  * If this is the console device, use the lp from
434                  * the first port entry
435                  */
436                 pi = &port_info[0];
437         spin_unlock_irqrestore(&consolelock, flags);
438         return pi;
439 }
440
441 /*
442  * Initialize the common fields in a charLpEvent
443  */
444 static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp)
445 {
446         struct HvLpEvent *hev = &viochar->event;
447
448         memset(viochar, 0, sizeof(struct viocharlpevent));
449
450         hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK |
451                 HV_LP_EVENT_INT;
452         hev->xType = HvLpEvent_Type_VirtualIo;
453         hev->xSubtype = viomajorsubtype_chario | viochardata;
454         hev->xSourceLp = HvLpConfig_getLpIndex();
455         hev->xTargetLp = lp;
456         hev->xSizeMinus1 = sizeof(struct viocharlpevent);
457         hev->xSourceInstanceId = viopath_sourceinst(lp);
458         hev->xTargetInstanceId = viopath_targetinst(lp);
459 }
460
461 /*
462  * early console device write
463  */
464 static void viocons_write_early(struct console *co, const char *s, unsigned count)
465 {
466         hvlogOutput(s, count);
467 }
468
469 /*
470  * console device write
471  */
472 static void viocons_write(struct console *co, const char *s, unsigned count)
473 {
474         int index;
475         int begin;
476         struct port_info *pi;
477
478         static const char cr = '\r';
479
480         /*
481          * Check port data first because the target LP might be valid but
482          * simply not active, in which case we want to hvlog the output.
483          */
484         pi = get_port_data(NULL);
485         if (pi == NULL) {
486                 hvlog("\n\rviocons_write: unable to get port data.");
487                 return;
488         }
489
490         hvlogOutput(s, count);
491
492         if (!viopath_isactive(pi->lp))
493                 return;
494
495         /* 
496          * Any newline character found will cause a
497          * carriage return character to be emitted as well. 
498          */
499         begin = 0;
500         for (index = 0; index < count; index++) {
501                 if (s[index] == '\n') {
502                         /* 
503                          * Newline found. Print everything up to and 
504                          * including the newline
505                          */
506                         internal_write(pi, &s[begin], index - begin + 1);
507                         begin = index + 1;
508                         /* Emit a carriage return as well */
509                         internal_write(pi, &cr, 1);
510                 }
511         }
512
513         /* If any characters left to write, write them now */
514         if ((index - begin) > 0)
515                 internal_write(pi, &s[begin], index - begin);
516 }
517
518 /*
519  * Work out the device associate with this console
520  */
521 static struct tty_driver *viocons_device(struct console *c, int *index)
522 {
523         *index = c->index;
524         return viotty_driver;
525 }
526
527 /*
528  * console device I/O methods
529  */
530 static struct console viocons_early = {
531         .name = "viocons",
532         .write = viocons_write_early,
533         .flags = CON_PRINTBUFFER,
534         .index = -1,
535 };
536
537 static struct console viocons = {
538         .name = "viocons",
539         .write = viocons_write,
540         .device = viocons_device,
541         .flags = CON_PRINTBUFFER,
542         .index = -1,
543 };
544
545 /*
546  * TTY Open method
547  */
548 static int viotty_open(struct tty_struct *tty, struct file *filp)
549 {
550         int port;
551         unsigned long flags;
552         struct port_info *pi;
553
554         port = tty->index;
555
556         if ((port < 0) || (port >= VTTY_PORTS))
557                 return -ENODEV;
558
559         spin_lock_irqsave(&consolelock, flags);
560
561         pi = &port_info[port];
562         /* If some other TTY is already connected here, reject the open */
563         if ((pi->tty) && (pi->tty != tty)) {
564                 spin_unlock_irqrestore(&consolelock, flags);
565                 printk(VIOCONS_KERN_WARN
566                        "attempt to open device twice from different ttys\n");
567                 return -EBUSY;
568         }
569         tty->driver_data = pi;
570         pi->tty = tty;
571         spin_unlock_irqrestore(&consolelock, flags);
572
573         return 0;
574 }
575
576 /*
577  * TTY Close method
578  */
579 static void viotty_close(struct tty_struct *tty, struct file *filp)
580 {
581         unsigned long flags;
582         struct port_info *pi;
583
584         spin_lock_irqsave(&consolelock, flags);
585         pi = (struct port_info *)tty->driver_data;
586
587         if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_close")) {
588                 spin_unlock_irqrestore(&consolelock, flags);
589                 return;
590         }
591         if (tty->count == 1)
592                 pi->tty = NULL;
593         spin_unlock_irqrestore(&consolelock, flags);
594 }
595
596 /*
597  * TTY Write method
598  */
599 static int viotty_write(struct tty_struct *tty, const unsigned char *buf,
600                 int count)
601 {
602         struct port_info *pi;
603
604         pi = get_port_data(tty);
605         if (pi == NULL) {
606                 hvlog("\n\rviotty_write: no port data.");
607                 return -ENODEV;
608         }
609
610         if (viochar_is_console(pi))
611                 hvlogOutput(buf, count);
612
613         /*
614          * If the path to this LP is closed, don't bother doing anything more.
615          * just dump the data on the floor and return count.  For some reason
616          * some user level programs will attempt to probe available tty's and
617          * they'll attempt a viotty_write on an invalid port which maps to an
618          * invalid target lp.  If this is the case then ignore the
619          * viotty_write call and, since the viopath isn't active to this
620          * partition, return count.
621          */
622         if (!viopath_isactive(pi->lp))
623                 return count;
624
625         return internal_write(pi, buf, count);
626 }
627
628 /*
629  * TTY put_char method
630  */
631 static void viotty_put_char(struct tty_struct *tty, unsigned char ch)
632 {
633         struct port_info *pi;
634
635         pi = get_port_data(tty);
636         if (pi == NULL)
637                 return;
638
639         /* This will append '\r' as well if the char is '\n' */
640         if (viochar_is_console(pi))
641                 hvlogOutput(&ch, 1);
642
643         if (viopath_isactive(pi->lp))
644                 internal_write(pi, &ch, 1);
645 }
646
647 /*
648  * TTY write_room method
649  */
650 static int viotty_write_room(struct tty_struct *tty)
651 {
652         int i;
653         int room = 0;
654         struct port_info *pi;
655         unsigned long flags;
656
657         spin_lock_irqsave(&consolelock, flags);
658         pi = (struct port_info *)tty->driver_data;
659         if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_write_room")) {
660                 spin_unlock_irqrestore(&consolelock, flags);
661                 return 0;
662         }
663
664         /* If no buffers are used, return the max size. */
665         if (pi->used == 0) {
666                 spin_unlock_irqrestore(&consolelock, flags);
667                 return VIOCHAR_MAX_DATA * VIOCHAR_NUM_BUF;
668         }
669
670         /*
671          * We retain the spinlock because we want to get an accurate
672          * count and it can change on us between each operation if we
673          * don't hold the spinlock.
674          */
675         for (i = 0; ((i < VIOCHAR_NUM_BUF) && (room < VIOCHAR_MAX_DATA)); i++)
676                 room += (VIOCHAR_MAX_DATA - pi->bufferBytes[i]);
677         spin_unlock_irqrestore(&consolelock, flags);
678
679         if (room > VIOCHAR_MAX_DATA)
680                 room = VIOCHAR_MAX_DATA;
681         return room;
682 }
683
684 /*
685  * TTY chars_in_buffer method
686  */
687 static int viotty_chars_in_buffer(struct tty_struct *tty)
688 {
689         return 0;
690 }
691
692 static int viotty_ioctl(struct tty_struct *tty, struct file *file,
693                         unsigned int cmd, unsigned long arg)
694 {
695         switch (cmd) {
696         /*
697          * the ioctls below read/set the flags usually shown in the leds
698          * don't use them - they will go away without warning
699          */
700         case KDGETLED:
701         case KDGKBLED:
702                 return put_user(0, (char *)arg);
703
704         case KDSKBLED:
705                 return 0;
706         }
707         /* FIXME: WTF is this being called for ??? */
708         lock_kernel();
709         ret =  n_tty_ioctl(tty, file, cmd, arg);
710         unlock_kernel();
711         return ret;
712 }
713
714 /*
715  * Handle an open charLpEvent.  Could be either interrupt or ack
716  */
717 static void vioHandleOpenEvent(struct HvLpEvent *event)
718 {
719         unsigned long flags;
720         struct viocharlpevent *cevent = (struct viocharlpevent *)event;
721         u8 port = cevent->virtual_device;
722         struct port_info *pi;
723         int reject = 0;
724
725         if (hvlpevent_is_ack(event)) {
726                 if (port >= VTTY_PORTS)
727                         return;
728
729                 spin_lock_irqsave(&consolelock, flags);
730                 /* Got the lock, don't cause console output */
731
732                 pi = &port_info[port];
733                 if (event->xRc == HvLpEvent_Rc_Good) {
734                         pi->seq = pi->ack = 0;
735                         /*
736                          * This line allows connections from the primary
737                          * partition but once one is connected from the
738                          * primary partition nothing short of a reboot
739                          * of linux will allow access from the hosting
740                          * partition again without a required iSeries fix.
741                          */
742                         pi->lp = event->xTargetLp;
743                 }
744
745                 spin_unlock_irqrestore(&consolelock, flags);
746                 if (event->xRc != HvLpEvent_Rc_Good)
747                         printk(VIOCONS_KERN_WARN
748                                "handle_open_event: event->xRc == (%d).\n",
749                                event->xRc);
750
751                 if (event->xCorrelationToken != 0) {
752                         atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
753                         atomic_set(aptr, 1);
754                 } else
755                         printk(VIOCONS_KERN_WARN
756                                "weird...got open ack without atomic\n");
757                 return;
758         }
759
760         /* This had better require an ack, otherwise complain */
761         if (!hvlpevent_need_ack(event)) {
762                 printk(VIOCONS_KERN_WARN "viocharopen without ack bit!\n");
763                 return;
764         }
765
766         spin_lock_irqsave(&consolelock, flags);
767         /* Got the lock, don't cause console output */
768
769         /* Make sure this is a good virtual tty */
770         if (port >= VTTY_PORTS) {
771                 event->xRc = HvLpEvent_Rc_SubtypeError;
772                 cevent->subtype_result_code = viorc_openRejected;
773                 /*
774                  * Flag state here since we can't printk while holding
775                  * a spinlock.
776                  */
777                 reject = 1;
778         } else {
779                 pi = &port_info[port];
780                 if ((pi->lp != HvLpIndexInvalid) &&
781                                 (pi->lp != event->xSourceLp)) {
782                         /*
783                          * If this is tty is already connected to a different
784                          * partition, fail.
785                          */
786                         event->xRc = HvLpEvent_Rc_SubtypeError;
787                         cevent->subtype_result_code = viorc_openRejected;
788                         reject = 2;
789                 } else {
790                         pi->lp = event->xSourceLp;
791                         event->xRc = HvLpEvent_Rc_Good;
792                         cevent->subtype_result_code = viorc_good;
793                         pi->seq = pi->ack = 0;
794                         reject = 0;
795                 }
796         }
797
798         spin_unlock_irqrestore(&consolelock, flags);
799
800         if (reject == 1)
801                 printk(VIOCONS_KERN_WARN "open rejected: bad virtual tty.\n");
802         else if (reject == 2)
803                 printk(VIOCONS_KERN_WARN
804                         "open rejected: console in exclusive use by another partition.\n");
805
806         /* Return the acknowledgement */
807         HvCallEvent_ackLpEvent(event);
808 }
809
810 /*
811  * Handle a close charLpEvent.  This should ONLY be an Interrupt because the
812  * virtual console should never actually issue a close event to the hypervisor
813  * because the virtual console never goes away.  A close event coming from the
814  * hypervisor simply means that there are no client consoles connected to the
815  * virtual console.
816  *
817  * Regardless of the number of connections masqueraded on the other side of
818  * the hypervisor ONLY ONE close event should be called to accompany the ONE
819  * open event that is called.  The close event should ONLY be called when NO
820  * MORE connections (masqueraded or not) exist on the other side of the
821  * hypervisor.
822  */
823 static void vioHandleCloseEvent(struct HvLpEvent *event)
824 {
825         unsigned long flags;
826         struct viocharlpevent *cevent = (struct viocharlpevent *)event;
827         u8 port = cevent->virtual_device;
828
829         if (hvlpevent_is_int(event)) {
830                 if (port >= VTTY_PORTS) {
831                         printk(VIOCONS_KERN_WARN
832                                         "close message from invalid virtual device.\n");
833                         return;
834                 }
835
836                 /* For closes, just mark the console partition invalid */
837                 spin_lock_irqsave(&consolelock, flags);
838                 /* Got the lock, don't cause console output */
839
840                 if (port_info[port].lp == event->xSourceLp)
841                         port_info[port].lp = HvLpIndexInvalid;
842
843                 spin_unlock_irqrestore(&consolelock, flags);
844                 printk(VIOCONS_KERN_INFO "close from %d\n", event->xSourceLp);
845         } else
846                 printk(VIOCONS_KERN_WARN
847                                 "got unexpected close acknowlegement\n");
848 }
849
850 /*
851  * Handle a config charLpEvent.  Could be either interrupt or ack
852  */
853 static void vioHandleConfig(struct HvLpEvent *event)
854 {
855         struct viocharlpevent *cevent = (struct viocharlpevent *)event;
856
857         HvCall_writeLogBuffer(cevent->data, cevent->len);
858
859         if (cevent->data[0] == 0x01)
860                 printk(VIOCONS_KERN_INFO "window resized to %d: %d: %d: %d\n",
861                        cevent->data[1], cevent->data[2],
862                        cevent->data[3], cevent->data[4]);
863         else
864                 printk(VIOCONS_KERN_WARN "unknown config event\n");
865 }
866
867 /*
868  * Handle a data charLpEvent. 
869  */
870 static void vioHandleData(struct HvLpEvent *event)
871 {
872         struct tty_struct *tty;
873         unsigned long flags;
874         struct viocharlpevent *cevent = (struct viocharlpevent *)event;
875         struct port_info *pi;
876         int index;
877         int num_pushed;
878         u8 port = cevent->virtual_device;
879
880         if (port >= VTTY_PORTS) {
881                 printk(VIOCONS_KERN_WARN "data on invalid virtual device %d\n",
882                                 port);
883                 return;
884         }
885
886         /*
887          * Hold the spinlock so that we don't take an interrupt that
888          * changes tty between the time we fetch the port_info
889          * pointer and the time we paranoia check.
890          */
891         spin_lock_irqsave(&consolelock, flags);
892         pi = &port_info[port];
893
894         /*
895          * Change 05/01/2003 - Ryan Arnold: If a partition other than
896          * the current exclusive partition tries to send us data
897          * events then just drop them on the floor because we don't
898          * want his stinking data.  He isn't authorized to receive
899          * data because he wasn't the first one to get the console,
900          * therefore he shouldn't be allowed to send data either.
901          * This will work without an iSeries fix.
902          */
903         if (pi->lp != event->xSourceLp) {
904                 spin_unlock_irqrestore(&consolelock, flags);
905                 return;
906         }
907
908         tty = pi->tty;
909         if (tty == NULL) {
910                 spin_unlock_irqrestore(&consolelock, flags);
911                 printk(VIOCONS_KERN_WARN "no tty for virtual device %d\n",
912                                 port);
913                 return;
914         }
915
916         if (tty->magic != TTY_MAGIC) {
917                 spin_unlock_irqrestore(&consolelock, flags);
918                 printk(VIOCONS_KERN_WARN "tty bad magic\n");
919                 return;
920         }
921
922         /*
923          * Just to be paranoid, make sure the tty points back to this port
924          */
925         pi = (struct port_info *)tty->driver_data;
926         if (!pi || viotty_paranoia_check(pi, tty->name, "vioHandleData")) {
927                 spin_unlock_irqrestore(&consolelock, flags);
928                 return;
929         }
930         spin_unlock_irqrestore(&consolelock, flags);
931
932         /*
933          * Change 07/21/2003 - Ryan Arnold: functionality added to
934          * support sysrq utilizing ^O as the sysrq key.  The sysrq
935          * functionality will only work if built into the kernel and
936          * then only if sysrq is enabled through the proc filesystem.
937          */
938         num_pushed = 0;
939         for (index = 0; index < cevent->len; index++) {
940                 /*
941                  * Will be optimized away if !CONFIG_MAGIC_SYSRQ:
942                  */
943                 if (sysrq_on()) {
944                         /* 0x0f is the ascii character for ^O */
945                         if (cevent->data[index] == '\x0f') {
946                                 vio_sysrq_pressed = 1;
947                                 /*
948                                  * continue because we don't want to add
949                                  * the sysrq key into the data string.
950                                  */
951                                 continue;
952                         } else if (vio_sysrq_pressed) {
953                                 handle_sysrq(cevent->data[index], tty);
954                                 vio_sysrq_pressed = 0;
955                                 /*
956                                  * continue because we don't want to add
957                                  * the sysrq sequence into the data string.
958                                  */
959                                 continue;
960                         }
961                 }
962                 /*
963                  * The sysrq sequence isn't included in this check if
964                  * sysrq is enabled and compiled into the kernel because
965                  * the sequence will never get inserted into the buffer.
966                  * Don't attempt to copy more data into the buffer than we
967                  * have room for because it would fail without indication.
968                  */
969                 if(tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL) == 0) {
970                         printk(VIOCONS_KERN_WARN "input buffer overflow!\n");
971                         break;
972                 }
973                 num_pushed++;
974         }
975
976         if (num_pushed)
977                 tty_flip_buffer_push(tty);
978 }
979
980 /*
981  * Handle an ack charLpEvent. 
982  */
983 static void vioHandleAck(struct HvLpEvent *event)
984 {
985         struct viocharlpevent *cevent = (struct viocharlpevent *)event;
986         unsigned long flags;
987         u8 port = cevent->virtual_device;
988
989         if (port >= VTTY_PORTS) {
990                 printk(VIOCONS_KERN_WARN "data on invalid virtual device\n");
991                 return;
992         }
993
994         spin_lock_irqsave(&consolelock, flags);
995         port_info[port].ack = event->xCorrelationToken;
996         spin_unlock_irqrestore(&consolelock, flags);
997
998         if (port_info[port].used)
999                 send_buffers(&port_info[port]);
1000 }
1001
1002 /*
1003  * Handle charLpEvents and route to the appropriate routine
1004  */
1005 static void vioHandleCharEvent(struct HvLpEvent *event)
1006 {
1007         int charminor;
1008
1009         if (event == NULL)
1010                 return;
1011
1012         charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
1013         switch (charminor) {
1014         case viocharopen:
1015                 vioHandleOpenEvent(event);
1016                 break;
1017         case viocharclose:
1018                 vioHandleCloseEvent(event);
1019                 break;
1020         case viochardata:
1021                 vioHandleData(event);
1022                 break;
1023         case viocharack:
1024                 vioHandleAck(event);
1025                 break;
1026         case viocharconfig:
1027                 vioHandleConfig(event);
1028                 break;
1029         default:
1030                 if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
1031                         event->xRc = HvLpEvent_Rc_InvalidSubtype;
1032                         HvCallEvent_ackLpEvent(event);
1033                 }
1034         }
1035 }
1036
1037 /*
1038  * Send an open event
1039  */
1040 static int send_open(HvLpIndex remoteLp, void *sem)
1041 {
1042         return HvCallEvent_signalLpEventFast(remoteLp,
1043                         HvLpEvent_Type_VirtualIo,
1044                         viomajorsubtype_chario | viocharopen,
1045                         HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
1046                         viopath_sourceinst(remoteLp),
1047                         viopath_targetinst(remoteLp),
1048                         (u64)(unsigned long)sem, VIOVERSION << 16,
1049                         0, 0, 0, 0);
1050 }
1051
1052 static const struct tty_operations serial_ops = {
1053         .open = viotty_open,
1054         .close = viotty_close,
1055         .write = viotty_write,
1056         .put_char = viotty_put_char,
1057         .write_room = viotty_write_room,
1058         .chars_in_buffer = viotty_chars_in_buffer,
1059         .ioctl = viotty_ioctl,
1060 };
1061
1062 static int __init viocons_init2(void)
1063 {
1064         atomic_t wait_flag;
1065         int rc;
1066
1067         if (!firmware_has_feature(FW_FEATURE_ISERIES))
1068                 return -ENODEV;
1069
1070         /* +2 for fudge */
1071         rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
1072                         viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
1073         if (rc)
1074                 printk(VIOCONS_KERN_WARN "error opening to primary %d\n", rc);
1075
1076         if (viopath_hostLp == HvLpIndexInvalid)
1077                 vio_set_hostlp();
1078
1079         /*
1080          * And if the primary is not the same as the hosting LP, open to the 
1081          * hosting lp
1082          */
1083         if ((viopath_hostLp != HvLpIndexInvalid) &&
1084             (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
1085                 printk(VIOCONS_KERN_INFO "open path to hosting (%d)\n",
1086                                 viopath_hostLp);
1087                 rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
1088                                 VIOCHAR_WINDOW + 2);    /* +2 for fudge */
1089                 if (rc)
1090                         printk(VIOCONS_KERN_WARN
1091                                 "error opening to partition %d: %d\n",
1092                                 viopath_hostLp, rc);
1093         }
1094
1095         if (vio_setHandler(viomajorsubtype_chario, vioHandleCharEvent) < 0)
1096                 printk(VIOCONS_KERN_WARN
1097                                 "error seting handler for console events!\n");
1098
1099         /*
1100          * First, try to open the console to the hosting lp.
1101          * Wait on a semaphore for the response.
1102          */
1103         atomic_set(&wait_flag, 0);
1104         if ((viopath_isactive(viopath_hostLp)) &&
1105             (send_open(viopath_hostLp, (void *)&wait_flag) == 0)) {
1106                 printk(VIOCONS_KERN_INFO "hosting partition %d\n",
1107                         viopath_hostLp);
1108                 while (atomic_read(&wait_flag) == 0)
1109                         mb();
1110                 atomic_set(&wait_flag, 0);
1111         }
1112
1113         /*
1114          * If we don't have an active console, try the primary
1115          */
1116         if ((!viopath_isactive(port_info[0].lp)) &&
1117             (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
1118             (send_open(HvLpConfig_getPrimaryLpIndex(), (void *)&wait_flag)
1119              == 0)) {
1120                 printk(VIOCONS_KERN_INFO "opening console to primary partition\n");
1121                 while (atomic_read(&wait_flag) == 0)
1122                         mb();
1123         }
1124
1125         /* Initialize the tty_driver structure */
1126         viotty_driver = alloc_tty_driver(VTTY_PORTS);
1127         viotty_driver->owner = THIS_MODULE;
1128         viotty_driver->driver_name = "vioconsole";
1129         viotty_driver->name = "tty";
1130         viotty_driver->name_base = 1;
1131         viotty_driver->major = TTY_MAJOR;
1132         viotty_driver->minor_start = 1;
1133         viotty_driver->type = TTY_DRIVER_TYPE_CONSOLE;
1134         viotty_driver->subtype = 1;
1135         viotty_driver->init_termios = tty_std_termios;
1136         viotty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
1137         tty_set_operations(viotty_driver, &serial_ops);
1138
1139         if (tty_register_driver(viotty_driver)) {
1140                 printk(VIOCONS_KERN_WARN "couldn't register console driver\n");
1141                 put_tty_driver(viotty_driver);
1142                 viotty_driver = NULL;
1143         }
1144
1145         unregister_console(&viocons_early);
1146         register_console(&viocons);
1147
1148         return 0;
1149 }
1150
1151 static int __init viocons_init(void)
1152 {
1153         int i;
1154
1155         if (!firmware_has_feature(FW_FEATURE_ISERIES))
1156                 return -ENODEV;
1157
1158         printk(VIOCONS_KERN_INFO "registering console\n");
1159         for (i = 0; i < VTTY_PORTS; i++) {
1160                 port_info[i].lp = HvLpIndexInvalid;
1161                 port_info[i].magic = VIOTTY_MAGIC;
1162         }
1163         HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437);
1164         add_preferred_console("viocons", 0, NULL);
1165         register_console(&viocons_early);
1166         return 0;
1167 }
1168
1169 console_initcall(viocons_init);
1170 module_init(viocons_init2);