Christian Borntraeger
2008-Jun-03 12:44 UTC
[RFC 0/3]: hvc_console rework for platform without hard irqs
This patch set if my first attempt to make virtio_console usable on s390. To do so, I had to change hvc_console, because s390 has no request_irq and no free_irq. I want to get feedback from the main users of hvc_console before I proceed. The basic idea of this patch set is to remove the calls to request_irq and free_irq and replace them with backend specific callbacks. Please see the descriptions of the patches for further details: 1/3: hvc_console: rework setup to replace irq functions with callbacks 2/3: virtio_console: use virtqueue notification for hvc_console 3/3: s390: use virtio_console for KVM on s390
Christian Borntraeger
2008-Jun-03 12:45 UTC
[RFC 1/3] 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. 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 "irq" with the opaque name "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. Feedback is appreciated. Signed-off-by: Christian Borntraeger <borntraeger at de.ibm.com> --- drivers/char/Kconfig | 8 ++++ drivers/char/Makefile | 1 drivers/char/hvc_console.c | 80 ++++++++++----------------------------------- drivers/char/hvc_console.h | 34 ++++++++++++++++--- drivers/char/hvc_irq.c | 37 ++++++++++++++++++++ drivers/char/hvc_iseries.c | 2 + drivers/char/hvc_vio.c | 2 + drivers/char/hvc_xen.c | 2 + 8 files changed, 100 insertions(+), 66 deletions(-) Index: kvm/drivers/char/Kconfig ==================================================================--- kvm.orig/drivers/char/Kconfig +++ kvm/drivers/char/Kconfig @@ -588,11 +588,17 @@ config HVC_DRIVER It will automatically be selected if one of the back-end console drivers is selected. +config HVC_IRQ + bool + help + Infrastructure for using the IRQ code for HVC console. + It will automatically be selected by the drivers that need it. config HVC_CONSOLE bool "pSeries Hypervisor Virtual Console support" depends on PPC_PSERIES select HVC_DRIVER + select HVC_IRQ help pSeries machines when partitioned support a hypervisor virtual console. This driver allows each pSeries partition to have a console @@ -603,6 +609,7 @@ config HVC_ISERIES depends on PPC_ISERIES default y select HVC_DRIVER + select HVC_IRQ help iSeries machines support a hypervisor virtual console. @@ -624,6 +631,7 @@ config HVC_XEN bool "Xen Hypervisor Console support" depends on XEN select HVC_DRIVER + select HVC_IRQ default y help Xen virtual console device driver Index: kvm/drivers/char/Makefile ==================================================================--- kvm.orig/drivers/char/Makefile +++ kvm/drivers/char/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_HVC_ISERIES) += hvc_iseries obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o +obj-$(CONFIG_HVC_IRQ) += hvc_irq.o obj-$(CONFIG_HVC_XEN) += hvc_xen.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o Index: kvm/drivers/char/hvc_console.c ==================================================================--- kvm.orig/drivers/char/hvc_console.c +++ kvm/drivers/char/hvc_console.c @@ -75,23 +75,6 @@ static int hvc_init(void); static int sysrq_pressed; #endif -struct hvc_struct { - spinlock_t lock; - int index; - struct tty_struct *tty; - unsigned int count; - int do_wakeup; - char *outbuf; - int outbuf_size; - int n_outbuf; - uint32_t vtermno; - struct hv_ops *ops; - int irq_requested; - int irq; - struct list_head next; - struct kref kref; /* ref count & hvc_struct lifetime */ -}; - /* dynamic list of hvc_struct instances */ static LIST_HEAD(hvc_structs); @@ -300,26 +283,12 @@ int hvc_instantiate(uint32_t vtermno, in } /* Wake the sleeping khvcd */ -static void hvc_kick(void) +void hvc_kick(void) { hvc_kicked = 1; wake_up_process(hvc_task); } -static int hvc_poll(struct hvc_struct *hp); - -/* - * NOTE: This API isn't used if the console adapter doesn't support interrupts. - * In this case the console is poll driven. - */ -static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance) -{ - /* if hvc_poll request a repoll, then kick the hvcd thread */ - if (hvc_poll(dev_instance)) - hvc_kick(); - return IRQ_HANDLED; -} - static void hvc_unthrottle(struct tty_struct *tty) { hvc_kick(); @@ -333,7 +302,6 @@ static int hvc_open(struct tty_struct *t { struct hvc_struct *hp; unsigned long flags; - int irq = 0; int rc = 0; /* Auto increments kref reference if found. */ @@ -352,18 +320,15 @@ static int hvc_open(struct tty_struct *t tty->low_latency = 1; /* Makes flushes to ldisc synchronous. */ hp->tty = tty; - /* Save for request_irq outside of spin_lock. */ - irq = hp->irq; - if (irq) - hp->irq_requested = 1; + + if (hp->ops->notifier_add) + rc = hp->ops->notifier_add(hp, hp->data); spin_unlock_irqrestore(&hp->lock, flags); - /* check error, fallback to non-irq */ - if (irq) - rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp); + /* - * If the request_irq() fails and we return an error. The tty layer + * If the notifier fails we return an error. The tty layer * will call hvc_close() after a failed open but we don't want to clean * up there so we'll clean up here and clear out the previously set * tty fields and return the kref reference. @@ -371,7 +336,6 @@ static int hvc_open(struct tty_struct *t if (rc) { spin_lock_irqsave(&hp->lock, flags); hp->tty = NULL; - hp->irq_requested = 0; spin_unlock_irqrestore(&hp->lock, flags); tty->driver_data = NULL; kref_put(&hp->kref, destroy_hvc_struct); @@ -386,7 +350,6 @@ static int hvc_open(struct tty_struct *t static void hvc_close(struct tty_struct *tty, struct file * filp) { struct hvc_struct *hp; - int irq = 0; unsigned long flags; if (tty_hung_up_p(filp)) @@ -404,9 +367,8 @@ static void hvc_close(struct tty_struct spin_lock_irqsave(&hp->lock, flags); if (--hp->count == 0) { - if (hp->irq_requested) - irq = hp->irq; - hp->irq_requested = 0; + if (hp->ops->notifier_del) + hp->ops->notifier_del(hp, hp->data); /* We are done with the tty pointer now. */ hp->tty = NULL; @@ -418,10 +380,6 @@ static void hvc_close(struct tty_struct * waking periodically to check chars_in_buffer(). */ tty_wait_until_sent(tty, HVC_CLOSE_WAIT); - - if (irq) - free_irq(irq, hp); - } else { if (hp->count < 0) printk(KERN_ERR "hvc_close %X: oops, count is %d\n", @@ -436,7 +394,6 @@ static void hvc_hangup(struct tty_struct { struct hvc_struct *hp = tty->driver_data; unsigned long flags; - int irq = 0; int temp_open_count; if (!hp) @@ -458,13 +415,12 @@ static void hvc_hangup(struct tty_struct hp->count = 0; hp->n_outbuf = 0; hp->tty = NULL; - if (hp->irq_requested) - /* Saved for use outside of spin_lock. */ - irq = hp->irq; - hp->irq_requested = 0; + + if (hp->ops->notifier_del) + hp->ops->notifier_del(hp, hp->data); + spin_unlock_irqrestore(&hp->lock, flags); - if (irq) - free_irq(irq, hp); + while(temp_open_count) { --temp_open_count; kref_put(&hp->kref, destroy_hvc_struct); @@ -575,7 +531,7 @@ static u32 timeout = MIN_TIMEOUT; #define HVC_POLL_READ 0x00000001 #define HVC_POLL_WRITE 0x00000002 -static int hvc_poll(struct hvc_struct *hp) +int hvc_poll(struct hvc_struct *hp) { struct tty_struct *tty; int i, n, poll_mask = 0; @@ -602,10 +558,10 @@ static int hvc_poll(struct hvc_struct *h if (test_bit(TTY_THROTTLED, &tty->flags)) goto throttled; - /* If we aren't interrupt driven and aren't throttled, we always + /* If we aren't notifier driven and aren't throttled, we always * request a reschedule */ - if (hp->irq == 0) + if (!hp->ops->notifier_add) poll_mask |= HVC_POLL_READ; /* Read data if any */ @@ -739,7 +695,7 @@ static const struct tty_operations hvc_o .chars_in_buffer = hvc_chars_in_buffer, }; -struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, +struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data, struct hv_ops *ops, int outbuf_size) { struct hvc_struct *hp; @@ -760,7 +716,7 @@ struct hvc_struct __devinit *hvc_alloc(u memset(hp, 0x00, sizeof(*hp)); hp->vtermno = vtermno; - hp->irq = irq; + hp->data = data; hp->ops = ops; hp->outbuf_size = outbuf_size; hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; Index: kvm/drivers/char/hvc_console.h ==================================================================--- kvm.orig/drivers/char/hvc_console.h +++ kvm/drivers/char/hvc_console.h @@ -42,22 +42,48 @@ */ #define HVC_ALLOC_TTY_ADAPTERS 8 +struct hvc_struct { + spinlock_t lock; + int index; + struct tty_struct *tty; + unsigned int count; + int do_wakeup; + char *outbuf; + int outbuf_size; + int n_outbuf; + uint32_t vtermno; + struct hv_ops *ops; + int data; + struct list_head next; + struct kref kref; /* ref count & hvc_struct lifetime */ +}; /* implemented by a low level driver */ struct hv_ops { int (*get_chars)(uint32_t vtermno, char *buf, int count); int (*put_chars)(uint32_t vtermno, const char *buf, int count); -}; -struct hvc_struct; + /* Callbacks for notification. Called in open and close */ + int (*notifier_add)(struct hvc_struct *hp, int data); + void (*notifier_del)(struct hvc_struct *hp, int data); +}; /* Register a vterm and a slot index for use as a console (console_init) */ extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops); /* register a vterm for hvc tty operation (module_init or hotplug add) */ -extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq, +extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data, struct hv_ops *ops, int outbuf_size); -/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ +/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ extern int __devexit hvc_remove(struct hvc_struct *hp); +/* data available */ +int hvc_poll(struct hvc_struct *hp); +void hvc_kick(void); + +#ifdef CONFIG_HVC_IRQ +/* default notifier for irq based notification */ +extern int notifier_add_irq(struct hvc_struct *hp, int irq); +extern void notifier_del_irq(struct hvc_struct *hp, int irq); +#endif #endif // HVC_CONSOLE_H Index: kvm/drivers/char/hvc_irq.c ==================================================================--- /dev/null +++ kvm/drivers/char/hvc_irq.c @@ -0,0 +1,37 @@ +/* + * Copyright IBM Corp. 2001,2008 + * + * This file contains the IRQ specific code for hvc_console + * + */ + +#include <linux/interrupt.h> + +#include "hvc_console.h" + +static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance) +{ + /* if hvc_poll request a repoll, then kick the hvcd thread */ + if (hvc_poll(dev_instance)) + hvc_kick(); + return IRQ_HANDLED; +} + +/* + * For IRQ based systems these callbacks can be used + */ +int notifier_add_irq(struct hvc_struct *hp, int irq) +{ + if (!irq) + return 0; + return request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, + "hvc_console", hp); +} + +void notifier_del_irq(struct hvc_struct *hp, int irq) +{ + if (!irq) + return; + free_irq(irq, hp); +} + Index: kvm/drivers/char/hvc_iseries.c ==================================================================--- kvm.orig/drivers/char/hvc_iseries.c +++ kvm/drivers/char/hvc_iseries.c @@ -200,6 +200,8 @@ done: static struct hv_ops hvc_get_put_ops = { .get_chars = get_chars, .put_chars = put_chars, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, }; static int __devinit hvc_vio_probe(struct vio_dev *vdev, Index: kvm/drivers/char/hvc_vio.c ==================================================================--- kvm.orig/drivers/char/hvc_vio.c +++ kvm/drivers/char/hvc_vio.c @@ -80,6 +80,8 @@ static int filtered_get_chars(uint32_t v static struct hv_ops hvc_get_put_ops = { .get_chars = filtered_get_chars, .put_chars = hvc_put_chars, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, }; static int __devinit hvc_vio_probe(struct vio_dev *vdev, Index: kvm/drivers/char/hvc_xen.c ==================================================================--- kvm.orig/drivers/char/hvc_xen.c +++ kvm/drivers/char/hvc_xen.c @@ -95,6 +95,8 @@ static int read_console(uint32_t vtermno static struct hv_ops hvc_ops = { .get_chars = read_console, .put_chars = write_console, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, }; static int __init xen_init(void)
Christian Borntraeger
2008-Jun-03 12:46 UTC
[RFC 2/3] virtio_console: use virtqueue notification for hvc_console
This patch exploits the new notifier callbacks of the hvc_console. We can use the virtio callbacks instead of the polling code. I also added a small Kconfig change that allows the user to specify the virtio console in menuconfig. Signed-off-by: Christian Borntraeger <borntraeger at de.ibm.com> --- drivers/char/Kconfig | 6 +++++- drivers/char/virtio_console.c | 27 +++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) Index: kvm/drivers/char/Kconfig ==================================================================--- kvm.orig/drivers/char/Kconfig +++ kvm/drivers/char/Kconfig @@ -637,8 +637,12 @@ config HVC_XEN Xen virtual console device driver config VIRTIO_CONSOLE - bool + bool "Virtio console" + depends on VIRTIO select HVC_DRIVER + help + Virtio console for use with lguest and other hypervisors. + config HVCS tristate "IBM Hypervisor Virtual Console Server support" Index: kvm/drivers/char/virtio_console.c ==================================================================--- kvm.orig/drivers/char/virtio_console.c +++ kvm/drivers/char/virtio_console.c @@ -46,6 +46,9 @@ static char *in, *inbuf; /* The operations for our console. */ static struct hv_ops virtio_cons; +/* The hvc device */ +struct hvc_struct *hvc; + /*D:310 The put_chars() callback is pretty straightforward. * * We turn the characters into a scatter-gather list, add it to the output @@ -134,6 +137,25 @@ int __init virtio_cons_early_init(int (* return hvc_instantiate(0, 0, &virtio_cons); } +/* + * we support only one console, the hvc struct is a global var + * There is no need to do anything + */ +static int notifier_add_vio(struct hvc_struct *hp, int data) +{ + return 0; +} + +static void notifier_del_vio(struct hvc_struct *hp, int data) +{ +} + +static void hvc_handle_input(struct virtqueue *vq) +{ + if (hvc_poll(hvc)) + hvc_kick(); +} + /*D:370 Once we're further in boot, we get probed like any other virtio device. * At this stage we set up the output virtqueue. * @@ -144,7 +166,6 @@ int __init virtio_cons_early_init(int (* static int __devinit virtcons_probe(struct virtio_device *dev) { int err; - struct hvc_struct *hvc; vdev = dev; @@ -158,7 +179,7 @@ static int __devinit virtcons_probe(stru /* Find the input queue. */ /* FIXME: This is why we want to wean off hvc: we do nothing * when input comes in. */ - in_vq = vdev->config->find_vq(vdev, 0, NULL); + in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input); if (IS_ERR(in_vq)) { err = PTR_ERR(in_vq); goto free; @@ -173,6 +194,8 @@ static int __devinit virtcons_probe(stru /* Start using the new console output. */ virtio_cons.get_chars = get_chars; virtio_cons.put_chars = put_chars; + virtio_cons.notifier_add = notifier_add_vio; + virtio_cons.notifier_del = notifier_del_vio; /* The first argument of hvc_alloc() is the virtual console number, so * we use zero. The second argument is the interrupt number; we
Christian Borntraeger
2008-Jun-03 12:46 UTC
[RFC 3/3] s390: use virtio_console for KVM on s390
This patch enables virtio_console as the default console on kvm for s390. We currently use the same notify hack as lguest for early console output. I will try to address this for lguest and s390 later. Signed-off-by: Christian Borntraeger <borntraeger at de.ibm.com> --- arch/s390/Kconfig | 1 + arch/s390/kernel/setup.c | 4 +++- drivers/s390/kvm/kvm_virtio.c | 20 ++++++++++++++++++++ include/asm-s390/kvm_virtio.h | 10 ++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) Index: kvm/arch/s390/Kconfig ==================================================================--- kvm.orig/arch/s390/Kconfig +++ kvm/arch/s390/Kconfig @@ -540,6 +540,7 @@ bool "s390 guest support (EXPERIMENTAL)" depends on 64BIT && EXPERIMENTAL select VIRTIO select VIRTIO_RING + select VIRTIO_CONSOLE help Select this option if you want to run the kernel under s390 linux endmenu Index: kvm/arch/s390/kernel/setup.c ==================================================================--- kvm.orig/arch/s390/kernel/setup.c +++ kvm/arch/s390/kernel/setup.c @@ -54,6 +54,7 @@ #include <asm/sections.h> #include <asm/ebcdic.h> #include <asm/compat.h> +#include <asm/kvm_virtio.h> long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | PSW_MASK_MCHECK | PSW_DEFAULT_KEY); @@ -799,7 +800,8 @@ setup_arch(char **cmdline_p) printk("We are running under VM (64 bit mode)\n"); else if (MACHINE_IS_KVM) { printk("We are running under KVM (64 bit mode)\n"); - add_preferred_console("ttyS", 1, NULL); + add_preferred_console("hvc", 0, NULL); + s390_virtio_console_init(); } else printk("We are running native (64 bit mode)\n"); #endif /* CONFIG_64BIT */ Index: kvm/drivers/s390/kvm/kvm_virtio.c ==================================================================--- kvm.orig/drivers/s390/kvm/kvm_virtio.c +++ kvm/drivers/s390/kvm/kvm_virtio.c @@ -15,6 +15,7 @@ #include <linux/err.h> #include <linux/virtio.h> #include <linux/virtio_config.h> +#include <linux/virtio_console.h> #include <linux/interrupt.h> #include <linux/virtio_ring.h> #include <linux/pfn.h> @@ -338,6 +339,25 @@ static int __init kvm_devices_init(void) return 0; } +/* code for early console output with virtio_console */ +static __init int early_put_chars(u32 vtermno, const char *buf, int count) +{ + char scratch[17]; + unsigned int len = count; + + if (len > sizeof(scratch) - 1) + len = sizeof(scratch) - 1; + scratch[len] = '\0'; + memcpy(scratch, buf, len); + kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, __pa(scratch)); + return len; +} + +void s390_virtio_console_init(void) +{ + virtio_cons_early_init(early_put_chars); +} + /* * We do this after core stuff, but before the drivers. */ Index: kvm/include/asm-s390/kvm_virtio.h ==================================================================--- kvm.orig/include/asm-s390/kvm_virtio.h +++ kvm/include/asm-s390/kvm_virtio.h @@ -50,4 +50,14 @@ struct kvm_vqconfig { #define KVM_S390_VIRTIO_RESET 1 #define KVM_S390_VIRTIO_SET_STATUS 2 +#ifdef __KERNEL__ +/* early virtio console setup */ +#ifdef CONFIG_VIRTIO_CONSOLE +extern void s390_virtio_console_init(void); +#else +static inline void s390_virtio_console_init(void) +{ +} +#endif /* CONFIG_VIRTIO_CONSOLE */ +#endif /* __KERNEL__ */ #endif
Christian Borntraeger
2008-Jun-03 12:49 UTC
[RFC 1/3] hvc_console: rework setup to replace irq functions with callbacks (not word wrapped)
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. 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 "irq" with the opaque name "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. Feedback is appreciated. Signed-off-by: Christian Borntraeger <borntraeger at de.ibm.com> CC: Rusty Russell <rusty at rustcorp.com.au> CC: Jeremy Fitzhardinge <jeremy at goop.org> CC: LKML <linux-kernel at vger.kernel.org> CC: Virtualization Mailing List <virtualization at lists.osdl.org> CC: Linux PPC devel <linuxppc-dev at ozlabs.org> --- drivers/char/Kconfig | 8 ++++ drivers/char/Makefile | 1 drivers/char/hvc_console.c | 80 ++++++++++----------------------------------- drivers/char/hvc_console.h | 34 ++++++++++++++++--- drivers/char/hvc_irq.c | 37 ++++++++++++++++++++ drivers/char/hvc_iseries.c | 2 + drivers/char/hvc_vio.c | 2 + drivers/char/hvc_xen.c | 2 + 8 files changed, 100 insertions(+), 66 deletions(-) Index: kvm/drivers/char/Kconfig ==================================================================--- kvm.orig/drivers/char/Kconfig +++ kvm/drivers/char/Kconfig @@ -588,11 +588,17 @@ config HVC_DRIVER It will automatically be selected if one of the back-end console drivers is selected. +config HVC_IRQ + bool + help + Infrastructure for using the IRQ code for HVC console. + It will automatically be selected by the drivers that need it. config HVC_CONSOLE bool "pSeries Hypervisor Virtual Console support" depends on PPC_PSERIES select HVC_DRIVER + select HVC_IRQ help pSeries machines when partitioned support a hypervisor virtual console. This driver allows each pSeries partition to have a console @@ -603,6 +609,7 @@ config HVC_ISERIES depends on PPC_ISERIES default y select HVC_DRIVER + select HVC_IRQ help iSeries machines support a hypervisor virtual console. @@ -624,6 +631,7 @@ config HVC_XEN bool "Xen Hypervisor Console support" depends on XEN select HVC_DRIVER + select HVC_IRQ default y help Xen virtual console device driver Index: kvm/drivers/char/Makefile ==================================================================--- kvm.orig/drivers/char/Makefile +++ kvm/drivers/char/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_HVC_ISERIES) += hvc_iseries obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o +obj-$(CONFIG_HVC_IRQ) += hvc_irq.o obj-$(CONFIG_HVC_XEN) += hvc_xen.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o Index: kvm/drivers/char/hvc_console.c ==================================================================--- kvm.orig/drivers/char/hvc_console.c +++ kvm/drivers/char/hvc_console.c @@ -75,23 +75,6 @@ static int hvc_init(void); static int sysrq_pressed; #endif -struct hvc_struct { - spinlock_t lock; - int index; - struct tty_struct *tty; - unsigned int count; - int do_wakeup; - char *outbuf; - int outbuf_size; - int n_outbuf; - uint32_t vtermno; - struct hv_ops *ops; - int irq_requested; - int irq; - struct list_head next; - struct kref kref; /* ref count & hvc_struct lifetime */ -}; - /* dynamic list of hvc_struct instances */ static LIST_HEAD(hvc_structs); @@ -300,26 +283,12 @@ int hvc_instantiate(uint32_t vtermno, in } /* Wake the sleeping khvcd */ -static void hvc_kick(void) +void hvc_kick(void) { hvc_kicked = 1; wake_up_process(hvc_task); } -static int hvc_poll(struct hvc_struct *hp); - -/* - * NOTE: This API isn't used if the console adapter doesn't support interrupts. - * In this case the console is poll driven. - */ -static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance) -{ - /* if hvc_poll request a repoll, then kick the hvcd thread */ - if (hvc_poll(dev_instance)) - hvc_kick(); - return IRQ_HANDLED; -} - static void hvc_unthrottle(struct tty_struct *tty) { hvc_kick(); @@ -333,7 +302,6 @@ static int hvc_open(struct tty_struct *t { struct hvc_struct *hp; unsigned long flags; - int irq = 0; int rc = 0; /* Auto increments kref reference if found. */ @@ -352,18 +320,15 @@ static int hvc_open(struct tty_struct *t tty->low_latency = 1; /* Makes flushes to ldisc synchronous. */ hp->tty = tty; - /* Save for request_irq outside of spin_lock. */ - irq = hp->irq; - if (irq) - hp->irq_requested = 1; + + if (hp->ops->notifier_add) + rc = hp->ops->notifier_add(hp, hp->data); spin_unlock_irqrestore(&hp->lock, flags); - /* check error, fallback to non-irq */ - if (irq) - rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp); + /* - * If the request_irq() fails and we return an error. The tty layer + * If the notifier fails we return an error. The tty layer * will call hvc_close() after a failed open but we don't want to clean * up there so we'll clean up here and clear out the previously set * tty fields and return the kref reference. @@ -371,7 +336,6 @@ static int hvc_open(struct tty_struct *t if (rc) { spin_lock_irqsave(&hp->lock, flags); hp->tty = NULL; - hp->irq_requested = 0; spin_unlock_irqrestore(&hp->lock, flags); tty->driver_data = NULL; kref_put(&hp->kref, destroy_hvc_struct); @@ -386,7 +350,6 @@ static int hvc_open(struct tty_struct *t static void hvc_close(struct tty_struct *tty, struct file * filp) { struct hvc_struct *hp; - int irq = 0; unsigned long flags; if (tty_hung_up_p(filp)) @@ -404,9 +367,8 @@ static void hvc_close(struct tty_struct spin_lock_irqsave(&hp->lock, flags); if (--hp->count == 0) { - if (hp->irq_requested) - irq = hp->irq; - hp->irq_requested = 0; + if (hp->ops->notifier_del) + hp->ops->notifier_del(hp, hp->data); /* We are done with the tty pointer now. */ hp->tty = NULL; @@ -418,10 +380,6 @@ static void hvc_close(struct tty_struct * waking periodically to check chars_in_buffer(). */ tty_wait_until_sent(tty, HVC_CLOSE_WAIT); - - if (irq) - free_irq(irq, hp); - } else { if (hp->count < 0) printk(KERN_ERR "hvc_close %X: oops, count is %d\n", @@ -436,7 +394,6 @@ static void hvc_hangup(struct tty_struct { struct hvc_struct *hp = tty->driver_data; unsigned long flags; - int irq = 0; int temp_open_count; if (!hp) @@ -458,13 +415,12 @@ static void hvc_hangup(struct tty_struct hp->count = 0; hp->n_outbuf = 0; hp->tty = NULL; - if (hp->irq_requested) - /* Saved for use outside of spin_lock. */ - irq = hp->irq; - hp->irq_requested = 0; + + if (hp->ops->notifier_del) + hp->ops->notifier_del(hp, hp->data); + spin_unlock_irqrestore(&hp->lock, flags); - if (irq) - free_irq(irq, hp); + while(temp_open_count) { --temp_open_count; kref_put(&hp->kref, destroy_hvc_struct); @@ -575,7 +531,7 @@ static u32 timeout = MIN_TIMEOUT; #define HVC_POLL_READ 0x00000001 #define HVC_POLL_WRITE 0x00000002 -static int hvc_poll(struct hvc_struct *hp) +int hvc_poll(struct hvc_struct *hp) { struct tty_struct *tty; int i, n, poll_mask = 0; @@ -602,10 +558,10 @@ static int hvc_poll(struct hvc_struct *h if (test_bit(TTY_THROTTLED, &tty->flags)) goto throttled; - /* If we aren't interrupt driven and aren't throttled, we always + /* If we aren't notifier driven and aren't throttled, we always * request a reschedule */ - if (hp->irq == 0) + if (!hp->ops->notifier_add) poll_mask |= HVC_POLL_READ; /* Read data if any */ @@ -739,7 +695,7 @@ static const struct tty_operations hvc_o .chars_in_buffer = hvc_chars_in_buffer, }; -struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, +struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data, struct hv_ops *ops, int outbuf_size) { struct hvc_struct *hp; @@ -760,7 +716,7 @@ struct hvc_struct __devinit *hvc_alloc(u memset(hp, 0x00, sizeof(*hp)); hp->vtermno = vtermno; - hp->irq = irq; + hp->data = data; hp->ops = ops; hp->outbuf_size = outbuf_size; hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; Index: kvm/drivers/char/hvc_console.h ==================================================================--- kvm.orig/drivers/char/hvc_console.h +++ kvm/drivers/char/hvc_console.h @@ -42,22 +42,48 @@ */ #define HVC_ALLOC_TTY_ADAPTERS 8 +struct hvc_struct { + spinlock_t lock; + int index; + struct tty_struct *tty; + unsigned int count; + int do_wakeup; + char *outbuf; + int outbuf_size; + int n_outbuf; + uint32_t vtermno; + struct hv_ops *ops; + int data; + struct list_head next; + struct kref kref; /* ref count & hvc_struct lifetime */ +}; /* implemented by a low level driver */ struct hv_ops { int (*get_chars)(uint32_t vtermno, char *buf, int count); int (*put_chars)(uint32_t vtermno, const char *buf, int count); -}; -struct hvc_struct; + /* Callbacks for notification. Called in open and close */ + int (*notifier_add)(struct hvc_struct *hp, int data); + void (*notifier_del)(struct hvc_struct *hp, int data); +}; /* Register a vterm and a slot index for use as a console (console_init) */ extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops); /* register a vterm for hvc tty operation (module_init or hotplug add) */ -extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq, +extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data, struct hv_ops *ops, int outbuf_size); -/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ +/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ extern int __devexit hvc_remove(struct hvc_struct *hp); +/* data available */ +int hvc_poll(struct hvc_struct *hp); +void hvc_kick(void); + +#ifdef CONFIG_HVC_IRQ +/* default notifier for irq based notification */ +extern int notifier_add_irq(struct hvc_struct *hp, int irq); +extern void notifier_del_irq(struct hvc_struct *hp, int irq); +#endif #endif // HVC_CONSOLE_H Index: kvm/drivers/char/hvc_irq.c ==================================================================--- /dev/null +++ kvm/drivers/char/hvc_irq.c @@ -0,0 +1,37 @@ +/* + * Copyright IBM Corp. 2001,2008 + * + * This file contains the IRQ specific code for hvc_console + * + */ + +#include <linux/interrupt.h> + +#include "hvc_console.h" + +static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance) +{ + /* if hvc_poll request a repoll, then kick the hvcd thread */ + if (hvc_poll(dev_instance)) + hvc_kick(); + return IRQ_HANDLED; +} + +/* + * For IRQ based systems these callbacks can be used + */ +int notifier_add_irq(struct hvc_struct *hp, int irq) +{ + if (!irq) + return 0; + return request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, + "hvc_console", hp); +} + +void notifier_del_irq(struct hvc_struct *hp, int irq) +{ + if (!irq) + return; + free_irq(irq, hp); +} + Index: kvm/drivers/char/hvc_iseries.c ==================================================================--- kvm.orig/drivers/char/hvc_iseries.c +++ kvm/drivers/char/hvc_iseries.c @@ -200,6 +200,8 @@ done: static struct hv_ops hvc_get_put_ops = { .get_chars = get_chars, .put_chars = put_chars, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, }; static int __devinit hvc_vio_probe(struct vio_dev *vdev, Index: kvm/drivers/char/hvc_vio.c ==================================================================--- kvm.orig/drivers/char/hvc_vio.c +++ kvm/drivers/char/hvc_vio.c @@ -80,6 +80,8 @@ static int filtered_get_chars(uint32_t v static struct hv_ops hvc_get_put_ops = { .get_chars = filtered_get_chars, .put_chars = hvc_put_chars, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, }; static int __devinit hvc_vio_probe(struct vio_dev *vdev, Index: kvm/drivers/char/hvc_xen.c ==================================================================--- kvm.orig/drivers/char/hvc_xen.c +++ kvm/drivers/char/hvc_xen.c @@ -95,6 +95,8 @@ static int read_console(uint32_t vtermno static struct hv_ops hvc_ops = { .get_chars = read_console, .put_chars = write_console, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, }; static int __init xen_init(void)
Arnd Bergmann
2008-Jun-03 17:24 UTC
[RFC 2/3] virtio_console: use virtqueue notification for hvc_console
On Tuesday 03 June 2008, Christian Borntraeger wrote:> > +/* The hvc device */ > +struct hvc_struct *hvc; > +I guess this should be static, a three letter identifier for a global variable is not really unique. Arnd <><
Rusty Russell
2008-Jun-04 00:13 UTC
[RFC 1/3] hvc_console: rework setup to replace irq functions with callbacks
On Tuesday 03 June 2008 22:45:22 Christian Borntraeger wrote:> 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.Two questions. Is it possible to make the timer backoff a third kind of notifier? And is it possible to make the dependency static, rather than dynamic, or does someone need two options at runtime? Thanks, Rusty.
Christian Borntraeger
2008-Jun-04 11:15 UTC
[RFC 1/3] hvc_console: rework setup to replace irq functions with callbacks
Am Mittwoch, 4. Juni 2008 schrieb Rusty Russell:> Two questions. Is it possible to make the timer backoff a third kind of > notifier?I can try. The timer handling code is sprinkled a bit in hvc_console but it should be possible.> And is it possible to make the dependency static, rather than > dynamic, or does someone need two options at runtime?Not sure. Some drivers pass get the irq number from another component. If the number is 0, the console is poll driven, otherwise irq driven.
Christian Borntraeger
2008-Jun-20 13:24 UTC
[RFC 1/3 v2] 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 at de.ibm.com> --- drivers/char/Kconfig | 5 ++ drivers/char/Makefile | 1 drivers/char/hvc_console.c | 80 ++++++++++----------------------------------- drivers/char/hvc_console.h | 34 ++++++++++++++++--- drivers/char/hvc_irq.c | 45 +++++++++++++++++++++++++ drivers/char/hvc_iseries.c | 2 + drivers/char/hvc_vio.c | 2 + drivers/char/hvc_xen.c | 2 + 8 files changed, 105 insertions(+), 66 deletions(-) Index: kvm/drivers/char/Kconfig ==================================================================--- kvm.orig/drivers/char/Kconfig +++ kvm/drivers/char/Kconfig @@ -588,11 +588,14 @@ config HVC_DRIVER It will automatically be selected if one of the back-end console drivers is selected. +config HVC_IRQ + bool config HVC_CONSOLE bool "pSeries Hypervisor Virtual Console support" depends on PPC_PSERIES select HVC_DRIVER + select HVC_IRQ help pSeries machines when partitioned support a hypervisor virtual console. This driver allows each pSeries partition to have a console @@ -603,6 +606,7 @@ config HVC_ISERIES depends on PPC_ISERIES default y select HVC_DRIVER + select HVC_IRQ help iSeries machines support a hypervisor virtual console. @@ -624,6 +628,7 @@ config HVC_XEN bool "Xen Hypervisor Console support" depends on XEN select HVC_DRIVER + select HVC_IRQ default y help Xen virtual console device driver Index: kvm/drivers/char/Makefile ==================================================================--- kvm.orig/drivers/char/Makefile +++ kvm/drivers/char/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_HVC_ISERIES) += hvc_iseries obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o +obj-$(CONFIG_HVC_IRQ) += hvc_irq.o obj-$(CONFIG_HVC_XEN) += hvc_xen.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o Index: kvm/drivers/char/hvc_console.c ==================================================================--- kvm.orig/drivers/char/hvc_console.c +++ kvm/drivers/char/hvc_console.c @@ -75,23 +75,6 @@ static int hvc_init(void); static int sysrq_pressed; #endif -struct hvc_struct { - spinlock_t lock; - int index; - struct tty_struct *tty; - unsigned int count; - int do_wakeup; - char *outbuf; - int outbuf_size; - int n_outbuf; - uint32_t vtermno; - struct hv_ops *ops; - int irq_requested; - int irq; - struct list_head next; - struct kref kref; /* ref count & hvc_struct lifetime */ -}; - /* dynamic list of hvc_struct instances */ static LIST_HEAD(hvc_structs); @@ -300,26 +283,12 @@ int hvc_instantiate(uint32_t vtermno, in } /* Wake the sleeping khvcd */ -static void hvc_kick(void) +void hvc_kick(void) { hvc_kicked = 1; wake_up_process(hvc_task); } -static int hvc_poll(struct hvc_struct *hp); - -/* - * NOTE: This API isn't used if the console adapter doesn't support interrupts. - * In this case the console is poll driven. - */ -static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance) -{ - /* if hvc_poll request a repoll, then kick the hvcd thread */ - if (hvc_poll(dev_instance)) - hvc_kick(); - return IRQ_HANDLED; -} - static void hvc_unthrottle(struct tty_struct *tty) { hvc_kick(); @@ -333,7 +302,6 @@ static int hvc_open(struct tty_struct *t { struct hvc_struct *hp; unsigned long flags; - int irq = 0; int rc = 0; /* Auto increments kref reference if found. */ @@ -352,18 +320,15 @@ static int hvc_open(struct tty_struct *t tty->low_latency = 1; /* Makes flushes to ldisc synchronous. */ hp->tty = tty; - /* Save for request_irq outside of spin_lock. */ - irq = hp->irq; - if (irq) - hp->irq_requested = 1; + + if (hp->ops->notifier_add) + rc = hp->ops->notifier_add(hp, hp->data); spin_unlock_irqrestore(&hp->lock, flags); - /* check error, fallback to non-irq */ - if (irq) - rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp); + /* - * If the request_irq() fails and we return an error. The tty layer + * If the notifier fails we return an error. The tty layer * will call hvc_close() after a failed open but we don't want to clean * up there so we'll clean up here and clear out the previously set * tty fields and return the kref reference. @@ -371,7 +336,6 @@ static int hvc_open(struct tty_struct *t if (rc) { spin_lock_irqsave(&hp->lock, flags); hp->tty = NULL; - hp->irq_requested = 0; spin_unlock_irqrestore(&hp->lock, flags); tty->driver_data = NULL; kref_put(&hp->kref, destroy_hvc_struct); @@ -386,7 +350,6 @@ static int hvc_open(struct tty_struct *t static void hvc_close(struct tty_struct *tty, struct file * filp) { struct hvc_struct *hp; - int irq = 0; unsigned long flags; if (tty_hung_up_p(filp)) @@ -404,9 +367,8 @@ static void hvc_close(struct tty_struct spin_lock_irqsave(&hp->lock, flags); if (--hp->count == 0) { - if (hp->irq_requested) - irq = hp->irq; - hp->irq_requested = 0; + if (hp->ops->notifier_del) + hp->ops->notifier_del(hp, hp->data); /* We are done with the tty pointer now. */ hp->tty = NULL; @@ -418,10 +380,6 @@ static void hvc_close(struct tty_struct * waking periodically to check chars_in_buffer(). */ tty_wait_until_sent(tty, HVC_CLOSE_WAIT); - - if (irq) - free_irq(irq, hp); - } else { if (hp->count < 0) printk(KERN_ERR "hvc_close %X: oops, count is %d\n", @@ -436,7 +394,6 @@ static void hvc_hangup(struct tty_struct { struct hvc_struct *hp = tty->driver_data; unsigned long flags; - int irq = 0; int temp_open_count; if (!hp) @@ -458,13 +415,12 @@ static void hvc_hangup(struct tty_struct hp->count = 0; hp->n_outbuf = 0; hp->tty = NULL; - if (hp->irq_requested) - /* Saved for use outside of spin_lock. */ - irq = hp->irq; - hp->irq_requested = 0; + + if (hp->ops->notifier_del) + hp->ops->notifier_del(hp, hp->data); + spin_unlock_irqrestore(&hp->lock, flags); - if (irq) - free_irq(irq, hp); + while(temp_open_count) { --temp_open_count; kref_put(&hp->kref, destroy_hvc_struct); @@ -575,7 +531,7 @@ static u32 timeout = MIN_TIMEOUT; #define HVC_POLL_READ 0x00000001 #define HVC_POLL_WRITE 0x00000002 -static int hvc_poll(struct hvc_struct *hp) +int hvc_poll(struct hvc_struct *hp) { struct tty_struct *tty; int i, n, poll_mask = 0; @@ -602,10 +558,10 @@ static int hvc_poll(struct hvc_struct *h if (test_bit(TTY_THROTTLED, &tty->flags)) goto throttled; - /* If we aren't interrupt driven and aren't throttled, we always + /* If we aren't notifier driven and aren't throttled, we always * request a reschedule */ - if (hp->irq == 0) + if (!hp->irq_requested) poll_mask |= HVC_POLL_READ; /* Read data if any */ @@ -739,7 +695,7 @@ static const struct tty_operations hvc_o .chars_in_buffer = hvc_chars_in_buffer, }; -struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, +struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data, struct hv_ops *ops, int outbuf_size) { struct hvc_struct *hp; @@ -760,7 +716,7 @@ struct hvc_struct __devinit *hvc_alloc(u memset(hp, 0x00, sizeof(*hp)); hp->vtermno = vtermno; - hp->irq = irq; + hp->data = data; hp->ops = ops; hp->outbuf_size = outbuf_size; hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; Index: kvm/drivers/char/hvc_console.h ==================================================================--- kvm.orig/drivers/char/hvc_console.h +++ kvm/drivers/char/hvc_console.h @@ -42,22 +42,48 @@ */ #define HVC_ALLOC_TTY_ADAPTERS 8 +struct hvc_struct { + spinlock_t lock; + int index; + struct tty_struct *tty; + unsigned int count; + int do_wakeup; + char *outbuf; + int outbuf_size; + int n_outbuf; + uint32_t vtermno; + struct hv_ops *ops; + int irq_requested; + int data; + struct list_head next; + struct kref kref; /* ref count & hvc_struct lifetime */ +}; /* implemented by a low level driver */ struct hv_ops { int (*get_chars)(uint32_t vtermno, char *buf, int count); int (*put_chars)(uint32_t vtermno, const char *buf, int count); -}; -struct hvc_struct; + /* Callbacks for notification. Called in open and close */ + int (*notifier_add)(struct hvc_struct *hp, int irq); + void (*notifier_del)(struct hvc_struct *hp, int irq); +}; /* Register a vterm and a slot index for use as a console (console_init) */ extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops); /* register a vterm for hvc tty operation (module_init or hotplug add) */ -extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq, +extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data, struct hv_ops *ops, int outbuf_size); -/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ +/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ extern int __devexit hvc_remove(struct hvc_struct *hp); +/* data available */ +int hvc_poll(struct hvc_struct *hp); +void hvc_kick(void); + +/* default notifier for irq based notification */ +extern int notifier_add_irq(struct hvc_struct *hp, int data); +extern void notifier_del_irq(struct hvc_struct *hp, int data); + #endif // HVC_CONSOLE_H Index: kvm/drivers/char/hvc_irq.c ==================================================================--- /dev/null +++ kvm/drivers/char/hvc_irq.c @@ -0,0 +1,45 @@ +/* + * Copyright IBM Corp. 2001,2008 + * + * This file contains the IRQ specific code for hvc_console + * + */ + +#include <linux/interrupt.h> + +#include "hvc_console.h" + +static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance) +{ + /* if hvc_poll request a repoll, then kick the hvcd thread */ + if (hvc_poll(dev_instance)) + hvc_kick(); + return IRQ_HANDLED; +} + +/* + * For IRQ based systems these callbacks can be used + */ +int notifier_add_irq(struct hvc_struct *hp, int irq) +{ + int rc; + + if (!irq) { + hp->irq_requested = 0; + return 0; + } + rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, + "hvc_console", hp); + if (!rc) + hp->irq_requested = 1; + return rc; +} + +void notifier_del_irq(struct hvc_struct *hp, int irq) +{ + if (!irq) + return; + free_irq(irq, hp); + hp->irq_requested = 0; +} + Index: kvm/drivers/char/hvc_iseries.c ==================================================================--- kvm.orig/drivers/char/hvc_iseries.c +++ kvm/drivers/char/hvc_iseries.c @@ -200,6 +200,8 @@ done: static struct hv_ops hvc_get_put_ops = { .get_chars = get_chars, .put_chars = put_chars, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, }; static int __devinit hvc_vio_probe(struct vio_dev *vdev, Index: kvm/drivers/char/hvc_vio.c ==================================================================--- kvm.orig/drivers/char/hvc_vio.c +++ kvm/drivers/char/hvc_vio.c @@ -80,6 +80,8 @@ static int filtered_get_chars(uint32_t v static struct hv_ops hvc_get_put_ops = { .get_chars = filtered_get_chars, .put_chars = hvc_put_chars, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, }; static int __devinit hvc_vio_probe(struct vio_dev *vdev, Index: kvm/drivers/char/hvc_xen.c ==================================================================--- kvm.orig/drivers/char/hvc_xen.c +++ kvm/drivers/char/hvc_xen.c @@ -95,6 +95,8 @@ static int read_console(uint32_t vtermno static struct hv_ops hvc_ops = { .get_chars = read_console, .put_chars = write_console, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, }; static int __init xen_init(void)
Christian Borntraeger
2008-Jun-20 13:24 UTC
[RFC 2/3 v2] virtio_console: use virtqueue notification for hvc_console
This patch exploits the new notifier callbacks of the hvc_console. We can use the virtio callbacks instead of the polling code. I also added a small Kconfig change that allows the user to specify the virtio console in menuconfig. Signed-off-by: Christian Borntraeger <borntraeger at de.ibm.com> --- drivers/char/Kconfig | 6 +++++- drivers/char/virtio_console.c | 40 +++++++++++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 8 deletions(-) Index: kvm/drivers/char/Kconfig ==================================================================--- kvm.orig/drivers/char/Kconfig +++ kvm/drivers/char/Kconfig @@ -634,8 +634,12 @@ config HVC_XEN Xen virtual console device driver config VIRTIO_CONSOLE - bool + bool "Virtio console" + depends on VIRTIO select HVC_DRIVER + help + Virtio console for use with lguest and other hypervisors. + config HVCS tristate "IBM Hypervisor Virtual Console Server support" Index: kvm/drivers/char/virtio_console.c ==================================================================--- kvm.orig/drivers/char/virtio_console.c +++ kvm/drivers/char/virtio_console.c @@ -46,6 +46,9 @@ static char *in, *inbuf; /* The operations for our console. */ static struct hv_ops virtio_cons; +/* The hvc device */ +static struct hvc_struct *hvc; + /*D:310 The put_chars() callback is pretty straightforward. * * We turn the characters into a scatter-gather list, add it to the output @@ -134,6 +137,27 @@ int __init virtio_cons_early_init(int (* return hvc_instantiate(0, 0, &virtio_cons); } +/* + * we support only one console, the hvc struct is a global var + * There is no need to do anything + */ +static int notifier_add_vio(struct hvc_struct *hp, int data) +{ + hp->irq_requested = 1; + return 0; +} + +static void notifier_del_vio(struct hvc_struct *hp, int data) +{ + hp->irq_requested = 0; +} + +static void hvc_handle_input(struct virtqueue *vq) +{ + if (hvc_poll(hvc)) + hvc_kick(); +} + /*D:370 Once we're further in boot, we get probed like any other virtio device. * At this stage we set up the output virtqueue. * @@ -144,7 +168,6 @@ int __init virtio_cons_early_init(int (* static int __devinit virtcons_probe(struct virtio_device *dev) { int err; - struct hvc_struct *hvc; vdev = dev; @@ -158,7 +181,7 @@ static int __devinit virtcons_probe(stru /* Find the input queue. */ /* FIXME: This is why we want to wean off hvc: we do nothing * when input comes in. */ - in_vq = vdev->config->find_vq(vdev, 0, NULL); + in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input); if (IS_ERR(in_vq)) { err = PTR_ERR(in_vq); goto free; @@ -173,15 +196,18 @@ static int __devinit virtcons_probe(stru /* Start using the new console output. */ virtio_cons.get_chars = get_chars; virtio_cons.put_chars = put_chars; + virtio_cons.notifier_add = notifier_add_vio; + virtio_cons.notifier_del = notifier_del_vio; /* The first argument of hvc_alloc() is the virtual console number, so - * we use zero. The second argument is the interrupt number; we - * currently leave this as zero: it would be better not to use the - * hvc mechanism and fix this (FIXME!). + * we use zero. The second argument is the parameter for the + * notification mechanism (like irq number). We currently leave this + * as zero, virtqueues have implicit notifications. * * The third argument is a "struct hv_ops" containing the put_chars() - * and get_chars() pointers. The final argument is the output buffer - * size: we can do any size, so we put PAGE_SIZE here. */ + * get_chars(), notifier_add() and notifier_del() pointers. + * The final argument is the output buffer size: we can do any size, + * so we put PAGE_SIZE here. */ hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE); if (IS_ERR(hvc)) { err = PTR_ERR(hvc);
Christian Borntraeger
2008-Jun-20 13:24 UTC
[RFC 3/3 v2] s390: use virtio_console for KVM on s390
This patch enables virtio_console as the default console on kvm for s390. We currently use the same notify hack as lguest for early console output. I will try to address this for lguest and s390 later. Signed-off-by: Christian Borntraeger <borntraeger at de.ibm.com> --- arch/s390/Kconfig | 1 + arch/s390/kernel/setup.c | 4 +++- drivers/s390/kvm/kvm_virtio.c | 20 ++++++++++++++++++++ include/asm-s390/kvm_virtio.h | 10 ++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) Index: kvm/arch/s390/Kconfig ==================================================================--- kvm.orig/arch/s390/Kconfig +++ kvm/arch/s390/Kconfig @@ -544,6 +544,7 @@ bool "s390 guest support (EXPERIMENTAL)" depends on 64BIT && EXPERIMENTAL select VIRTIO select VIRTIO_RING + select VIRTIO_CONSOLE help Select this option if you want to run the kernel under s390 linux endmenu Index: kvm/arch/s390/kernel/setup.c ==================================================================--- kvm.orig/arch/s390/kernel/setup.c +++ kvm/arch/s390/kernel/setup.c @@ -54,6 +54,7 @@ #include <asm/sections.h> #include <asm/ebcdic.h> #include <asm/compat.h> +#include <asm/kvm_virtio.h> long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | PSW_MASK_MCHECK | PSW_DEFAULT_KEY); @@ -799,7 +800,8 @@ setup_arch(char **cmdline_p) printk("We are running under VM (64 bit mode)\n"); else if (MACHINE_IS_KVM) { printk("We are running under KVM (64 bit mode)\n"); - add_preferred_console("ttyS", 1, NULL); + add_preferred_console("hvc", 0, NULL); + s390_virtio_console_init(); } else printk("We are running native (64 bit mode)\n"); #endif /* CONFIG_64BIT */ Index: kvm/drivers/s390/kvm/kvm_virtio.c ==================================================================--- kvm.orig/drivers/s390/kvm/kvm_virtio.c +++ kvm/drivers/s390/kvm/kvm_virtio.c @@ -15,6 +15,7 @@ #include <linux/err.h> #include <linux/virtio.h> #include <linux/virtio_config.h> +#include <linux/virtio_console.h> #include <linux/interrupt.h> #include <linux/virtio_ring.h> #include <linux/pfn.h> @@ -333,6 +334,25 @@ static int __init kvm_devices_init(void) return 0; } +/* code for early console output with virtio_console */ +static __init int early_put_chars(u32 vtermno, const char *buf, int count) +{ + char scratch[17]; + unsigned int len = count; + + if (len > sizeof(scratch) - 1) + len = sizeof(scratch) - 1; + scratch[len] = '\0'; + memcpy(scratch, buf, len); + kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, __pa(scratch)); + return len; +} + +void s390_virtio_console_init(void) +{ + virtio_cons_early_init(early_put_chars); +} + /* * We do this after core stuff, but before the drivers. */ Index: kvm/include/asm-s390/kvm_virtio.h ==================================================================--- kvm.orig/include/asm-s390/kvm_virtio.h +++ kvm/include/asm-s390/kvm_virtio.h @@ -50,4 +50,14 @@ struct kvm_vqconfig { #define KVM_S390_VIRTIO_RESET 1 #define KVM_S390_VIRTIO_SET_STATUS 2 +#ifdef __KERNEL__ +/* early virtio console setup */ +#ifdef CONFIG_VIRTIO_CONSOLE +extern void s390_virtio_console_init(void); +#else +static inline void s390_virtio_console_init(void) +{ +} +#endif /* CONFIG_VIRTIO_CONSOLE */ +#endif /* __KERNEL__ */ #endif
On Friday 20 June 2008 23:24:18 Christian Borntraeger wrote:> This patch enables virtio_console as the default console on kvm for > s390. We currently use the same notify hack as lguest for early > console output. I will try to address this for lguest and s390 later. > > Signed-off-by: Christian Borntraeger <borntraeger at de.ibm.com>Thanks, applied all three. Cheers, Rusty.
Rusty Russell
2008-Jun-27 05:27 UTC
[RFC 1/3 v2] hvc_console: rework setup to replace irq functions with callbacks
On Friday 20 June 2008 23:24:08 Christian Borntraeger wrote:> I also kept hvc_struct defined in hvc_console.h so that hvc_irq.c can > access the irq_requested element.Added this fix: Fix compile of hvc_rtas.c Moving the struct definition out to the header had bad effect under one ppc64 config that I tried: drivers/char/hvc_console.h:59: error: field ?kref? has incomplete type So move the include of kref.h too. Signed-off-by: Rusty Russell <rusty at rustcorp.com.au> diff -r f382d8f562a8 drivers/char/hvc_console.c --- a/drivers/char/hvc_console.c Fri Jun 27 15:17:49 2008 +1000 +++ b/drivers/char/hvc_console.c Fri Jun 27 15:24:15 2008 +1000 @@ -27,7 +27,6 @@ #include <linux/init.h> #include <linux/kbd_kern.h> #include <linux/kernel.h> -#include <linux/kref.h> #include <linux/kthread.h> #include <linux/list.h> #include <linux/module.h> diff -r f382d8f562a8 drivers/char/hvc_console.h --- a/drivers/char/hvc_console.h Fri Jun 27 15:17:49 2008 +1000 +++ b/drivers/char/hvc_console.h Fri Jun 27 15:24:15 2008 +1000 @@ -26,6 +26,7 @@ #ifndef HVC_CONSOLE_H #define HVC_CONSOLE_H +#include <linux/kref.h> /* * This is the max number of console adapters that can/will be found as
Possibly Parallel Threads
- [RFC 0/3]: hvc_console rework for platform without hard irqs
- [PATCH 00/31] virtio: console: Fixes, multiple devices and generic ports
- [PATCH 00/31] virtio: console: Fixes, multiple devices and generic ports
- virtio_console: support for multiple ports, console and generic.
- Multiple port support for virtio-console