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