X-Git-Url: http://git.onelab.eu/?p=linux-2.6.git;a=blobdiff_plain;f=drivers%2Fchar%2Fhvc_console.c;fp=drivers%2Fchar%2Fhvc_console.c;h=d763a97f1f400b1756a813d5187fc8ae0cc64f58;hp=613d67f1c7f06a054f1f8fdf78418cb8762afaac;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 613d67f1c..d763a97f1 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -22,6 +22,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include @@ -38,10 +39,8 @@ #include #include #include - #include - -#include "hvc_console.h" +#include #define HVC_MAJOR 229 #define HVC_MINOR 0 @@ -55,14 +54,17 @@ #define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ /* - * These sizes are most efficient for vio, because they are the - * native transfer size. We could make them selectable in the - * future to better deal with backends that want other buffer sizes. + * The Linux TTY code does not support dynamic addition of tty derived devices + * so we need to know how many tty devices we might need when space is allocated + * for the tty device. Since this driver supports hotplug of vty adapters we + * need to make sure we have enough allocated. */ +#define HVC_ALLOC_TTY_ADAPTERS 8 + #define N_OUTBUF 16 #define N_INBUF 16 -#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) +#define __ALIGNED__ __attribute__((__aligned__(8))) static struct tty_driver *hvc_driver; static struct task_struct *hvc_task; @@ -152,7 +154,7 @@ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = void hvc_console_print(struct console *co, const char *b, unsigned count) { - char c[N_OUTBUF] __ALIGNED__; + char c[16] __ALIGNED__; unsigned i = 0, n = 0; int r, donecr = 0, index = co->index; @@ -346,7 +348,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&hp->lock, flags); /* check error, fallback to non-irq */ if (irq != NO_IRQ) - rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp); + rc = request_irq(irq, hvc_handle_interrupt, SA_INTERRUPT, "hvc_console", hp); /* * If the request_irq() fails and we return an error. The tty layer @@ -471,10 +473,8 @@ static void hvc_push(struct hvc_struct *hp) n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); if (n <= 0) { - if (n == 0) { - hp->do_wakeup = 1; + if (n == 0) return; - } /* throw away output on error; this happens when there is no session connected to the vterm. */ hp->n_outbuf = 0; @@ -486,19 +486,12 @@ static void hvc_push(struct hvc_struct *hp) hp->do_wakeup = 1; } -static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) +static inline int __hvc_write_kernel(struct hvc_struct *hp, + const unsigned char *buf, int count) { - struct hvc_struct *hp = tty->driver_data; unsigned long flags; int rsize, written = 0; - /* This write was probably executed during a tty close. */ - if (!hp) - return -EPIPE; - - if (hp->count <= 0) - return -EIO; - spin_lock_irqsave(&hp->lock, flags); /* Push pending writes */ @@ -517,8 +510,26 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count } spin_unlock_irqrestore(&hp->lock, flags); + return written; +} +static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) +{ + struct hvc_struct *hp = tty->driver_data; + int written; + + /* This write was probably executed during a tty close. */ + if (!hp) + return -EPIPE; + + if (hp->count <= 0) + return -EIO; + + written = __hvc_write_kernel(hp, buf, count); + /* * Racy, but harmless, kick thread if there is still pending data. + * There really is nothing wrong with kicking the thread, even if there + * is no buffered data. */ if (hp->n_outbuf) hvc_kick(); @@ -552,6 +563,7 @@ static int hvc_chars_in_buffer(struct tty_struct *tty) #define HVC_POLL_READ 0x00000001 #define HVC_POLL_WRITE 0x00000002 +#define HVC_POLL_QUICK 0x00000004 static int hvc_poll(struct hvc_struct *hp) { @@ -566,7 +578,6 @@ static int hvc_poll(struct hvc_struct *hp) /* Push pending writes */ if (hp->n_outbuf > 0) hvc_push(hp); - /* Reschedule us if still some write pending */ if (hp->n_outbuf > 0) poll_mask |= HVC_POLL_WRITE; @@ -603,13 +614,6 @@ static int hvc_poll(struct hvc_struct *hp) spin_unlock_irqrestore(&hp->lock, flags); tty_hangup(tty); spin_lock_irqsave(&hp->lock, flags); - } else if ( n == -EAGAIN ) { - /* - * Some back-ends can only ensure a certain min - * num of bytes read, which may be > 'count'. - * Let the tty clear the flip buff to make room. - */ - poll_mask |= HVC_POLL_READ; } break; } @@ -631,7 +635,16 @@ static int hvc_poll(struct hvc_struct *hp) tty_insert_flip_char(tty, buf[i], 0); } + /* + * Account for the total amount read in one loop, and if above + * 64 bytes, we do a quick schedule loop to let the tty grok + * the data and eventually throttle us. + */ read_total += n; + if (read_total >= 64) { + poll_mask |= HVC_POLL_QUICK; + break; + } } throttled: /* Wakeup write queue if necessary */ @@ -680,7 +693,7 @@ int khvcd(void *unused) poll_mask |= HVC_POLL_READ; if (hvc_kicked) continue; - if (poll_mask & HVC_POLL_WRITE) { + if (poll_mask & HVC_POLL_QUICK) { yield(); continue; } @@ -755,8 +768,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, * see if this vterm id matches one registered for console. */ for (i=0; i < MAX_NR_HVC_CONSOLES; i++) - if (vtermnos[i] == hp->vtermno && - cons_ops[i] == hp->ops) + if (vtermnos[i] == hp->vtermno) break; /* no matching slot, just use a counter */ @@ -812,37 +824,34 @@ EXPORT_SYMBOL(hvc_remove); * interfaces start to become available. */ int __init hvc_init(void) { - struct tty_driver *drv; - /* We need more than hvc_count adapters due to hotplug additions. */ - drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); - if (!drv) + hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); + if (!hvc_driver) return -ENOMEM; - drv->owner = THIS_MODULE; - drv->driver_name = "hvc"; - drv->name = "hvc"; - drv->major = HVC_MAJOR; - drv->minor_start = HVC_MINOR; - drv->type = TTY_DRIVER_TYPE_SYSTEM; - drv->init_termios = tty_std_termios; - drv->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(drv, &hvc_ops); + hvc_driver->owner = THIS_MODULE; + hvc_driver->devfs_name = "hvc/"; + hvc_driver->driver_name = "hvc"; + hvc_driver->name = "hvc"; + hvc_driver->major = HVC_MAJOR; + hvc_driver->minor_start = HVC_MINOR; + hvc_driver->type = TTY_DRIVER_TYPE_SYSTEM; + hvc_driver->init_termios = tty_std_termios; + hvc_driver->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(hvc_driver, &hvc_ops); /* Always start the kthread because there can be hotplug vty adapters * added later. */ hvc_task = kthread_run(khvcd, NULL, "khvcd"); if (IS_ERR(hvc_task)) { panic("Couldn't create kthread for console.\n"); - put_tty_driver(drv); + put_tty_driver(hvc_driver); return -EIO; } - if (tty_register_driver(drv)) + if (tty_register_driver(hvc_driver)) panic("Couldn't register hvc console driver\n"); - mb(); - hvc_driver = drv; return 0; } module_init(hvc_init);