aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/hvc_console.c
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2008-06-20 09:24:08 -0400
committerRusty Russell <rusty@rustcorp.com.au>2008-07-24 22:06:06 -0400
commit611e097d7707741a336a0677d9d69bec40f29f3d (patch)
tree0b0059544914bf027ada51a1ba90f694c54df835 /drivers/char/hvc_console.c
parent066f4d82a67f621ddd547bfa4b9c94631d8457b0 (diff)
hvc_console: rework setup to replace irq functions with callbacks
This patch tries to change hvc_console to not use request_irq/free_irq if the backend does not use irqs. This allows virtio_console to use hvc_console without having a linker reference to request_irq/free_irq. In addition, together with patch 2/3 it improves the performance for virtio console input. (an earlier version of this patch was tested by Yajin on lguest) The irq specific code is moved to hvc_irq.c and selected by the drivers that use irqs (System p, System i, XEN). I replaced "int irq" with the opaque "int data". The request_irq and free_irq calls are replaced with notifier_add and notifier_del. I have also changed the code a bit to call the notifier_add and notifier_del inside the spinlock area as the callbacks are found via hp->ops. Changes since last version: o remove ifdef o reintroduce "irq_requested" as "notified" o cleanups, sparse.. I did not move the timer based polling into a separate polling scheme. I played with several variants, but it seems we need to sleep/schedule in a thread even for irq based consoles, as there are throttleing and buffer size constraints. I also kept hvc_struct defined in hvc_console.h so that hvc_irq.c can access the irq_requested element. Feedback is appreciated. virtio_console is currently the only available console for kvm on s390. I plan to push this change as soon as all affected parties agree on it. I would love to get test results from System p, Xen etc. Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/char/hvc_console.c')
-rw-r--r--drivers/char/hvc_console.c81
1 files changed, 18 insertions, 63 deletions
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 2f9759d625cc..2f5b7fb67045 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -27,7 +27,6 @@
27#include <linux/init.h> 27#include <linux/init.h>
28#include <linux/kbd_kern.h> 28#include <linux/kbd_kern.h>
29#include <linux/kernel.h> 29#include <linux/kernel.h>
30#include <linux/kref.h>
31#include <linux/kthread.h> 30#include <linux/kthread.h>
32#include <linux/list.h> 31#include <linux/list.h>
33#include <linux/module.h> 32#include <linux/module.h>
@@ -75,23 +74,6 @@ static int hvc_init(void);
75static int sysrq_pressed; 74static int sysrq_pressed;
76#endif 75#endif
77 76
78struct hvc_struct {
79 spinlock_t lock;
80 int index;
81 struct tty_struct *tty;
82 unsigned int count;
83 int do_wakeup;
84 char *outbuf;
85 int outbuf_size;
86 int n_outbuf;
87 uint32_t vtermno;
88 struct hv_ops *ops;
89 int irq_requested;
90 int irq;
91 struct list_head next;
92 struct kref kref; /* ref count & hvc_struct lifetime */
93};
94
95/* dynamic list of hvc_struct instances */ 77/* dynamic list of hvc_struct instances */
96static LIST_HEAD(hvc_structs); 78static LIST_HEAD(hvc_structs);
97 79
@@ -300,26 +282,12 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
300} 282}
301 283
302/* Wake the sleeping khvcd */ 284/* Wake the sleeping khvcd */
303static void hvc_kick(void) 285void hvc_kick(void)
304{ 286{
305 hvc_kicked = 1; 287 hvc_kicked = 1;
306 wake_up_process(hvc_task); 288 wake_up_process(hvc_task);
307} 289}
308 290
309static int hvc_poll(struct hvc_struct *hp);
310
311/*
312 * NOTE: This API isn't used if the console adapter doesn't support interrupts.
313 * In this case the console is poll driven.
314 */
315static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
316{
317 /* if hvc_poll request a repoll, then kick the hvcd thread */
318 if (hvc_poll(dev_instance))
319 hvc_kick();
320 return IRQ_HANDLED;
321}
322
323static void hvc_unthrottle(struct tty_struct *tty) 291static void hvc_unthrottle(struct tty_struct *tty)
324{ 292{
325 hvc_kick(); 293 hvc_kick();
@@ -333,7 +301,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
333{ 301{
334 struct hvc_struct *hp; 302 struct hvc_struct *hp;
335 unsigned long flags; 303 unsigned long flags;
336 int irq = 0;
337 int rc = 0; 304 int rc = 0;
338 305
339 /* Auto increments kref reference if found. */ 306 /* Auto increments kref reference if found. */
@@ -352,18 +319,15 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
352 tty->low_latency = 1; /* Makes flushes to ldisc synchronous. */ 319 tty->low_latency = 1; /* Makes flushes to ldisc synchronous. */
353 320
354 hp->tty = tty; 321 hp->tty = tty;
355 /* Save for request_irq outside of spin_lock. */ 322
356 irq = hp->irq; 323 if (hp->ops->notifier_add)
357 if (irq) 324 rc = hp->ops->notifier_add(hp, hp->data);
358 hp->irq_requested = 1;
359 325
360 spin_unlock_irqrestore(&hp->lock, flags); 326 spin_unlock_irqrestore(&hp->lock, flags);
361 /* check error, fallback to non-irq */ 327
362 if (irq)
363 rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp);
364 328
365 /* 329 /*
366 * If the request_irq() fails and we return an error. The tty layer 330 * If the notifier fails we return an error. The tty layer
367 * will call hvc_close() after a failed open but we don't want to clean 331 * will call hvc_close() after a failed open but we don't want to clean
368 * up there so we'll clean up here and clear out the previously set 332 * up there so we'll clean up here and clear out the previously set
369 * tty fields and return the kref reference. 333 * tty fields and return the kref reference.
@@ -371,7 +335,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
371 if (rc) { 335 if (rc) {
372 spin_lock_irqsave(&hp->lock, flags); 336 spin_lock_irqsave(&hp->lock, flags);
373 hp->tty = NULL; 337 hp->tty = NULL;
374 hp->irq_requested = 0;
375 spin_unlock_irqrestore(&hp->lock, flags); 338 spin_unlock_irqrestore(&hp->lock, flags);
376 tty->driver_data = NULL; 339 tty->driver_data = NULL;
377 kref_put(&hp->kref, destroy_hvc_struct); 340 kref_put(&hp->kref, destroy_hvc_struct);
@@ -386,7 +349,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
386static void hvc_close(struct tty_struct *tty, struct file * filp) 349static void hvc_close(struct tty_struct *tty, struct file * filp)
387{ 350{
388 struct hvc_struct *hp; 351 struct hvc_struct *hp;
389 int irq = 0;
390 unsigned long flags; 352 unsigned long flags;
391 353
392 if (tty_hung_up_p(filp)) 354 if (tty_hung_up_p(filp))
@@ -404,9 +366,8 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
404 spin_lock_irqsave(&hp->lock, flags); 366 spin_lock_irqsave(&hp->lock, flags);
405 367
406 if (--hp->count == 0) { 368 if (--hp->count == 0) {
407 if (hp->irq_requested) 369 if (hp->ops->notifier_del)
408 irq = hp->irq; 370 hp->ops->notifier_del(hp, hp->data);
409 hp->irq_requested = 0;
410 371
411 /* We are done with the tty pointer now. */ 372 /* We are done with the tty pointer now. */
412 hp->tty = NULL; 373 hp->tty = NULL;
@@ -418,10 +379,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
418 * waking periodically to check chars_in_buffer(). 379 * waking periodically to check chars_in_buffer().
419 */ 380 */
420 tty_wait_until_sent(tty, HVC_CLOSE_WAIT); 381 tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
421
422 if (irq)
423 free_irq(irq, hp);
424
425 } else { 382 } else {
426 if (hp->count < 0) 383 if (hp->count < 0)
427 printk(KERN_ERR "hvc_close %X: oops, count is %d\n", 384 printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
@@ -436,7 +393,6 @@ static void hvc_hangup(struct tty_struct *tty)
436{ 393{
437 struct hvc_struct *hp = tty->driver_data; 394 struct hvc_struct *hp = tty->driver_data;
438 unsigned long flags; 395 unsigned long flags;
439 int irq = 0;
440 int temp_open_count; 396 int temp_open_count;
441 397
442 if (!hp) 398 if (!hp)
@@ -458,13 +414,12 @@ static void hvc_hangup(struct tty_struct *tty)
458 hp->count = 0; 414 hp->count = 0;
459 hp->n_outbuf = 0; 415 hp->n_outbuf = 0;
460 hp->tty = NULL; 416 hp->tty = NULL;
461 if (hp->irq_requested) 417
462 /* Saved for use outside of spin_lock. */ 418 if (hp->ops->notifier_del)
463 irq = hp->irq; 419 hp->ops->notifier_del(hp, hp->data);
464 hp->irq_requested = 0; 420
465 spin_unlock_irqrestore(&hp->lock, flags); 421 spin_unlock_irqrestore(&hp->lock, flags);
466 if (irq) 422
467 free_irq(irq, hp);
468 while(temp_open_count) { 423 while(temp_open_count) {
469 --temp_open_count; 424 --temp_open_count;
470 kref_put(&hp->kref, destroy_hvc_struct); 425 kref_put(&hp->kref, destroy_hvc_struct);
@@ -575,7 +530,7 @@ static u32 timeout = MIN_TIMEOUT;
575#define HVC_POLL_READ 0x00000001 530#define HVC_POLL_READ 0x00000001
576#define HVC_POLL_WRITE 0x00000002 531#define HVC_POLL_WRITE 0x00000002
577 532
578static int hvc_poll(struct hvc_struct *hp) 533int hvc_poll(struct hvc_struct *hp)
579{ 534{
580 struct tty_struct *tty; 535 struct tty_struct *tty;
581 int i, n, poll_mask = 0; 536 int i, n, poll_mask = 0;
@@ -602,10 +557,10 @@ static int hvc_poll(struct hvc_struct *hp)
602 if (test_bit(TTY_THROTTLED, &tty->flags)) 557 if (test_bit(TTY_THROTTLED, &tty->flags))
603 goto throttled; 558 goto throttled;
604 559
605 /* If we aren't interrupt driven and aren't throttled, we always 560 /* If we aren't notifier driven and aren't throttled, we always
606 * request a reschedule 561 * request a reschedule
607 */ 562 */
608 if (hp->irq == 0) 563 if (!hp->irq_requested)
609 poll_mask |= HVC_POLL_READ; 564 poll_mask |= HVC_POLL_READ;
610 565
611 /* Read data if any */ 566 /* Read data if any */
@@ -733,7 +688,7 @@ static const struct tty_operations hvc_ops = {
733 .chars_in_buffer = hvc_chars_in_buffer, 688 .chars_in_buffer = hvc_chars_in_buffer,
734}; 689};
735 690
736struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, 691struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
737 struct hv_ops *ops, int outbuf_size) 692 struct hv_ops *ops, int outbuf_size)
738{ 693{
739 struct hvc_struct *hp; 694 struct hvc_struct *hp;
@@ -754,7 +709,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
754 memset(hp, 0x00, sizeof(*hp)); 709 memset(hp, 0x00, sizeof(*hp));
755 710
756 hp->vtermno = vtermno; 711 hp->vtermno = vtermno;
757 hp->irq = irq; 712 hp->data = data;
758 hp->ops = ops; 713 hp->ops = ops;
759 hp->outbuf_size = outbuf_size; 714 hp->outbuf_size = outbuf_size;
760 hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; 715 hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];