blob: d9d138d35e01a89b34bf5ebe054abeceee1ebb37 [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");
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800549 memcpy(&dev_ctx->device_id, &dev_ctx->device_obj.dev_instance,
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700550 sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700551
Bill Pemberton454f18a2009-07-27 16:47:24 -0400552 /* No need to bind a driver to the root device. */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700553 dev_ctx->device.parent = NULL;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700554 /* NULL; vmbus_remove() does not get invoked */
555 dev_ctx->device.bus = &vmbus_drv_ctx->bus;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700556
Bill Pemberton454f18a2009-07-27 16:47:24 -0400557 /* Setup the device dispatch table */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700558 dev_ctx->device.release = vmbus_bus_release;
559
Bill Pemberton454f18a2009-07-27 16:47:24 -0400560 /* Setup the bus as root device */
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400561 ret = device_register(&dev_ctx->device);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700562 if (ret) {
563 DPRINT_ERR(VMBUS_DRV,
564 "ERROR - Unable to register vmbus root device");
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400565
566 free_irq(vmbus_irq, NULL);
567 bus_unregister(&vmbus_drv_ctx->bus);
568
569 ret = -1;
570 goto cleanup;
571 }
572
Greg Kroah-Hartman2d6e8822010-12-02 08:50:58 -0800573 vmbus_request_offers();
Haiyang Zhang8b5d6d32010-05-28 23:22:44 +0000574 wait_for_completion(&hv_channel_ready);
575
Hank Janssen3e7ee492009-07-13 16:02:34 -0700576cleanup:
Hank Janssen3e7ee492009-07-13 16:02:34 -0700577 return ret;
578}
579
Hank Janssen3e189512010-03-04 22:11:00 +0000580/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700581 * vmbus_bus_exit - Terminate the vmbus driver.
582 *
583 * This routine is opposite of vmbus_bus_init()
584 */
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700585static void vmbus_bus_exit(void)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700586{
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800587 struct hv_driver *driver = &vmbus_drv.drv_obj;
588 struct vmbus_driver_context *vmbus_drv_ctx = &vmbus_drv;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700589
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800590 struct vm_device *dev_ctx = &vmbus_drv.device_ctx;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700591
Bill Pemberton454f18a2009-07-27 16:47:24 -0400592 /* Remove the root device */
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800593 if (driver->dev_rm)
594 driver->dev_rm(&dev_ctx->device_obj);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700595
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800596 if (driver->cleanup)
597 driver->cleanup(driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700598
Bill Pemberton454f18a2009-07-27 16:47:24 -0400599 /* Unregister the root bus device */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700600 device_unregister(&dev_ctx->device);
601
602 bus_unregister(&vmbus_drv_ctx->bus);
603
604 free_irq(vmbus_irq, NULL);
605
606 tasklet_kill(&vmbus_drv_ctx->msg_dpc);
607 tasklet_kill(&vmbus_drv_ctx->event_dpc);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700608}
609
Hank Janssen3e189512010-03-04 22:11:00 +0000610
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700611/**
Hank Janssen3e189512010-03-04 22:11:00 +0000612 * vmbus_child_driver_register() - Register a vmbus's child driver
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800613 * @drv: Pointer to driver structure you want to register
Hank Janssen3e189512010-03-04 22:11:00 +0000614 *
Hank Janssen3e189512010-03-04 22:11:00 +0000615 *
616 * Registers the given driver with Linux through the 'driver_register()' call
617 * And sets up the hyper-v vmbus handling for this driver.
618 * It will return the state of the 'driver_register()' call.
619 *
620 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700621 */
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800622int vmbus_child_driver_register(struct device_driver *drv)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700623{
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400624 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700625
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700626 DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s",
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800627 drv, drv->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700628
Bill Pemberton454f18a2009-07-27 16:47:24 -0400629 /* The child driver on this vmbus */
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800630 drv->bus = &vmbus_drv.bus;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700631
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800632 ret = driver_register(drv);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700633
Greg Kroah-Hartman2d6e8822010-12-02 08:50:58 -0800634 vmbus_request_offers();
Hank Janssen3e7ee492009-07-13 16:02:34 -0700635
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400636 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700637}
Hank Janssen3e7ee492009-07-13 16:02:34 -0700638EXPORT_SYMBOL(vmbus_child_driver_register);
639
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700640/**
Hank Janssen3e189512010-03-04 22:11:00 +0000641 * vmbus_child_driver_unregister() - Unregister a vmbus's child driver
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800642 * @drv: Pointer to driver structure you want to un-register
Hank Janssen3e189512010-03-04 22:11:00 +0000643 *
Hank Janssen3e189512010-03-04 22:11:00 +0000644 *
645 * Un-register the given driver with Linux through the 'driver_unregister()'
646 * call. And ungegisters the driver from the Hyper-V vmbus handler.
647 *
648 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700649 */
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800650void vmbus_child_driver_unregister(struct device_driver *drv)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700651{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700652 DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s",
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800653 drv, drv->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700654
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800655 driver_unregister(drv);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700656
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800657 drv->bus = NULL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700658}
Hank Janssen3e7ee492009-07-13 16:02:34 -0700659EXPORT_SYMBOL(vmbus_child_driver_unregister);
660
Hank Janssen3e189512010-03-04 22:11:00 +0000661/*
Hank Janssen3e189512010-03-04 22:11:00 +0000662 * vmbus_child_device_create - Creates and registers a new child device
663 * on the vmbus.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700664 */
Greg Kroah-Hartman89733aa2010-12-02 08:22:41 -0800665struct hv_device *vmbus_child_device_create(struct hv_guid *type,
666 struct hv_guid *instance,
667 struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700668{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000669 struct vm_device *child_device_ctx;
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200670 struct hv_device *child_device_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700671
Bill Pemberton454f18a2009-07-27 16:47:24 -0400672 /* Allocate the new child device */
Haiyang Zhangf916a342010-02-17 20:58:47 +0000673 child_device_ctx = kzalloc(sizeof(struct vm_device), GFP_KERNEL);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700674 if (!child_device_ctx) {
675 DPRINT_ERR(VMBUS_DRV,
676 "unable to allocate device_context for child device");
Hank Janssen3e7ee492009-07-13 16:02:34 -0700677 return NULL;
678 }
679
680 DPRINT_DBG(VMBUS_DRV, "child device (%p) allocated - "
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700681 "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
682 "%02x%02x%02x%02x%02x%02x%02x%02x},"
683 "id {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
684 "%02x%02x%02x%02x%02x%02x%02x%02x}",
Hank Janssen3e7ee492009-07-13 16:02:34 -0700685 &child_device_ctx->device,
Greg Kroah-Hartmandaaa8cc2009-08-19 16:18:56 -0700686 type->data[3], type->data[2], type->data[1], type->data[0],
687 type->data[5], type->data[4], type->data[7], type->data[6],
688 type->data[8], type->data[9], type->data[10], type->data[11],
689 type->data[12], type->data[13], type->data[14], type->data[15],
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700690 instance->data[3], instance->data[2],
691 instance->data[1], instance->data[0],
692 instance->data[5], instance->data[4],
693 instance->data[7], instance->data[6],
694 instance->data[8], instance->data[9],
695 instance->data[10], instance->data[11],
696 instance->data[12], instance->data[13],
697 instance->data[14], instance->data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700698
699 child_device_obj = &child_device_ctx->device_obj;
Greg Kroah-Hartmancae5b842010-10-21 09:05:27 -0700700 child_device_obj->channel = channel;
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800701 memcpy(&child_device_obj->dev_type, type, sizeof(struct hv_guid));
702 memcpy(&child_device_obj->dev_instance, instance,
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700703 sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700704
Milan Dadok9fb5cce2009-10-28 23:23:27 +0100705 memcpy(&child_device_ctx->device_id, instance, sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700706
Hank Janssen3e7ee492009-07-13 16:02:34 -0700707 return child_device_obj;
708}
709
Hank Janssen3e189512010-03-04 22:11:00 +0000710/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700711 * vmbus_child_device_register - Register the child device on the specified bus
712 */
Greg Kroah-Hartman98293a22010-12-02 09:16:04 -0800713int vmbus_child_device_register(struct hv_device *root_device_obj,
714 struct hv_device *child_device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700715{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700716 int ret = 0;
Haiyang Zhangf916a342010-02-17 20:58:47 +0000717 struct vm_device *root_device_ctx =
718 to_vm_device(root_device_obj);
719 struct vm_device *child_device_ctx =
720 to_vm_device(child_device_obj);
Bill Pembertonf4888412009-07-29 17:00:12 -0400721 static atomic_t device_num = ATOMIC_INIT(0);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700722
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700723 DPRINT_DBG(VMBUS_DRV, "child device (%p) registering",
724 child_device_ctx);
Bill Pemberton454f18a2009-07-27 16:47:24 -0400725
Haiyang Zhang1bb40a22009-10-23 18:14:24 +0000726 /* Set the device name. Otherwise, device_register() will fail. */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700727 dev_set_name(&child_device_ctx->device, "vmbus_0_%d",
728 atomic_inc_return(&device_num));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700729
Bill Pemberton454f18a2009-07-27 16:47:24 -0400730 /* The new device belongs to this bus */
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800731 child_device_ctx->device.bus = &vmbus_drv.bus; /* device->dev.bus; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700732 child_device_ctx->device.parent = &root_device_ctx->device;
733 child_device_ctx->device.release = vmbus_device_release;
734
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700735 /*
736 * Register with the LDM. This will kick off the driver/device
737 * binding...which will eventually call vmbus_match() and vmbus_probe()
738 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700739 ret = device_register(&child_device_ctx->device);
740
Bill Pemberton454f18a2009-07-27 16:47:24 -0400741 /* vmbus_probe() error does not get propergate to device_register(). */
K. Y. Srinivasan70b0af42011-03-07 13:34:48 -0800742 ret = child_device_ctx->device_obj.probe_error;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700743
744 if (ret)
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700745 DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p)",
746 &child_device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700747 else
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700748 DPRINT_INFO(VMBUS_DRV, "child device (%p) registered",
749 &child_device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700750
Hank Janssen3e7ee492009-07-13 16:02:34 -0700751 return ret;
752}
753
Hank Janssen3e189512010-03-04 22:11:00 +0000754/*
755 * vmbus_child_device_unregister - Remove the specified child device
756 * from the vmbus.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700757 */
Greg Kroah-Hartman9d8bd712010-12-02 08:34:45 -0800758void vmbus_child_device_unregister(struct hv_device *device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700759{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000760 struct vm_device *device_ctx = to_vm_device(device_obj);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700761
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700762 DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)",
763 &device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700764
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700765 /*
766 * Kick off the process of unregistering the device.
767 * This will call vmbus_remove() and eventually vmbus_device_release()
768 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700769 device_unregister(&device_ctx->device);
770
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700771 DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered",
772 &device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700773}
774
Hank Janssen3e189512010-03-04 22:11:00 +0000775/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700776 * vmbus_uevent - add uevent for our device
777 *
778 * This routine is invoked when a device is added or removed on the vmbus to
779 * generate a uevent to udev in the userspace. The udev will then look at its
780 * rule and the uevent generated here to load the appropriate driver
781 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700782static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
783{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000784 struct vm_device *device_ctx = device_to_vm_device(device);
K. Y. Srinivasan65c22792011-03-07 13:35:10 -0800785 struct hv_device *dev = &device_ctx->device_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700786 int ret;
787
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700788 DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={"
789 "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
790 "%02x%02x%02x%02x%02x%02x%02x%02x}",
K. Y. Srinivasan65c22792011-03-07 13:35:10 -0800791 dev->dev_type.data[3], dev->dev_type.data[2],
792 dev->dev_type.data[1], dev->dev_type.data[0],
793 dev->dev_type.data[5], dev->dev_type.data[4],
794 dev->dev_type.data[7], dev->dev_type.data[6],
795 dev->dev_type.data[8], dev->dev_type.data[9],
796 dev->dev_type.data[10],
797 dev->dev_type.data[11],
798 dev->dev_type.data[12],
799 dev->dev_type.data[13],
800 dev->dev_type.data[14],
801 dev->dev_type.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700802
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700803 ret = add_uevent_var(env, "VMBUS_DEVICE_CLASS_GUID={"
804 "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
805 "%02x%02x%02x%02x%02x%02x%02x%02x}",
K. Y. Srinivasan65c22792011-03-07 13:35:10 -0800806 dev->dev_type.data[3],
807 dev->dev_type.data[2],
808 dev->dev_type.data[1],
809 dev->dev_type.data[0],
810 dev->dev_type.data[5],
811 dev->dev_type.data[4],
812 dev->dev_type.data[7],
813 dev->dev_type.data[6],
814 dev->dev_type.data[8],
815 dev->dev_type.data[9],
816 dev->dev_type.data[10],
817 dev->dev_type.data[11],
818 dev->dev_type.data[12],
819 dev->dev_type.data[13],
820 dev->dev_type.data[14],
821 dev->dev_type.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700822
823 if (ret)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700824 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700825
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700826 ret = add_uevent_var(env, "VMBUS_DEVICE_DEVICE_GUID={"
827 "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
828 "%02x%02x%02x%02x%02x%02x%02x%02x}",
829 device_ctx->device_id.data[3],
830 device_ctx->device_id.data[2],
831 device_ctx->device_id.data[1],
832 device_ctx->device_id.data[0],
833 device_ctx->device_id.data[5],
834 device_ctx->device_id.data[4],
835 device_ctx->device_id.data[7],
836 device_ctx->device_id.data[6],
837 device_ctx->device_id.data[8],
838 device_ctx->device_id.data[9],
839 device_ctx->device_id.data[10],
840 device_ctx->device_id.data[11],
841 device_ctx->device_id.data[12],
842 device_ctx->device_id.data[13],
843 device_ctx->device_id.data[14],
844 device_ctx->device_id.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700845 if (ret)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700846 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700847
Hank Janssen3e7ee492009-07-13 16:02:34 -0700848 return 0;
849}
850
Hank Janssen3e189512010-03-04 22:11:00 +0000851/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700852 * vmbus_match - Attempt to match the specified device to the specified driver
853 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700854static int vmbus_match(struct device *device, struct device_driver *driver)
855{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700856 int match = 0;
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800857 struct hv_driver *drv = drv_to_hv_drv(driver);
Haiyang Zhangf916a342010-02-17 20:58:47 +0000858 struct vm_device *device_ctx = device_to_vm_device(device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700859
Bill Pemberton454f18a2009-07-27 16:47:24 -0400860 /* We found our driver ? */
K. Y. Srinivasan65c22792011-03-07 13:35:10 -0800861 if (memcmp(&device_ctx->device_obj.dev_type, &drv->dev_type,
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700862 sizeof(struct hv_guid)) == 0) {
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700863
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800864 device_ctx->device_obj.drv = drv->priv;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700865 DPRINT_INFO(VMBUS_DRV,
866 "device object (%p) set to driver object (%p)",
867 &device_ctx->device_obj,
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800868 device_ctx->device_obj.drv);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700869
870 match = 1;
871 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700872 return match;
873}
874
Hank Janssen3e189512010-03-04 22:11:00 +0000875/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700876 * vmbus_probe_failed_cb - Callback when a driver probe failed in vmbus_probe()
877 *
878 * We need a callback because we cannot invoked device_unregister() inside
879 * vmbus_probe() since vmbus_probe() may be invoked inside device_register()
880 * i.e. we cannot call device_unregister() inside device_register()
881 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700882static void vmbus_probe_failed_cb(struct work_struct *context)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700883{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000884 struct vm_device *device_ctx = (struct vm_device *)context;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700885
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700886 /*
887 * Kick off the process of unregistering the device.
888 * This will call vmbus_remove() and eventually vmbus_device_release()
889 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700890 device_unregister(&device_ctx->device);
891
Bill Pemberton454f18a2009-07-27 16:47:24 -0400892 /* put_device(&device_ctx->device); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700893}
894
Hank Janssen3e189512010-03-04 22:11:00 +0000895/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700896 * vmbus_probe - Add the new vmbus's child device
897 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700898static int vmbus_probe(struct device *child_device)
899{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700900 int ret = 0;
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800901 struct hv_driver *drv =
902 drv_to_hv_drv(child_device->driver);
Haiyang Zhangf916a342010-02-17 20:58:47 +0000903 struct vm_device *device_ctx =
904 device_to_vm_device(child_device);
K. Y. Srinivasana3c7fe92011-03-07 13:34:27 -0800905 struct hv_device *dev = &device_ctx->device_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700906
Bill Pemberton454f18a2009-07-27 16:47:24 -0400907 /* Let the specific open-source driver handles the probe if it can */
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800908 if (drv->driver.probe) {
K. Y. Srinivasan70b0af42011-03-07 13:34:48 -0800909 ret = device_ctx->device_obj.probe_error =
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800910 drv->driver.probe(child_device);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700911 if (ret != 0) {
912 DPRINT_ERR(VMBUS_DRV, "probe() failed for device %s "
913 "(%p) on driver %s (%d)...",
914 dev_name(child_device), child_device,
915 child_device->driver->name, ret);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700916
K. Y. Srinivasana3c7fe92011-03-07 13:34:27 -0800917 INIT_WORK(&dev->probe_failed_work_item,
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700918 vmbus_probe_failed_cb);
K. Y. Srinivasana3c7fe92011-03-07 13:34:27 -0800919 schedule_work(&dev->probe_failed_work_item);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700920 }
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700921 } else {
922 DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s",
923 child_device->driver->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700924 ret = -1;
925 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700926 return ret;
927}
928
Hank Janssen3e189512010-03-04 22:11:00 +0000929/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700930 * vmbus_remove - Remove a vmbus device
931 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700932static int vmbus_remove(struct device *child_device)
933{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700934 int ret;
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800935 struct hv_driver *drv;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700936
Bill Pemberton454f18a2009-07-27 16:47:24 -0400937 /* Special case root bus device */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700938 if (child_device->parent == NULL) {
939 /*
940 * No-op since it is statically defined and handle in
941 * vmbus_bus_exit()
942 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700943 return 0;
944 }
945
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700946 if (child_device->driver) {
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800947 drv = drv_to_hv_drv(child_device->driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700948
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700949 /*
950 * Let the specific open-source driver handles the removal if
951 * it can
952 */
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800953 if (drv->driver.remove) {
954 ret = drv->driver.remove(child_device);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700955 } else {
956 DPRINT_ERR(VMBUS_DRV,
957 "remove() method not set for driver - %s",
958 child_device->driver->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700959 ret = -1;
960 }
961 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700962
Hank Janssen3e7ee492009-07-13 16:02:34 -0700963 return 0;
964}
965
Hank Janssen3e189512010-03-04 22:11:00 +0000966/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700967 * vmbus_shutdown - Shutdown a vmbus device
968 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700969static void vmbus_shutdown(struct device *child_device)
970{
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800971 struct hv_driver *drv;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700972
Bill Pemberton454f18a2009-07-27 16:47:24 -0400973 /* Special case root bus device */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700974 if (child_device->parent == NULL) {
975 /*
976 * No-op since it is statically defined and handle in
977 * vmbus_bus_exit()
978 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700979 return;
980 }
981
Bill Pemberton454f18a2009-07-27 16:47:24 -0400982 /* The device may not be attached yet */
Greg Kroah-Hartman83c720e2010-07-22 15:14:04 -0700983 if (!child_device->driver)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700984 return;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700985
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800986 drv = drv_to_hv_drv(child_device->driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700987
Bill Pemberton454f18a2009-07-27 16:47:24 -0400988 /* Let the specific open-source driver handles the removal if it can */
K. Y. Srinivasan150f9392011-03-07 13:32:31 -0800989 if (drv->driver.shutdown)
990 drv->driver.shutdown(child_device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700991
Hank Janssen3e7ee492009-07-13 16:02:34 -0700992 return;
993}
994
Hank Janssen3e189512010-03-04 22:11:00 +0000995/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700996 * vmbus_bus_release - Final callback release of the vmbus root device
997 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700998static void vmbus_bus_release(struct device *device)
999{
Greg Kroah-Hartman689bf402009-09-01 20:12:58 -07001000 /* FIXME */
1001 /* Empty release functions are a bug, or a major sign
1002 * of a problem design, this MUST BE FIXED! */
1003 dev_err(device, "%s needs to be fixed!\n", __func__);
1004 WARN_ON(1);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001005}
1006
Hank Janssen3e189512010-03-04 22:11:00 +00001007/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001008 * vmbus_device_release - Final callback release of the vmbus child device
1009 */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001010static void vmbus_device_release(struct device *device)
1011{
Haiyang Zhangf916a342010-02-17 20:58:47 +00001012 struct vm_device *device_ctx = device_to_vm_device(device);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001013
Hank Janssen3e7ee492009-07-13 16:02:34 -07001014 kfree(device_ctx);
1015
Bill Pemberton454f18a2009-07-27 16:47:24 -04001016 /* !!DO NOT REFERENCE device_ctx anymore at this point!! */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001017}
1018
Hank Janssen3e189512010-03-04 22:11:00 +00001019/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001020 * vmbus_msg_dpc - Tasklet routine to handle hypervisor messages
1021 */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001022static void vmbus_msg_dpc(unsigned long data)
1023{
Greg Kroah-Hartmana69a6692010-12-02 09:42:18 -08001024 struct hv_driver *driver = (struct hv_driver *)data;
Hank Janssen3e7ee492009-07-13 16:02:34 -07001025
Bill Pemberton454f18a2009-07-27 16:47:24 -04001026 /* Call to bus driver to handle interrupt */
Greg Kroah-Hartmana69a6692010-12-02 09:42:18 -08001027 vmbus_on_msg_dpc(driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001028}
1029
Hank Janssen3e189512010-03-04 22:11:00 +00001030/*
Greg Kroah-Hartman4a1494f2010-12-02 08:44:48 -08001031 * vmbus_event_dpc - Tasklet routine to handle hypervisor events
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001032 */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001033static void vmbus_event_dpc(unsigned long data)
1034{
Bill Pemberton454f18a2009-07-27 16:47:24 -04001035 /* Call to bus driver to handle interrupt */
Haiyang Zhangc6977672011-01-26 12:12:08 -08001036 vmbus_on_event();
Hank Janssen3e7ee492009-07-13 16:02:34 -07001037}
1038
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001039static irqreturn_t vmbus_isr(int irq, void *dev_id)
Hank Janssen3e7ee492009-07-13 16:02:34 -07001040{
Haiyang Zhangadf874c2011-01-26 12:12:09 -08001041 struct hv_driver *driver = &vmbus_drv.drv_obj;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001042 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -07001043
Bill Pemberton454f18a2009-07-27 16:47:24 -04001044 /* Call to bus driver to handle interrupt */
Greg Kroah-Hartmana69a6692010-12-02 09:42:18 -08001045 ret = vmbus_on_isr(driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001046
Bill Pemberton454f18a2009-07-27 16:47:24 -04001047 /* Schedules a dpc if necessary */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001048 if (ret > 0) {
1049 if (test_bit(0, (unsigned long *)&ret))
Haiyang Zhangadf874c2011-01-26 12:12:09 -08001050 tasklet_schedule(&vmbus_drv.msg_dpc);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001051
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001052 if (test_bit(1, (unsigned long *)&ret))
Haiyang Zhangadf874c2011-01-26 12:12:09 -08001053 tasklet_schedule(&vmbus_drv.event_dpc);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001054
Hank Janssen3e7ee492009-07-13 16:02:34 -07001055 return IRQ_HANDLED;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001056 } else {
Hank Janssen3e7ee492009-07-13 16:02:34 -07001057 return IRQ_NONE;
1058 }
1059}
1060
Greg Kroah-Hartmanc22090f2010-02-25 16:43:15 -08001061static struct dmi_system_id __initdata microsoft_hv_dmi_table[] = {
1062 {
1063 .ident = "Hyper-V",
1064 .matches = {
1065 DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
1066 DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
1067 DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
1068 },
1069 },
1070 { },
1071};
1072MODULE_DEVICE_TABLE(dmi, microsoft_hv_dmi_table);
1073
Hank Janssen3e7ee492009-07-13 16:02:34 -07001074static int __init vmbus_init(void)
1075{
Hank Janssen3e7ee492009-07-13 16:02:34 -07001076 DPRINT_INFO(VMBUS_DRV,
1077 "Vmbus initializing.... current log level 0x%x (%x,%x)",
1078 vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel));
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001079 /* Todo: it is used for loglevel, to be ported to new kernel. */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001080
Greg Kroah-Hartmanc22090f2010-02-25 16:43:15 -08001081 if (!dmi_check_system(microsoft_hv_dmi_table))
1082 return -ENODEV;
1083
Greg Kroah-Hartman6c884552010-12-02 12:04:00 -08001084 return vmbus_bus_init();
Hank Janssen3e7ee492009-07-13 16:02:34 -07001085}
1086
Hank Janssen3e7ee492009-07-13 16:02:34 -07001087static void __exit vmbus_exit(void)
1088{
Hank Janssen3e7ee492009-07-13 16:02:34 -07001089 vmbus_bus_exit();
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001090 /* Todo: it is used for loglevel, to be ported to new kernel. */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001091}
1092
Greg Kroah-Hartman9a775db2010-02-25 16:42:10 -08001093/*
1094 * We use a PCI table to determine if we should autoload this driver This is
1095 * needed by distro tools to determine if the hyperv drivers should be
1096 * installed and/or configured. We don't do anything else with the table, but
1097 * it needs to be present.
Greg Kroah-Hartman9a775db2010-02-25 16:42:10 -08001098 */
Tobias Klauser15f0beb2010-05-20 10:39:38 +02001099static const struct pci_device_id microsoft_hv_pci_table[] = {
Greg Kroah-Hartman9a775db2010-02-25 16:42:10 -08001100 { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
1101 { 0 }
1102};
1103MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table);
1104
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001105MODULE_LICENSE("GPL");
Hank Janssen26c14cc2010-02-11 23:02:42 +00001106MODULE_VERSION(HV_DRV_VERSION);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001107module_param(vmbus_irq, int, S_IRUGO);
1108module_param(vmbus_loglevel, int, S_IRUGO);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001109
1110module_init(vmbus_init);
1111module_exit(vmbus_exit);