diff options
| -rw-r--r-- | arch/powerpc/platforms/pseries/hvconsole.c | 5 | ||||
| -rw-r--r-- | drivers/char/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/char/Makefile | 3 | ||||
| -rw-r--r-- | drivers/char/hvc_console.c | 69 | ||||
| -rw-r--r-- | drivers/char/hvc_console.h | 63 | ||||
| -rw-r--r-- | drivers/char/hvc_vio.c | 11 | ||||
| -rw-r--r-- | include/asm-powerpc/hvconsole.h | 26 |
7 files changed, 128 insertions, 59 deletions
diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c index 138e128a3886..ba6befd96636 100644 --- a/arch/powerpc/platforms/pseries/hvconsole.c +++ b/arch/powerpc/platforms/pseries/hvconsole.c | |||
| @@ -62,6 +62,11 @@ int hvc_put_chars(uint32_t vtermno, const char *buf, int count) | |||
| 62 | unsigned long *lbuf = (unsigned long *) buf; | 62 | unsigned long *lbuf = (unsigned long *) buf; |
| 63 | long ret; | 63 | long ret; |
| 64 | 64 | ||
| 65 | |||
| 66 | /* hcall will ret H_PARAMETER if 'count' exceeds firmware max.*/ | ||
| 67 | if (count > MAX_VIO_PUT_CHARS) | ||
| 68 | count = MAX_VIO_PUT_CHARS; | ||
| 69 | |||
| 65 | ret = plpar_hcall_norets(H_PUT_TERM_CHAR, vtermno, count, lbuf[0], | 70 | ret = plpar_hcall_norets(H_PUT_TERM_CHAR, vtermno, count, lbuf[0], |
| 66 | lbuf[1]); | 71 | lbuf[1]); |
| 67 | if (ret == H_Success) | 72 | if (ret == H_Success) |
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index facc3f1d9e37..831419381cf5 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig | |||
| @@ -561,9 +561,19 @@ config TIPAR | |||
| 561 | 561 | ||
| 562 | If unsure, say N. | 562 | If unsure, say N. |
| 563 | 563 | ||
| 564 | config HVC_DRIVER | ||
| 565 | bool | ||
| 566 | help | ||
| 567 | Users of pSeries machines that want to utilize the hvc console front-end | ||
| 568 | module for their backend console driver should select this option. | ||
| 569 | It will automatically be selected if one of the back-end console drivers | ||
| 570 | is selected. | ||
| 571 | |||
| 572 | |||
| 564 | config HVC_CONSOLE | 573 | config HVC_CONSOLE |
| 565 | bool "pSeries Hypervisor Virtual Console support" | 574 | bool "pSeries Hypervisor Virtual Console support" |
| 566 | depends on PPC_PSERIES | 575 | depends on PPC_PSERIES |
| 576 | select HVC_DRIVER | ||
| 567 | help | 577 | help |
| 568 | pSeries machines when partitioned support a hypervisor virtual | 578 | pSeries machines when partitioned support a hypervisor virtual |
| 569 | console. This driver allows each pSeries partition to have a console | 579 | console. This driver allows each pSeries partition to have a console |
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index b2a11245fa95..e6c03335fd6a 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
| @@ -41,7 +41,8 @@ obj-$(CONFIG_N_HDLC) += n_hdlc.o | |||
| 41 | obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o | 41 | obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o |
| 42 | obj-$(CONFIG_SX) += sx.o generic_serial.o | 42 | obj-$(CONFIG_SX) += sx.o generic_serial.o |
| 43 | obj-$(CONFIG_RIO) += rio/ generic_serial.o | 43 | obj-$(CONFIG_RIO) += rio/ generic_serial.o |
| 44 | obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvc_vio.o hvsi.o | 44 | obj-$(CONFIG_HVC_DRIVER) += hvc_console.o |
| 45 | obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o | ||
| 45 | obj-$(CONFIG_RAW_DRIVER) += raw.o | 46 | obj-$(CONFIG_RAW_DRIVER) += raw.o |
| 46 | obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o | 47 | obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o |
| 47 | obj-$(CONFIG_MMTIMER) += mmtimer.o | 48 | obj-$(CONFIG_MMTIMER) += mmtimer.o |
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index a94c5b0cac52..2b6a56b2bf35 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
| @@ -39,8 +39,10 @@ | |||
| 39 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
| 40 | #include <linux/spinlock.h> | 40 | #include <linux/spinlock.h> |
| 41 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
| 42 | |||
| 42 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
| 43 | #include <asm/hvconsole.h> | 44 | |
| 45 | #include "hvc_console.h" | ||
| 44 | 46 | ||
| 45 | #define HVC_MAJOR 229 | 47 | #define HVC_MAJOR 229 |
| 46 | #define HVC_MINOR 0 | 48 | #define HVC_MINOR 0 |
| @@ -54,17 +56,14 @@ | |||
| 54 | #define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ | 56 | #define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ |
| 55 | 57 | ||
| 56 | /* | 58 | /* |
| 57 | * The Linux TTY code does not support dynamic addition of tty derived devices | 59 | * These sizes are most efficient for vio, because they are the |
| 58 | * so we need to know how many tty devices we might need when space is allocated | 60 | * native transfer size. We could make them selectable in the |
| 59 | * for the tty device. Since this driver supports hotplug of vty adapters we | 61 | * future to better deal with backends that want other buffer sizes. |
| 60 | * need to make sure we have enough allocated. | ||
| 61 | */ | 62 | */ |
| 62 | #define HVC_ALLOC_TTY_ADAPTERS 8 | ||
| 63 | |||
| 64 | #define N_OUTBUF 16 | 63 | #define N_OUTBUF 16 |
| 65 | #define N_INBUF 16 | 64 | #define N_INBUF 16 |
| 66 | 65 | ||
| 67 | #define __ALIGNED__ __attribute__((__aligned__(8))) | 66 | #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) |
| 68 | 67 | ||
| 69 | static struct tty_driver *hvc_driver; | 68 | static struct tty_driver *hvc_driver; |
| 70 | static struct task_struct *hvc_task; | 69 | static struct task_struct *hvc_task; |
| @@ -154,7 +153,7 @@ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = | |||
| 154 | 153 | ||
| 155 | void hvc_console_print(struct console *co, const char *b, unsigned count) | 154 | void hvc_console_print(struct console *co, const char *b, unsigned count) |
| 156 | { | 155 | { |
| 157 | char c[16] __ALIGNED__; | 156 | char c[N_OUTBUF] __ALIGNED__; |
| 158 | unsigned i = 0, n = 0; | 157 | unsigned i = 0, n = 0; |
| 159 | int r, donecr = 0, index = co->index; | 158 | int r, donecr = 0, index = co->index; |
| 160 | 159 | ||
| @@ -473,8 +472,10 @@ static void hvc_push(struct hvc_struct *hp) | |||
| 473 | 472 | ||
| 474 | n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); | 473 | n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); |
| 475 | if (n <= 0) { | 474 | if (n <= 0) { |
| 476 | if (n == 0) | 475 | if (n == 0) { |
| 476 | hp->do_wakeup = 1; | ||
| 477 | return; | 477 | return; |
| 478 | } | ||
| 478 | /* throw away output on error; this happens when | 479 | /* throw away output on error; this happens when |
| 479 | there is no session connected to the vterm. */ | 480 | there is no session connected to the vterm. */ |
| 480 | hp->n_outbuf = 0; | 481 | hp->n_outbuf = 0; |
| @@ -486,12 +487,19 @@ static void hvc_push(struct hvc_struct *hp) | |||
| 486 | hp->do_wakeup = 1; | 487 | hp->do_wakeup = 1; |
| 487 | } | 488 | } |
| 488 | 489 | ||
| 489 | static inline int __hvc_write_kernel(struct hvc_struct *hp, | 490 | static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) |
| 490 | const unsigned char *buf, int count) | ||
| 491 | { | 491 | { |
| 492 | struct hvc_struct *hp = tty->driver_data; | ||
| 492 | unsigned long flags; | 493 | unsigned long flags; |
| 493 | int rsize, written = 0; | 494 | int rsize, written = 0; |
| 494 | 495 | ||
| 496 | /* This write was probably executed during a tty close. */ | ||
| 497 | if (!hp) | ||
| 498 | return -EPIPE; | ||
| 499 | |||
| 500 | if (hp->count <= 0) | ||
| 501 | return -EIO; | ||
| 502 | |||
| 495 | spin_lock_irqsave(&hp->lock, flags); | 503 | spin_lock_irqsave(&hp->lock, flags); |
| 496 | 504 | ||
| 497 | /* Push pending writes */ | 505 | /* Push pending writes */ |
| @@ -510,26 +518,8 @@ static inline int __hvc_write_kernel(struct hvc_struct *hp, | |||
| 510 | } | 518 | } |
| 511 | spin_unlock_irqrestore(&hp->lock, flags); | 519 | spin_unlock_irqrestore(&hp->lock, flags); |
| 512 | 520 | ||
| 513 | return written; | ||
| 514 | } | ||
| 515 | static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) | ||
| 516 | { | ||
| 517 | struct hvc_struct *hp = tty->driver_data; | ||
| 518 | int written; | ||
| 519 | |||
| 520 | /* This write was probably executed during a tty close. */ | ||
| 521 | if (!hp) | ||
| 522 | return -EPIPE; | ||
| 523 | |||
| 524 | if (hp->count <= 0) | ||
| 525 | return -EIO; | ||
| 526 | |||
| 527 | written = __hvc_write_kernel(hp, buf, count); | ||
| 528 | |||
| 529 | /* | 521 | /* |
| 530 | * Racy, but harmless, kick thread if there is still pending data. | 522 | * Racy, but harmless, kick thread if there is still pending data. |
| 531 | * There really is nothing wrong with kicking the thread, even if there | ||
| 532 | * is no buffered data. | ||
| 533 | */ | 523 | */ |
| 534 | if (hp->n_outbuf) | 524 | if (hp->n_outbuf) |
| 535 | hvc_kick(); | 525 | hvc_kick(); |
| @@ -614,6 +604,13 @@ static int hvc_poll(struct hvc_struct *hp) | |||
| 614 | spin_unlock_irqrestore(&hp->lock, flags); | 604 | spin_unlock_irqrestore(&hp->lock, flags); |
| 615 | tty_hangup(tty); | 605 | tty_hangup(tty); |
| 616 | spin_lock_irqsave(&hp->lock, flags); | 606 | spin_lock_irqsave(&hp->lock, flags); |
| 607 | } else if ( n == -EAGAIN ) { | ||
| 608 | /* | ||
| 609 | * Some back-ends can only ensure a certain min | ||
| 610 | * num of bytes read, which may be > 'count'. | ||
| 611 | * Let the tty clear the flip buff to make room. | ||
| 612 | */ | ||
| 613 | poll_mask |= HVC_POLL_READ; | ||
| 617 | } | 614 | } |
| 618 | break; | 615 | break; |
| 619 | } | 616 | } |
| @@ -635,16 +632,7 @@ static int hvc_poll(struct hvc_struct *hp) | |||
| 635 | tty_insert_flip_char(tty, buf[i], 0); | 632 | tty_insert_flip_char(tty, buf[i], 0); |
| 636 | } | 633 | } |
| 637 | 634 | ||
| 638 | /* | ||
| 639 | * Account for the total amount read in one loop, and if above | ||
| 640 | * 64 bytes, we do a quick schedule loop to let the tty grok | ||
| 641 | * the data and eventually throttle us. | ||
| 642 | */ | ||
| 643 | read_total += n; | 635 | read_total += n; |
| 644 | if (read_total >= 64) { | ||
| 645 | poll_mask |= HVC_POLL_QUICK; | ||
| 646 | break; | ||
| 647 | } | ||
| 648 | } | 636 | } |
| 649 | throttled: | 637 | throttled: |
| 650 | /* Wakeup write queue if necessary */ | 638 | /* Wakeup write queue if necessary */ |
| @@ -767,7 +755,8 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, | |||
| 767 | * see if this vterm id matches one registered for console. | 755 | * see if this vterm id matches one registered for console. |
| 768 | */ | 756 | */ |
| 769 | for (i=0; i < MAX_NR_HVC_CONSOLES; i++) | 757 | for (i=0; i < MAX_NR_HVC_CONSOLES; i++) |
| 770 | if (vtermnos[i] == hp->vtermno) | 758 | if (vtermnos[i] == hp->vtermno && |
| 759 | cons_ops[i] == hp->ops) | ||
| 771 | break; | 760 | break; |
| 772 | 761 | ||
| 773 | /* no matching slot, just use a counter */ | 762 | /* no matching slot, just use a counter */ |
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h new file mode 100644 index 000000000000..96b7401319c1 --- /dev/null +++ b/drivers/char/hvc_console.h | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | /* | ||
| 2 | * hvc_console.h | ||
| 3 | * Copyright (C) 2005 IBM Corporation | ||
| 4 | * | ||
| 5 | * Author(s): | ||
| 6 | * Ryan S. Arnold <rsa@us.ibm.com> | ||
| 7 | * | ||
| 8 | * hvc_console header information: | ||
| 9 | * moved here from include/asm-powerpc/hvconsole.h | ||
| 10 | * and drivers/char/hvc_console.c | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License as published by | ||
| 14 | * the Free Software Foundation; either version 2 of the License, or | ||
| 15 | * (at your option) any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef HVC_CONSOLE_H | ||
| 28 | #define HVC_CONSOLE_H | ||
| 29 | |||
| 30 | /* | ||
| 31 | * This is the max number of console adapters that can/will be found as | ||
| 32 | * console devices on first stage console init. Any number beyond this range | ||
| 33 | * can't be used as a console device but is still a valid tty device. | ||
| 34 | */ | ||
| 35 | #define MAX_NR_HVC_CONSOLES 16 | ||
| 36 | |||
| 37 | /* | ||
| 38 | * The Linux TTY code does not support dynamic addition of tty derived devices | ||
| 39 | * so we need to know how many tty devices we might need when space is allocated | ||
| 40 | * for the tty device. Since this driver supports hotplug of vty adapters we | ||
| 41 | * need to make sure we have enough allocated. | ||
| 42 | */ | ||
| 43 | #define HVC_ALLOC_TTY_ADAPTERS 8 | ||
| 44 | |||
| 45 | |||
| 46 | /* implemented by a low level driver */ | ||
| 47 | struct hv_ops { | ||
| 48 | int (*get_chars)(uint32_t vtermno, char *buf, int count); | ||
| 49 | int (*put_chars)(uint32_t vtermno, const char *buf, int count); | ||
| 50 | }; | ||
| 51 | |||
| 52 | struct hvc_struct; | ||
| 53 | |||
| 54 | /* Register a vterm and a slot index for use as a console (console_init) */ | ||
| 55 | extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops); | ||
| 56 | |||
| 57 | /* register a vterm for hvc tty operation (module_init or hotplug add) */ | ||
| 58 | extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq, | ||
| 59 | struct hv_ops *ops); | ||
| 60 | /* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ | ||
| 61 | extern int __devexit hvc_remove(struct hvc_struct *hp); | ||
| 62 | |||
| 63 | #endif // HVC_CONSOLE_H | ||
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index f5212eb2b41d..9add81ceb440 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c | |||
| @@ -31,10 +31,13 @@ | |||
| 31 | 31 | ||
| 32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
| 33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
| 34 | |||
| 34 | #include <asm/hvconsole.h> | 35 | #include <asm/hvconsole.h> |
| 35 | #include <asm/vio.h> | 36 | #include <asm/vio.h> |
| 36 | #include <asm/prom.h> | 37 | #include <asm/prom.h> |
| 37 | 38 | ||
| 39 | #include "hvc_console.h" | ||
| 40 | |||
| 38 | char hvc_driver_name[] = "hvc_console"; | 41 | char hvc_driver_name[] = "hvc_console"; |
| 39 | 42 | ||
| 40 | static struct vio_device_id hvc_driver_table[] __devinitdata = { | 43 | static struct vio_device_id hvc_driver_table[] __devinitdata = { |
| @@ -48,6 +51,14 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count) | |||
| 48 | unsigned long got; | 51 | unsigned long got; |
| 49 | int i; | 52 | int i; |
| 50 | 53 | ||
| 54 | /* | ||
| 55 | * Vio firmware will read up to SIZE_VIO_GET_CHARS at its own discretion | ||
| 56 | * so we play safe and avoid the situation where got > count which could | ||
| 57 | * overload the flip buffer. | ||
| 58 | */ | ||
| 59 | if (count < SIZE_VIO_GET_CHARS) | ||
| 60 | return -EAGAIN; | ||
| 61 | |||
| 51 | got = hvc_get_chars(vtermno, buf, count); | 62 | got = hvc_get_chars(vtermno, buf, count); |
| 52 | 63 | ||
| 53 | /* | 64 | /* |
diff --git a/include/asm-powerpc/hvconsole.h b/include/asm-powerpc/hvconsole.h index 34daf7b9b62f..35ea69e8121f 100644 --- a/include/asm-powerpc/hvconsole.h +++ b/include/asm-powerpc/hvconsole.h | |||
| @@ -24,28 +24,18 @@ | |||
| 24 | #ifdef __KERNEL__ | 24 | #ifdef __KERNEL__ |
| 25 | 25 | ||
| 26 | /* | 26 | /* |
| 27 | * This is the max number of console adapters that can/will be found as | 27 | * PSeries firmware will only send/recv up to 16 bytes of character data per |
| 28 | * console devices on first stage console init. Any number beyond this range | 28 | * hcall. |
| 29 | * can't be used as a console device but is still a valid tty device. | ||
| 30 | */ | 29 | */ |
| 31 | #define MAX_NR_HVC_CONSOLES 16 | 30 | #define MAX_VIO_PUT_CHARS 16 |
| 31 | #define SIZE_VIO_GET_CHARS 16 | ||
| 32 | 32 | ||
| 33 | /* implemented by a low level driver */ | 33 | /* |
| 34 | struct hv_ops { | 34 | * Vio firmware always attempts to fetch MAX_VIO_GET_CHARS chars. The 'count' |
| 35 | int (*get_chars)(uint32_t vtermno, char *buf, int count); | 35 | * parm is included to conform to put_chars() function pointer template |
| 36 | int (*put_chars)(uint32_t vtermno, const char *buf, int count); | 36 | */ |
| 37 | }; | ||
| 38 | extern int hvc_get_chars(uint32_t vtermno, char *buf, int count); | 37 | extern int hvc_get_chars(uint32_t vtermno, char *buf, int count); |
| 39 | extern int hvc_put_chars(uint32_t vtermno, const char *buf, int count); | 38 | extern int hvc_put_chars(uint32_t vtermno, const char *buf, int count); |
| 40 | 39 | ||
| 41 | struct hvc_struct; | ||
| 42 | |||
| 43 | /* Register a vterm and a slot index for use as a console (console_init) */ | ||
| 44 | extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops); | ||
| 45 | /* register a vterm for hvc tty operation (module_init or hotplug add) */ | ||
| 46 | extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq, | ||
| 47 | struct hv_ops *ops); | ||
| 48 | /* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ | ||
| 49 | extern int __devexit hvc_remove(struct hvc_struct *hp); | ||
| 50 | #endif /* __KERNEL__ */ | 40 | #endif /* __KERNEL__ */ |
| 51 | #endif /* _PPC64_HVCONSOLE_H */ | 41 | #endif /* _PPC64_HVCONSOLE_H */ |
