blob: 819366221524fce68ec98d668fc3d273a8e926a6 [file] [log] [blame]
Hank Janssen3e7ee492009-07-13 16:02:34 -07001/*
Hank Janssen3e7ee492009-07-13 16:02:34 -07002 * 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 Janssen3e7ee492009-07-13 16:02:34 -070020 */
Hank Janssen3e7ee492009-07-13 16:02:34 -070021#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-Hartman9a775db2010-02-25 16:42:10 -080027#include <linux/pci.h>
Greg Kroah-Hartmanc22090f2010-02-25 16:43:15 -080028#include <linux/dmi.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090029#include <linux/slab.h>
Haiyang Zhang8b5d6d32010-05-28 23:22:44 +000030#include <linux/completion.h>
Greg Kroah-Hartman2d82f6c2010-05-05 22:52:28 -070031#include "version_info.h"
K. Y. Srinivasane3fe0bb2011-02-11 10:00:12 -080032#include "hv_api.h"
Greg Kroah-Hartman645954c2009-08-28 16:22:59 -070033#include "logging.h"
Greg Kroah-Hartman870cde82009-08-19 16:21:28 -070034#include "vmbus.h"
Greg Kroah-Hartman150b19d2010-10-20 16:07:11 -070035#include "channel.h"
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -080036#include "vmbus_private.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070037
Hank Janssen3e7ee492009-07-13 16:02:34 -070038
Bill Pemberton454f18a2009-07-27 16:47:24 -040039/* FIXME! We need to do this dynamically for PIC and APIC system */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070040#define VMBUS_IRQ 0x5
41#define VMBUS_IRQ_VECTOR IRQ5_VECTOR
Bill Pemberton454f18a2009-07-27 16:47:24 -040042
43/* Main vmbus driver data structure */
Hank Janssen3e7ee492009-07-13 16:02:34 -070044struct vmbus_driver_context {
Greg Kroah-Hartmana69a6692010-12-02 09:42:18 -080045 struct hv_driver drv_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -070046
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070047 struct bus_type bus;
48 struct tasklet_struct msg_dpc;
49 struct tasklet_struct event_dpc;
Hank Janssen3e7ee492009-07-13 16:02:34 -070050
Bill Pemberton454f18a2009-07-27 16:47:24 -040051 /* The bus root device */
Haiyang Zhangf916a342010-02-17 20:58:47 +000052 struct vm_device device_ctx;
Hank Janssen3e7ee492009-07-13 16:02:34 -070053};
54
Hank Janssen3e7ee492009-07-13 16:02:34 -070055static int vmbus_match(struct device *device, struct device_driver *driver);
56static int vmbus_probe(struct device *device);
57static int vmbus_remove(struct device *device);
58static void vmbus_shutdown(struct device *device);
Hank Janssen3e7ee492009-07-13 16:02:34 -070059static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env);
Hank Janssen3e7ee492009-07-13 16:02:34 -070060static void vmbus_msg_dpc(unsigned long data);
61static void vmbus_event_dpc(unsigned long data);
62
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070063static irqreturn_t vmbus_isr(int irq, void *dev_id);
Hank Janssen3e7ee492009-07-13 16:02:34 -070064
65static void vmbus_device_release(struct device *device);
66static void vmbus_bus_release(struct device *device);
67
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070068static ssize_t vmbus_show_device_attr(struct device *dev,
69 struct device_attribute *dev_attr,
70 char *buf);
Hank Janssen3e7ee492009-07-13 16:02:34 -070071
Hank Janssen3e7ee492009-07-13 16:02:34 -070072
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070073unsigned int vmbus_loglevel = (ALL_MODULES << 16 | INFO_LVL);
Hank Janssen3e7ee492009-07-13 16:02:34 -070074EXPORT_SYMBOL(vmbus_loglevel);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070075 /* (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT); */
76 /* (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT); */
Hank Janssen3e7ee492009-07-13 16:02:34 -070077
78static int vmbus_irq = VMBUS_IRQ;
79
Bill Pemberton454f18a2009-07-27 16:47:24 -040080/* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */
Hank Janssen3e7ee492009-07-13 16:02:34 -070081static 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 Janssen3e7ee492009-07-13 16:02:34 -0700109
Bill Pemberton454f18a2009-07-27 16:47:24 -0400110/* The one and only one */
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800111static struct vmbus_driver_context vmbus_drv = {
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700112 .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 Janssen3e7ee492009-07-13 16:02:34 -0700119};
120
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800121static const char *driver_name = "hyperv";
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800122
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 Zhangadf874c2011-01-26 12:12:09 -0800128static const struct hv_guid device_type = {
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800129 .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 Zhangadf874c2011-01-26 12:12:09 -0800136static const struct hv_guid device_id = {
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800137 .data = {
138 0xfc, 0x60, 0x37, 0xac, 0xdf, 0x9a, 0xaa, 0x40,
139 0x94, 0x27, 0xa7, 0x0e, 0xd6, 0xde, 0x95, 0xc5
140 }
141};
142
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800143static struct hv_device *vmbus_device; /* vmbus root device */
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800144
145/*
Haiyang Zhang646f1ea2011-01-26 12:12:10 -0800146 * vmbus_child_dev_add - Registers the child device with the vmbus
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800147 */
Haiyang Zhang646f1ea2011-01-26 12:12:10 -0800148int vmbus_child_dev_add(struct hv_device *child_dev)
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800149{
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800150 return vmbus_child_device_register(vmbus_device, child_dev);
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800151}
152
153/*
Haiyang Zhang646f1ea2011-01-26 12:12:10 -0800154 * vmbus_dev_add - Callback when the root bus device is added
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800155 */
Haiyang Zhang646f1ea2011-01-26 12:12:10 -0800156static int vmbus_dev_add(struct hv_device *dev, void *info)
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800157{
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800158 u32 *irqvector = info;
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800159 int ret;
160
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800161 vmbus_device = dev;
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800162
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800163 memcpy(&vmbus_device->dev_type, &device_type, sizeof(struct hv_guid));
164 memcpy(&vmbus_device->dev_instance, &device_id,
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800165 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 Zhangc6977672011-01-26 12:12:08 -0800172 ret = vmbus_connect();
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800173
174 /* VmbusSendEvent(device->localPortId+1); */
175 return ret;
176}
177
178/*
Haiyang Zhang646f1ea2011-01-26 12:12:10 -0800179 * vmbus_dev_rm - Callback when the root bus device is removed
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800180 */
Haiyang Zhang646f1ea2011-01-26 12:12:10 -0800181static int vmbus_dev_rm(struct hv_device *dev)
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800182{
183 int ret = 0;
184
185 vmbus_release_unattached_channels();
Haiyang Zhangc6977672011-01-26 12:12:08 -0800186 vmbus_disconnect();
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800187 on_each_cpu(hv_synic_cleanup, NULL, 1);
188 return ret;
189}
190
191/*
Haiyang Zhang646f1ea2011-01-26 12:12:10 -0800192 * vmbus_cleanup - Perform any cleanup when the driver is removed
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800193 */
Haiyang Zhang646f1ea2011-01-26 12:12:10 -0800194static void vmbus_cleanup(struct hv_driver *drv)
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800195{
196 /* struct vmbus_driver *driver = (struct vmbus_driver *)drv; */
197
198 hv_cleanup();
199}
200
Timo Teräsbf6506f2010-12-15 20:48:08 +0200201struct onmessage_work_context {
202 struct work_struct work;
203 struct hv_message msg;
204};
205
206static 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-Hartman36199a92010-12-02 11:59:22 -0800216/*
217 * vmbus_on_msg_dpc - DPC routine to handle messages from the hypervisior
218 */
Greg Kroah-Hartmancef6dbf2010-12-02 12:11:25 -0800219static void vmbus_on_msg_dpc(struct hv_driver *drv)
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800220{
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äsbf6506f2010-12-15 20:48:08 +0200225 struct onmessage_work_context *ctx;
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800226
227 while (1) {
228 if (msg->header.message_type == HVMSG_NONE) {
229 /* no msg */
230 break;
231 } else {
Timo Teräsbf6506f2010-12-15 20:48:08 +0200232 ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
233 if (ctx == NULL)
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800234 continue;
Timo Teräsbf6506f2010-12-15 20:48:08 +0200235 INIT_WORK(&ctx->work, vmbus_onmessage_work);
236 memcpy(&ctx->msg, msg, sizeof(*msg));
Haiyang Zhangda9fcb72011-01-26 12:12:14 -0800237 queue_work(vmbus_connection.work_queue, &ctx->work);
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800238 }
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-Hartman36199a92010-12-02 11:59:22 -0800263 * vmbus_on_isr - ISR routine
264 */
Greg Kroah-Hartmancef6dbf2010-12-02 12:11:25 -0800265static int vmbus_on_isr(struct hv_driver *drv)
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800266{
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-Hartman150b19d2010-10-20 16:07:11 -0700297static 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-Hartmancae5b842010-10-21 09:05:27 -0700302 if (!device->channel)
Greg Kroah-Hartman150b19d2010-10-20 16:07:11 -0700303 return;
304
Greg Kroah-Hartmancae5b842010-10-21 09:05:27 -0700305 vmbus_get_debug_info(device->channel, &debug_info);
Greg Kroah-Hartman150b19d2010-10-20 16:07:11 -0700306
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800307 info->chn_id = debug_info.relid;
308 info->chn_state = debug_info.state;
309 memcpy(&info->chn_type, &debug_info.interfacetype,
Greg Kroah-Hartman150b19d2010-10-20 16:07:11 -0700310 sizeof(struct hv_guid));
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800311 memcpy(&info->chn_instance, &debug_info.interface_instance,
Greg Kroah-Hartman150b19d2010-10-20 16:07:11 -0700312 sizeof(struct hv_guid));
313
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800314 info->monitor_id = debug_info.monitorid;
Greg Kroah-Hartman150b19d2010-10-20 16:07:11 -0700315
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800316 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-Hartman150b19d2010-10-20 16:07:11 -0700319
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800320 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-Hartman150b19d2010-10-20 16:07:11 -0700323
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800324 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 Zhang82f8bd42010-11-08 14:04:45 -0800330 debug_info.inbound.bytes_avail_towrite;
Greg Kroah-Hartman150b19d2010-10-20 16:07:11 -0700331
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800332 info->outbound.int_mask =
Haiyang Zhang82f8bd42010-11-08 14:04:45 -0800333 debug_info.outbound.current_interrupt_mask;
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800334 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 Zhang82f8bd42010-11-08 14:04:45 -0800337 debug_info.outbound.bytes_avail_toread;
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800338 info->outbound.bytes_avail_towrite =
Haiyang Zhang82f8bd42010-11-08 14:04:45 -0800339 debug_info.outbound.bytes_avail_towrite;
Greg Kroah-Hartman150b19d2010-10-20 16:07:11 -0700340}
341
Hank Janssen3e189512010-03-04 22:11:00 +0000342/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700343 * 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 */
348static ssize_t vmbus_show_device_attr(struct device *dev,
349 struct device_attribute *dev_attr,
350 char *buf)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700351{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000352 struct vm_device *device_ctx = device_to_vm_device(dev);
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700353 struct hv_device_info device_info;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700354
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700355 memset(&device_info, 0, sizeof(struct hv_device_info));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700356
Greg Kroah-Hartmana4e91ed22010-10-20 16:02:49 -0700357 get_channel_info(&device_ctx->device_obj, &device_info);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700358
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700359 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 Zhangca623ad2011-01-26 12:12:11 -0800362 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-Hartman90c99602009-09-02 07:11:14 -0700378 } 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 Zhangca623ad2011-01-26 12:12:11 -0800381 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-Hartman90c99602009-09-02 07:11:14 -0700397 } else if (!strcmp(dev_attr->attr.name, "state")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800398 return sprintf(buf, "%d\n", device_info.chn_state);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700399 } else if (!strcmp(dev_attr->attr.name, "id")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800400 return sprintf(buf, "%d\n", device_info.chn_id);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700401 } else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800402 return sprintf(buf, "%d\n", device_info.outbound.int_mask);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700403 } else if (!strcmp(dev_attr->attr.name, "out_read_index")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800404 return sprintf(buf, "%d\n", device_info.outbound.read_idx);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700405 } else if (!strcmp(dev_attr->attr.name, "out_write_index")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800406 return sprintf(buf, "%d\n", device_info.outbound.write_idx);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700407 } else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) {
408 return sprintf(buf, "%d\n",
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800409 device_info.outbound.bytes_avail_toread);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700410 } else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) {
411 return sprintf(buf, "%d\n",
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800412 device_info.outbound.bytes_avail_towrite);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700413 } else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800414 return sprintf(buf, "%d\n", device_info.inbound.int_mask);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700415 } else if (!strcmp(dev_attr->attr.name, "in_read_index")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800416 return sprintf(buf, "%d\n", device_info.inbound.read_idx);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700417 } else if (!strcmp(dev_attr->attr.name, "in_write_index")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800418 return sprintf(buf, "%d\n", device_info.inbound.write_idx);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700419 } else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) {
420 return sprintf(buf, "%d\n",
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800421 device_info.inbound.bytes_avail_toread);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700422 } else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) {
423 return sprintf(buf, "%d\n",
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800424 device_info.inbound.bytes_avail_towrite);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700425 } else if (!strcmp(dev_attr->attr.name, "monitor_id")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800426 return sprintf(buf, "%d\n", device_info.monitor_id);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700427 } else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800428 return sprintf(buf, "%d\n", device_info.server_monitor_pending);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700429 } else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800430 return sprintf(buf, "%d\n", device_info.server_monitor_latency);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700431 } else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) {
432 return sprintf(buf, "%d\n",
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800433 device_info.server_monitor_conn_id);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700434 } else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800435 return sprintf(buf, "%d\n", device_info.client_monitor_pending);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700436 } else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) {
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800437 return sprintf(buf, "%d\n", device_info.client_monitor_latency);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700438 } else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) {
439 return sprintf(buf, "%d\n",
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800440 device_info.client_monitor_conn_id);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700441 } else {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700442 return 0;
443 }
444}
445
Hank Janssen3e189512010-03-04 22:11:00 +0000446/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700447 * vmbus_bus_init -Main vmbus driver initialization routine.
448 *
449 * Here, we
Lars Lindley0686e4f2010-03-11 23:51:23 +0100450 * - 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-Hartman90c99602009-09-02 07:11:14 -0700457 */
Greg Kroah-Hartman6c884552010-12-02 12:04:00 -0800458static int vmbus_bus_init(void)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700459{
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800460 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-Hartman90c99602009-09-02 07:11:14 -0700463 int ret;
464 unsigned int vector;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700465
Greg Kroah-Hartman6d26e38fa22010-12-02 12:08:08 -0800466 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 Zhangadf874c2011-01-26 12:12:09 -0800477 driver->name = driver_name;
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800478 memcpy(&driver->dev_type, &device_type, sizeof(struct hv_guid));
Greg Kroah-Hartman6d26e38fa22010-12-02 12:08:08 -0800479
480 /* Setup dispatch table */
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800481 driver->dev_add = vmbus_dev_add;
482 driver->dev_rm = vmbus_dev_rm;
483 driver->cleanup = vmbus_cleanup;
Greg Kroah-Hartman6d26e38fa22010-12-02 12:08:08 -0800484
485 /* Hypervisor initialization...setup hypercall page..etc */
486 ret = hv_init();
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700487 if (ret != 0) {
Greg Kroah-Hartman6d26e38fa22010-12-02 12:08:08 -0800488 DPRINT_ERR(VMBUS, "Unable to initialize the hypervisor - 0x%x",
489 ret);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700490 goto cleanup;
491 }
492
Bill Pemberton454f18a2009-07-27 16:47:24 -0400493 /* Sanity checks */
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800494 if (!driver->dev_add) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700495 DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set");
496 ret = -1;
497 goto cleanup;
498 }
499
Greg Kroah-Hartmana69a6692010-12-02 09:42:18 -0800500 vmbus_drv_ctx->bus.name = driver->name;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700501
Bill Pemberton454f18a2009-07-27 16:47:24 -0400502 /* Initialize the bus context */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700503 tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc,
Greg Kroah-Hartmana69a6692010-12-02 09:42:18 -0800504 (unsigned long)driver);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700505 tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc,
Greg Kroah-Hartmana69a6692010-12-02 09:42:18 -0800506 (unsigned long)driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700507
Bill Pemberton454f18a2009-07-27 16:47:24 -0400508 /* Now, register the bus driver with LDM */
Bill Pembertonc19fbca2009-07-27 16:47:35 -0400509 ret = bus_register(&vmbus_drv_ctx->bus);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700510 if (ret) {
Bill Pembertonc19fbca2009-07-27 16:47:35 -0400511 ret = -1;
512 goto cleanup;
513 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700514
Bill Pemberton454f18a2009-07-27 16:47:24 -0400515 /* Get the interrupt resource */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700516 ret = request_irq(vmbus_irq, vmbus_isr, IRQF_SAMPLE_RANDOM,
Greg Kroah-Hartmana69a6692010-12-02 09:42:18 -0800517 driver->name, NULL);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700518
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700519 if (ret != 0) {
520 DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d",
521 vmbus_irq);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700522
523 bus_unregister(&vmbus_drv_ctx->bus);
524
525 ret = -1;
526 goto cleanup;
527 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700528 vector = VMBUS_IRQ_VECTOR;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700529
530 DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector);
531
Bill Pemberton454f18a2009-07-27 16:47:24 -0400532 /* Call to bus driver to add the root device */
Haiyang Zhangf916a342010-02-17 20:58:47 +0000533 memset(dev_ctx, 0, sizeof(struct vm_device));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700534
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800535 ret = driver->dev_add(&dev_ctx->device_obj, &vector);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700536 if (ret != 0) {
537 DPRINT_ERR(VMBUS_DRV,
538 "ERROR - Unable to add vmbus root device");
Hank Janssen3e7ee492009-07-13 16:02:34 -0700539
540 free_irq(vmbus_irq, NULL);
541
542 bus_unregister(&vmbus_drv_ctx->bus);
543
544 ret = -1;
545 goto cleanup;
546 }
Bill Pemberton454f18a2009-07-27 16:47:24 -0400547 /* strcpy(dev_ctx->device.bus_id, dev_ctx->device_obj.name); */
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -0700548 dev_set_name(&dev_ctx->device, "vmbus_0_0");
Hank Janssen3e7ee492009-07-13 16:02:34 -0700549
Bill Pemberton454f18a2009-07-27 16:47:24 -0400550 /* No need to bind a driver to the root device. */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700551 dev_ctx->device.parent = NULL;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700552 /* NULL; vmbus_remove() does not get invoked */
553 dev_ctx->device.bus = &vmbus_drv_ctx->bus;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700554
Bill Pemberton454f18a2009-07-27 16:47:24 -0400555 /* Setup the device dispatch table */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700556 dev_ctx->device.release = vmbus_bus_release;
557
Bill Pemberton454f18a2009-07-27 16:47:24 -0400558 /* Setup the bus as root device */
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400559 ret = device_register(&dev_ctx->device);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700560 if (ret) {
561 DPRINT_ERR(VMBUS_DRV,
562 "ERROR - Unable to register vmbus root device");
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400563
564 free_irq(vmbus_irq, NULL);
565 bus_unregister(&vmbus_drv_ctx->bus);
566
567 ret = -1;
568 goto cleanup;
569 }
570
Greg Kroah-Hartman2d6e8822010-12-02 08:50:58 -0800571 vmbus_request_offers();
Haiyang Zhang8b5d6d32010-05-28 23:22:44 +0000572 wait_for_completion(&hv_channel_ready);
573
Hank Janssen3e7ee492009-07-13 16:02:34 -0700574cleanup:
Hank Janssen3e7ee492009-07-13 16:02:34 -0700575 return ret;
576}
577
Hank Janssen3e189512010-03-04 22:11:00 +0000578/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700579 * vmbus_bus_exit - Terminate the vmbus driver.
580 *
581 * This routine is opposite of vmbus_bus_init()
582 */
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700583static void vmbus_bus_exit(void)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700584{
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800585 struct hv_driver *driver = &vmbus_drv.drv_obj;
586 struct vmbus_driver_context *vmbus_drv_ctx = &vmbus_drv;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700587
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800588 struct vm_device *dev_ctx = &vmbus_drv.device_ctx;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700589
Bill Pemberton454f18a2009-07-27 16:47:24 -0400590 /* Remove the root device */
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800591 if (driver->dev_rm)
592 driver->dev_rm(&dev_ctx->device_obj);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700593
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800594 if (driver->cleanup)
595 driver->cleanup(driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700596
Bill Pemberton454f18a2009-07-27 16:47:24 -0400597 /* Unregister the root bus device */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700598 device_unregister(&dev_ctx->device);
599
600 bus_unregister(&vmbus_drv_ctx->bus);
601
602 free_irq(vmbus_irq, NULL);
603
604 tasklet_kill(&vmbus_drv_ctx->msg_dpc);
605 tasklet_kill(&vmbus_drv_ctx->event_dpc);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700606}
607
Hank Janssen3e189512010-03-04 22:11:00 +0000608
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700609/**
Hank Janssen3e189512010-03-04 22:11:00 +0000610 * vmbus_child_driver_register() - Register a vmbus's child driver
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800611 * @drv: Pointer to driver structure you want to register
Hank Janssen3e189512010-03-04 22:11:00 +0000612 *
Hank Janssen3e189512010-03-04 22:11:00 +0000613 *
614 * Registers the given driver with Linux through the 'driver_register()' call
615 * And sets up the hyper-v vmbus handling for this driver.
616 * It will return the state of the 'driver_register()' call.
617 *
618 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700619 */
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800620int vmbus_child_driver_register(struct device_driver *drv)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700621{
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400622 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700623
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700624 DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s",
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800625 drv, drv->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700626
Bill Pemberton454f18a2009-07-27 16:47:24 -0400627 /* The child driver on this vmbus */
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800628 drv->bus = &vmbus_drv.bus;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700629
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800630 ret = driver_register(drv);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700631
Greg Kroah-Hartman2d6e8822010-12-02 08:50:58 -0800632 vmbus_request_offers();
Hank Janssen3e7ee492009-07-13 16:02:34 -0700633
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400634 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700635}
Hank Janssen3e7ee492009-07-13 16:02:34 -0700636EXPORT_SYMBOL(vmbus_child_driver_register);
637
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700638/**
Hank Janssen3e189512010-03-04 22:11:00 +0000639 * vmbus_child_driver_unregister() - Unregister a vmbus's child driver
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800640 * @drv: Pointer to driver structure you want to un-register
Hank Janssen3e189512010-03-04 22:11:00 +0000641 *
Hank Janssen3e189512010-03-04 22:11:00 +0000642 *
643 * Un-register the given driver with Linux through the 'driver_unregister()'
644 * call. And ungegisters the driver from the Hyper-V vmbus handler.
645 *
646 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700647 */
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800648void vmbus_child_driver_unregister(struct device_driver *drv)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700649{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700650 DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s",
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800651 drv, drv->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700652
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800653 driver_unregister(drv);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700654
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800655 drv->bus = NULL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700656}
Hank Janssen3e7ee492009-07-13 16:02:34 -0700657EXPORT_SYMBOL(vmbus_child_driver_unregister);
658
Hank Janssen3e189512010-03-04 22:11:00 +0000659/*
Hank Janssen3e189512010-03-04 22:11:00 +0000660 * vmbus_child_device_create - Creates and registers a new child device
661 * on the vmbus.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700662 */
Greg Kroah-Hartman89733aa2010-12-02 08:22:41 -0800663struct hv_device *vmbus_child_device_create(struct hv_guid *type,
664 struct hv_guid *instance,
665 struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700666{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000667 struct vm_device *child_device_ctx;
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200668 struct hv_device *child_device_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700669
Bill Pemberton454f18a2009-07-27 16:47:24 -0400670 /* Allocate the new child device */
Haiyang Zhangf916a342010-02-17 20:58:47 +0000671 child_device_ctx = kzalloc(sizeof(struct vm_device), GFP_KERNEL);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700672 if (!child_device_ctx) {
673 DPRINT_ERR(VMBUS_DRV,
674 "unable to allocate device_context for child device");
Hank Janssen3e7ee492009-07-13 16:02:34 -0700675 return NULL;
676 }
677
678 DPRINT_DBG(VMBUS_DRV, "child device (%p) allocated - "
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700679 "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
680 "%02x%02x%02x%02x%02x%02x%02x%02x},"
681 "id {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
682 "%02x%02x%02x%02x%02x%02x%02x%02x}",
Hank Janssen3e7ee492009-07-13 16:02:34 -0700683 &child_device_ctx->device,
Greg Kroah-Hartmandaaa8cc2009-08-19 16:18:56 -0700684 type->data[3], type->data[2], type->data[1], type->data[0],
685 type->data[5], type->data[4], type->data[7], type->data[6],
686 type->data[8], type->data[9], type->data[10], type->data[11],
687 type->data[12], type->data[13], type->data[14], type->data[15],
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700688 instance->data[3], instance->data[2],
689 instance->data[1], instance->data[0],
690 instance->data[5], instance->data[4],
691 instance->data[7], instance->data[6],
692 instance->data[8], instance->data[9],
693 instance->data[10], instance->data[11],
694 instance->data[12], instance->data[13],
695 instance->data[14], instance->data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700696
697 child_device_obj = &child_device_ctx->device_obj;
Greg Kroah-Hartmancae5b842010-10-21 09:05:27 -0700698 child_device_obj->channel = channel;
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800699 memcpy(&child_device_obj->dev_type, type, sizeof(struct hv_guid));
700 memcpy(&child_device_obj->dev_instance, instance,
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700701 sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700702
Hank Janssen3e7ee492009-07-13 16:02:34 -0700703
Hank Janssen3e7ee492009-07-13 16:02:34 -0700704 return child_device_obj;
705}
706
Hank Janssen3e189512010-03-04 22:11:00 +0000707/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700708 * vmbus_child_device_register - Register the child device on the specified bus
709 */
Greg Kroah-Hartman98293a22010-12-02 09:16:04 -0800710int vmbus_child_device_register(struct hv_device *root_device_obj,
711 struct hv_device *child_device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700712{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700713 int ret = 0;
Haiyang Zhangf916a342010-02-17 20:58:47 +0000714 struct vm_device *root_device_ctx =
715 to_vm_device(root_device_obj);
716 struct vm_device *child_device_ctx =
717 to_vm_device(child_device_obj);
Bill Pembertonf4888412009-07-29 17:00:12 -0400718 static atomic_t device_num = ATOMIC_INIT(0);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700719
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700720 DPRINT_DBG(VMBUS_DRV, "child device (%p) registering",
721 child_device_ctx);
Bill Pemberton454f18a2009-07-27 16:47:24 -0400722
Haiyang Zhang1bb40a22009-10-23 18:14:24 +0000723 /* Set the device name. Otherwise, device_register() will fail. */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700724 dev_set_name(&child_device_ctx->device, "vmbus_0_%d",
725 atomic_inc_return(&device_num));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700726
Bill Pemberton454f18a2009-07-27 16:47:24 -0400727 /* The new device belongs to this bus */
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800728 child_device_ctx->device.bus = &vmbus_drv.bus; /* device->dev.bus; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700729 child_device_ctx->device.parent = &root_device_ctx->device;
730 child_device_ctx->device.release = vmbus_device_release;
731
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700732 /*
733 * Register with the LDM. This will kick off the driver/device
734 * binding...which will eventually call vmbus_match() and vmbus_probe()
735 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700736 ret = device_register(&child_device_ctx->device);
737
Bill Pemberton454f18a2009-07-27 16:47:24 -0400738 /* vmbus_probe() error does not get propergate to device_register(). */
K. Y. Srinivasan70b0af42011-03-07 13:34:48 -0800739 ret = child_device_ctx->device_obj.probe_error;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700740
741 if (ret)
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700742 DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p)",
743 &child_device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700744 else
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700745 DPRINT_INFO(VMBUS_DRV, "child device (%p) registered",
746 &child_device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700747
Hank Janssen3e7ee492009-07-13 16:02:34 -0700748 return ret;
749}
750
Hank Janssen3e189512010-03-04 22:11:00 +0000751/*
752 * vmbus_child_device_unregister - Remove the specified child device
753 * from the vmbus.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700754 */
Greg Kroah-Hartman9d8bd712010-12-02 08:34:45 -0800755void vmbus_child_device_unregister(struct hv_device *device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700756{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000757 struct vm_device *device_ctx = to_vm_device(device_obj);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700758
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700759 DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)",
760 &device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700761
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700762 /*
763 * Kick off the process of unregistering the device.
764 * This will call vmbus_remove() and eventually vmbus_device_release()
765 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700766 device_unregister(&device_ctx->device);
767
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700768 DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered",
769 &device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700770}
771
Hank Janssen3e189512010-03-04 22:11:00 +0000772/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700773 * vmbus_uevent - add uevent for our device
774 *
775 * This routine is invoked when a device is added or removed on the vmbus to
776 * generate a uevent to udev in the userspace. The udev will then look at its
777 * rule and the uevent generated here to load the appropriate driver
778 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700779static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
780{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000781 struct vm_device *device_ctx = device_to_vm_device(device);
K. Y. Srinivasan65c22792011-03-07 13:35:10 -0800782 struct hv_device *dev = &device_ctx->device_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700783 int ret;
784
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700785 DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={"
786 "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
787 "%02x%02x%02x%02x%02x%02x%02x%02x}",
K. Y. Srinivasan65c22792011-03-07 13:35:10 -0800788 dev->dev_type.data[3], dev->dev_type.data[2],
789 dev->dev_type.data[1], dev->dev_type.data[0],
790 dev->dev_type.data[5], dev->dev_type.data[4],
791 dev->dev_type.data[7], dev->dev_type.data[6],
792 dev->dev_type.data[8], dev->dev_type.data[9],
793 dev->dev_type.data[10],
794 dev->dev_type.data[11],
795 dev->dev_type.data[12],
796 dev->dev_type.data[13],
797 dev->dev_type.data[14],
798 dev->dev_type.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700799
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700800 ret = add_uevent_var(env, "VMBUS_DEVICE_CLASS_GUID={"
801 "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
802 "%02x%02x%02x%02x%02x%02x%02x%02x}",
K. Y. Srinivasan65c22792011-03-07 13:35:10 -0800803 dev->dev_type.data[3],
804 dev->dev_type.data[2],
805 dev->dev_type.data[1],
806 dev->dev_type.data[0],
807 dev->dev_type.data[5],
808 dev->dev_type.data[4],
809 dev->dev_type.data[7],
810 dev->dev_type.data[6],
811 dev->dev_type.data[8],
812 dev->dev_type.data[9],
813 dev->dev_type.data[10],
814 dev->dev_type.data[11],
815 dev->dev_type.data[12],
816 dev->dev_type.data[13],
817 dev->dev_type.data[14],
818 dev->dev_type.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700819
820 if (ret)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700821 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700822
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700823 ret = add_uevent_var(env, "VMBUS_DEVICE_DEVICE_GUID={"
824 "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
825 "%02x%02x%02x%02x%02x%02x%02x%02x}",
K. Y. Srinivasand5889772011-03-07 13:35:30 -0800826 dev->dev_instance.data[3],
827 dev->dev_instance.data[2],
828 dev->dev_instance.data[1],
829 dev->dev_instance.data[0],
830 dev->dev_instance.data[5],
831 dev->dev_instance.data[4],
832 dev->dev_instance.data[7],
833 dev->dev_instance.data[6],
834 dev->dev_instance.data[8],
835 dev->dev_instance.data[9],
836 dev->dev_instance.data[10],
837 dev->dev_instance.data[11],
838 dev->dev_instance.data[12],
839 dev->dev_instance.data[13],
840 dev->dev_instance.data[14],
841 dev->dev_instance.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700842 if (ret)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700843 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700844
Hank Janssen3e7ee492009-07-13 16:02:34 -0700845 return 0;
846}
847
Hank Janssen3e189512010-03-04 22:11:00 +0000848/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700849 * vmbus_match - Attempt to match the specified device to the specified driver
850 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700851static int vmbus_match(struct device *device, struct device_driver *driver)
852{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700853 int match = 0;
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800854 struct hv_driver *drv = drv_to_hv_drv(driver);
Haiyang Zhangf916a342010-02-17 20:58:47 +0000855 struct vm_device *device_ctx = device_to_vm_device(device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700856
Bill Pemberton454f18a2009-07-27 16:47:24 -0400857 /* We found our driver ? */
K. Y. Srinivasan65c22792011-03-07 13:35:10 -0800858 if (memcmp(&device_ctx->device_obj.dev_type, &drv->dev_type,
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700859 sizeof(struct hv_guid)) == 0) {
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700860
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800861 device_ctx->device_obj.drv = drv->priv;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700862 DPRINT_INFO(VMBUS_DRV,
863 "device object (%p) set to driver object (%p)",
864 &device_ctx->device_obj,
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800865 device_ctx->device_obj.drv);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700866
867 match = 1;
868 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700869 return match;
870}
871
Hank Janssen3e189512010-03-04 22:11:00 +0000872/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700873 * vmbus_probe_failed_cb - Callback when a driver probe failed in vmbus_probe()
874 *
875 * We need a callback because we cannot invoked device_unregister() inside
876 * vmbus_probe() since vmbus_probe() may be invoked inside device_register()
877 * i.e. we cannot call device_unregister() inside device_register()
878 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700879static void vmbus_probe_failed_cb(struct work_struct *context)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700880{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000881 struct vm_device *device_ctx = (struct vm_device *)context;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700882
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700883 /*
884 * Kick off the process of unregistering the device.
885 * This will call vmbus_remove() and eventually vmbus_device_release()
886 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700887 device_unregister(&device_ctx->device);
888
Bill Pemberton454f18a2009-07-27 16:47:24 -0400889 /* put_device(&device_ctx->device); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700890}
891
Hank Janssen3e189512010-03-04 22:11:00 +0000892/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700893 * vmbus_probe - Add the new vmbus's child device
894 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700895static int vmbus_probe(struct device *child_device)
896{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700897 int ret = 0;
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800898 struct hv_driver *drv =
899 drv_to_hv_drv(child_device->driver);
Haiyang Zhangf916a342010-02-17 20:58:47 +0000900 struct vm_device *device_ctx =
901 device_to_vm_device(child_device);
K. Y. Srinivasana3c7fe92011-03-07 13:34:27 -0800902 struct hv_device *dev = &device_ctx->device_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700903
Bill Pemberton454f18a2009-07-27 16:47:24 -0400904 /* Let the specific open-source driver handles the probe if it can */
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800905 if (drv->driver.probe) {
K. Y. Srinivasan70b0af42011-03-07 13:34:48 -0800906 ret = device_ctx->device_obj.probe_error =
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800907 drv->driver.probe(child_device);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700908 if (ret != 0) {
909 DPRINT_ERR(VMBUS_DRV, "probe() failed for device %s "
910 "(%p) on driver %s (%d)...",
911 dev_name(child_device), child_device,
912 child_device->driver->name, ret);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700913
K. Y. Srinivasana3c7fe92011-03-07 13:34:27 -0800914 INIT_WORK(&dev->probe_failed_work_item,
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700915 vmbus_probe_failed_cb);
K. Y. Srinivasana3c7fe92011-03-07 13:34:27 -0800916 schedule_work(&dev->probe_failed_work_item);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700917 }
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700918 } else {
919 DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s",
920 child_device->driver->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700921 ret = -1;
922 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700923 return ret;
924}
925
Hank Janssen3e189512010-03-04 22:11:00 +0000926/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700927 * vmbus_remove - Remove a vmbus device
928 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700929static int vmbus_remove(struct device *child_device)
930{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700931 int ret;
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800932 struct hv_driver *drv;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700933
Bill Pemberton454f18a2009-07-27 16:47:24 -0400934 /* Special case root bus device */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700935 if (child_device->parent == NULL) {
936 /*
937 * No-op since it is statically defined and handle in
938 * vmbus_bus_exit()
939 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700940 return 0;
941 }
942
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700943 if (child_device->driver) {
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800944 drv = drv_to_hv_drv(child_device->driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700945
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700946 /*
947 * Let the specific open-source driver handles the removal if
948 * it can
949 */
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800950 if (drv->driver.remove) {
951 ret = drv->driver.remove(child_device);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700952 } else {
953 DPRINT_ERR(VMBUS_DRV,
954 "remove() method not set for driver - %s",
955 child_device->driver->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700956 ret = -1;
957 }
958 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700959
Hank Janssen3e7ee492009-07-13 16:02:34 -0700960 return 0;
961}
962
Hank Janssen3e189512010-03-04 22:11:00 +0000963/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700964 * vmbus_shutdown - Shutdown a vmbus device
965 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700966static void vmbus_shutdown(struct device *child_device)
967{
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800968 struct hv_driver *drv;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700969
Bill Pemberton454f18a2009-07-27 16:47:24 -0400970 /* Special case root bus device */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700971 if (child_device->parent == NULL) {
972 /*
973 * No-op since it is statically defined and handle in
974 * vmbus_bus_exit()
975 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700976 return;
977 }
978
Bill Pemberton454f18a2009-07-27 16:47:24 -0400979 /* The device may not be attached yet */
Greg Kroah-Hartman83c720e2010-07-22 15:14:04 -0700980 if (!child_device->driver)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700981 return;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700982
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800983 drv = drv_to_hv_drv(child_device->driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700984
Bill Pemberton454f18a2009-07-27 16:47:24 -0400985 /* Let the specific open-source driver handles the removal if it can */
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800986 if (drv->driver.shutdown)
987 drv->driver.shutdown(child_device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700988
Hank Janssen3e7ee492009-07-13 16:02:34 -0700989 return;
990}
991
Hank Janssen3e189512010-03-04 22:11:00 +0000992/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700993 * vmbus_bus_release - Final callback release of the vmbus root device
994 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700995static void vmbus_bus_release(struct device *device)
996{
Greg Kroah-Hartman689bf402009-09-01 20:12:58 -0700997 /* FIXME */
998 /* Empty release functions are a bug, or a major sign
999 * of a problem design, this MUST BE FIXED! */
1000 dev_err(device, "%s needs to be fixed!\n", __func__);
1001 WARN_ON(1);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001002}
1003
Hank Janssen3e189512010-03-04 22:11:00 +00001004/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001005 * vmbus_device_release - Final callback release of the vmbus child device
1006 */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001007static void vmbus_device_release(struct device *device)
1008{
Haiyang Zhangf916a342010-02-17 20:58:47 +00001009 struct vm_device *device_ctx = device_to_vm_device(device);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001010
Hank Janssen3e7ee492009-07-13 16:02:34 -07001011 kfree(device_ctx);
1012
Bill Pemberton454f18a2009-07-27 16:47:24 -04001013 /* !!DO NOT REFERENCE device_ctx anymore at this point!! */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001014}
1015
Hank Janssen3e189512010-03-04 22:11:00 +00001016/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001017 * vmbus_msg_dpc - Tasklet routine to handle hypervisor messages
1018 */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001019static void vmbus_msg_dpc(unsigned long data)
1020{
Greg Kroah-Hartmana69a6692010-12-02 09:42:18 -08001021 struct hv_driver *driver = (struct hv_driver *)data;
Hank Janssen3e7ee492009-07-13 16:02:34 -07001022
Bill Pemberton454f18a2009-07-27 16:47:24 -04001023 /* Call to bus driver to handle interrupt */
Greg Kroah-Hartmana69a6692010-12-02 09:42:18 -08001024 vmbus_on_msg_dpc(driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001025}
1026
Hank Janssen3e189512010-03-04 22:11:00 +00001027/*
Greg Kroah-Hartman4a1494f2010-12-02 08:44:48 -08001028 * vmbus_event_dpc - Tasklet routine to handle hypervisor events
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001029 */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001030static void vmbus_event_dpc(unsigned long data)
1031{
Bill Pemberton454f18a2009-07-27 16:47:24 -04001032 /* Call to bus driver to handle interrupt */
Haiyang Zhangc6977672011-01-26 12:12:08 -08001033 vmbus_on_event();
Hank Janssen3e7ee492009-07-13 16:02:34 -07001034}
1035
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001036static irqreturn_t vmbus_isr(int irq, void *dev_id)
Hank Janssen3e7ee492009-07-13 16:02:34 -07001037{
Haiyang Zhangadf874c2011-01-26 12:12:09 -08001038 struct hv_driver *driver = &vmbus_drv.drv_obj;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001039 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -07001040
Bill Pemberton454f18a2009-07-27 16:47:24 -04001041 /* Call to bus driver to handle interrupt */
Greg Kroah-Hartmana69a6692010-12-02 09:42:18 -08001042 ret = vmbus_on_isr(driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001043
Bill Pemberton454f18a2009-07-27 16:47:24 -04001044 /* Schedules a dpc if necessary */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001045 if (ret > 0) {
1046 if (test_bit(0, (unsigned long *)&ret))
Haiyang Zhangadf874c2011-01-26 12:12:09 -08001047 tasklet_schedule(&vmbus_drv.msg_dpc);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001048
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001049 if (test_bit(1, (unsigned long *)&ret))
Haiyang Zhangadf874c2011-01-26 12:12:09 -08001050 tasklet_schedule(&vmbus_drv.event_dpc);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001051
Hank Janssen3e7ee492009-07-13 16:02:34 -07001052 return IRQ_HANDLED;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001053 } else {
Hank Janssen3e7ee492009-07-13 16:02:34 -07001054 return IRQ_NONE;
1055 }
1056}
1057
Greg Kroah-Hartmanc22090f2010-02-25 16:43:15 -08001058static struct dmi_system_id __initdata microsoft_hv_dmi_table[] = {
1059 {
1060 .ident = "Hyper-V",
1061 .matches = {
1062 DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
1063 DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
1064 DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
1065 },
1066 },
1067 { },
1068};
1069MODULE_DEVICE_TABLE(dmi, microsoft_hv_dmi_table);
1070
Hank Janssen3e7ee492009-07-13 16:02:34 -07001071static int __init vmbus_init(void)
1072{
Hank Janssen3e7ee492009-07-13 16:02:34 -07001073 DPRINT_INFO(VMBUS_DRV,
1074 "Vmbus initializing.... current log level 0x%x (%x,%x)",
1075 vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel));
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001076 /* Todo: it is used for loglevel, to be ported to new kernel. */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001077
Greg Kroah-Hartmanc22090f2010-02-25 16:43:15 -08001078 if (!dmi_check_system(microsoft_hv_dmi_table))
1079 return -ENODEV;
1080
Greg Kroah-Hartman6c884552010-12-02 12:04:00 -08001081 return vmbus_bus_init();
Hank Janssen3e7ee492009-07-13 16:02:34 -07001082}
1083
Hank Janssen3e7ee492009-07-13 16:02:34 -07001084static void __exit vmbus_exit(void)
1085{
Hank Janssen3e7ee492009-07-13 16:02:34 -07001086 vmbus_bus_exit();
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001087 /* Todo: it is used for loglevel, to be ported to new kernel. */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001088}
1089
Greg Kroah-Hartman9a775db2010-02-25 16:42:10 -08001090/*
1091 * We use a PCI table to determine if we should autoload this driver This is
1092 * needed by distro tools to determine if the hyperv drivers should be
1093 * installed and/or configured. We don't do anything else with the table, but
1094 * it needs to be present.
Greg Kroah-Hartman9a775db2010-02-25 16:42:10 -08001095 */
Tobias Klauser15f0beb2010-05-20 10:39:38 +02001096static const struct pci_device_id microsoft_hv_pci_table[] = {
Greg Kroah-Hartman9a775db2010-02-25 16:42:10 -08001097 { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
1098 { 0 }
1099};
1100MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table);
1101
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001102MODULE_LICENSE("GPL");
Hank Janssen26c14cc2010-02-11 23:02:42 +00001103MODULE_VERSION(HV_DRV_VERSION);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001104module_param(vmbus_irq, int, S_IRUGO);
1105module_param(vmbus_loglevel, int, S_IRUGO);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001106
1107module_init(vmbus_init);
1108module_exit(vmbus_exit);