diff options
Diffstat (limited to 'drivers/tty/hvc')
-rw-r--r-- | drivers/tty/hvc/Kconfig | 14 | ||||
-rw-r--r-- | drivers/tty/hvc/Makefile | 4 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_console.c | 72 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_console.h | 4 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_irq.c | 2 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_iseries.c | 1 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_vio.c | 409 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_xen.c | 2 | ||||
-rw-r--r-- | drivers/tty/hvc/hvcs.c | 10 | ||||
-rw-r--r-- | drivers/tty/hvc/hvsi.c | 131 |
10 files changed, 493 insertions, 156 deletions
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig index 6f2c980..4222035 100644 --- a/drivers/tty/hvc/Kconfig +++ b/drivers/tty/hvc/Kconfig @@ -19,6 +19,11 @@ config HVC_CONSOLE console. This driver allows each pSeries partition to have a console which is accessed via the HMC. +config HVC_OLD_HVSI + bool "Old driver for pSeries serial port (/dev/hvsi*)" + depends on HVC_CONSOLE + default n + config HVC_ISERIES bool "iSeries Hypervisor Virtual Console support" depends on PPC_ISERIES @@ -29,6 +34,15 @@ config HVC_ISERIES help iSeries machines support a hypervisor virtual console. +config HVC_OPAL + bool "OPAL Console support" + depends on PPC_POWERNV + select HVC_DRIVER + select HVC_IRQ + default y + help + PowerNV machines running under OPAL need that driver to get a console + config HVC_RTAS bool "IBM RTAS Console support" depends on PPC_RTAS diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile index 40a25d9..89abf40b 100644 --- a/drivers/tty/hvc/Makefile +++ b/drivers/tty/hvc/Makefile @@ -1,4 +1,6 @@ -obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o +obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi_lib.o +obj-$(CONFIG_HVC_OPAL) += hvc_opal.o hvsi_lib.o +obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_TILE) += hvc_tile.o diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index aa84555..443547b 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -31,6 +31,7 @@ #include <linux/list.h> #include <linux/module.h> #include <linux/major.h> +#include <linux/atomic.h> #include <linux/sysrq.h> #include <linux/tty.h> #include <linux/tty_flip.h> @@ -39,6 +40,7 @@ #include <linux/delay.h> #include <linux/freezer.h> #include <linux/slab.h> +#include <linux/serial_core.h> #include <asm/uaccess.h> @@ -69,6 +71,9 @@ static struct task_struct *hvc_task; /* Picks up late kicks after list walk but before schedule() */ static int hvc_kicked; +/* hvc_init is triggered from hvc_alloc, i.e. only when actually used */ +static atomic_t hvc_needs_init __read_mostly = ATOMIC_INIT(-1); + static int hvc_init(void); #ifdef CONFIG_MAGIC_SYSRQ @@ -185,8 +190,8 @@ static struct tty_driver *hvc_console_device(struct console *c, int *index) return hvc_driver; } -static int __init hvc_console_setup(struct console *co, char *options) -{ +static int hvc_console_setup(struct console *co, char *options) +{ if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES) return -ENODEV; @@ -387,7 +392,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) * there is no buffered data otherwise sleeps on a wait queue * waking periodically to check chars_in_buffer(). */ - tty_wait_until_sent(tty, HVC_CLOSE_WAIT); + tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT); } else { if (hp->count < 0) printk(KERN_ERR "hvc_close %X: oops, count is %d\n", @@ -747,6 +752,58 @@ static int khvcd(void *unused) return 0; } +static int hvc_tiocmget(struct tty_struct *tty) +{ + struct hvc_struct *hp = tty->driver_data; + + if (!hp || !hp->ops->tiocmget) + return -EINVAL; + return hp->ops->tiocmget(hp); +} + +static int hvc_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct hvc_struct *hp = tty->driver_data; + + if (!hp || !hp->ops->tiocmset) + return -EINVAL; + return hp->ops->tiocmset(hp, set, clear); +} + +#ifdef CONFIG_CONSOLE_POLL +int hvc_poll_init(struct tty_driver *driver, int line, char *options) +{ + return 0; +} + +static int hvc_poll_get_char(struct tty_driver *driver, int line) +{ + struct tty_struct *tty = driver->ttys[0]; + struct hvc_struct *hp = tty->driver_data; + int n; + char ch; + + n = hp->ops->get_chars(hp->vtermno, &ch, 1); + + if (n == 0) + return NO_POLL_CHAR; + + return ch; +} + +static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch) +{ + struct tty_struct *tty = driver->ttys[0]; + struct hvc_struct *hp = tty->driver_data; + int n; + + do { + n = hp->ops->put_chars(hp->vtermno, &ch, 1); + } while (n <= 0); +} +#endif + static const struct tty_operations hvc_ops = { .open = hvc_open, .close = hvc_close, @@ -755,6 +812,13 @@ static const struct tty_operations hvc_ops = { .unthrottle = hvc_unthrottle, .write_room = hvc_write_room, .chars_in_buffer = hvc_chars_in_buffer, + .tiocmget = hvc_tiocmget, + .tiocmset = hvc_tiocmset, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = hvc_poll_init, + .poll_get_char = hvc_poll_get_char, + .poll_put_char = hvc_poll_put_char, +#endif }; struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, @@ -765,7 +829,7 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, int i; /* We wait until a driver actually comes along */ - if (!hvc_driver) { + if (atomic_inc_not_zero(&hvc_needs_init)) { int err = hvc_init(); if (err) return ERR_PTR(err); diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index 54381eba..c335a14 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -73,6 +73,10 @@ struct hv_ops { int (*notifier_add)(struct hvc_struct *hp, int irq); void (*notifier_del)(struct hvc_struct *hp, int irq); void (*notifier_hangup)(struct hvc_struct *hp, int irq); + + /* tiocmget/set implementation */ + int (*tiocmget)(struct hvc_struct *hp); + int (*tiocmset)(struct hvc_struct *hp, unsigned int set, unsigned int clear); }; /* Register a vterm and a slot index for use as a console (console_init) */ diff --git a/drivers/tty/hvc/hvc_irq.c b/drivers/tty/hvc/hvc_irq.c index 2623e17..c9adb05 100644 --- a/drivers/tty/hvc/hvc_irq.c +++ b/drivers/tty/hvc/hvc_irq.c @@ -28,7 +28,7 @@ int notifier_add_irq(struct hvc_struct *hp, int irq) hp->irq_requested = 0; return 0; } - rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, + rc = request_irq(irq, hvc_handle_interrupt, 0, "hvc_console", hp); if (!rc) hp->irq_requested = 1; diff --git a/drivers/tty/hvc/hvc_iseries.c b/drivers/tty/hvc/hvc_iseries.c index 21c5495..3f4a897 100644 --- a/drivers/tty/hvc/hvc_iseries.c +++ b/drivers/tty/hvc/hvc_iseries.c @@ -23,6 +23,7 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/spinlock.h> #include <linux/console.h> diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index e6eea14..fc3c3ad 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -27,15 +27,28 @@ * 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 + * + * TODO: + * + * - handle error in sending hvsi protocol packets + * - retry nego on subsequent sends ? */ +#undef DEBUG + #include <linux/types.h> #include <linux/init.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/console.h> +#include <linux/module.h> #include <asm/hvconsole.h> #include <asm/vio.h> #include <asm/prom.h> #include <asm/firmware.h> +#include <asm/hvsi.h> +#include <asm/udbg.h> #include "hvc_console.h" @@ -43,59 +56,236 @@ static const char hvc_driver_name[] = "hvc_console"; static struct vio_device_id hvc_driver_table[] __devinitdata = { {"serial", "hvterm1"}, +#ifndef HVC_OLD_HVSI + {"serial", "hvterm-protocol"}, +#endif { "", "" } }; MODULE_DEVICE_TABLE(vio, hvc_driver_table); -static int filtered_get_chars(uint32_t vtermno, char *buf, int count) +typedef enum hv_protocol { + HV_PROTOCOL_RAW, + HV_PROTOCOL_HVSI +} hv_protocol_t; + +struct hvterm_priv { + u32 termno; /* HV term number */ + hv_protocol_t proto; /* Raw data or HVSI packets */ + struct hvsi_priv hvsi; /* HVSI specific data */ + spinlock_t buf_lock; + char buf[SIZE_VIO_GET_CHARS]; + int left; + int offset; +}; +static struct hvterm_priv *hvterm_privs[MAX_NR_HVC_CONSOLES]; +/* For early boot console */ +static struct hvterm_priv hvterm_priv0; + +static int hvterm_raw_get_chars(uint32_t vtermno, char *buf, int count) { - unsigned long got; - int i; + struct hvterm_priv *pv = hvterm_privs[vtermno]; + unsigned long i; + unsigned long flags; + int got; - /* - * Vio firmware will read up to SIZE_VIO_GET_CHARS at its own discretion - * so we play safe and avoid the situation where got > count which could - * overload the flip buffer. - */ - if (count < SIZE_VIO_GET_CHARS) - return -EAGAIN; + if (WARN_ON(!pv)) + return 0; - got = hvc_get_chars(vtermno, buf, count); + spin_lock_irqsave(&pv->buf_lock, flags); - /* - * Work around a HV bug where it gives us a null - * after every \r. -- paulus - */ - 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); + if (pv->left == 0) { + pv->offset = 0; + pv->left = hvc_get_chars(pv->termno, pv->buf, count); + + /* + * Work around a HV bug where it gives us a null + * after every \r. -- paulus + */ + for (i = 1; i < pv->left; ++i) { + if (pv->buf[i] == 0 && pv->buf[i-1] == '\r') { + --pv->left; + if (i < pv->left) { + memmove(&pv->buf[i], &pv->buf[i+1], + pv->left - i); + } + } } } + + got = min(count, pv->left); + memcpy(buf, &pv->buf[pv->offset], got); + pv->offset += got; + pv->left -= got; + + spin_unlock_irqrestore(&pv->buf_lock, flags); + return got; } -static const struct hv_ops hvc_get_put_ops = { - .get_chars = filtered_get_chars, - .put_chars = hvc_put_chars, +static int hvterm_raw_put_chars(uint32_t vtermno, const char *buf, int count) +{ + struct hvterm_priv *pv = hvterm_privs[vtermno]; + + if (WARN_ON(!pv)) + return 0; + + return hvc_put_chars(pv->termno, buf, count); +} + +static const struct hv_ops hvterm_raw_ops = { + .get_chars = hvterm_raw_get_chars, + .put_chars = hvterm_raw_put_chars, .notifier_add = notifier_add_irq, .notifier_del = notifier_del_irq, .notifier_hangup = notifier_hangup_irq, }; +static int hvterm_hvsi_get_chars(uint32_t vtermno, char *buf, int count) +{ + struct hvterm_priv *pv = hvterm_privs[vtermno]; + + if (WARN_ON(!pv)) + return 0; + + return hvsilib_get_chars(&pv->hvsi, buf, count); +} + +static int hvterm_hvsi_put_chars(uint32_t vtermno, const char *buf, int count) +{ + struct hvterm_priv *pv = hvterm_privs[vtermno]; + + if (WARN_ON(!pv)) + return 0; + + return hvsilib_put_chars(&pv->hvsi, buf, count); +} + +static int hvterm_hvsi_open(struct hvc_struct *hp, int data) +{ + struct hvterm_priv *pv = hvterm_privs[hp->vtermno]; + int rc; + + pr_devel("HVSI@%x: open !\n", pv->termno); + + rc = notifier_add_irq(hp, data); + if (rc) + return rc; + + return hvsilib_open(&pv->hvsi, hp); +} + +static void hvterm_hvsi_close(struct hvc_struct *hp, int data) +{ + struct hvterm_priv *pv = hvterm_privs[hp->vtermno]; + + pr_devel("HVSI@%x: do close !\n", pv->termno); + + hvsilib_close(&pv->hvsi, hp); + + notifier_del_irq(hp, data); +} + +void hvterm_hvsi_hangup(struct hvc_struct *hp, int data) +{ + struct hvterm_priv *pv = hvterm_privs[hp->vtermno]; + + pr_devel("HVSI@%x: do hangup !\n", pv->termno); + + hvsilib_close(&pv->hvsi, hp); + + notifier_hangup_irq(hp, data); +} + +static int hvterm_hvsi_tiocmget(struct hvc_struct *hp) +{ + struct hvterm_priv *pv = hvterm_privs[hp->vtermno]; + + if (!pv) + return -EINVAL; + return pv->hvsi.mctrl; +} + +static int hvterm_hvsi_tiocmset(struct hvc_struct *hp, unsigned int set, + unsigned int clear) +{ + struct hvterm_priv *pv = hvterm_privs[hp->vtermno]; + + pr_devel("HVSI@%x: Set modem control, set=%x,clr=%x\n", + pv->termno, set, clear); + + if (set & TIOCM_DTR) + hvsilib_write_mctrl(&pv->hvsi, 1); + else if (clear & TIOCM_DTR) + hvsilib_write_mctrl(&pv->hvsi, 0); + + return 0; +} + +static const struct hv_ops hvterm_hvsi_ops = { + .get_chars = hvterm_hvsi_get_chars, + .put_chars = hvterm_hvsi_put_chars, + .notifier_add = hvterm_hvsi_open, + .notifier_del = hvterm_hvsi_close, + .notifier_hangup = hvterm_hvsi_hangup, + .tiocmget = hvterm_hvsi_tiocmget, + .tiocmset = hvterm_hvsi_tiocmset, +}; + static int __devinit hvc_vio_probe(struct vio_dev *vdev, - const struct vio_device_id *id) + const struct vio_device_id *id) { + const struct hv_ops *ops; struct hvc_struct *hp; + struct hvterm_priv *pv; + hv_protocol_t proto; + int i, termno = -1; /* probed with invalid parameters. */ if (!vdev || !id) return -EPERM; - hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops, - MAX_VIO_PUT_CHARS); + if (of_device_is_compatible(vdev->dev.of_node, "hvterm1")) { + proto = HV_PROTOCOL_RAW; + ops = &hvterm_raw_ops; + } else if (of_device_is_compatible(vdev->dev.of_node, "hvterm-protocol")) { + proto = HV_PROTOCOL_HVSI; + ops = &hvterm_hvsi_ops; + } else { + pr_err("hvc_vio: Unkown protocol for %s\n", vdev->dev.of_node->full_name); + return -ENXIO; + } + + pr_devel("hvc_vio_probe() device %s, using %s protocol\n", + vdev->dev.of_node->full_name, + proto == HV_PROTOCOL_RAW ? "raw" : "hvsi"); + + /* Is it our boot one ? */ + if (hvterm_privs[0] == &hvterm_priv0 && + vdev->unit_address == hvterm_priv0.termno) { + pv = hvterm_privs[0]; + termno = 0; + pr_devel("->boot console, using termno 0\n"); + } + /* nope, allocate a new one */ + else { + for (i = 0; i < MAX_NR_HVC_CONSOLES && termno < 0; i++) + if (!hvterm_privs[i]) + termno = i; + pr_devel("->non-boot console, using termno %d\n", termno); + if (termno < 0) + return -ENODEV; + pv = kzalloc(sizeof(struct hvterm_priv), GFP_KERNEL); + if (!pv) + return -ENOMEM; + pv->termno = vdev->unit_address; + pv->proto = proto; + spin_lock_init(&pv->buf_lock); + hvterm_privs[termno] = pv; + hvsilib_init(&pv->hvsi, hvc_get_chars, hvc_put_chars, + pv->termno, 0); + } + + hp = hvc_alloc(termno, vdev->irq, ops, MAX_VIO_PUT_CHARS); if (IS_ERR(hp)) return PTR_ERR(hp); dev_set_drvdata(&vdev->dev, hp); @@ -106,8 +296,16 @@ static int __devinit hvc_vio_probe(struct vio_dev *vdev, static int __devexit hvc_vio_remove(struct vio_dev *vdev) { struct hvc_struct *hp = dev_get_drvdata(&vdev->dev); + int rc, termno; - return hvc_remove(hp); + termno = hp->vtermno; + rc = hvc_remove(hp); + if (rc == 0) { + if (hvterm_privs[termno] != &hvterm_priv0) + kfree(hvterm_privs[termno]); + hvterm_privs[termno] = NULL; + } + return rc; } static struct vio_driver hvc_vio_driver = { @@ -140,34 +338,149 @@ static void __exit hvc_vio_exit(void) } module_exit(hvc_vio_exit); -/* the device tree order defines our numbering */ -static int hvc_find_vtys(void) +static void udbg_hvc_putc(char c) { - struct device_node *vty; - int num_found = 0; + int count = -1; - for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; - vty = of_find_node_by_name(vty, "vty")) { - const uint32_t *vtermno; + if (c == '\n') + udbg_hvc_putc('\r'); - /* We have statically defined space for only a certain number - * of console adapters. - */ - if (num_found >= MAX_NR_HVC_CONSOLES) { - of_node_put(vty); + do { + switch(hvterm_priv0.proto) { + case HV_PROTOCOL_RAW: + count = hvterm_raw_put_chars(0, &c, 1); + break; + case HV_PROTOCOL_HVSI: + count = hvterm_hvsi_put_chars(0, &c, 1); break; } + } while(count == 0); +} + +static int udbg_hvc_getc_poll(void) +{ + int rc = 0; + char c; - vtermno = of_get_property(vty, "reg", NULL); - if (!vtermno) - continue; + switch(hvterm_priv0.proto) { + case HV_PROTOCOL_RAW: + rc = hvterm_raw_get_chars(0, &c, 1); + break; + case HV_PROTOCOL_HVSI: + rc = hvterm_hvsi_get_chars(0, &c, 1); + break; + } + if (!rc) + return -1; + return c; +} - if (of_device_is_compatible(vty, "hvterm1")) { - hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops); - ++num_found; +static int udbg_hvc_getc(void) +{ + int ch; + for (;;) { + ch = udbg_hvc_getc_poll(); + if (ch == -1) { + /* This shouldn't be needed...but... */ + volatile unsigned long delay; + for (delay=0; delay < 2000000; delay++) + ; + } else { + return ch; } } +} + +void __init hvc_vio_init_early(void) +{ + struct device_node *stdout_node; + const u32 *termno; + const char *name; + const struct hv_ops *ops; + + /* find the boot console from /chosen/stdout */ + if (!of_chosen) + return; + name = of_get_property(of_chosen, "linux,stdout-path", NULL); + if (name == NULL) + return; + stdout_node = of_find_node_by_path(name); + if (!stdout_node) + return; + name = of_get_property(stdout_node, "name", NULL); + if (!name) { + printk(KERN_WARNING "stdout node missing 'name' property!\n"); + goto out; + } + + /* Check if it's a virtual terminal */ + if (strncmp(name, "vty", 3) != 0) + goto out; + termno = of_get_property(stdout_node, "reg", NULL); + if (termno == NULL) + goto out; + hvterm_priv0.termno = *termno; + spin_lock_init(&hvterm_priv0.buf_lock); + hvterm_privs[0] = &hvterm_priv0; + + /* Check the protocol */ + if (of_device_is_compatible(stdout_node, "hvterm1")) { + hvterm_priv0.proto = HV_PROTOCOL_RAW; + ops = &hvterm_raw_ops; + } + else if (of_device_is_compatible(stdout_node, "hvterm-protocol")) { + hvterm_priv0.proto = HV_PROTOCOL_HVSI; + ops = &hvterm_hvsi_ops; + hvsilib_init(&hvterm_priv0.hvsi, hvc_get_chars, hvc_put_chars, + hvterm_priv0.termno, 1); + /* HVSI, perform the handshake now */ + hvsilib_establish(&hvterm_priv0.hvsi); + } else + goto out; + udbg_putc = udbg_hvc_putc; + udbg_getc = udbg_hvc_getc; + udbg_getc_poll = udbg_hvc_getc_poll; +#ifdef HVC_OLD_HVSI + /* When using the old HVSI driver don't register the HVC + * backend for HVSI, only do udbg + */ + if (hvterm_priv0.proto == HV_PROTOCOL_HVSI) + goto out; +#endif + add_preferred_console("hvc", 0, NULL); + hvc_instantiate(0, 0, ops); +out: + of_node_put(stdout_node); +} - return num_found; +/* call this from early_init() for a working debug console on + * vterm capable LPAR machines + */ +#ifdef CONFIG_PPC_EARLY_DEBUG_LPAR +void __init udbg_init_debug_lpar(void) +{ + hvterm_privs[0] = &hvterm_priv0; + hvterm_priv0.termno = 0; + hvterm_priv0.proto = HV_PROTOCOL_RAW; + spin_lock_init(&hvterm_priv0.buf_lock); + udbg_putc = udbg_hvc_putc; + udbg_getc = udbg_hvc_getc; + udbg_getc_poll = udbg_hvc_getc_poll; +} +#endif /* CONFIG_PPC_EARLY_DEBUG_LPAR */ + +#ifdef CONFIG_PPC_EARLY_DEBUG_LPAR_HVSI +void __init udbg_init_debug_lpar_hvsi(void) +{ + hvterm_privs[0] = &hvterm_priv0; + hvterm_priv0.termno = CONFIG_PPC_EARLY_DEBUG_HVSI_VTERMNO; + hvterm_priv0.proto = HV_PROTOCOL_HVSI; + spin_lock_init(&hvterm_priv0.buf_lock); + udbg_putc = udbg_hvc_putc; + udbg_getc = udbg_hvc_getc; + udbg_getc_poll = udbg_hvc_getc_poll; + hvsilib_init(&hvterm_priv0.hvsi, hvc_get_chars, hvc_put_chars, + hvterm_priv0.termno, 1); + hvsilib_establish(&hvterm_priv0.hvsi); } -console_initcall(hvc_find_vtys); +#endif /* CONFIG_PPC_EARLY_DEBUG_LPAR_HVSI */ diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 52fdf60..df8f8e0 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -167,7 +167,7 @@ static int __init xen_hvc_init(void) if (xen_initial_domain()) { ops = &dom0_hvc_ops; - xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0); + xencons_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0, false); } else { if (!xen_start_info->console.domU.evtchn) return -ENODEV; diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 4c8b665..b9040be 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1057,7 +1057,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, * the conn was registered and now. */ if (!(rc = request_irq(irq, &hvcs_handle_interrupt, - IRQF_DISABLED, "ibmhvcs", hvcsd))) { + 0, "ibmhvcs", hvcsd))) { /* * It is possible the vty-server was removed after the irq was * requested but before we have time to enable interrupts. @@ -1237,7 +1237,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) irq = hvcsd->vdev->irq; spin_unlock_irqrestore(&hvcsd->lock, flags); - tty_wait_until_sent(tty, HVCS_CLOSE_WAIT); + tty_wait_until_sent_from_close(tty, HVCS_CLOSE_WAIT); /* * This line is important because it tells hvcs_open that this @@ -1532,7 +1532,7 @@ static int __devinit hvcs_initialize(void) goto register_fail; } - hvcs_pi_buff = kmalloc(PAGE_SIZE, GFP_KERNEL); + hvcs_pi_buff = (unsigned long *) __get_free_page(GFP_KERNEL); if (!hvcs_pi_buff) { rc = -ENOMEM; goto buff_alloc_fail; @@ -1548,7 +1548,7 @@ static int __devinit hvcs_initialize(void) return 0; kthread_fail: - kfree(hvcs_pi_buff); + free_page((unsigned long)hvcs_pi_buff); buff_alloc_fail: tty_unregister_driver(hvcs_tty_driver); register_fail: @@ -1597,7 +1597,7 @@ static void __exit hvcs_module_exit(void) kthread_stop(hvcs_task); spin_lock(&hvcs_pi_lock); - kfree(hvcs_pi_buff); + free_page((unsigned long)hvcs_pi_buff); hvcs_pi_buff = NULL; spin_unlock(&hvcs_pi_lock); diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 8a8d637..cdfa3e0 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -49,6 +49,7 @@ #include <asm/uaccess.h> #include <asm/vio.h> #include <asm/param.h> +#include <asm/hvsi.h> #define HVSI_MAJOR 229 #define HVSI_MINOR 128 @@ -109,68 +110,6 @@ enum HVSI_PROTOCOL_STATE { }; #define HVSI_CONSOLE 0x1 -#define VS_DATA_PACKET_HEADER 0xff -#define VS_CONTROL_PACKET_HEADER 0xfe -#define VS_QUERY_PACKET_HEADER 0xfd -#define VS_QUERY_RESPONSE_PACKET_HEADER 0xfc - -/* control verbs */ -#define VSV_SET_MODEM_CTL 1 /* to service processor only */ -#define VSV_MODEM_CTL_UPDATE 2 /* from service processor only */ -#define VSV_CLOSE_PROTOCOL 3 - -/* query verbs */ -#define VSV_SEND_VERSION_NUMBER 1 -#define VSV_SEND_MODEM_CTL_STATUS 2 - -/* yes, these masks are not consecutive. */ -#define HVSI_TSDTR 0x01 -#define HVSI_TSCD 0x20 - -struct hvsi_header { - uint8_t type; - uint8_t len; - uint16_t seqno; -} __attribute__((packed)); - -struct hvsi_data { - uint8_t type; - uint8_t len; - uint16_t seqno; - uint8_t data[HVSI_MAX_OUTGOING_DATA]; -} __attribute__((packed)); - -struct hvsi_control { - uint8_t type; - uint8_t len; - uint16_t seqno; - uint16_t verb; - /* optional depending on verb: */ - uint32_t word; - uint32_t mask; -} __attribute__((packed)); - -struct hvsi_query { - uint8_t type; - uint8_t len; - uint16_t seqno; - uint16_t verb; -} __attribute__((packed)); - -struct hvsi_query_response { - uint8_t type; - uint8_t len; - uint16_t seqno; - uint16_t verb; - uint16_t query_seqno; - union { - uint8_t version; - uint32_t mctrl_word; - } u; -} __attribute__((packed)); - - - static inline int is_console(struct hvsi_struct *hp) { return hp->flags & HVSI_CONSOLE; @@ -356,18 +295,18 @@ static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno) struct hvsi_query_response packet __ALIGNED__; int wrote; - packet.type = VS_QUERY_RESPONSE_PACKET_HEADER; - packet.len = sizeof(struct hvsi_query_response); - packet.seqno = atomic_inc_return(&hp->seqno); + packet.hdr.type = VS_QUERY_RESPONSE_PACKET_HEADER; + packet.hdr.len = sizeof(struct hvsi_query_response); + packet.hdr.seqno = atomic_inc_return(&hp->seqno); packet.verb = VSV_SEND_VERSION_NUMBER; packet.u.version = HVSI_VERSION; packet.query_seqno = query_seqno+1; - pr_debug("%s: sending %i bytes\n", __func__, packet.len); - dbg_dump_hex((uint8_t*)&packet, packet.len); + pr_debug("%s: sending %i bytes\n", __func__, packet.hdr.len); + dbg_dump_hex((uint8_t*)&packet, packet.hdr.len); - wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); - if (wrote != packet.len) { + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.hdr.len); + if (wrote != packet.hdr.len) { printk(KERN_ERR "hvsi%i: couldn't send query response!\n", hp->index); return -EIO; @@ -382,7 +321,7 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) switch (hp->state) { case HVSI_WAIT_FOR_VER_QUERY: - hvsi_version_respond(hp, query->seqno); + hvsi_version_respond(hp, query->hdr.seqno); __set_state(hp, HVSI_OPEN); break; default: @@ -640,16 +579,16 @@ static int hvsi_query(struct hvsi_struct *hp, uint16_t verb) struct hvsi_query packet __ALIGNED__; int wrote; - packet.type = VS_QUERY_PACKET_HEADER; - packet.len = sizeof(struct hvsi_query); - packet.seqno = atomic_inc_return(&hp->seqno); + packet.hdr.type = VS_QUERY_PACKET_HEADER; + packet.hdr.len = sizeof(struct hvsi_query); + packet.hdr.seqno = atomic_inc_return(&hp->seqno); packet.verb = verb; - pr_debug("%s: sending %i bytes\n", __func__, packet.len); - dbg_dump_hex((uint8_t*)&packet, packet.len); + pr_debug("%s: sending %i bytes\n", __func__, packet.hdr.len); + dbg_dump_hex((uint8_t*)&packet, packet.hdr.len); - wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); - if (wrote != packet.len) { + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.hdr.len); + if (wrote != packet.hdr.len) { printk(KERN_ERR "hvsi%i: couldn't send query (%i)!\n", hp->index, wrote); return -EIO; @@ -683,20 +622,20 @@ static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl) struct hvsi_control packet __ALIGNED__; int wrote; - packet.type = VS_CONTROL_PACKET_HEADER, - packet.seqno = atomic_inc_return(&hp->seqno); - packet.len = sizeof(struct hvsi_control); + packet.hdr.type = VS_CONTROL_PACKET_HEADER, + packet.hdr.seqno = atomic_inc_return(&hp->seqno); + packet.hdr.len = sizeof(struct hvsi_control); packet.verb = VSV_SET_MODEM_CTL; packet.mask = HVSI_TSDTR; if (mctrl & TIOCM_DTR) packet.word = HVSI_TSDTR; - pr_debug("%s: sending %i bytes\n", __func__, packet.len); - dbg_dump_hex((uint8_t*)&packet, packet.len); + pr_debug("%s: sending %i bytes\n", __func__, packet.hdr.len); + dbg_dump_hex((uint8_t*)&packet, packet.hdr.len); - wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); - if (wrote != packet.len) { + wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.hdr.len); + if (wrote != packet.hdr.len) { printk(KERN_ERR "hvsi%i: couldn't set DTR!\n", hp->index); return -EIO; } @@ -766,13 +705,13 @@ static int hvsi_put_chars(struct hvsi_struct *hp, const char *buf, int count) BUG_ON(count > HVSI_MAX_OUTGOING_DATA); - packet.type = VS_DATA_PACKET_HEADER; - packet.seqno = atomic_inc_return(&hp->seqno); - packet.len = count + sizeof(struct hvsi_header); + packet.hdr.type = VS_DATA_PACKET_HEADER; + packet.hdr.seqno = atomic_inc_return(&hp->seqno); + packet.hdr.len = count + sizeof(struct hvsi_header); memcpy(&packet.data, buf, count); - ret = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); - if (ret == packet.len) { + ret = hvc_put_chars(hp->vtermno, (char *)&packet, packet.hdr.len); + if (ret == packet.hdr.len) { /* return the number of chars written, not the packet length */ return count; } @@ -783,15 +722,15 @@ static void hvsi_close_protocol(struct hvsi_struct *hp) { struct hvsi_control packet __ALIGNED__; - packet.type = VS_CONTROL_PACKET_HEADER; - packet.seqno = atomic_inc_return(&hp->seqno); - packet.len = 6; + packet.hdr.type = VS_CONTROL_PACKET_HEADER; + packet.hdr.seqno = atomic_inc_return(&hp->seqno); + packet.hdr.len = 6; packet.verb = VSV_CLOSE_PROTOCOL; - pr_debug("%s: sending %i bytes\n", __func__, packet.len); - dbg_dump_hex((uint8_t*)&packet, packet.len); + pr_debug("%s: sending %i bytes\n", __func__, packet.hdr.len); + dbg_dump_hex((uint8_t*)&packet, packet.hdr.len); - hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); + hvc_put_chars(hp->vtermno, (char *)&packet, packet.hdr.len); } static int hvsi_open(struct tty_struct *tty, struct file *filp) @@ -1166,7 +1105,7 @@ static int __init hvsi_init(void) struct hvsi_struct *hp = &hvsi_ports[i]; int ret = 1; - ret = request_irq(hp->virq, hvsi_interrupt, IRQF_DISABLED, "hvsi", hp); + ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp); if (ret) printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n", hp->virq, ret); |