diff -Nru a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile --- a/arch/ppc64/kernel/Makefile Tue Nov 4 14:31:54 2003 +++ b/arch/ppc64/kernel/Makefile Tue Nov 4 14:31:54 2003 @@ -36,9 +36,9 @@ endif ifeq ($(CONFIG_PPC_PSERIES),y) obj-$(CONFIG_PCI) += pSeries_pci.o eeh.o - -obj-y += nvram.o rtasd.o endif + +obj-$(CONFIG_PPC_PSERIES) += nvram.o rtasd.o hvconsole.o obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o diff -Nru a/arch/ppc64/kernel/hvconsole.c b/arch/ppc64/kernel/hvconsole.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc64/kernel/hvconsole.c Tue Nov 4 14:31:54 2003 @@ -0,0 +1,96 @@ +/* + * hvconsole.c + * Copyright (C) 2001 Anton Blanchard , IBM Corporation + * Copyright (C) 2001 Paul Mackerras , IBM Corporation + * + * pSeries LPAR hypervisor console support. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +int hvc_get_chars(struct hvc_struct *hvc, char *buf, int count) +{ + unsigned long got; + + if (plpar_hcall(H_GET_TERM_CHAR, hvc->vtermno, 0, 0, 0, &got, + (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) { + /* + * Work around a HV bug where it gives us a null + * after every \r. -- paulus + */ + if (got > 0) { + int i; + for (i = 1; i < got; ++i) { + if (buf[i] == 0 && buf[i-1] == '\r') { + --got; + if (i < got) + memmove(&buf[i], &buf[i+1], + got - i); + } + } + } + return got; + } + return 0; +} + +int hvc_put_chars(struct hvc_struct *hvc, const char *buf, int count) +{ + unsigned long dummy; + unsigned long *lbuf = (unsigned long *) buf; + long ret; + + ret = plpar_hcall(H_PUT_TERM_CHAR, hvc->vtermno, count, lbuf[0], lbuf[1], + &dummy, &dummy, &dummy); + if (ret == H_Success) + return count; + if (ret == H_Busy) + return 0; + return -1; +} + +int hvc_get_vterms(void) +{ + struct hvc_arch_funcs vty_funcs = { + .put_chars = hvc_put_chars, + .get_chars = hvc_get_chars, + .ioctl = NULL, + }; + struct device_node *vtys; + + if (NULL == (vtys = find_devices("vty"))) { + printk(KERN_WARNING "no vty device nodes\n"); + return -1; + } + + for (; vtys; vtys = vtys->next) { + u32 *vtermno = (u32 *)get_property(vtys, "reg", NULL); + + if (!vtermno || !device_is_compatible(vtys, "hvterm1")) + continue; + + hvc_instantiate(*vtermno, &vty_funcs, NULL); + } + + return 0; +} + diff -Nru a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c --- a/arch/ppc64/kernel/pSeries_lpar.c Tue Nov 4 14:31:54 2003 +++ b/arch/ppc64/kernel/pSeries_lpar.c Tue Nov 4 14:31:54 2003 @@ -303,81 +303,6 @@ -int hvc_get_chars(int index, char *buf, int count) -{ - unsigned long got; - - if (plpar_hcall(H_GET_TERM_CHAR, index, 0, 0, 0, &got, - (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) { - /* - * Work around a HV bug where it gives us a null - * after every \r. -- paulus - */ - if (got > 0) { - int i; - for (i = 1; i < got; ++i) { - if (buf[i] == 0 && buf[i-1] == '\r') { - --got; - if (i < got) - memmove(&buf[i], &buf[i+1], - got - i); - } - } - } - return got; - } - return 0; -} - -int hvc_put_chars(int index, const char *buf, int count) -{ - unsigned long dummy; - unsigned long *lbuf = (unsigned long *) buf; - long ret; - - ret = plpar_hcall(H_PUT_TERM_CHAR, index, count, lbuf[0], lbuf[1], - &dummy, &dummy, &dummy); - if (ret == H_Success) - return count; - if (ret == H_Busy) - return 0; - return -1; -} - -/* return the number of client vterms present */ -/* XXX this requires an interface change to handle multiple discontiguous - * vterms */ -int hvc_count(int *start_termno) -{ - u32 *termno; - struct device_node *rtas; - struct device_node *vtys; - - /* consider only the first vty node. - * we should _always_ be able to find one. however, it may not be compatible - * with hvterm1, in which case hvc_console can't use it. */ - vtys = find_devices("vty"); - if (vtys && device_is_compatible(vtys, "hvterm1")) { - termno = (u32 *)get_property(vtys, "reg", 0); - if (start_termno && termno) - *start_termno = *termno; - return 1; /* we can't support >1 with this interface */ - } - - /* no vty nodes; use the /rtas/ibm,termno property */ - printk(KERN_ERR "%s: couldn't find a 'vty' node\n", __FUNCTION__); - if ((rtas = find_path_device("/rtas")) != NULL) { - if ((termno = (u32 *)get_property(rtas, "ibm,termno", 0)) != NULL) { - if (start_termno) - *start_termno = termno[0]; - return termno[1]; - } - } - - /* couldn't find any vterms */ - return 0; -} - #ifndef CONFIG_PPC_ISERIES void pSeries_lpar_mm_init(void); diff -Nru a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c --- a/drivers/char/hvc_console.c Tue Nov 4 14:31:54 2003 +++ b/drivers/char/hvc_console.c Tue Nov 4 14:31:54 2003 @@ -29,10 +29,7 @@ #include #include #include - -extern int hvc_count(int *); -extern int hvc_get_chars(int index, char *buf, int count); -extern int hvc_put_chars(int index, const char *buf, int count); +#include #define HVC_MAJOR 229 #define HVC_MINOR 0 @@ -46,24 +43,11 @@ static struct tty_struct *hvc_table[MAX_NR_HVC_CONSOLES]; static struct termios *hvc_termios[MAX_NR_HVC_CONSOLES]; static struct termios *hvc_termios_locked[MAX_NR_HVC_CONSOLES]; -static int hvc_offset; #ifdef CONFIG_MAGIC_SYSRQ static int sysrq_pressed; #endif -#define N_OUTBUF 16 - -#define __ALIGNED__ __attribute__((__aligned__(8))) - -struct hvc_struct { - spinlock_t lock; - int index; - struct tty_struct *tty; - unsigned int count; - int do_wakeup; - char outbuf[N_OUTBUF] __ALIGNED__; - int n_outbuf; -}; +static int next_free_hvc = 0; struct hvc_struct hvc_struct[MAX_NR_HVC_CONSOLES]; @@ -73,7 +57,7 @@ struct hvc_struct *hp; unsigned long flags; - if (line < 0 || line >= MAX_NR_HVC_CONSOLES) + if (line < 0 || line >= next_free_hvc) return -ENODEV; hp = &hvc_struct[line]; @@ -115,7 +99,7 @@ { int n; - n = hvc_put_chars(hp->index + hvc_offset, hp->outbuf, hp->n_outbuf); + n = hp->funcs.put_chars(hp, hp->outbuf, hp->n_outbuf); if (n <= 0) { if (n == 0) return; @@ -195,7 +179,7 @@ for (;;) { if (TTY_FLIPBUF_SIZE - tty->flip.count < sizeof(buf)) break; - n = hvc_get_chars(index + hvc_offset, buf, sizeof(buf)); + n = hp->funcs.get_chars(hp, buf, sizeof(buf)); if (n <= 0) break; for (i = 0; i < n; ++i) { @@ -237,19 +221,35 @@ sigfillset(¤t->blocked); for (;;) { - for (i = 0; i < MAX_NR_HVC_CONSOLES; ++i) + for (i = 0; i < next_free_hvc; ++i) hvc_poll(i); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(TIMEOUT); } } -int __init hvc_init(void) +int hvc_instantiate(int vtermno, struct hvc_arch_funcs *funcs, void *arch_data) { - int i; + struct hvc_struct *hvc = &hvc_struct[next_free_hvc]; + + if (next_free_hvc >= MAX_NR_HVC_CONSOLES) + return -1; + + hvc->lock = SPIN_LOCK_UNLOCKED; + hvc->vtermno = vtermno; + hvc->n_outbuf = 0; + hvc->funcs = *funcs; + hvc->arch_data = arch_data; - memset(&hvc_driver, 0, sizeof(struct tty_driver)); + tty_register_devfs(&hvc_driver, 0, hvc_driver.minor_start + next_free_hvc); + hvc_driver.num++; + next_free_hvc++; + return 0; +} + +int __init hvc_init(void) +{ hvc_driver.magic = TTY_DRIVER_MAGIC; hvc_driver.driver_name = "hvc"; #ifdef CONFIG_DEVFS_FS @@ -259,9 +259,6 @@ #endif hvc_driver.major = HVC_MAJOR; hvc_driver.minor_start = HVC_MINOR; - hvc_driver.num = hvc_count(&hvc_offset); - if (hvc_driver.num > MAX_NR_HVC_CONSOLES) - hvc_driver.num = MAX_NR_HVC_CONSOLES; hvc_driver.type = TTY_DRIVER_TYPE_SYSTEM; hvc_driver.init_termios = tty_std_termios; hvc_driver.flags = TTY_DRIVER_REAL_RAW; @@ -277,17 +274,10 @@ hvc_driver.write_room = hvc_write_room; hvc_driver.chars_in_buffer = hvc_chars_in_buffer; - for (i = 0; i < hvc_driver.num; i++) { - hvc_struct[i].lock = SPIN_LOCK_UNLOCKED; - hvc_struct[i].index = i; - tty_register_devfs(&hvc_driver, 0, hvc_driver.minor_start + i); - } - if (tty_register_driver(&hvc_driver)) panic("Couldn't register hvc console driver\n"); - if (hvc_driver.num > 0) - kernel_thread(khvcd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); + kernel_thread(khvcd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); return 0; } @@ -301,6 +291,7 @@ char c[16] __ALIGNED__; unsigned i, n; int r, donecr = 0; + struct hvc_struct *hp = &hvc_struct[co->index]; i = n = 0; while (count > 0 || i > 0) { @@ -314,7 +305,7 @@ --count; } } else { - r = hvc_put_chars(co->index + hvc_offset, c, i); + r = hp->funcs.put_chars(hp, c, i); if (r < 0) { /* throw away chars on error */ i = 0; @@ -335,17 +326,18 @@ int hvc_wait_for_keypress(struct console *co) { char c[16] __ALIGNED__; + struct hvc_struct *hp = &hvc_struct[co->index]; - while (hvc_get_chars(co->index, &c[0], 1) < 1) + while (hp->funcs.get_chars(hp, &c[0], 1) < 1) ; return 0; } static int __init hvc_console_setup(struct console *co, char *options) { - if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES - || co->index >= hvc_count(&hvc_offset)) + if (co->index < 0 || co->index >= next_free_hvc) return -1; + return 0; } @@ -360,6 +352,10 @@ int __init hvc_console_init(void) { + /* the only discovery call. it must be here in case hvc_console_setup() + * isn't called. */ + hvc_get_vterms(); + register_console(&hvc_con_driver); return 0; } diff -Nru a/include/linux/hvconsole.h b/include/linux/hvconsole.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/hvconsole.h Tue Nov 4 14:31:54 2003 @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2001 Anton Blanchard , IBM + * Copyright (C) 2001 Paul Mackerras , IBM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __HVCONSOLE_H +#define __HVCONSOLE_H + +#include + +#define N_OUTBUF 16 +#define __ALIGNED__ __attribute__((__aligned__(8))) + +struct hvc_arch_funcs { + int (*get_chars)(struct hvc_struct *hvc, char *buf, int count); + int (*put_chars)(struct hvc_struct *hvc, const char *buf, int count); + int (*ioctl)(struct hvc_struct *hvc, long cmd, long val); +}; + +struct hvc_struct { + spinlock_t lock; + int vtermno; + struct tty_struct *tty; + unsigned int count; + int do_wakeup; + char outbuf[N_OUTBUF] __ALIGNED__; + int n_outbuf; + struct hvc_arch_funcs funcs; + void *arch_data; +}; + +extern int hvc_get_vterms(void); + +#endif /* __HVCONSOLE_H */