Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1 | /* |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 2 | * Copyright (c) 2009, Microsoft Corporation. |
| 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify it |
| 5 | * under the terms and conditions of the GNU General Public License, |
| 6 | * version 2, as published by the Free Software Foundation. |
| 7 | * |
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT |
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 11 | * more details. |
| 12 | * |
| 13 | * You should have received a copy of the GNU General Public License along with |
| 14 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
| 15 | * Place - Suite 330, Boston, MA 02111-1307 USA. |
| 16 | * |
| 17 | * Authors: |
| 18 | * Haiyang Zhang <haiyangz@microsoft.com> |
| 19 | * Hank Janssen <hjanssen@microsoft.com> |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 20 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 21 | #include <linux/init.h> |
| 22 | #include <linux/module.h> |
| 23 | #include <linux/device.h> |
| 24 | #include <linux/irq.h> |
| 25 | #include <linux/interrupt.h> |
| 26 | #include <linux/sysctl.h> |
Greg Kroah-Hartman | 9a775db | 2010-02-25 16:42:10 -0800 | [diff] [blame] | 27 | #include <linux/pci.h> |
Greg Kroah-Hartman | c22090f | 2010-02-25 16:43:15 -0800 | [diff] [blame] | 28 | #include <linux/dmi.h> |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 29 | #include <linux/slab.h> |
Haiyang Zhang | 8b5d6d3 | 2010-05-28 23:22:44 +0000 | [diff] [blame] | 30 | #include <linux/completion.h> |
Greg Kroah-Hartman | 2d82f6c | 2010-05-05 22:52:28 -0700 | [diff] [blame] | 31 | #include "version_info.h" |
K. Y. Srinivasan | e3fe0bb | 2011-02-11 10:00:12 -0800 | [diff] [blame] | 32 | #include "hv_api.h" |
Greg Kroah-Hartman | 645954c | 2009-08-28 16:22:59 -0700 | [diff] [blame] | 33 | #include "logging.h" |
Greg Kroah-Hartman | 870cde8 | 2009-08-19 16:21:28 -0700 | [diff] [blame] | 34 | #include "vmbus.h" |
Greg Kroah-Hartman | 150b19d | 2010-10-20 16:07:11 -0700 | [diff] [blame] | 35 | #include "channel.h" |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 36 | #include "vmbus_private.h" |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 37 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 38 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 39 | /* FIXME! We need to do this dynamically for PIC and APIC system */ |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 40 | #define VMBUS_IRQ 0x5 |
| 41 | #define VMBUS_IRQ_VECTOR IRQ5_VECTOR |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 42 | |
| 43 | /* Main vmbus driver data structure */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 44 | struct vmbus_driver_context { |
Greg Kroah-Hartman | a69a669 | 2010-12-02 09:42:18 -0800 | [diff] [blame] | 45 | struct hv_driver drv_obj; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 46 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 47 | struct bus_type bus; |
| 48 | struct tasklet_struct msg_dpc; |
| 49 | struct tasklet_struct event_dpc; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 50 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 51 | /* The bus root device */ |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 52 | struct vm_device device_ctx; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 53 | }; |
| 54 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 55 | static int vmbus_match(struct device *device, struct device_driver *driver); |
| 56 | static int vmbus_probe(struct device *device); |
| 57 | static int vmbus_remove(struct device *device); |
| 58 | static void vmbus_shutdown(struct device *device); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 59 | static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 60 | static void vmbus_msg_dpc(unsigned long data); |
| 61 | static void vmbus_event_dpc(unsigned long data); |
| 62 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 63 | static irqreturn_t vmbus_isr(int irq, void *dev_id); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 64 | |
| 65 | static void vmbus_device_release(struct device *device); |
| 66 | static void vmbus_bus_release(struct device *device); |
| 67 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 68 | static ssize_t vmbus_show_device_attr(struct device *dev, |
| 69 | struct device_attribute *dev_attr, |
| 70 | char *buf); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 71 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 72 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 73 | unsigned int vmbus_loglevel = (ALL_MODULES << 16 | INFO_LVL); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 74 | EXPORT_SYMBOL(vmbus_loglevel); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 75 | /* (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT); */ |
| 76 | /* (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT); */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 77 | |
| 78 | static int vmbus_irq = VMBUS_IRQ; |
| 79 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 80 | /* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 81 | static struct device_attribute vmbus_device_attrs[] = { |
| 82 | __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL), |
| 83 | __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL), |
| 84 | __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL), |
| 85 | __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL), |
| 86 | __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL), |
| 87 | |
| 88 | __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), |
| 89 | __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), |
| 90 | __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), |
| 91 | |
| 92 | __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL), |
| 93 | __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL), |
| 94 | __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL), |
| 95 | |
| 96 | __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), |
| 97 | __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL), |
| 98 | __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL), |
| 99 | __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), |
| 100 | __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), |
| 101 | |
| 102 | __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL), |
| 103 | __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL), |
| 104 | __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL), |
| 105 | __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), |
| 106 | __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL), |
| 107 | __ATTR_NULL |
| 108 | }; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 109 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 110 | /* The one and only one */ |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 111 | static struct vmbus_driver_context vmbus_drv = { |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 112 | .bus.name = "vmbus", |
| 113 | .bus.match = vmbus_match, |
| 114 | .bus.shutdown = vmbus_shutdown, |
| 115 | .bus.remove = vmbus_remove, |
| 116 | .bus.probe = vmbus_probe, |
| 117 | .bus.uevent = vmbus_uevent, |
| 118 | .bus.dev_attrs = vmbus_device_attrs, |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 119 | }; |
| 120 | |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 121 | static const char *driver_name = "hyperv"; |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 122 | |
| 123 | /* |
| 124 | * Windows vmbus does not defined this. |
| 125 | * We defined this to be consistent with other devices |
| 126 | */ |
| 127 | /* {c5295816-f63a-4d5f-8d1a-4daf999ca185} */ |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 128 | static const struct hv_guid device_type = { |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 129 | .data = { |
| 130 | 0x16, 0x58, 0x29, 0xc5, 0x3a, 0xf6, 0x5f, 0x4d, |
| 131 | 0x8d, 0x1a, 0x4d, 0xaf, 0x99, 0x9c, 0xa1, 0x85 |
| 132 | } |
| 133 | }; |
| 134 | |
| 135 | /* {ac3760fc-9adf-40aa-9427-a70ed6de95c5} */ |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 136 | static const struct hv_guid device_id = { |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 137 | .data = { |
| 138 | 0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40, |
| 139 | 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5 |
| 140 | } |
| 141 | }; |
| 142 | |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 143 | static struct hv_device *vmbus_device; /* vmbus root device */ |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 144 | |
| 145 | /* |
Haiyang Zhang | 646f1ea | 2011-01-26 12:12:10 -0800 | [diff] [blame] | 146 | * vmbus_child_dev_add - Registers the child device with the vmbus |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 147 | */ |
Haiyang Zhang | 646f1ea | 2011-01-26 12:12:10 -0800 | [diff] [blame] | 148 | int vmbus_child_dev_add(struct hv_device *child_dev) |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 149 | { |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 150 | return vmbus_child_device_register(vmbus_device, child_dev); |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 151 | } |
| 152 | |
| 153 | /* |
Haiyang Zhang | 646f1ea | 2011-01-26 12:12:10 -0800 | [diff] [blame] | 154 | * vmbus_dev_add - Callback when the root bus device is added |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 155 | */ |
Haiyang Zhang | 646f1ea | 2011-01-26 12:12:10 -0800 | [diff] [blame] | 156 | static int vmbus_dev_add(struct hv_device *dev, void *info) |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 157 | { |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 158 | u32 *irqvector = info; |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 159 | int ret; |
| 160 | |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 161 | vmbus_device = dev; |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 162 | |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 163 | memcpy(&vmbus_device->dev_type, &device_type, sizeof(struct hv_guid)); |
| 164 | memcpy(&vmbus_device->dev_instance, &device_id, |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 165 | sizeof(struct hv_guid)); |
| 166 | |
| 167 | /* strcpy(dev->name, "vmbus"); */ |
| 168 | /* SynIC setup... */ |
| 169 | on_each_cpu(hv_synic_init, (void *)irqvector, 1); |
| 170 | |
| 171 | /* Connect to VMBus in the root partition */ |
Haiyang Zhang | c697767 | 2011-01-26 12:12:08 -0800 | [diff] [blame] | 172 | ret = vmbus_connect(); |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 173 | |
| 174 | /* VmbusSendEvent(device->localPortId+1); */ |
| 175 | return ret; |
| 176 | } |
| 177 | |
| 178 | /* |
Haiyang Zhang | 646f1ea | 2011-01-26 12:12:10 -0800 | [diff] [blame] | 179 | * vmbus_dev_rm - Callback when the root bus device is removed |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 180 | */ |
Haiyang Zhang | 646f1ea | 2011-01-26 12:12:10 -0800 | [diff] [blame] | 181 | static int vmbus_dev_rm(struct hv_device *dev) |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 182 | { |
| 183 | int ret = 0; |
| 184 | |
| 185 | vmbus_release_unattached_channels(); |
Haiyang Zhang | c697767 | 2011-01-26 12:12:08 -0800 | [diff] [blame] | 186 | vmbus_disconnect(); |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 187 | on_each_cpu(hv_synic_cleanup, NULL, 1); |
| 188 | return ret; |
| 189 | } |
| 190 | |
| 191 | /* |
Haiyang Zhang | 646f1ea | 2011-01-26 12:12:10 -0800 | [diff] [blame] | 192 | * vmbus_cleanup - Perform any cleanup when the driver is removed |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 193 | */ |
Haiyang Zhang | 646f1ea | 2011-01-26 12:12:10 -0800 | [diff] [blame] | 194 | static void vmbus_cleanup(struct hv_driver *drv) |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 195 | { |
| 196 | /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */ |
| 197 | |
| 198 | hv_cleanup(); |
| 199 | } |
| 200 | |
Timo Teräs | bf6506f | 2010-12-15 20:48:08 +0200 | [diff] [blame] | 201 | struct onmessage_work_context { |
| 202 | struct work_struct work; |
| 203 | struct hv_message msg; |
| 204 | }; |
| 205 | |
| 206 | static void vmbus_onmessage_work(struct work_struct *work) |
| 207 | { |
| 208 | struct onmessage_work_context *ctx; |
| 209 | |
| 210 | ctx = container_of(work, struct onmessage_work_context, |
| 211 | work); |
| 212 | vmbus_onmessage(&ctx->msg); |
| 213 | kfree(ctx); |
| 214 | } |
| 215 | |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 216 | /* |
| 217 | * vmbus_on_msg_dpc - DPC routine to handle messages from the hypervisior |
| 218 | */ |
Greg Kroah-Hartman | cef6dbf | 2010-12-02 12:11:25 -0800 | [diff] [blame] | 219 | static void vmbus_on_msg_dpc(struct hv_driver *drv) |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 220 | { |
| 221 | int cpu = smp_processor_id(); |
| 222 | void *page_addr = hv_context.synic_message_page[cpu]; |
| 223 | struct hv_message *msg = (struct hv_message *)page_addr + |
| 224 | VMBUS_MESSAGE_SINT; |
Timo Teräs | bf6506f | 2010-12-15 20:48:08 +0200 | [diff] [blame] | 225 | struct onmessage_work_context *ctx; |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 226 | |
| 227 | while (1) { |
| 228 | if (msg->header.message_type == HVMSG_NONE) { |
| 229 | /* no msg */ |
| 230 | break; |
| 231 | } else { |
Timo Teräs | bf6506f | 2010-12-15 20:48:08 +0200 | [diff] [blame] | 232 | ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC); |
| 233 | if (ctx == NULL) |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 234 | continue; |
Timo Teräs | bf6506f | 2010-12-15 20:48:08 +0200 | [diff] [blame] | 235 | INIT_WORK(&ctx->work, vmbus_onmessage_work); |
| 236 | memcpy(&ctx->msg, msg, sizeof(*msg)); |
Haiyang Zhang | da9fcb7 | 2011-01-26 12:12:14 -0800 | [diff] [blame] | 237 | queue_work(vmbus_connection.work_queue, &ctx->work); |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 238 | } |
| 239 | |
| 240 | msg->header.message_type = HVMSG_NONE; |
| 241 | |
| 242 | /* |
| 243 | * Make sure the write to MessageType (ie set to |
| 244 | * HVMSG_NONE) happens before we read the |
| 245 | * MessagePending and EOMing. Otherwise, the EOMing |
| 246 | * will not deliver any more messages since there is |
| 247 | * no empty slot |
| 248 | */ |
| 249 | mb(); |
| 250 | |
| 251 | if (msg->header.message_flags.msg_pending) { |
| 252 | /* |
| 253 | * This will cause message queue rescan to |
| 254 | * possibly deliver another msg from the |
| 255 | * hypervisor |
| 256 | */ |
| 257 | wrmsrl(HV_X64_MSR_EOM, 0); |
| 258 | } |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | /* |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 263 | * vmbus_on_isr - ISR routine |
| 264 | */ |
Greg Kroah-Hartman | cef6dbf | 2010-12-02 12:11:25 -0800 | [diff] [blame] | 265 | static int vmbus_on_isr(struct hv_driver *drv) |
Greg Kroah-Hartman | 36199a9 | 2010-12-02 11:59:22 -0800 | [diff] [blame] | 266 | { |
| 267 | int ret = 0; |
| 268 | int cpu = smp_processor_id(); |
| 269 | void *page_addr; |
| 270 | struct hv_message *msg; |
| 271 | union hv_synic_event_flags *event; |
| 272 | |
| 273 | page_addr = hv_context.synic_message_page[cpu]; |
| 274 | msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; |
| 275 | |
| 276 | /* Check if there are actual msgs to be process */ |
| 277 | if (msg->header.message_type != HVMSG_NONE) { |
| 278 | DPRINT_DBG(VMBUS, "received msg type %d size %d", |
| 279 | msg->header.message_type, |
| 280 | msg->header.payload_size); |
| 281 | ret |= 0x1; |
| 282 | } |
| 283 | |
| 284 | /* TODO: Check if there are events to be process */ |
| 285 | page_addr = hv_context.synic_event_page[cpu]; |
| 286 | event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT; |
| 287 | |
| 288 | /* Since we are a child, we only need to check bit 0 */ |
| 289 | if (test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) { |
| 290 | DPRINT_DBG(VMBUS, "received event %d", event->flags32[0]); |
| 291 | ret |= 0x2; |
| 292 | } |
| 293 | |
| 294 | return ret; |
| 295 | } |
| 296 | |
Greg Kroah-Hartman | 150b19d | 2010-10-20 16:07:11 -0700 | [diff] [blame] | 297 | static void get_channel_info(struct hv_device *device, |
| 298 | struct hv_device_info *info) |
| 299 | { |
| 300 | struct vmbus_channel_debug_info debug_info; |
| 301 | |
Greg Kroah-Hartman | cae5b84 | 2010-10-21 09:05:27 -0700 | [diff] [blame] | 302 | if (!device->channel) |
Greg Kroah-Hartman | 150b19d | 2010-10-20 16:07:11 -0700 | [diff] [blame] | 303 | return; |
| 304 | |
Greg Kroah-Hartman | cae5b84 | 2010-10-21 09:05:27 -0700 | [diff] [blame] | 305 | vmbus_get_debug_info(device->channel, &debug_info); |
Greg Kroah-Hartman | 150b19d | 2010-10-20 16:07:11 -0700 | [diff] [blame] | 306 | |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 307 | info->chn_id = debug_info.relid; |
| 308 | info->chn_state = debug_info.state; |
| 309 | memcpy(&info->chn_type, &debug_info.interfacetype, |
Greg Kroah-Hartman | 150b19d | 2010-10-20 16:07:11 -0700 | [diff] [blame] | 310 | sizeof(struct hv_guid)); |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 311 | memcpy(&info->chn_instance, &debug_info.interface_instance, |
Greg Kroah-Hartman | 150b19d | 2010-10-20 16:07:11 -0700 | [diff] [blame] | 312 | sizeof(struct hv_guid)); |
| 313 | |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 314 | info->monitor_id = debug_info.monitorid; |
Greg Kroah-Hartman | 150b19d | 2010-10-20 16:07:11 -0700 | [diff] [blame] | 315 | |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 316 | info->server_monitor_pending = debug_info.servermonitor_pending; |
| 317 | info->server_monitor_latency = debug_info.servermonitor_latency; |
| 318 | info->server_monitor_conn_id = debug_info.servermonitor_connectionid; |
Greg Kroah-Hartman | 150b19d | 2010-10-20 16:07:11 -0700 | [diff] [blame] | 319 | |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 320 | info->client_monitor_pending = debug_info.clientmonitor_pending; |
| 321 | info->client_monitor_latency = debug_info.clientmonitor_latency; |
| 322 | info->client_monitor_conn_id = debug_info.clientmonitor_connectionid; |
Greg Kroah-Hartman | 150b19d | 2010-10-20 16:07:11 -0700 | [diff] [blame] | 323 | |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 324 | info->inbound.int_mask = debug_info.inbound.current_interrupt_mask; |
| 325 | info->inbound.read_idx = debug_info.inbound.current_read_index; |
| 326 | info->inbound.write_idx = debug_info.inbound.current_write_index; |
| 327 | info->inbound.bytes_avail_toread = |
| 328 | debug_info.inbound.bytes_avail_toread; |
| 329 | info->inbound.bytes_avail_towrite = |
Haiyang Zhang | 82f8bd4 | 2010-11-08 14:04:45 -0800 | [diff] [blame] | 330 | debug_info.inbound.bytes_avail_towrite; |
Greg Kroah-Hartman | 150b19d | 2010-10-20 16:07:11 -0700 | [diff] [blame] | 331 | |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 332 | info->outbound.int_mask = |
Haiyang Zhang | 82f8bd4 | 2010-11-08 14:04:45 -0800 | [diff] [blame] | 333 | debug_info.outbound.current_interrupt_mask; |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 334 | info->outbound.read_idx = debug_info.outbound.current_read_index; |
| 335 | info->outbound.write_idx = debug_info.outbound.current_write_index; |
| 336 | info->outbound.bytes_avail_toread = |
Haiyang Zhang | 82f8bd4 | 2010-11-08 14:04:45 -0800 | [diff] [blame] | 337 | debug_info.outbound.bytes_avail_toread; |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 338 | info->outbound.bytes_avail_towrite = |
Haiyang Zhang | 82f8bd4 | 2010-11-08 14:04:45 -0800 | [diff] [blame] | 339 | debug_info.outbound.bytes_avail_towrite; |
Greg Kroah-Hartman | 150b19d | 2010-10-20 16:07:11 -0700 | [diff] [blame] | 340 | } |
| 341 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 342 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 343 | * vmbus_show_device_attr - Show the device attribute in sysfs. |
| 344 | * |
| 345 | * This is invoked when user does a |
| 346 | * "cat /sys/bus/vmbus/devices/<busdevice>/<attr name>" |
| 347 | */ |
| 348 | static ssize_t vmbus_show_device_attr(struct device *dev, |
| 349 | struct device_attribute *dev_attr, |
| 350 | char *buf) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 351 | { |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 352 | struct vm_device *device_ctx = device_to_vm_device(dev); |
Greg Kroah-Hartman | ee3d7dd | 2009-08-20 12:17:36 -0700 | [diff] [blame] | 353 | struct hv_device_info device_info; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 354 | |
Greg Kroah-Hartman | ee3d7dd | 2009-08-20 12:17:36 -0700 | [diff] [blame] | 355 | memset(&device_info, 0, sizeof(struct hv_device_info)); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 356 | |
Greg Kroah-Hartman | a4e91ed2 | 2010-10-20 16:02:49 -0700 | [diff] [blame] | 357 | get_channel_info(&device_ctx->device_obj, &device_info); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 358 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 359 | if (!strcmp(dev_attr->attr.name, "class_id")) { |
| 360 | return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-" |
| 361 | "%02x%02x%02x%02x%02x%02x%02x%02x}\n", |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 362 | device_info.chn_type.data[3], |
| 363 | device_info.chn_type.data[2], |
| 364 | device_info.chn_type.data[1], |
| 365 | device_info.chn_type.data[0], |
| 366 | device_info.chn_type.data[5], |
| 367 | device_info.chn_type.data[4], |
| 368 | device_info.chn_type.data[7], |
| 369 | device_info.chn_type.data[6], |
| 370 | device_info.chn_type.data[8], |
| 371 | device_info.chn_type.data[9], |
| 372 | device_info.chn_type.data[10], |
| 373 | device_info.chn_type.data[11], |
| 374 | device_info.chn_type.data[12], |
| 375 | device_info.chn_type.data[13], |
| 376 | device_info.chn_type.data[14], |
| 377 | device_info.chn_type.data[15]); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 378 | } else if (!strcmp(dev_attr->attr.name, "device_id")) { |
| 379 | return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-" |
| 380 | "%02x%02x%02x%02x%02x%02x%02x%02x}\n", |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 381 | device_info.chn_instance.data[3], |
| 382 | device_info.chn_instance.data[2], |
| 383 | device_info.chn_instance.data[1], |
| 384 | device_info.chn_instance.data[0], |
| 385 | device_info.chn_instance.data[5], |
| 386 | device_info.chn_instance.data[4], |
| 387 | device_info.chn_instance.data[7], |
| 388 | device_info.chn_instance.data[6], |
| 389 | device_info.chn_instance.data[8], |
| 390 | device_info.chn_instance.data[9], |
| 391 | device_info.chn_instance.data[10], |
| 392 | device_info.chn_instance.data[11], |
| 393 | device_info.chn_instance.data[12], |
| 394 | device_info.chn_instance.data[13], |
| 395 | device_info.chn_instance.data[14], |
| 396 | device_info.chn_instance.data[15]); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 397 | } else if (!strcmp(dev_attr->attr.name, "state")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 398 | return sprintf(buf, "%d\n", device_info.chn_state); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 399 | } else if (!strcmp(dev_attr->attr.name, "id")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 400 | return sprintf(buf, "%d\n", device_info.chn_id); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 401 | } else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 402 | return sprintf(buf, "%d\n", device_info.outbound.int_mask); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 403 | } else if (!strcmp(dev_attr->attr.name, "out_read_index")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 404 | return sprintf(buf, "%d\n", device_info.outbound.read_idx); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 405 | } else if (!strcmp(dev_attr->attr.name, "out_write_index")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 406 | return sprintf(buf, "%d\n", device_info.outbound.write_idx); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 407 | } else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) { |
| 408 | return sprintf(buf, "%d\n", |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 409 | device_info.outbound.bytes_avail_toread); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 410 | } else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) { |
| 411 | return sprintf(buf, "%d\n", |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 412 | device_info.outbound.bytes_avail_towrite); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 413 | } else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 414 | return sprintf(buf, "%d\n", device_info.inbound.int_mask); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 415 | } else if (!strcmp(dev_attr->attr.name, "in_read_index")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 416 | return sprintf(buf, "%d\n", device_info.inbound.read_idx); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 417 | } else if (!strcmp(dev_attr->attr.name, "in_write_index")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 418 | return sprintf(buf, "%d\n", device_info.inbound.write_idx); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 419 | } else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) { |
| 420 | return sprintf(buf, "%d\n", |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 421 | device_info.inbound.bytes_avail_toread); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 422 | } else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) { |
| 423 | return sprintf(buf, "%d\n", |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 424 | device_info.inbound.bytes_avail_towrite); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 425 | } else if (!strcmp(dev_attr->attr.name, "monitor_id")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 426 | return sprintf(buf, "%d\n", device_info.monitor_id); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 427 | } else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 428 | return sprintf(buf, "%d\n", device_info.server_monitor_pending); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 429 | } else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 430 | return sprintf(buf, "%d\n", device_info.server_monitor_latency); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 431 | } else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) { |
| 432 | return sprintf(buf, "%d\n", |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 433 | device_info.server_monitor_conn_id); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 434 | } else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 435 | return sprintf(buf, "%d\n", device_info.client_monitor_pending); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 436 | } else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) { |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 437 | return sprintf(buf, "%d\n", device_info.client_monitor_latency); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 438 | } else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) { |
| 439 | return sprintf(buf, "%d\n", |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 440 | device_info.client_monitor_conn_id); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 441 | } else { |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 442 | return 0; |
| 443 | } |
| 444 | } |
| 445 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 446 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 447 | * vmbus_bus_init -Main vmbus driver initialization routine. |
| 448 | * |
| 449 | * Here, we |
Lars Lindley | 0686e4f | 2010-03-11 23:51:23 +0100 | [diff] [blame] | 450 | * - initialize the vmbus driver context |
| 451 | * - setup various driver entry points |
| 452 | * - invoke the vmbus hv main init routine |
| 453 | * - get the irq resource |
| 454 | * - invoke the vmbus to add the vmbus root device |
| 455 | * - setup the vmbus root device |
| 456 | * - retrieve the channel offers |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 457 | */ |
Greg Kroah-Hartman | 6c88455 | 2010-12-02 12:04:00 -0800 | [diff] [blame] | 458 | static int vmbus_bus_init(void) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 459 | { |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 460 | struct vmbus_driver_context *vmbus_drv_ctx = &vmbus_drv; |
| 461 | struct hv_driver *driver = &vmbus_drv.drv_obj; |
| 462 | struct vm_device *dev_ctx = &vmbus_drv.device_ctx; |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 463 | int ret; |
| 464 | unsigned int vector; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 465 | |
Greg Kroah-Hartman | 6d26e38fa2 | 2010-12-02 12:08:08 -0800 | [diff] [blame] | 466 | DPRINT_INFO(VMBUS, "+++++++ HV Driver version = %s +++++++", |
| 467 | HV_DRV_VERSION); |
| 468 | DPRINT_INFO(VMBUS, "+++++++ Vmbus supported version = %d +++++++", |
| 469 | VMBUS_REVISION_NUMBER); |
| 470 | DPRINT_INFO(VMBUS, "+++++++ Vmbus using SINT %d +++++++", |
| 471 | VMBUS_MESSAGE_SINT); |
| 472 | DPRINT_DBG(VMBUS, "sizeof(vmbus_channel_packet_page_buffer)=%zd, " |
| 473 | "sizeof(VMBUS_CHANNEL_PACKET_MULITPAGE_BUFFER)=%zd", |
| 474 | sizeof(struct vmbus_channel_packet_page_buffer), |
| 475 | sizeof(struct vmbus_channel_packet_multipage_buffer)); |
| 476 | |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 477 | driver->name = driver_name; |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 478 | memcpy(&driver->dev_type, &device_type, sizeof(struct hv_guid)); |
Greg Kroah-Hartman | 6d26e38fa2 | 2010-12-02 12:08:08 -0800 | [diff] [blame] | 479 | |
| 480 | /* Setup dispatch table */ |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 481 | driver->dev_add = vmbus_dev_add; |
| 482 | driver->dev_rm = vmbus_dev_rm; |
| 483 | driver->cleanup = vmbus_cleanup; |
Greg Kroah-Hartman | 6d26e38fa2 | 2010-12-02 12:08:08 -0800 | [diff] [blame] | 484 | |
| 485 | /* Hypervisor initialization...setup hypercall page..etc */ |
| 486 | ret = hv_init(); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 487 | if (ret != 0) { |
Greg Kroah-Hartman | 6d26e38fa2 | 2010-12-02 12:08:08 -0800 | [diff] [blame] | 488 | DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x", |
| 489 | ret); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 490 | goto cleanup; |
| 491 | } |
| 492 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 493 | /* Sanity checks */ |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 494 | if (!driver->dev_add) { |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 495 | DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set"); |
| 496 | ret = -1; |
| 497 | goto cleanup; |
| 498 | } |
| 499 | |
Greg Kroah-Hartman | a69a669 | 2010-12-02 09:42:18 -0800 | [diff] [blame] | 500 | vmbus_drv_ctx->bus.name = driver->name; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 501 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 502 | /* Initialize the bus context */ |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 503 | tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc, |
Greg Kroah-Hartman | a69a669 | 2010-12-02 09:42:18 -0800 | [diff] [blame] | 504 | (unsigned long)driver); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 505 | tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc, |
Greg Kroah-Hartman | a69a669 | 2010-12-02 09:42:18 -0800 | [diff] [blame] | 506 | (unsigned long)driver); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 507 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 508 | /* Now, register the bus driver with LDM */ |
Bill Pemberton | c19fbca | 2009-07-27 16:47:35 -0400 | [diff] [blame] | 509 | ret = bus_register(&vmbus_drv_ctx->bus); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 510 | if (ret) { |
Bill Pemberton | c19fbca | 2009-07-27 16:47:35 -0400 | [diff] [blame] | 511 | ret = -1; |
| 512 | goto cleanup; |
| 513 | } |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 514 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 515 | /* Get the interrupt resource */ |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 516 | ret = request_irq(vmbus_irq, vmbus_isr, IRQF_SAMPLE_RANDOM, |
Greg Kroah-Hartman | a69a669 | 2010-12-02 09:42:18 -0800 | [diff] [blame] | 517 | driver->name, NULL); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 518 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 519 | if (ret != 0) { |
| 520 | DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d", |
| 521 | vmbus_irq); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 522 | |
| 523 | bus_unregister(&vmbus_drv_ctx->bus); |
| 524 | |
| 525 | ret = -1; |
| 526 | goto cleanup; |
| 527 | } |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 528 | vector = VMBUS_IRQ_VECTOR; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 529 | |
| 530 | DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector); |
| 531 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 532 | /* Call to bus driver to add the root device */ |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 533 | memset(dev_ctx, 0, sizeof(struct vm_device)); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 534 | |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 535 | ret = driver->dev_add(&dev_ctx->device_obj, &vector); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 536 | if (ret != 0) { |
| 537 | DPRINT_ERR(VMBUS_DRV, |
| 538 | "ERROR - Unable to add vmbus root device"); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 539 | |
| 540 | free_irq(vmbus_irq, NULL); |
| 541 | |
| 542 | bus_unregister(&vmbus_drv_ctx->bus); |
| 543 | |
| 544 | ret = -1; |
| 545 | goto cleanup; |
| 546 | } |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 547 | /* strcpy(dev_ctx->device.bus_id, dev_ctx->device_obj.name); */ |
Greg Kroah-Hartman | 09d50ff | 2009-07-13 17:09:34 -0700 | [diff] [blame] | 548 | dev_set_name(&dev_ctx->device, "vmbus_0_0"); |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 549 | memcpy(&dev_ctx->class_id, &dev_ctx->device_obj.dev_type, |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 550 | sizeof(struct hv_guid)); |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 551 | memcpy(&dev_ctx->device_id, &dev_ctx->device_obj.dev_instance, |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 552 | sizeof(struct hv_guid)); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 553 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 554 | /* No need to bind a driver to the root device. */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 555 | dev_ctx->device.parent = NULL; |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 556 | /* NULL; vmbus_remove() does not get invoked */ |
| 557 | dev_ctx->device.bus = &vmbus_drv_ctx->bus; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 558 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 559 | /* Setup the device dispatch table */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 560 | dev_ctx->device.release = vmbus_bus_release; |
| 561 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 562 | /* Setup the bus as root device */ |
Bill Pemberton | 5d48a1c | 2009-07-27 16:47:36 -0400 | [diff] [blame] | 563 | ret = device_register(&dev_ctx->device); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 564 | if (ret) { |
| 565 | DPRINT_ERR(VMBUS_DRV, |
| 566 | "ERROR - Unable to register vmbus root device"); |
Bill Pemberton | 5d48a1c | 2009-07-27 16:47:36 -0400 | [diff] [blame] | 567 | |
| 568 | free_irq(vmbus_irq, NULL); |
| 569 | bus_unregister(&vmbus_drv_ctx->bus); |
| 570 | |
| 571 | ret = -1; |
| 572 | goto cleanup; |
| 573 | } |
| 574 | |
Greg Kroah-Hartman | 2d6e882 | 2010-12-02 08:50:58 -0800 | [diff] [blame] | 575 | vmbus_request_offers(); |
Haiyang Zhang | 8b5d6d3 | 2010-05-28 23:22:44 +0000 | [diff] [blame] | 576 | wait_for_completion(&hv_channel_ready); |
| 577 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 578 | cleanup: |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 579 | return ret; |
| 580 | } |
| 581 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 582 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 583 | * vmbus_bus_exit - Terminate the vmbus driver. |
| 584 | * |
| 585 | * This routine is opposite of vmbus_bus_init() |
| 586 | */ |
Greg Kroah-Hartman | bd1de70 | 2009-07-29 09:04:51 -0700 | [diff] [blame] | 587 | static void vmbus_bus_exit(void) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 588 | { |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 589 | struct hv_driver *driver = &vmbus_drv.drv_obj; |
| 590 | struct vmbus_driver_context *vmbus_drv_ctx = &vmbus_drv; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 591 | |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 592 | struct vm_device *dev_ctx = &vmbus_drv.device_ctx; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 593 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 594 | /* Remove the root device */ |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 595 | if (driver->dev_rm) |
| 596 | driver->dev_rm(&dev_ctx->device_obj); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 597 | |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 598 | if (driver->cleanup) |
| 599 | driver->cleanup(driver); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 600 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 601 | /* Unregister the root bus device */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 602 | device_unregister(&dev_ctx->device); |
| 603 | |
| 604 | bus_unregister(&vmbus_drv_ctx->bus); |
| 605 | |
| 606 | free_irq(vmbus_irq, NULL); |
| 607 | |
| 608 | tasklet_kill(&vmbus_drv_ctx->msg_dpc); |
| 609 | tasklet_kill(&vmbus_drv_ctx->event_dpc); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 610 | } |
| 611 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 612 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 613 | /** |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 614 | * vmbus_child_driver_register() - Register a vmbus's child driver |
K. Y. Srinivasan | c643269d | 2011-03-07 13:23:43 -0800 | [diff] [blame] | 615 | * @drv: Pointer to driver structure you want to register |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 616 | * |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 617 | * |
| 618 | * Registers the given driver with Linux through the 'driver_register()' call |
| 619 | * And sets up the hyper-v vmbus handling for this driver. |
| 620 | * It will return the state of the 'driver_register()' call. |
| 621 | * |
| 622 | * Mainly used by Hyper-V drivers. |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 623 | */ |
K. Y. Srinivasan | c643269d | 2011-03-07 13:23:43 -0800 | [diff] [blame] | 624 | int vmbus_child_driver_register(struct device_driver *drv) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 625 | { |
Bill Pemberton | 5d48a1c | 2009-07-27 16:47:36 -0400 | [diff] [blame] | 626 | int ret; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 627 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 628 | DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s", |
K. Y. Srinivasan | c643269d | 2011-03-07 13:23:43 -0800 | [diff] [blame] | 629 | drv, drv->name); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 630 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 631 | /* The child driver on this vmbus */ |
K. Y. Srinivasan | c643269d | 2011-03-07 13:23:43 -0800 | [diff] [blame] | 632 | drv->bus = &vmbus_drv.bus; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 633 | |
K. Y. Srinivasan | c643269d | 2011-03-07 13:23:43 -0800 | [diff] [blame] | 634 | ret = driver_register(drv); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 635 | |
Greg Kroah-Hartman | 2d6e882 | 2010-12-02 08:50:58 -0800 | [diff] [blame] | 636 | vmbus_request_offers(); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 637 | |
Bill Pemberton | 5d48a1c | 2009-07-27 16:47:36 -0400 | [diff] [blame] | 638 | return ret; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 639 | } |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 640 | EXPORT_SYMBOL(vmbus_child_driver_register); |
| 641 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 642 | /** |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 643 | * vmbus_child_driver_unregister() - Unregister a vmbus's child driver |
K. Y. Srinivasan | 06de23f | 2011-03-07 13:24:23 -0800 | [diff] [blame] | 644 | * @drv: Pointer to driver structure you want to un-register |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 645 | * |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 646 | * |
| 647 | * Un-register the given driver with Linux through the 'driver_unregister()' |
| 648 | * call. And ungegisters the driver from the Hyper-V vmbus handler. |
| 649 | * |
| 650 | * Mainly used by Hyper-V drivers. |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 651 | */ |
K. Y. Srinivasan | 06de23f | 2011-03-07 13:24:23 -0800 | [diff] [blame] | 652 | void vmbus_child_driver_unregister(struct device_driver *drv) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 653 | { |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 654 | DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s", |
K. Y. Srinivasan | 06de23f | 2011-03-07 13:24:23 -0800 | [diff] [blame] | 655 | drv, drv->name); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 656 | |
K. Y. Srinivasan | 06de23f | 2011-03-07 13:24:23 -0800 | [diff] [blame] | 657 | driver_unregister(drv); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 658 | |
K. Y. Srinivasan | 06de23f | 2011-03-07 13:24:23 -0800 | [diff] [blame] | 659 | drv->bus = NULL; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 660 | } |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 661 | EXPORT_SYMBOL(vmbus_child_driver_unregister); |
| 662 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 663 | /* |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 664 | * vmbus_child_device_create - Creates and registers a new child device |
| 665 | * on the vmbus. |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 666 | */ |
Greg Kroah-Hartman | 89733aa | 2010-12-02 08:22:41 -0800 | [diff] [blame] | 667 | struct hv_device *vmbus_child_device_create(struct hv_guid *type, |
| 668 | struct hv_guid *instance, |
| 669 | struct vmbus_channel *channel) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 670 | { |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 671 | struct vm_device *child_device_ctx; |
Nicolas Palix | 3d3b551 | 2009-07-28 17:32:53 +0200 | [diff] [blame] | 672 | struct hv_device *child_device_obj; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 673 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 674 | /* Allocate the new child device */ |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 675 | child_device_ctx = kzalloc(sizeof(struct vm_device), GFP_KERNEL); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 676 | if (!child_device_ctx) { |
| 677 | DPRINT_ERR(VMBUS_DRV, |
| 678 | "unable to allocate device_context for child device"); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 679 | return NULL; |
| 680 | } |
| 681 | |
| 682 | DPRINT_DBG(VMBUS_DRV, "child device (%p) allocated - " |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 683 | "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-" |
| 684 | "%02x%02x%02x%02x%02x%02x%02x%02x}," |
| 685 | "id {%02x%02x%02x%02x-%02x%02x-%02x%02x-" |
| 686 | "%02x%02x%02x%02x%02x%02x%02x%02x}", |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 687 | &child_device_ctx->device, |
Greg Kroah-Hartman | daaa8cc | 2009-08-19 16:18:56 -0700 | [diff] [blame] | 688 | type->data[3], type->data[2], type->data[1], type->data[0], |
| 689 | type->data[5], type->data[4], type->data[7], type->data[6], |
| 690 | type->data[8], type->data[9], type->data[10], type->data[11], |
| 691 | type->data[12], type->data[13], type->data[14], type->data[15], |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 692 | instance->data[3], instance->data[2], |
| 693 | instance->data[1], instance->data[0], |
| 694 | instance->data[5], instance->data[4], |
| 695 | instance->data[7], instance->data[6], |
| 696 | instance->data[8], instance->data[9], |
| 697 | instance->data[10], instance->data[11], |
| 698 | instance->data[12], instance->data[13], |
| 699 | instance->data[14], instance->data[15]); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 700 | |
| 701 | child_device_obj = &child_device_ctx->device_obj; |
Greg Kroah-Hartman | cae5b84 | 2010-10-21 09:05:27 -0700 | [diff] [blame] | 702 | child_device_obj->channel = channel; |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 703 | memcpy(&child_device_obj->dev_type, type, sizeof(struct hv_guid)); |
| 704 | memcpy(&child_device_obj->dev_instance, instance, |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 705 | sizeof(struct hv_guid)); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 706 | |
Milan Dadok | 9fb5cce | 2009-10-28 23:23:27 +0100 | [diff] [blame] | 707 | memcpy(&child_device_ctx->class_id, type, sizeof(struct hv_guid)); |
| 708 | memcpy(&child_device_ctx->device_id, instance, sizeof(struct hv_guid)); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 709 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 710 | return child_device_obj; |
| 711 | } |
| 712 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 713 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 714 | * vmbus_child_device_register - Register the child device on the specified bus |
| 715 | */ |
Greg Kroah-Hartman | 98293a2 | 2010-12-02 09:16:04 -0800 | [diff] [blame] | 716 | int vmbus_child_device_register(struct hv_device *root_device_obj, |
| 717 | struct hv_device *child_device_obj) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 718 | { |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 719 | int ret = 0; |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 720 | struct vm_device *root_device_ctx = |
| 721 | to_vm_device(root_device_obj); |
| 722 | struct vm_device *child_device_ctx = |
| 723 | to_vm_device(child_device_obj); |
Bill Pemberton | f488841 | 2009-07-29 17:00:12 -0400 | [diff] [blame] | 724 | static atomic_t device_num = ATOMIC_INIT(0); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 725 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 726 | DPRINT_DBG(VMBUS_DRV, "child device (%p) registering", |
| 727 | child_device_ctx); |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 728 | |
Haiyang Zhang | 1bb40a2 | 2009-10-23 18:14:24 +0000 | [diff] [blame] | 729 | /* Set the device name. Otherwise, device_register() will fail. */ |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 730 | dev_set_name(&child_device_ctx->device, "vmbus_0_%d", |
| 731 | atomic_inc_return(&device_num)); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 732 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 733 | /* The new device belongs to this bus */ |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 734 | child_device_ctx->device.bus = &vmbus_drv.bus; /* device->dev.bus; */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 735 | child_device_ctx->device.parent = &root_device_ctx->device; |
| 736 | child_device_ctx->device.release = vmbus_device_release; |
| 737 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 738 | /* |
| 739 | * Register with the LDM. This will kick off the driver/device |
| 740 | * binding...which will eventually call vmbus_match() and vmbus_probe() |
| 741 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 742 | ret = device_register(&child_device_ctx->device); |
| 743 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 744 | /* vmbus_probe() error does not get propergate to device_register(). */ |
K. Y. Srinivasan | 70b0af4 | 2011-03-07 13:34:48 -0800 | [diff] [blame^] | 745 | ret = child_device_ctx->device_obj.probe_error; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 746 | |
| 747 | if (ret) |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 748 | DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p)", |
| 749 | &child_device_ctx->device); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 750 | else |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 751 | DPRINT_INFO(VMBUS_DRV, "child device (%p) registered", |
| 752 | &child_device_ctx->device); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 753 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 754 | return ret; |
| 755 | } |
| 756 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 757 | /* |
| 758 | * vmbus_child_device_unregister - Remove the specified child device |
| 759 | * from the vmbus. |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 760 | */ |
Greg Kroah-Hartman | 9d8bd71 | 2010-12-02 08:34:45 -0800 | [diff] [blame] | 761 | void vmbus_child_device_unregister(struct hv_device *device_obj) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 762 | { |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 763 | struct vm_device *device_ctx = to_vm_device(device_obj); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 764 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 765 | DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)", |
| 766 | &device_ctx->device); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 767 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 768 | /* |
| 769 | * Kick off the process of unregistering the device. |
| 770 | * This will call vmbus_remove() and eventually vmbus_device_release() |
| 771 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 772 | device_unregister(&device_ctx->device); |
| 773 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 774 | DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered", |
| 775 | &device_ctx->device); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 776 | } |
| 777 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 778 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 779 | * vmbus_uevent - add uevent for our device |
| 780 | * |
| 781 | * This routine is invoked when a device is added or removed on the vmbus to |
| 782 | * generate a uevent to udev in the userspace. The udev will then look at its |
| 783 | * rule and the uevent generated here to load the appropriate driver |
| 784 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 785 | static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env) |
| 786 | { |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 787 | struct vm_device *device_ctx = device_to_vm_device(device); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 788 | int ret; |
| 789 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 790 | DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={" |
| 791 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-" |
| 792 | "%02x%02x%02x%02x%02x%02x%02x%02x}", |
| 793 | device_ctx->class_id.data[3], device_ctx->class_id.data[2], |
| 794 | device_ctx->class_id.data[1], device_ctx->class_id.data[0], |
| 795 | device_ctx->class_id.data[5], device_ctx->class_id.data[4], |
| 796 | device_ctx->class_id.data[7], device_ctx->class_id.data[6], |
| 797 | device_ctx->class_id.data[8], device_ctx->class_id.data[9], |
| 798 | device_ctx->class_id.data[10], |
| 799 | device_ctx->class_id.data[11], |
| 800 | device_ctx->class_id.data[12], |
| 801 | device_ctx->class_id.data[13], |
| 802 | device_ctx->class_id.data[14], |
| 803 | device_ctx->class_id.data[15]); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 804 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 805 | ret = add_uevent_var(env, "VMBUS_DEVICE_CLASS_GUID={" |
| 806 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-" |
| 807 | "%02x%02x%02x%02x%02x%02x%02x%02x}", |
| 808 | device_ctx->class_id.data[3], |
| 809 | device_ctx->class_id.data[2], |
| 810 | device_ctx->class_id.data[1], |
| 811 | device_ctx->class_id.data[0], |
| 812 | device_ctx->class_id.data[5], |
| 813 | device_ctx->class_id.data[4], |
| 814 | device_ctx->class_id.data[7], |
| 815 | device_ctx->class_id.data[6], |
| 816 | device_ctx->class_id.data[8], |
| 817 | device_ctx->class_id.data[9], |
| 818 | device_ctx->class_id.data[10], |
| 819 | device_ctx->class_id.data[11], |
| 820 | device_ctx->class_id.data[12], |
| 821 | device_ctx->class_id.data[13], |
| 822 | device_ctx->class_id.data[14], |
| 823 | device_ctx->class_id.data[15]); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 824 | |
| 825 | if (ret) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 826 | return ret; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 827 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 828 | ret = add_uevent_var(env, "VMBUS_DEVICE_DEVICE_GUID={" |
| 829 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-" |
| 830 | "%02x%02x%02x%02x%02x%02x%02x%02x}", |
| 831 | device_ctx->device_id.data[3], |
| 832 | device_ctx->device_id.data[2], |
| 833 | device_ctx->device_id.data[1], |
| 834 | device_ctx->device_id.data[0], |
| 835 | device_ctx->device_id.data[5], |
| 836 | device_ctx->device_id.data[4], |
| 837 | device_ctx->device_id.data[7], |
| 838 | device_ctx->device_id.data[6], |
| 839 | device_ctx->device_id.data[8], |
| 840 | device_ctx->device_id.data[9], |
| 841 | device_ctx->device_id.data[10], |
| 842 | device_ctx->device_id.data[11], |
| 843 | device_ctx->device_id.data[12], |
| 844 | device_ctx->device_id.data[13], |
| 845 | device_ctx->device_id.data[14], |
| 846 | device_ctx->device_id.data[15]); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 847 | if (ret) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 848 | return ret; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 849 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 850 | return 0; |
| 851 | } |
| 852 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 853 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 854 | * vmbus_match - Attempt to match the specified device to the specified driver |
| 855 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 856 | static int vmbus_match(struct device *device, struct device_driver *driver) |
| 857 | { |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 858 | int match = 0; |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 859 | struct hv_driver *drv = drv_to_hv_drv(driver); |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 860 | struct vm_device *device_ctx = device_to_vm_device(device); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 861 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 862 | /* We found our driver ? */ |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 863 | if (memcmp(&device_ctx->class_id, &drv->dev_type, |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 864 | sizeof(struct hv_guid)) == 0) { |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 865 | |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 866 | device_ctx->device_obj.drv = drv->priv; |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 867 | DPRINT_INFO(VMBUS_DRV, |
| 868 | "device object (%p) set to driver object (%p)", |
| 869 | &device_ctx->device_obj, |
Haiyang Zhang | ca623ad | 2011-01-26 12:12:11 -0800 | [diff] [blame] | 870 | device_ctx->device_obj.drv); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 871 | |
| 872 | match = 1; |
| 873 | } |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 874 | return match; |
| 875 | } |
| 876 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 877 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 878 | * vmbus_probe_failed_cb - Callback when a driver probe failed in vmbus_probe() |
| 879 | * |
| 880 | * We need a callback because we cannot invoked device_unregister() inside |
| 881 | * vmbus_probe() since vmbus_probe() may be invoked inside device_register() |
| 882 | * i.e. we cannot call device_unregister() inside device_register() |
| 883 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 884 | static void vmbus_probe_failed_cb(struct work_struct *context) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 885 | { |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 886 | struct vm_device *device_ctx = (struct vm_device *)context; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 887 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 888 | /* |
| 889 | * Kick off the process of unregistering the device. |
| 890 | * This will call vmbus_remove() and eventually vmbus_device_release() |
| 891 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 892 | device_unregister(&device_ctx->device); |
| 893 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 894 | /* put_device(&device_ctx->device); */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 895 | } |
| 896 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 897 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 898 | * vmbus_probe - Add the new vmbus's child device |
| 899 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 900 | static int vmbus_probe(struct device *child_device) |
| 901 | { |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 902 | int ret = 0; |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 903 | struct hv_driver *drv = |
| 904 | drv_to_hv_drv(child_device->driver); |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 905 | struct vm_device *device_ctx = |
| 906 | device_to_vm_device(child_device); |
K. Y. Srinivasan | a3c7fe9 | 2011-03-07 13:34:27 -0800 | [diff] [blame] | 907 | struct hv_device *dev = &device_ctx->device_obj; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 908 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 909 | /* Let the specific open-source driver handles the probe if it can */ |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 910 | if (drv->driver.probe) { |
K. Y. Srinivasan | 70b0af4 | 2011-03-07 13:34:48 -0800 | [diff] [blame^] | 911 | ret = device_ctx->device_obj.probe_error = |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 912 | drv->driver.probe(child_device); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 913 | if (ret != 0) { |
| 914 | DPRINT_ERR(VMBUS_DRV, "probe() failed for device %s " |
| 915 | "(%p) on driver %s (%d)...", |
| 916 | dev_name(child_device), child_device, |
| 917 | child_device->driver->name, ret); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 918 | |
K. Y. Srinivasan | a3c7fe9 | 2011-03-07 13:34:27 -0800 | [diff] [blame] | 919 | INIT_WORK(&dev->probe_failed_work_item, |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 920 | vmbus_probe_failed_cb); |
K. Y. Srinivasan | a3c7fe9 | 2011-03-07 13:34:27 -0800 | [diff] [blame] | 921 | schedule_work(&dev->probe_failed_work_item); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 922 | } |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 923 | } else { |
| 924 | DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s", |
| 925 | child_device->driver->name); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 926 | ret = -1; |
| 927 | } |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 928 | return ret; |
| 929 | } |
| 930 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 931 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 932 | * vmbus_remove - Remove a vmbus device |
| 933 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 934 | static int vmbus_remove(struct device *child_device) |
| 935 | { |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 936 | int ret; |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 937 | struct hv_driver *drv; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 938 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 939 | /* Special case root bus device */ |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 940 | if (child_device->parent == NULL) { |
| 941 | /* |
| 942 | * No-op since it is statically defined and handle in |
| 943 | * vmbus_bus_exit() |
| 944 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 945 | return 0; |
| 946 | } |
| 947 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 948 | if (child_device->driver) { |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 949 | drv = drv_to_hv_drv(child_device->driver); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 950 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 951 | /* |
| 952 | * Let the specific open-source driver handles the removal if |
| 953 | * it can |
| 954 | */ |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 955 | if (drv->driver.remove) { |
| 956 | ret = drv->driver.remove(child_device); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 957 | } else { |
| 958 | DPRINT_ERR(VMBUS_DRV, |
| 959 | "remove() method not set for driver - %s", |
| 960 | child_device->driver->name); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 961 | ret = -1; |
| 962 | } |
| 963 | } |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 964 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 965 | return 0; |
| 966 | } |
| 967 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 968 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 969 | * vmbus_shutdown - Shutdown a vmbus device |
| 970 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 971 | static void vmbus_shutdown(struct device *child_device) |
| 972 | { |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 973 | struct hv_driver *drv; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 974 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 975 | /* Special case root bus device */ |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 976 | if (child_device->parent == NULL) { |
| 977 | /* |
| 978 | * No-op since it is statically defined and handle in |
| 979 | * vmbus_bus_exit() |
| 980 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 981 | return; |
| 982 | } |
| 983 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 984 | /* The device may not be attached yet */ |
Greg Kroah-Hartman | 83c720e | 2010-07-22 15:14:04 -0700 | [diff] [blame] | 985 | if (!child_device->driver) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 986 | return; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 987 | |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 988 | drv = drv_to_hv_drv(child_device->driver); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 989 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 990 | /* Let the specific open-source driver handles the removal if it can */ |
K. Y. Srinivasan | 150f939 | 2011-03-07 13:32:31 -0800 | [diff] [blame] | 991 | if (drv->driver.shutdown) |
| 992 | drv->driver.shutdown(child_device); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 993 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 994 | return; |
| 995 | } |
| 996 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 997 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 998 | * vmbus_bus_release - Final callback release of the vmbus root device |
| 999 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1000 | static void vmbus_bus_release(struct device *device) |
| 1001 | { |
Greg Kroah-Hartman | 689bf40 | 2009-09-01 20:12:58 -0700 | [diff] [blame] | 1002 | /* FIXME */ |
| 1003 | /* Empty release functions are a bug, or a major sign |
| 1004 | * of a problem design, this MUST BE FIXED! */ |
| 1005 | dev_err(device, "%s needs to be fixed!\n", __func__); |
| 1006 | WARN_ON(1); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1007 | } |
| 1008 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 1009 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 1010 | * vmbus_device_release - Final callback release of the vmbus child device |
| 1011 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1012 | static void vmbus_device_release(struct device *device) |
| 1013 | { |
Haiyang Zhang | f916a34 | 2010-02-17 20:58:47 +0000 | [diff] [blame] | 1014 | struct vm_device *device_ctx = device_to_vm_device(device); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1015 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1016 | kfree(device_ctx); |
| 1017 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 1018 | /* !!DO NOT REFERENCE device_ctx anymore at this point!! */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1019 | } |
| 1020 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 1021 | /* |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 1022 | * vmbus_msg_dpc - Tasklet routine to handle hypervisor messages |
| 1023 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1024 | static void vmbus_msg_dpc(unsigned long data) |
| 1025 | { |
Greg Kroah-Hartman | a69a669 | 2010-12-02 09:42:18 -0800 | [diff] [blame] | 1026 | struct hv_driver *driver = (struct hv_driver *)data; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1027 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 1028 | /* Call to bus driver to handle interrupt */ |
Greg Kroah-Hartman | a69a669 | 2010-12-02 09:42:18 -0800 | [diff] [blame] | 1029 | vmbus_on_msg_dpc(driver); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1030 | } |
| 1031 | |
Hank Janssen | 3e18951 | 2010-03-04 22:11:00 +0000 | [diff] [blame] | 1032 | /* |
Greg Kroah-Hartman | 4a1494f | 2010-12-02 08:44:48 -0800 | [diff] [blame] | 1033 | * vmbus_event_dpc - Tasklet routine to handle hypervisor events |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 1034 | */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1035 | static void vmbus_event_dpc(unsigned long data) |
| 1036 | { |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 1037 | /* Call to bus driver to handle interrupt */ |
Haiyang Zhang | c697767 | 2011-01-26 12:12:08 -0800 | [diff] [blame] | 1038 | vmbus_on_event(); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1039 | } |
| 1040 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 1041 | static irqreturn_t vmbus_isr(int irq, void *dev_id) |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1042 | { |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 1043 | struct hv_driver *driver = &vmbus_drv.drv_obj; |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 1044 | int ret; |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1045 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 1046 | /* Call to bus driver to handle interrupt */ |
Greg Kroah-Hartman | a69a669 | 2010-12-02 09:42:18 -0800 | [diff] [blame] | 1047 | ret = vmbus_on_isr(driver); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1048 | |
Bill Pemberton | 454f18a | 2009-07-27 16:47:24 -0400 | [diff] [blame] | 1049 | /* Schedules a dpc if necessary */ |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 1050 | if (ret > 0) { |
| 1051 | if (test_bit(0, (unsigned long *)&ret)) |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 1052 | tasklet_schedule(&vmbus_drv.msg_dpc); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1053 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 1054 | if (test_bit(1, (unsigned long *)&ret)) |
Haiyang Zhang | adf874c | 2011-01-26 12:12:09 -0800 | [diff] [blame] | 1055 | tasklet_schedule(&vmbus_drv.event_dpc); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1056 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1057 | return IRQ_HANDLED; |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 1058 | } else { |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1059 | return IRQ_NONE; |
| 1060 | } |
| 1061 | } |
| 1062 | |
Greg Kroah-Hartman | c22090f | 2010-02-25 16:43:15 -0800 | [diff] [blame] | 1063 | static struct dmi_system_id __initdata microsoft_hv_dmi_table[] = { |
| 1064 | { |
| 1065 | .ident = "Hyper-V", |
| 1066 | .matches = { |
| 1067 | DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), |
| 1068 | DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"), |
| 1069 | DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"), |
| 1070 | }, |
| 1071 | }, |
| 1072 | { }, |
| 1073 | }; |
| 1074 | MODULE_DEVICE_TABLE(dmi, microsoft_hv_dmi_table); |
| 1075 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1076 | static int __init vmbus_init(void) |
| 1077 | { |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1078 | DPRINT_INFO(VMBUS_DRV, |
| 1079 | "Vmbus initializing.... current log level 0x%x (%x,%x)", |
| 1080 | vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel)); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 1081 | /* Todo: it is used for loglevel, to be ported to new kernel. */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1082 | |
Greg Kroah-Hartman | c22090f | 2010-02-25 16:43:15 -0800 | [diff] [blame] | 1083 | if (!dmi_check_system(microsoft_hv_dmi_table)) |
| 1084 | return -ENODEV; |
| 1085 | |
Greg Kroah-Hartman | 6c88455 | 2010-12-02 12:04:00 -0800 | [diff] [blame] | 1086 | return vmbus_bus_init(); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1087 | } |
| 1088 | |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1089 | static void __exit vmbus_exit(void) |
| 1090 | { |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1091 | vmbus_bus_exit(); |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 1092 | /* Todo: it is used for loglevel, to be ported to new kernel. */ |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1093 | } |
| 1094 | |
Greg Kroah-Hartman | 9a775db | 2010-02-25 16:42:10 -0800 | [diff] [blame] | 1095 | /* |
| 1096 | * We use a PCI table to determine if we should autoload this driver This is |
| 1097 | * needed by distro tools to determine if the hyperv drivers should be |
| 1098 | * installed and/or configured. We don't do anything else with the table, but |
| 1099 | * it needs to be present. |
Greg Kroah-Hartman | 9a775db | 2010-02-25 16:42:10 -0800 | [diff] [blame] | 1100 | */ |
Tobias Klauser | 15f0beb | 2010-05-20 10:39:38 +0200 | [diff] [blame] | 1101 | static const struct pci_device_id microsoft_hv_pci_table[] = { |
Greg Kroah-Hartman | 9a775db | 2010-02-25 16:42:10 -0800 | [diff] [blame] | 1102 | { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */ |
| 1103 | { 0 } |
| 1104 | }; |
| 1105 | MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table); |
| 1106 | |
Greg Kroah-Hartman | 90c9960 | 2009-09-02 07:11:14 -0700 | [diff] [blame] | 1107 | MODULE_LICENSE("GPL"); |
Hank Janssen | 26c14cc | 2010-02-11 23:02:42 +0000 | [diff] [blame] | 1108 | MODULE_VERSION(HV_DRV_VERSION); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1109 | module_param(vmbus_irq, int, S_IRUGO); |
| 1110 | module_param(vmbus_loglevel, int, S_IRUGO); |
Hank Janssen | 3e7ee49 | 2009-07-13 16:02:34 -0700 | [diff] [blame] | 1111 | |
| 1112 | module_init(vmbus_init); |
| 1113 | module_exit(vmbus_exit); |