Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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