[PATCH 01/10] virtio: console: Add a __send_control_msg() that can send messages without a valid port
We will introduce control messages that operate on the device as a whole rather than just ports. Make send_control_msg() a wrapper around __send_control_msg() which does not need a valid port. Signed-off-by: Amit Shah amit.s...@redhat.com --- drivers/char/virtio_console.c | 16 +++- 1 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8f665bc..5d24015 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -373,22 +373,22 @@ out: return ret; } -static ssize_t send_control_msg(struct port *port, unsigned int event, - unsigned int value) +static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, + unsigned int event, unsigned int value) { struct scatterlist sg[1]; struct virtio_console_control cpkt; struct virtqueue *vq; unsigned int len; - if (!use_multiport(port-portdev)) + if (!use_multiport(portdev)) return 0; - cpkt.id = port-id; + cpkt.id = port_id; cpkt.event = event; cpkt.value = value; - vq = port-portdev-c_ovq; + vq = portdev-c_ovq; sg_init_one(sg, cpkt, sizeof(cpkt)); if (vq-vq_ops-add_buf(vq, sg, 1, 0, cpkt) = 0) { @@ -399,6 +399,12 @@ static ssize_t send_control_msg(struct port *port, unsigned int event, return 0; } +static ssize_t send_control_msg(struct port *port, unsigned int event, + unsigned int value) +{ + return __send_control_msg(port-portdev, port-id, event, value); +} + static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count) { struct scatterlist sg[1]; -- 1.6.2.5 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/virtualization
[PATCH 05/10] virtio: console: Remove config work handler
We're going to switch to using control messages for port hot-plug and initial port discovery. Remove the config work handler which handled port hot-plug so far. Signed-off-by: Amit Shah amit.s...@redhat.com --- drivers/char/virtio_console.c | 64 + 1 files changed, 1 insertions(+), 63 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index b40b112..0473221 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -109,7 +109,6 @@ struct ports_device { * notification */ struct work_struct control_work; - struct work_struct config_work; struct list_head ports; @@ -1091,10 +1090,7 @@ static void config_intr(struct virtio_device *vdev) struct ports_device *portdev; portdev = vdev-priv; - if (use_multiport(portdev)) { - /* Handle port hot-add */ - schedule_work(portdev-config_work); - } + /* * We'll use this way of resizing only for legacy support. * For newer userspace (VIRTIO_CONSOLE_F_MULTPORT+), use @@ -1237,62 +1233,6 @@ fail: return err; } -/* - * The workhandler for config-space updates. - * - * This is called when ports are hot-added. - */ -static void config_work_handler(struct work_struct *work) -{ - struct virtio_console_config virtconconf; - struct ports_device *portdev; - struct virtio_device *vdev; - int err; - - portdev = container_of(work, struct ports_device, config_work); - - vdev = portdev-vdev; - vdev-config-get(vdev, - offsetof(struct virtio_console_config, nr_ports), - virtconconf.nr_ports, - sizeof(virtconconf.nr_ports)); - - if (portdev-config.nr_ports == virtconconf.nr_ports) { - /* -* Port 0 got hot-added. Since we already did all the -* other initialisation for it, just tell the Host -* that the port is ready if we find the port. In -* case the port was hot-removed earlier, we call -* add_port to add the port. -*/ - struct port *port; - - port = find_port_by_id(portdev, 0); - if (!port) - add_port(portdev, 0); - else - send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); - return; - } - if (virtconconf.nr_ports portdev-config.max_nr_ports) { - dev_warn(vdev-dev, -More ports specified (%u) than allowed (%u), -portdev-config.nr_ports + 1, -portdev-config.max_nr_ports); - return; - } - if (virtconconf.nr_ports portdev-config.nr_ports) - return; - - /* Hot-add ports */ - while (virtconconf.nr_ports - portdev-config.nr_ports) { - err = add_port(portdev, portdev-config.nr_ports); - if (err) - break; - portdev-config.nr_ports++; - } -} - static int init_vqs(struct ports_device *portdev) { vq_callback_t **io_callbacks; @@ -1485,7 +1425,6 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) spin_lock_init(portdev-cvq_lock); INIT_WORK(portdev-control_work, control_work_handler); - INIT_WORK(portdev-config_work, config_work_handler); nr_added_bufs = fill_queue(portdev-c_ivq, portdev-cvq_lock); if (!nr_added_bufs) { @@ -1528,7 +1467,6 @@ static void virtcons_remove(struct virtio_device *vdev) portdev = vdev-priv; cancel_work_sync(portdev-control_work); - cancel_work_sync(portdev-config_work); list_for_each_entry_safe(port, port2, portdev-ports, list) remove_port(port); -- 1.6.2.5 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/virtualization
[PATCH 04/10] virtio: console: Don't call hvc_remove() on unplugging console ports
hvc_remove() has some bug which freezes other active hvc ports when one port is removed. So disable calling of hvc_remove() which deregisters a port with the hvc_console. If the hvc_console code calls into our get_chars() routine as a result of a poll operation, we will return -EPIPE and the hvc_console code will then do the necessary cleanup. This call will be restored when the bug in hvc_remove() is found and fixed. Signed-off-by: Amit Shah amit.s...@redhat.com --- drivers/char/virtio_console.c | 11 +++ 1 files changed, 11 insertions(+), 0 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 733276d..b40b112 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -876,7 +876,18 @@ static int remove_port(struct port *port) spin_lock_irq(pdrvdata_lock); list_del(port-cons.list); spin_unlock_irq(pdrvdata_lock); +#if 0 + /* +* hvc_remove() not called as removing one hvc port +* results in other hvc ports getting frozen. +* +* Once this is resolved in hvc, this functionality +* will be enabled. Till that is done, the -EPIPE +* return from get_chars() above will help +* hvc_console.c to clean up on ports we remove here. +*/ hvc_remove(port-cons.hvc); +#endif } if (port-guest_connected) send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); -- 1.6.2.5 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/virtualization
[PATCH 10/10] virtio: console: Add support for nonblocking write()s
If the host port is not open, a write() should either just return if the file is opened in non-blocking mode, or block till the host port is opened. Also, don't spin till host consumes data for nonblocking ports. For non-blocking ports, we can do away with the spinning and reclaim the buffers consumed by the host on the next write call or on the condition that'll make poll return. Signed-off-by: Amit Shah amit.s...@redhat.com --- drivers/char/virtio_console.c | 82 +++-- 1 files changed, 78 insertions(+), 4 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 680ea25..d70efda 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -183,6 +183,8 @@ struct port { /* The 'id' to identify the port with the Host */ u32 id; + bool outvq_full; + /* Is the host device open */ bool host_connected; @@ -404,7 +406,19 @@ static ssize_t send_control_msg(struct port *port, unsigned int event, return __send_control_msg(port-portdev, port-id, event, value); } -static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count) +static void reclaim_consumed_buffers(struct port *port) +{ + void *buf; + unsigned int len; + + while ((buf = port-out_vq-vq_ops-get_buf(port-out_vq, len))) { + kfree(buf); + port-outvq_full = false; + } +} + +static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count, + bool nonblock) { struct scatterlist sg[1]; struct virtqueue *out_vq; @@ -413,6 +427,8 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count) out_vq = port-out_vq; + reclaim_consumed_buffers(port); + sg_init_one(sg, in_buf, in_count); ret = out_vq-vq_ops-add_buf(out_vq, sg, 1, 0, in_buf); @@ -424,6 +440,12 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count) goto fail; } + if (ret == 0) + port-outvq_full = true; + + if (nonblock) + return in_count; + /* * Wait till the host acknowledges it pushed out the data we * sent. This is done for ports in blocking mode or for data @@ -491,6 +513,20 @@ static bool will_read_block(struct port *port) return !port_has_data(port) port-host_connected; } +static bool will_write_block(struct port *port) +{ + if (!port-host_connected) + return true; + + /* +* Check if the Host has consumed any buffers since we last +* sent data (this is only applicable for nonblocking ports). +*/ + reclaim_consumed_buffers(port); + + return port-outvq_full; +} + static ssize_t port_fops_read(struct file *filp, char __user *ubuf, size_t count, loff_t *offp) { @@ -537,9 +573,22 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, struct port *port; char *buf; ssize_t ret; + bool nonblock; port = filp-private_data; + nonblock = filp-f_flags O_NONBLOCK; + + if (will_write_block(port)) { + if (nonblock) + return -EAGAIN; + + ret = wait_event_interruptible(port-waitqueue, + !will_write_block(port)); + if (ret 0) + return ret; + } + count = min((size_t)(32 * 1024), count); buf = kmalloc(count, GFP_KERNEL); @@ -552,9 +601,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf, goto free_buf; } - ret = send_buf(port, buf, count); + ret = send_buf(port, buf, count, nonblock); + + if (nonblock ret 0) + goto out; + free_buf: kfree(buf); +out: return ret; } @@ -569,7 +623,7 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait) ret = 0; if (port-inbuf) ret |= POLLIN | POLLRDNORM; - if (port-host_connected) + if (!will_write_block(port)) ret |= POLLOUT; if (!port-host_connected) ret |= POLLHUP; @@ -592,6 +646,7 @@ static int port_fops_release(struct inode *inode, struct file *filp) discard_port_data(port); spin_unlock_irq(port-inbuf_lock); + reclaim_consumed_buffers(port); return 0; } @@ -621,6 +676,13 @@ static int port_fops_open(struct inode *inode, struct file *filp) port-guest_connected = true; spin_unlock_irq(port-inbuf_lock); + /* +* There might be a chance that we missed reclaiming a few +* buffers in the window of the port getting previously closed +* and opening now. +*/ + reclaim_consumed_buffers(port); + /* Notify host of port
[PATCH 09/10] virtio: console: Rename wait_is_over() to will_read_block()
We'll introduce a function that checks if write will block. Have function names that are similar for the two cases. Signed-off-by: Amit Shah amit.s...@redhat.com --- drivers/char/virtio_console.c |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 3d70729..680ea25 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -486,9 +486,9 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count, } /* The condition that must be true for polling to end */ -static bool wait_is_over(struct port *port) +static bool will_read_block(struct port *port) { - return port_has_data(port) || !port-host_connected; + return !port_has_data(port) port-host_connected; } static ssize_t port_fops_read(struct file *filp, char __user *ubuf, @@ -511,7 +511,7 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf, return -EAGAIN; ret = wait_event_interruptible(port-waitqueue, - wait_is_over(port)); + !will_read_block(port)); if (ret 0) return ret; } -- 1.6.2.5 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/virtualization
[PATCH 07/10] virtio: console: Use a control message to add ports
Instead of the host and guest independently enumerating ports, switch to a control message to add ports where the host supplies the port number so there's no ambiguity or a possibility of a race between the host and the guest port numbers. We now no longer need the 'nr_ports' config value. Since no kernel has been released with the MULTIPORT changes yet, we have a chance to fiddle with the config space without adding compatibility features. This is beneficial for management software, which would now be able to instantiate ports at known locations and avoid problems that arise with implicit numbering in the host and the guest. This removes the 'guessing game' part of it, and management software can now actually indicate which id to spawn a particular port on. Signed-off-by: Amit Shah amit.s...@redhat.com --- drivers/char/virtio_console.c | 78 +-- include/linux/virtio_console.h | 17 - 2 files changed, 42 insertions(+), 53 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index fd98861..7b2dcdd 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1053,7 +1053,7 @@ static void handle_control_message(struct ports_device *portdev, cpkt = (struct virtio_console_control *)(buf-buf + buf-offset); port = find_port_by_id(portdev, cpkt-id); - if (!port) { + if (!port cpkt-event != VIRTIO_CONSOLE_PORT_ADD) { /* No valid header at start of buffer. Drop it. */ dev_dbg(portdev-vdev-dev, Invalid index %u in control packet\n, cpkt-id); @@ -1061,6 +1061,30 @@ static void handle_control_message(struct ports_device *portdev, } switch (cpkt-event) { + case VIRTIO_CONSOLE_PORT_ADD: + if (port) { + /* +* This can happen for port 0: we have to +* create a console port during probe() as was +* the behaviour before the MULTIPORT feature. +* On a newer host, when the host tells us +* that a port 0 is available, we should just +* say we have the port all set up. +*/ + send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); + break; + } + if (cpkt-id = portdev-config.max_nr_ports) { + dev_warn(portdev-vdev-dev, + Request for adding port with out-of-bound id %u, max. supported id: %u\n, + cpkt-id, portdev-config.max_nr_ports - 1); + break; + } + add_port(portdev, cpkt-id); + break; + case VIRTIO_CONSOLE_PORT_REMOVE: + remove_port(port); + break; case VIRTIO_CONSOLE_CONSOLE_PORT: if (!cpkt-value) break; @@ -1119,32 +1143,6 @@ static void handle_control_message(struct ports_device *portdev, kobject_uevent(port-dev-kobj, KOBJ_CHANGE); } break; - case VIRTIO_CONSOLE_PORT_REMOVE: - /* -* Hot unplug the port. We don't decrement nr_ports -* since we don't want to deal with extra complexities -* of using the lowest-available port id: We can just -* pick up the nr_ports number as the id and not have -* userspace send it to us. This helps us in two -* ways: -* -* - We don't need to have a 'port_id' field in the -* config space when a port is hot-added. This is a -* good thing as we might queue up multiple hotplug -* requests issued in our workqueue. -* -* - Another way to deal with this would have been to -* use a bitmap of the active ports and select the -* lowest non-active port from that map. That -* bloats the already tight config space and we -* would end up artificially limiting the -* max. number of ports to sizeof(bitmap). Right -* now we can support 2^32 ports (as the port id is -* stored in a u32 type). -* -*/ - remove_port(port); - break; } } @@ -1352,7 +1350,6 @@ static const struct file_operations portdev_fops = { static int __devinit virtcons_probe(struct virtio_device *vdev) { struct ports_device *portdev; - u32 i; int err; bool multiport; @@ -1381,29 +1378,15 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) } multiport = false; -
[PATCH 08/10] virtio: console: Don't always create a port 0 if using multiport
If we're using multiport, there's no point in always creating a console port. Create the console port only if the host doesn't support multiport. Signed-off-by: Amit Shah amit.s...@redhat.com --- drivers/char/virtio_console.c | 33 +++-- 1 files changed, 15 insertions(+), 18 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 7b2dcdd..3d70729 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -791,6 +791,13 @@ int init_port_console(struct port *port) spin_unlock_irq(pdrvdata_lock); port-guest_connected = true; + /* +* Start using the new console output if this is the first +* console to come up. +*/ + if (early_put_chars) + early_put_chars = NULL; + /* Notify host of port being opened */ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); @@ -1063,14 +1070,8 @@ static void handle_control_message(struct ports_device *portdev, switch (cpkt-event) { case VIRTIO_CONSOLE_PORT_ADD: if (port) { - /* -* This can happen for port 0: we have to -* create a console port during probe() as was -* the behaviour before the MULTIPORT feature. -* On a newer host, when the host tells us -* that a port 0 is available, we should just -* say we have the port all set up. -*/ + dev_dbg(portdev-vdev-dev, + Port %u already added\n, port-id); send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); break; } @@ -1414,18 +1415,14 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) err = -ENOMEM; goto free_vqs; } - + } else { + /* +* If we're running on an older host, we always want +* to create a console port. +*/ + add_port(portdev, 0); } - /* -* For backward compatibility: if we're running on an older -* host, we always want to create a console port. -*/ - add_port(portdev, 0); - - /* Start using the new console output. */ - early_put_chars = NULL; - __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, VIRTIO_CONSOLE_DEVICE_READY, 1); return 0; -- 1.6.2.5 ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/virtualization
A clocksource driver for HyperV
I am attaching a clocksource driver for HyperV. Signed-off-by: K. Y. Srinivasan ksriniva...@novell.com From: K. Y. Srinivasan ksriniva...@novell.com Subject: A clocksource for Linux guests hosted on HyperV. References: None Patch-mainline: This patch is a clocksource implementation suitable for guests hosted on HyperV. Time keeping in Linux guests hosted on HyperV is unstable. This clocksource driver fixes the problem. Signed-off-by: K. Y. Srinivasan ksriniva...@novell.com Index: linux/drivers/staging/hv/hv_timesource.c === --- /dev/null 1970-01-01 00:00:00.0 + +++ linux/drivers/staging/hv/hv_timesource.c2010-04-05 13:33:36.0 -0600 @@ -0,0 +1,148 @@ +/* + * A clocksource for Linux running on HyperV. + * + * + * Copyright (C) 2010, Novell, Inc. + * Author : K. Y. Srinivasan ksriniva...@novell.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include linux/version.h +#include linux/clocksource.h +#include linux/init.h +#include linux/module.h +#include linux/pci.h +#include linux/dmi.h + +#define HV_CLOCK_SHIFT 22 +/* + * HyperV defined synthetic CPUID leaves: + */ +#define HV_CPUID_SIGNATURE 0x4000 +#define HV_CPUID_MIN 0x4005 +#define HV_HYPERVISOR_PRESENT_BIT 0x8000 +#define HV_CPUID_FEATURES 0x4003 +#define HV_CPUID_RECOMMENDATIONS 0x4004 + +/* + * HyperV defined synthetic MSRs + */ + +#define HV_X64_MSR_TIME_REF_COUNT 0x4020 + + +static cycle_t read_hv_clock(struct clocksource *arg) +{ + cycle_t current_tick; + /* +* Read the partition counter to get the current tick count. This count +* is set to 0 when the partition is created and is incremented in +* 100 nanosecond units. +*/ + rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); + return current_tick; +} + +static struct clocksource clocksource_hyperv = { + .name = hyperv_clocksource, + .rating = 400, /* use this when running on Hyperv*/ + .read = read_hv_clock, + .mask = CLOCKSOURCE_MASK(64), + .shift = HV_CLOCK_SHIFT, +}; + +static struct dmi_system_id __initconst +hv_timesource_dmi_table[] __maybe_unused = { + { + .ident = Hyper-V, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, Microsoft Corporation), + DMI_MATCH(DMI_PRODUCT_NAME, Virtual Machine), + DMI_MATCH(DMI_BOARD_NAME, Virtual Machine), + }, + }, + { }, +}; +MODULE_DEVICE_TABLE(dmi, hv_timesource_dmi_table); + +static struct pci_device_id __initconst +hv_timesource_pci_table[] __maybe_unused = { + { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */ + { 0 } +}; +MODULE_DEVICE_TABLE(pci, hv_timesource_pci_table); + + +static int __init hv_detect_hyperv(void) +{ + u32 eax, ebx, ecx, edx; + static char hyp_signature[20]; + + cpuid(1, eax, ebx, ecx, edx); + if (!(ecx HV_HYPERVISOR_PRESENT_BIT)) { + printk(KERN_WARNING + Not on a Hypervisor\n); + return 1; + } + cpuid(HV_CPUID_SIGNATURE, eax, ebx, ecx, edx); + *(u32 *)(hyp_signature + 0) = ebx; + *(u32 *)(hyp_signature + 4) = ecx; + *(u32 *)(hyp_signature + 8) = edx; + hyp_signature[12] = 0; + + if ((eax HV_CPUID_MIN) || (strcmp(Microsoft Hv, hyp_signature))) { + printk(KERN_WARNING + Not on HyperV; signature %s, eax %x\n, + hyp_signature, eax); + return 1; + } + /* +* Extract the features, recommendations etc. +*/ + cpuid(HV_CPUID_FEATURES, eax, ebx, ecx, edx); + if (!(eax 0x10)) { + printk(KERN_WARNING HyperV Time Ref Counter not available!\n); + return 1; + } + + cpuid(HV_CPUID_RECOMMENDATIONS, eax, ebx, ecx, edx); + printk(KERN_INFO HyperV recommendations: %x\n, eax); + printk(KERN_INFO HyperV spin count: %x\n, ebx); + return 0; +} + + +static int __init init_hv_clocksource(void) +{ + if
A clocksource driver for HyperV
I am attaching a clocksource driver for HyperV. Signed-off-by: K. Y. Srinivasan ksriniva...@novell.com From: K. Y. Srinivasan ksriniva...@novell.com Subject: A clocksource for Linux guests hosted on HyperV. References: None Patch-mainline: This patch is a clocksource implementation suitable for guests hosted on HyperV. Time keeping in Linux guests hosted on HyperV is unstable. This clocksource driver fixes the problem. Signed-off-by: K. Y. Srinivasan ksriniva...@novell.com Index: linux/drivers/staging/hv/hv_timesource.c === --- /dev/null 1970-01-01 00:00:00.0 + +++ linux/drivers/staging/hv/hv_timesource.c2010-04-05 13:33:36.0 -0600 @@ -0,0 +1,148 @@ +/* + * A clocksource for Linux running on HyperV. + * + * + * Copyright (C) 2010, Novell, Inc. + * Author : K. Y. Srinivasan ksriniva...@novell.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include linux/version.h +#include linux/clocksource.h +#include linux/init.h +#include linux/module.h +#include linux/pci.h +#include linux/dmi.h + +#define HV_CLOCK_SHIFT 22 +/* + * HyperV defined synthetic CPUID leaves: + */ +#define HV_CPUID_SIGNATURE 0x4000 +#define HV_CPUID_MIN 0x4005 +#define HV_HYPERVISOR_PRESENT_BIT 0x8000 +#define HV_CPUID_FEATURES 0x4003 +#define HV_CPUID_RECOMMENDATIONS 0x4004 + +/* + * HyperV defined synthetic MSRs + */ + +#define HV_X64_MSR_TIME_REF_COUNT 0x4020 + + +static cycle_t read_hv_clock(struct clocksource *arg) +{ + cycle_t current_tick; + /* +* Read the partition counter to get the current tick count. This count +* is set to 0 when the partition is created and is incremented in +* 100 nanosecond units. +*/ + rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); + return current_tick; +} + +static struct clocksource clocksource_hyperv = { + .name = hyperv_clocksource, + .rating = 400, /* use this when running on Hyperv*/ + .read = read_hv_clock, + .mask = CLOCKSOURCE_MASK(64), + .shift = HV_CLOCK_SHIFT, +}; + +static struct dmi_system_id __initconst +hv_timesource_dmi_table[] __maybe_unused = { + { + .ident = Hyper-V, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, Microsoft Corporation), + DMI_MATCH(DMI_PRODUCT_NAME, Virtual Machine), + DMI_MATCH(DMI_BOARD_NAME, Virtual Machine), + }, + }, + { }, +}; +MODULE_DEVICE_TABLE(dmi, hv_timesource_dmi_table); + +static struct pci_device_id __initconst +hv_timesource_pci_table[] __maybe_unused = { + { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */ + { 0 } +}; +MODULE_DEVICE_TABLE(pci, hv_timesource_pci_table); + + +static int __init hv_detect_hyperv(void) +{ + u32 eax, ebx, ecx, edx; + static char hyp_signature[20]; + + cpuid(1, eax, ebx, ecx, edx); + if (!(ecx HV_HYPERVISOR_PRESENT_BIT)) { + printk(KERN_WARNING + Not on a Hypervisor\n); + return 1; + } + cpuid(HV_CPUID_SIGNATURE, eax, ebx, ecx, edx); + *(u32 *)(hyp_signature + 0) = ebx; + *(u32 *)(hyp_signature + 4) = ecx; + *(u32 *)(hyp_signature + 8) = edx; + hyp_signature[12] = 0; + + if ((eax HV_CPUID_MIN) || (strcmp(Microsoft Hv, hyp_signature))) { + printk(KERN_WARNING + Not on HyperV; signature %s, eax %x\n, + hyp_signature, eax); + return 1; + } + /* +* Extract the features, recommendations etc. +*/ + cpuid(HV_CPUID_FEATURES, eax, ebx, ecx, edx); + if (!(eax 0x10)) { + printk(KERN_WARNING HyperV Time Ref Counter not available!\n); + return 1; + } + + cpuid(HV_CPUID_RECOMMENDATIONS, eax, ebx, ecx, edx); + printk(KERN_INFO HyperV recommendations: %x\n, eax); + printk(KERN_INFO HyperV spin count: %x\n, ebx); + return 0; +} + + +static int __init init_hv_clocksource(void) +{ + if
Re: A clocksource driver for HyperV
On 04/05/2010 01:30 PM, Ky Srinivasan wrote: +static cycle_t read_hv_clock(struct clocksource *arg) +{ + cycle_t current_tick; + /* + * Read the partition counter to get the current tick count. This count + * is set to 0 when the partition is created and is incremented in + * 100 nanosecond units. + */ + rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick); + return current_tick; +} + +static struct clocksource clocksource_hyperv = { + .name = hyperv_clocksource, Seems like a redundantly long name; any use of this string is going to be in a context where it is obviously a clocksource. How about just hyperv? + .rating = 400, /* use this when running on Hyperv*/ + .read = read_hv_clock, + .mask = CLOCKSOURCE_MASK(64), + .shift = HV_CLOCK_SHIFT, +}; + +static struct dmi_system_id __initconst +hv_timesource_dmi_table[] __maybe_unused = { + { + .ident = Hyper-V, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, Microsoft Corporation), + DMI_MATCH(DMI_PRODUCT_NAME, Virtual Machine), + DMI_MATCH(DMI_BOARD_NAME, Virtual Machine), + }, + }, + { }, +}; +MODULE_DEVICE_TABLE(dmi, hv_timesource_dmi_table); So you use the DMI signatures to determine whether the module is needed, but cpuid to work out if the feature is present? + +static struct pci_device_id __initconst +hv_timesource_pci_table[] __maybe_unused = { + { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */ + { 0 } +}; +MODULE_DEVICE_TABLE(pci, hv_timesource_pci_table); And/or PCI? Seems a bit... ad-hoc? Is this the official way to determine the presence of Hyper-V? + + +static int __init hv_detect_hyperv(void) This looks generally useful. Should it be hidden away in the clocksource driver, or in some common hyper-v code? Do other hyper-v drivers have versions of this? +{ + u32 eax, ebx, ecx, edx; + static char hyp_signature[20]; 20? static? + + cpuid(1,eax,ebx,ecx,edx); + if (!(ecx HV_HYPERVISOR_PRESENT_BIT)) { + printk(KERN_WARNING + Not on a Hypervisor\n); This just looks like noise, especially since it doesn't identify what is generating the message. And if you compile this code in as =y (non-modular) then it will complain every boot. + return 1; + } + cpuid(HV_CPUID_SIGNATURE,eax,ebx,ecx,edx); + *(u32 *)(hyp_signature + 0) = ebx; + *(u32 *)(hyp_signature + 4) = ecx; + *(u32 *)(hyp_signature + 8) = edx; + hyp_signature[12] = 0; + + if ((eax HV_CPUID_MIN) || (strcmp(Microsoft Hv, hyp_signature))) { memcmp, surely? + printk(KERN_WARNING + Not on HyperV; signature %s, eax %x\n, + hyp_signature, eax); + return 1; + } + /* + * Extract the features, recommendations etc. + */ + cpuid(HV_CPUID_FEATURES,eax,ebx,ecx,edx); + if (!(eax 0x10)) { + printk(KERN_WARNING HyperV Time Ref Counter not available!\n); + return 1; + } + + cpuid(HV_CPUID_RECOMMENDATIONS,eax,ebx,ecx,edx); + printk(KERN_INFO HyperV recommendations: %x\n, eax); + printk(KERN_INFO HyperV spin count: %x\n, ebx); + return 0; +} + + +static int __init init_hv_clocksource(void) +{ + if (hv_detect_hyperv()) + return -ENODEV; + /* + * The time ref counter in HyperV is in 100ns units. + * The definition of mult is: + * mult/2^shift = ns/cyc = 100 + * mult = (100 shift) + */ + clocksource_hyperv.mult = (100 HV_CLOCK_SHIFT); Why not initialize this in the structure? It's just 10022 isn't it? + printk(KERN_INFO Registering HyperV clock source\n); + return clocksource_register(clocksource_hyperv); +} + +module_init(init_hv_clocksource); +MODULE_DESCRIPTION(HyperV based clocksource); +MODULE_AUTHOR(K. Y. Srinivasanksriniva...@novell.com); +MODULE_LICENSE(GPL); Index: linux/drivers/staging/hv/Makefile === --- linux.orig/drivers/staging/hv/Makefile2010-04-05 13:02:06.0 -0600 +++ linux/drivers/staging/hv/Makefile 2010-04-05 13:02:13.0 -0600 @@ -1,4 +1,4 @@ -obj-$(CONFIG_HYPERV) += hv_vmbus.o +obj-$(CONFIG_HYPERV) += hv_vmbus.o hv_timesource.o obj-$(CONFIG_HYPERV_STORAGE)+= hv_storvsc.o obj-$(CONFIG_HYPERV_BLOCK) += hv_blkvsc.o obj-$(CONFIG_HYPERV_NET)+= hv_netvsc.o ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/virtualization
Re: [PATCH 07/10] virtio: console: Use a control message to add ports
On Mon, 5 Apr 2010 11:24:11 pm Amit Shah wrote: @@ -1431,13 +1414,20 @@ static int __devinit virtcons_probe(struct virtio_device *vdev) err = -ENOMEM; goto free_vqs; } + } Minor nit: gratuitous whitespace addition. Cheers, Rusty. ___ Virtualization mailing list Virtualization@lists.linux-foundation.org https://lists.linux-foundation.org/mailman/listinfo/virtualization