blob: 1700dd3be81188f182fa09b59b94f2d6c9efed3c [file] [log] [blame]
Hank Janssen3e7ee492009-07-13 16:02:34 -07001/*
2 *
3 * Copyright (c) 2009, Microsoft Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307 USA.
17 *
18 * Authors:
19 * Haiyang Zhang <haiyangz@microsoft.com>
20 * Hank Janssen <hjanssen@microsoft.com>
21 *
22 */
23
24
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/device.h>
28#include <linux/irq.h>
29#include <linux/interrupt.h>
30#include <linux/sysctl.h>
Greg Kroah-Hartman4983b392009-08-19 16:14:47 -070031#include "osd.h"
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -070032#include "include/logging.h"
Greg Kroah-Hartman870cde82009-08-19 16:21:28 -070033#include "vmbus.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070034
Hank Janssen3e7ee492009-07-13 16:02:34 -070035
Bill Pemberton454f18a2009-07-27 16:47:24 -040036/* Defines */
37
38
39/* FIXME! We need to do this dynamically for PIC and APIC system */
Hank Janssen3e7ee492009-07-13 16:02:34 -070040#define VMBUS_IRQ 0x5
Hank Janssen3e7ee492009-07-13 16:02:34 -070041#define VMBUS_IRQ_VECTOR IRQ5_VECTOR
Hank Janssen3e7ee492009-07-13 16:02:34 -070042
Bill Pemberton454f18a2009-07-27 16:47:24 -040043/* Data types */
44
45
46/* Main vmbus driver data structure */
Hank Janssen3e7ee492009-07-13 16:02:34 -070047struct vmbus_driver_context {
Bill Pemberton454f18a2009-07-27 16:47:24 -040048 /* !! These must be the first 2 fields !! */
49 /* The driver field is not used in here. Instead, the bus field is */
50 /* used to represent the driver */
Hank Janssen3e7ee492009-07-13 16:02:34 -070051 struct driver_context drv_ctx;
52 VMBUS_DRIVER_OBJECT drv_obj;
53
54 struct bus_type bus;
55 struct tasklet_struct msg_dpc;
56 struct tasklet_struct event_dpc;
57
Bill Pemberton454f18a2009-07-27 16:47:24 -040058 /* The bus root device */
Hank Janssen3e7ee492009-07-13 16:02:34 -070059 struct device_context device_ctx;
60};
61
Bill Pemberton454f18a2009-07-27 16:47:24 -040062
63/* Static decl */
64
Hank Janssen3e7ee492009-07-13 16:02:34 -070065static int vmbus_match(struct device *device, struct device_driver *driver);
66static int vmbus_probe(struct device *device);
67static int vmbus_remove(struct device *device);
68static void vmbus_shutdown(struct device *device);
Hank Janssen3e7ee492009-07-13 16:02:34 -070069static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env);
Hank Janssen3e7ee492009-07-13 16:02:34 -070070static void vmbus_msg_dpc(unsigned long data);
71static void vmbus_event_dpc(unsigned long data);
72
Hank Janssen3e7ee492009-07-13 16:02:34 -070073static irqreturn_t vmbus_isr(int irq, void* dev_id);
Hank Janssen3e7ee492009-07-13 16:02:34 -070074
75static void vmbus_device_release(struct device *device);
76static void vmbus_bus_release(struct device *device);
77
Greg Kroah-Hartmandaaa8cc2009-08-19 16:18:56 -070078static struct hv_device *vmbus_child_device_create(struct hv_guid *type, struct hv_guid *instance, void *context);
Nicolas Palix3d3b5512009-07-28 17:32:53 +020079static void vmbus_child_device_destroy(struct hv_device *device_obj);
80static int vmbus_child_device_register(struct hv_device *root_device_obj, struct hv_device *child_device_obj);
81static void vmbus_child_device_unregister(struct hv_device *child_device_obj);
82static void vmbus_child_device_get_info(struct hv_device *device_obj, DEVICE_INFO *device_info);
Hank Janssen3e7ee492009-07-13 16:02:34 -070083
Bill Pemberton454f18a2009-07-27 16:47:24 -040084/* static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf); */
85/* static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf); */
Hank Janssen3e7ee492009-07-13 16:02:34 -070086
87static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf);
88
Hank Janssen3e7ee492009-07-13 16:02:34 -070089
Bill Pemberton454f18a2009-07-27 16:47:24 -040090/* Global */
Hank Janssen3e7ee492009-07-13 16:02:34 -070091
Bill Pemberton454f18a2009-07-27 16:47:24 -040092
93/* Global logging setting */
94
95/* unsigned int vmbus_loglevel= (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT); */
96/* unsigned int vmbus_loglevel= (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT); */
Hank Janssen3e7ee492009-07-13 16:02:34 -070097unsigned int vmbus_loglevel= (ALL_MODULES << 16 | INFO_LVL);
98EXPORT_SYMBOL(vmbus_loglevel);
99
100static int vmbus_irq = VMBUS_IRQ;
101
Bill Pemberton454f18a2009-07-27 16:47:24 -0400102/* Setup /proc/sys/bus/vmbus/vmbus_loglevel */
103/* Allow usage of sysctl cmd to set the logging level */
Bill Pemberton454f18a2009-07-27 16:47:24 -0400104
105/* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */
106
Hank Janssen3e7ee492009-07-13 16:02:34 -0700107static struct device_attribute vmbus_device_attrs[] = {
108 __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL),
109 __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL),
110 __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL),
111 __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL),
112 __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL),
113
114 __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
115 __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
116 __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
117
118 __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
119 __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
120 __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
121
122 __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
123 __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
124 __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
125 __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
126 __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
127
128 __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
129 __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
130 __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
131 __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
132 __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
133 __ATTR_NULL
134};
Hank Janssen3e7ee492009-07-13 16:02:34 -0700135
Bill Pemberton454f18a2009-07-27 16:47:24 -0400136/* The one and only one */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700137static struct vmbus_driver_context g_vmbus_drv={
138 .bus.name = "vmbus",
139 .bus.match = vmbus_match,
Hank Janssen3e7ee492009-07-13 16:02:34 -0700140 .bus.shutdown = vmbus_shutdown,
141 .bus.remove = vmbus_remove,
142 .bus.probe = vmbus_probe,
143 .bus.uevent = vmbus_uevent,
144 .bus.dev_attrs = vmbus_device_attrs,
Hank Janssen3e7ee492009-07-13 16:02:34 -0700145};
146
Bill Pemberton454f18a2009-07-27 16:47:24 -0400147
148/* Routines */
149
Hank Janssen3e7ee492009-07-13 16:02:34 -0700150
151
152/*++
153
154Name: vmbus_show_device_attr()
155
156Desc: Show the device attribute in sysfs. This is invoked when user does a "cat /sys/bus/vmbus/devices/<bus device>/<attr name>"
157
158--*/
159static ssize_t vmbus_show_device_attr(struct device *dev, struct device_attribute *dev_attr, char *buf)
160{
161 struct device_context *device_ctx = device_to_device_context(dev);
162 DEVICE_INFO device_info;
163
164 memset(&device_info, 0, sizeof(DEVICE_INFO));
165
166 vmbus_child_device_get_info(&device_ctx->device_obj, &device_info);
167
168 if (!strcmp(dev_attr->attr.name, "class_id"))
169 {
170 return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n",
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700171 device_info.ChannelType.data[3], device_info.ChannelType.data[2],
172 device_info.ChannelType.data[1], device_info.ChannelType.data[0],
173 device_info.ChannelType.data[5], device_info.ChannelType.data[4],
174 device_info.ChannelType.data[7], device_info.ChannelType.data[6],
175 device_info.ChannelType.data[8], device_info.ChannelType.data[9],
176 device_info.ChannelType.data[10], device_info.ChannelType.data[11],
177 device_info.ChannelType.data[12], device_info.ChannelType.data[13],
178 device_info.ChannelType.data[14], device_info.ChannelType.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700179
180 }
181 else if (!strcmp(dev_attr->attr.name, "device_id"))
182 {
183 return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n",
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700184 device_info.ChannelInstance.data[3], device_info.ChannelInstance.data[2],
185 device_info.ChannelInstance.data[1], device_info.ChannelInstance.data[0],
186 device_info.ChannelInstance.data[5], device_info.ChannelInstance.data[4],
187 device_info.ChannelInstance.data[7], device_info.ChannelInstance.data[6],
188 device_info.ChannelInstance.data[8], device_info.ChannelInstance.data[9],
189 device_info.ChannelInstance.data[10], device_info.ChannelInstance.data[11],
190 device_info.ChannelInstance.data[12], device_info.ChannelInstance.data[13],
191 device_info.ChannelInstance.data[14], device_info.ChannelInstance.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700192 }
193 else if (!strcmp(dev_attr->attr.name, "state"))
194 {
195 return sprintf(buf, "%d\n", device_info.ChannelState);
196 }
197 else if (!strcmp(dev_attr->attr.name, "id"))
198 {
199 return sprintf(buf, "%d\n", device_info.ChannelId);
200 }
201 else if (!strcmp(dev_attr->attr.name, "out_intr_mask"))
202 {
203 return sprintf(buf, "%d\n", device_info.Outbound.InterruptMask);
204 }
205 else if (!strcmp(dev_attr->attr.name, "out_read_index"))
206 {
207 return sprintf(buf, "%d\n", device_info.Outbound.ReadIndex);
208 }
209 else if (!strcmp(dev_attr->attr.name, "out_write_index"))
210 {
211 return sprintf(buf, "%d\n", device_info.Outbound.WriteIndex);
212 }
213 else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail"))
214 {
215 return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToRead);
216 }
217 else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail"))
218 {
219 return sprintf(buf, "%d\n", device_info.Outbound.BytesAvailToWrite);
220 }
221 else if (!strcmp(dev_attr->attr.name, "in_intr_mask"))
222 {
223 return sprintf(buf, "%d\n", device_info.Inbound.InterruptMask);
224 }
225 else if (!strcmp(dev_attr->attr.name, "in_read_index"))
226 {
227 return sprintf(buf, "%d\n", device_info.Inbound.ReadIndex);
228 }
229 else if (!strcmp(dev_attr->attr.name, "in_write_index"))
230 {
231 return sprintf(buf, "%d\n", device_info.Inbound.WriteIndex);
232 }
233 else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail"))
234 {
235 return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToRead);
236 }
237 else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail"))
238 {
239 return sprintf(buf, "%d\n", device_info.Inbound.BytesAvailToWrite);
240 }
241 else if (!strcmp(dev_attr->attr.name, "monitor_id"))
242 {
243 return sprintf(buf, "%d\n", device_info.MonitorId);
244 }
245 else if (!strcmp(dev_attr->attr.name, "server_monitor_pending"))
246 {
247 return sprintf(buf, "%d\n", device_info.ServerMonitorPending);
248 }
249 else if (!strcmp(dev_attr->attr.name, "server_monitor_latency"))
250 {
251 return sprintf(buf, "%d\n", device_info.ServerMonitorLatency);
252 }
253 else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id"))
254 {
255 return sprintf(buf, "%d\n", device_info.ServerMonitorConnectionId);
256 }
257 else if (!strcmp(dev_attr->attr.name, "client_monitor_pending"))
258 {
259 return sprintf(buf, "%d\n", device_info.ClientMonitorPending);
260 }
261 else if (!strcmp(dev_attr->attr.name, "client_monitor_latency"))
262 {
263 return sprintf(buf, "%d\n", device_info.ClientMonitorLatency);
264 }
265 else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id"))
266 {
267 return sprintf(buf, "%d\n", device_info.ClientMonitorConnectionId);
268 }
269 else
270 {
271 return 0;
272 }
273}
274
275/*++
276
277Name: vmbus_show_class_id()
278
279Desc: Show the device class id in sysfs
280
281--*/
Bill Pemberton454f18a2009-07-27 16:47:24 -0400282/* static ssize_t vmbus_show_class_id(struct device *dev, struct device_attribute *attr, char *buf) */
283/* { */
284/* struct device_context *device_ctx = device_to_device_context(dev); */
285/* return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", */
286/* device_ctx->class_id[3], device_ctx->class_id[2], device_ctx->class_id[1], device_ctx->class_id[0], */
287/* device_ctx->class_id[5], device_ctx->class_id[4], */
288/* device_ctx->class_id[7], device_ctx->class_id[6], */
289/* device_ctx->class_id[8], device_ctx->class_id[9], device_ctx->class_id[10], device_ctx->class_id[11], device_ctx->class_id[12], device_ctx->class_id[13], device_ctx->class_id[14], device_ctx->class_id[15]); */
290/* } */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700291
292/*++
293
294Name: vmbus_show_device_id()
295
296Desc: Show the device instance id in sysfs
297
298--*/
Bill Pemberton454f18a2009-07-27 16:47:24 -0400299/* static ssize_t vmbus_show_device_id(struct device *dev, struct device_attribute *attr, char *buf) */
300/* { */
301/* struct device_context *device_ctx = device_to_device_context(dev); */
302/* return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}\n", */
303/* device_ctx->device_id[3], device_ctx->device_id[2], device_ctx->device_id[1], device_ctx->device_id[0], */
304/* device_ctx->device_id[5], device_ctx->device_id[4], */
305/* device_ctx->device_id[7], device_ctx->device_id[6], */
306/* device_ctx->device_id[8], device_ctx->device_id[9], device_ctx->device_id[10], device_ctx->device_id[11], device_ctx->device_id[12], device_ctx->device_id[13], device_ctx->device_id[14], device_ctx->device_id[15]); */
307/* } */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700308
309/*++
310
311Name: vmbus_bus_init()
312
313Desc: Main vmbus driver initialization routine. Here, we
314 - initialize the vmbus driver context
315 - setup various driver entry points
316 - invoke the vmbus hv main init routine
317 - get the irq resource
318 - invoke the vmbus to add the vmbus root device
319 - setup the vmbus root device
320 - retrieve the channel offers
321--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700322static int vmbus_bus_init(PFN_DRIVERINITIALIZE pfn_drv_init)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700323{
324 int ret=0;
325 unsigned int vector=0;
326
327 struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv;
328 VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
329
330 struct device_context *dev_ctx=&g_vmbus_drv.device_ctx;
331
332 DPRINT_ENTER(VMBUS_DRV);
333
Bill Pemberton454f18a2009-07-27 16:47:24 -0400334 /* Set this up to allow lower layer to callback to add/remove child devices on the bus */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700335 vmbus_drv_obj->OnChildDeviceCreate = vmbus_child_device_create;
336 vmbus_drv_obj->OnChildDeviceDestroy = vmbus_child_device_destroy;
337 vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register;
338 vmbus_drv_obj->OnChildDeviceRemove = vmbus_child_device_unregister;
339
Bill Pemberton454f18a2009-07-27 16:47:24 -0400340 /* Call to bus driver to initialize */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700341 ret = pfn_drv_init(&vmbus_drv_obj->Base);
342 if (ret != 0)
343 {
344 DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret);
345 goto cleanup;
346 }
347
Bill Pemberton454f18a2009-07-27 16:47:24 -0400348 /* Sanity checks */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700349 if (!vmbus_drv_obj->Base.OnDeviceAdd)
350 {
351 DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set");
352 ret = -1;
353 goto cleanup;
354 }
355
356 vmbus_drv_ctx->bus.name = vmbus_drv_obj->Base.name;
357
Bill Pemberton454f18a2009-07-27 16:47:24 -0400358 /* Initialize the bus context */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700359 tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc, (unsigned long)vmbus_drv_obj);
360 tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc, (unsigned long)vmbus_drv_obj);
361
Bill Pemberton454f18a2009-07-27 16:47:24 -0400362 /* Now, register the bus driver with LDM */
Bill Pembertonc19fbca2009-07-27 16:47:35 -0400363 ret = bus_register(&vmbus_drv_ctx->bus);
364 if (ret)
365 {
366 ret = -1;
367 goto cleanup;
368 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700369
Bill Pemberton454f18a2009-07-27 16:47:24 -0400370 /* Get the interrupt resource */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700371 ret = request_irq(vmbus_irq,
372 vmbus_isr,
373 IRQF_SAMPLE_RANDOM,
374 vmbus_drv_obj->Base.name,
375 NULL);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700376
377 if (ret != 0)
378 {
379 DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d", vmbus_irq);
380
381 bus_unregister(&vmbus_drv_ctx->bus);
382
383 ret = -1;
384 goto cleanup;
385 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700386 vector = VMBUS_IRQ_VECTOR;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700387
388 DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector);
389
Bill Pemberton454f18a2009-07-27 16:47:24 -0400390 /* Call to bus driver to add the root device */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700391 memset(dev_ctx, 0, sizeof(struct device_context));
392
393 ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector);
394 if (ret != 0)
395 {
396 DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to add vmbus root device");
397
398 free_irq(vmbus_irq, NULL);
399
400 bus_unregister(&vmbus_drv_ctx->bus);
401
402 ret = -1;
403 goto cleanup;
404 }
Bill Pemberton454f18a2009-07-27 16:47:24 -0400405 /* strcpy(dev_ctx->device.bus_id, dev_ctx->device_obj.name); */
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -0700406 dev_set_name(&dev_ctx->device, "vmbus_0_0");
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700407 memcpy(&dev_ctx->class_id, &dev_ctx->device_obj.deviceType, sizeof(struct hv_guid));
408 memcpy(&dev_ctx->device_id, &dev_ctx->device_obj.deviceInstance, sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700409
Bill Pemberton454f18a2009-07-27 16:47:24 -0400410 /* No need to bind a driver to the root device. */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700411 dev_ctx->device.parent = NULL;
Bill Pemberton454f18a2009-07-27 16:47:24 -0400412 dev_ctx->device.bus = &vmbus_drv_ctx->bus; /* NULL; vmbus_remove() does not get invoked */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700413
Bill Pemberton454f18a2009-07-27 16:47:24 -0400414 /* Setup the device dispatch table */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700415 dev_ctx->device.release = vmbus_bus_release;
416
Bill Pemberton454f18a2009-07-27 16:47:24 -0400417 /* Setup the bus as root device */
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400418 ret = device_register(&dev_ctx->device);
419 if (ret)
420 {
421 DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to register vmbus root device");
422
423 free_irq(vmbus_irq, NULL);
424 bus_unregister(&vmbus_drv_ctx->bus);
425
426 ret = -1;
427 goto cleanup;
428 }
429
Hank Janssen3e7ee492009-07-13 16:02:34 -0700430
431 vmbus_drv_obj->GetChannelOffers();
432
433cleanup:
434 DPRINT_EXIT(VMBUS_DRV);
435
436 return ret;
437}
438
439
440/*++
441
442Name: vmbus_bus_exit()
443
444Desc: Terminate the vmbus driver. This routine is opposite of vmbus_bus_init()
445
446--*/
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700447static void vmbus_bus_exit(void)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700448{
449 VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
450 struct vmbus_driver_context *vmbus_drv_ctx=&g_vmbus_drv;
451
452 struct device_context *dev_ctx=&g_vmbus_drv.device_ctx;
453
454 DPRINT_ENTER(VMBUS_DRV);
455
Bill Pemberton454f18a2009-07-27 16:47:24 -0400456 /* Remove the root device */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700457 if (vmbus_drv_obj->Base.OnDeviceRemove)
458 vmbus_drv_obj->Base.OnDeviceRemove(&dev_ctx->device_obj);
459
460 if (vmbus_drv_obj->Base.OnCleanup)
461 vmbus_drv_obj->Base.OnCleanup(&vmbus_drv_obj->Base);
462
Bill Pemberton454f18a2009-07-27 16:47:24 -0400463 /* Unregister the root bus device */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700464 device_unregister(&dev_ctx->device);
465
466 bus_unregister(&vmbus_drv_ctx->bus);
467
468 free_irq(vmbus_irq, NULL);
469
470 tasklet_kill(&vmbus_drv_ctx->msg_dpc);
471 tasklet_kill(&vmbus_drv_ctx->event_dpc);
472
473 DPRINT_EXIT(VMBUS_DRV);
474
475 return;
476}
477
478/*++
479
480Name: vmbus_child_driver_register()
481
482Desc: Register a vmbus's child driver
483
484--*/
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400485int vmbus_child_driver_register(struct driver_context* driver_ctx)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700486{
487 VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400488 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700489
490 DPRINT_ENTER(VMBUS_DRV);
491
492 DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s", driver_ctx, driver_ctx->driver.name);
493
Bill Pemberton454f18a2009-07-27 16:47:24 -0400494 /* The child driver on this vmbus */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700495 driver_ctx->driver.bus = &g_vmbus_drv.bus;
496
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400497 ret = driver_register(&driver_ctx->driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700498
499 vmbus_drv_obj->GetChannelOffers();
500
501 DPRINT_EXIT(VMBUS_DRV);
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400502
503 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700504}
505
506EXPORT_SYMBOL(vmbus_child_driver_register);
507
508/*++
509
510Name: vmbus_child_driver_unregister()
511
512Desc: Unregister a vmbus's child driver
513
514--*/
515void vmbus_child_driver_unregister(struct driver_context* driver_ctx)
516{
517 DPRINT_ENTER(VMBUS_DRV);
518
519 DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s", driver_ctx, driver_ctx->driver.name);
520
521 driver_unregister(&driver_ctx->driver);
522
523 driver_ctx->driver.bus = NULL;
524
525 DPRINT_EXIT(VMBUS_DRV);
526}
527
528EXPORT_SYMBOL(vmbus_child_driver_unregister);
529
530/*++
531
532Name: vmbus_get_interface()
533
534Desc: Get the vmbus channel interface. This is invoked by child/client driver that sits
535 above vmbus
536--*/
537void vmbus_get_interface(VMBUS_CHANNEL_INTERFACE *interface)
538{
539 VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
540
541 vmbus_drv_obj->GetChannelInterface(interface);
542}
543
544EXPORT_SYMBOL(vmbus_get_interface);
545
546
547/*++
548
549Name: vmbus_child_device_get_info()
550
551Desc: Get the vmbus child device info. This is invoked to display various device attributes in sysfs.
552--*/
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200553static void vmbus_child_device_get_info(struct hv_device *device_obj, DEVICE_INFO *device_info)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700554{
555 VMBUS_DRIVER_OBJECT *vmbus_drv_obj=&g_vmbus_drv.drv_obj;
556
557 vmbus_drv_obj->GetChannelInfo(device_obj, device_info);
558}
559
560
561/*++
562
563Name: vmbus_child_device_create()
564
565Desc: Creates and registers a new child device on the vmbus.
566
567--*/
Greg Kroah-Hartmandaaa8cc2009-08-19 16:18:56 -0700568static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
569 struct hv_guid *instance,
570 void *context)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700571{
572 struct device_context *child_device_ctx;
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200573 struct hv_device *child_device_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700574
575 DPRINT_ENTER(VMBUS_DRV);
576
Bill Pemberton454f18a2009-07-27 16:47:24 -0400577 /* Allocate the new child device */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700578 child_device_ctx = kzalloc(sizeof(struct device_context), GFP_KERNEL);
579 if (!child_device_ctx)
580 {
581 DPRINT_ERR(VMBUS_DRV, "unable to allocate device_context for child device");
582 DPRINT_EXIT(VMBUS_DRV);
583
584 return NULL;
585 }
586
587 DPRINT_DBG(VMBUS_DRV, "child device (%p) allocated - "
588 "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x},"
589 "id {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
590 &child_device_ctx->device,
Greg Kroah-Hartmandaaa8cc2009-08-19 16:18:56 -0700591 type->data[3], type->data[2], type->data[1], type->data[0],
592 type->data[5], type->data[4], type->data[7], type->data[6],
593 type->data[8], type->data[9], type->data[10], type->data[11],
594 type->data[12], type->data[13], type->data[14], type->data[15],
595 instance->data[3], instance->data[2], instance->data[1], instance->data[0],
596 instance->data[5], instance->data[4], instance->data[7], instance->data[6],
597 instance->data[8], instance->data[9], instance->data[10], instance->data[11],
598 instance->data[12], instance->data[13], instance->data[14], instance->data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700599
600 child_device_obj = &child_device_ctx->device_obj;
601 child_device_obj->context = context;
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700602 memcpy(&child_device_obj->deviceType, &type, sizeof(struct hv_guid));
603 memcpy(&child_device_obj->deviceInstance, &instance, sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700604
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700605 memcpy(&child_device_ctx->class_id, &type, sizeof(struct hv_guid));
606 memcpy(&child_device_ctx->device_id, &instance, sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700607
608 DPRINT_EXIT(VMBUS_DRV);
609
610 return child_device_obj;
611}
612
613/*++
614
615Name: vmbus_child_device_register()
616
617Desc: Register the child device on the specified bus
618
619--*/
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200620static int vmbus_child_device_register(struct hv_device *root_device_obj, struct hv_device *child_device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700621{
622 int ret=0;
623 struct device_context *root_device_ctx = to_device_context(root_device_obj);
624 struct device_context *child_device_ctx = to_device_context(child_device_obj);
Bill Pembertonf4888412009-07-29 17:00:12 -0400625 static atomic_t device_num = ATOMIC_INIT(0);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700626
627 DPRINT_ENTER(VMBUS_DRV);
628
629 DPRINT_DBG(VMBUS_DRV, "child device (%p) registering", child_device_ctx);
Bill Pemberton454f18a2009-07-27 16:47:24 -0400630
631 /* Make sure we are not registered already */
632
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -0700633 if (strlen(dev_name(&child_device_ctx->device)) != 0)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700634 {
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -0700635 DPRINT_ERR(VMBUS_DRV, "child device (%p) already registered - busid %s", child_device_ctx, dev_name(&child_device_ctx->device));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700636
637 ret = -1;
638 goto Cleanup;
639 }
640
Bill Pemberton454f18a2009-07-27 16:47:24 -0400641 /* Set the device bus id. Otherwise, device_register()will fail. */
Bill Pembertonf4888412009-07-29 17:00:12 -0400642 dev_set_name(&child_device_ctx->device, "vmbus_0_%d", atomic_inc_return(&device_num));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700643
Bill Pemberton454f18a2009-07-27 16:47:24 -0400644 /* The new device belongs to this bus */
645 child_device_ctx->device.bus = &g_vmbus_drv.bus; /* device->dev.bus; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700646 child_device_ctx->device.parent = &root_device_ctx->device;
647 child_device_ctx->device.release = vmbus_device_release;
648
Bill Pemberton454f18a2009-07-27 16:47:24 -0400649 /* Register with the LDM. This will kick off the driver/device binding...which will */
650 /* eventually call vmbus_match() and vmbus_probe() */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700651 ret = device_register(&child_device_ctx->device);
652
Bill Pemberton454f18a2009-07-27 16:47:24 -0400653 /* vmbus_probe() error does not get propergate to device_register(). */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700654 ret = child_device_ctx->probe_error;
655
656 if (ret)
Bill Pembertonb2aba7c2009-07-27 16:47:34 -0400657 DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p)", &child_device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700658 else
659 DPRINT_INFO(VMBUS_DRV, "child device (%p) registered", &child_device_ctx->device);
660
661Cleanup:
662 DPRINT_EXIT(VMBUS_DRV);
663
664 return ret;
665}
666
667/*++
668
669Name: vmbus_child_device_unregister()
670
671Desc: Remove the specified child device from the vmbus.
672
673--*/
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200674static void vmbus_child_device_unregister(struct hv_device *device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700675{
676 struct device_context *device_ctx = to_device_context(device_obj);
677
678 DPRINT_ENTER(VMBUS_DRV);
679
680 DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)", &device_ctx->device);
681
Bill Pemberton454f18a2009-07-27 16:47:24 -0400682 /* Kick off the process of unregistering the device. */
683 /* This will call vmbus_remove() and eventually vmbus_device_release() */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700684 device_unregister(&device_ctx->device);
685
686 DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered", &device_ctx->device);
687
688 DPRINT_EXIT(VMBUS_DRV);
689}
690
691
692/*++
693
694Name: vmbus_child_device_destroy()
695
696Desc: Destroy the specified child device on the vmbus.
697
698--*/
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200699static void vmbus_child_device_destroy(struct hv_device *device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700700{
701 DPRINT_ENTER(VMBUS_DRV);
702
703 DPRINT_EXIT(VMBUS_DRV);
704}
705
706/*++
707
708Name: vmbus_uevent()
709
710Desc: This routine is invoked when a device is added or removed on the vmbus to generate a uevent to udev in the
711 userspace. The udev will then look at its rule and the uevent generated here to load the appropriate driver
712
713--*/
Hank Janssen3e7ee492009-07-13 16:02:34 -0700714static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
715{
716 struct device_context *device_ctx = device_to_device_context(device);
717 int i=0;
718 int len=0;
719 int ret;
720
721 DPRINT_ENTER(VMBUS_DRV);
722
723 DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700724 device_ctx->class_id.data[3], device_ctx->class_id.data[2],
725 device_ctx->class_id.data[1], device_ctx->class_id.data[0],
726 device_ctx->class_id.data[5], device_ctx->class_id.data[4],
727 device_ctx->class_id.data[7], device_ctx->class_id.data[6],
728 device_ctx->class_id.data[8], device_ctx->class_id.data[9],
729 device_ctx->class_id.data[10], device_ctx->class_id.data[11],
730 device_ctx->class_id.data[12], device_ctx->class_id.data[13],
731 device_ctx->class_id.data[14], device_ctx->class_id.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700732
733 env->envp_idx = i;
734 env->buflen = len;
735 ret = add_uevent_var(env,
736 "VMBUS_DEVICE_CLASS_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700737 device_ctx->class_id.data[3], device_ctx->class_id.data[2],
738 device_ctx->class_id.data[1], device_ctx->class_id.data[0],
739 device_ctx->class_id.data[5], device_ctx->class_id.data[4],
740 device_ctx->class_id.data[7], device_ctx->class_id.data[6],
741 device_ctx->class_id.data[8], device_ctx->class_id.data[9],
742 device_ctx->class_id.data[10], device_ctx->class_id.data[11],
743 device_ctx->class_id.data[12], device_ctx->class_id.data[13],
744 device_ctx->class_id.data[14], device_ctx->class_id.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700745
746 if (ret)
747 {
748 return ret;
749 }
750
751 ret = add_uevent_var(env,
752 "VMBUS_DEVICE_DEVICE_GUID={%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x%02x%02x}",
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700753 device_ctx->device_id.data[3], device_ctx->device_id.data[2],
754 device_ctx->device_id.data[1], device_ctx->device_id.data[0],
755 device_ctx->device_id.data[5], device_ctx->device_id.data[4],
756 device_ctx->device_id.data[7], device_ctx->device_id.data[6],
757 device_ctx->device_id.data[8], device_ctx->device_id.data[9],
758 device_ctx->device_id.data[10], device_ctx->device_id.data[11],
759 device_ctx->device_id.data[12], device_ctx->device_id.data[13],
760 device_ctx->device_id.data[14], device_ctx->device_id.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700761
762 if (ret)
763 {
764 return ret;
765 }
766
767 env->envp[env->envp_idx] = NULL;
768
769 DPRINT_EXIT(VMBUS_DRV);
770
771 return 0;
772}
773
Hank Janssen3e7ee492009-07-13 16:02:34 -0700774/*++
775
776Name: vmbus_match()
777
778Desc: Attempt to match the specified device to the specified driver
779
780--*/
781static int vmbus_match(struct device *device, struct device_driver *driver)
782{
783 int match=0;
784 struct driver_context *driver_ctx = driver_to_driver_context(driver);
785 struct device_context *device_ctx = device_to_device_context(device);
786
787 DPRINT_ENTER(VMBUS_DRV);
788
Bill Pemberton454f18a2009-07-27 16:47:24 -0400789 /* We found our driver ? */
Greg Kroah-Hartmancaf26a32009-08-19 16:17:03 -0700790 if (memcmp(&device_ctx->class_id, &driver_ctx->class_id, sizeof(struct hv_guid)) == 0)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700791 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400792 /* !! NOTE: The driver_ctx is not a vmbus_drv_ctx. We typecast it here to access the */
Nicolas Palix775ef252009-07-29 14:09:45 +0200793 /* struct hv_driver field */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700794 struct vmbus_driver_context *vmbus_drv_ctx = (struct vmbus_driver_context*)driver_ctx;
795 device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj.Base;
796 DPRINT_INFO(VMBUS_DRV, "device object (%p) set to driver object (%p)", &device_ctx->device_obj, device_ctx->device_obj.Driver);
797
798 match = 1;
799 }
800
801 DPRINT_EXIT(VMBUS_DRV);
802
803 return match;
804}
805
806
807/*++
808
809Name: vmbus_probe_failed_cb()
810
811Desc: Callback when a driver probe failed in vmbus_probe(). We need a callback because
812 we cannot invoked device_unregister() inside vmbus_probe() since vmbus_probe() may be
813 invoked inside device_register() i.e. we cannot call device_unregister() inside
814 device_register()
815--*/
Hank Janssen3e7ee492009-07-13 16:02:34 -0700816static void vmbus_probe_failed_cb(struct work_struct *context)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700817{
818 struct device_context *device_ctx = (struct device_context*)context;
819
820
821 DPRINT_ENTER(VMBUS_DRV);
822
Bill Pemberton454f18a2009-07-27 16:47:24 -0400823 /* Kick off the process of unregistering the device. */
824 /* This will call vmbus_remove() and eventually vmbus_device_release() */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700825 device_unregister(&device_ctx->device);
826
Bill Pemberton454f18a2009-07-27 16:47:24 -0400827 /* put_device(&device_ctx->device); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700828 DPRINT_EXIT(VMBUS_DRV);
829}
830
831
832/*++
833
834Name: vmbus_probe()
835
836Desc: Add the new vmbus's child device
837
838--*/
839static int vmbus_probe(struct device *child_device)
840{
841 int ret=0;
842 struct driver_context *driver_ctx = driver_to_driver_context(child_device->driver);
843 struct device_context *device_ctx = device_to_device_context(child_device);
844
845 DPRINT_ENTER(VMBUS_DRV);
846
Bill Pemberton454f18a2009-07-27 16:47:24 -0400847 /* Let the specific open-source driver handles the probe if it can */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700848 if (driver_ctx->probe)
849 {
850 ret = device_ctx->probe_error = driver_ctx->probe(child_device);
851 if (ret != 0)
852 {
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -0700853 DPRINT_ERR(VMBUS_DRV, "probe() failed for device %s (%p) on driver %s (%d)...", dev_name(child_device), child_device, child_device->driver->name, ret);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700854
Hank Janssen3e7ee492009-07-13 16:02:34 -0700855 INIT_WORK(&device_ctx->probe_failed_work_item, vmbus_probe_failed_cb);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700856 schedule_work(&device_ctx->probe_failed_work_item);
857 }
858 }
859 else
860 {
861 DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s", child_device->driver->name);
862 ret = -1;
863 }
864
865 DPRINT_EXIT(VMBUS_DRV);
866 return ret;
867}
868
869
870/*++
871
872Name: vmbus_remove()
873
874Desc: Remove a vmbus device
875
876--*/
877static int vmbus_remove(struct device *child_device)
878{
879 int ret=0;
880 struct driver_context *driver_ctx;
881
882 DPRINT_ENTER(VMBUS_DRV);
883
Bill Pemberton454f18a2009-07-27 16:47:24 -0400884 /* Special case root bus device */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700885 if (child_device->parent == NULL)
886 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400887 /* No-op since it is statically defined and handle in vmbus_bus_exit() */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700888 DPRINT_EXIT(VMBUS_DRV);
889 return 0;
890 }
891
892 if (child_device->driver)
893 {
894 driver_ctx = driver_to_driver_context(child_device->driver);
895
Bill Pemberton454f18a2009-07-27 16:47:24 -0400896 /* Let the specific open-source driver handles the removal if it can */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700897 if (driver_ctx->remove)
898 {
899 ret = driver_ctx->remove(child_device);
900 }
901 else
902 {
903 DPRINT_ERR(VMBUS_DRV, "remove() method not set for driver - %s", child_device->driver->name);
904 ret = -1;
905 }
906 }
907 else
908 {
909
910 }
911
912 DPRINT_EXIT(VMBUS_DRV);
913
914 return 0;
915}
916
917/*++
918
919Name: vmbus_shutdown()
920
921Desc: Shutdown a vmbus device
922
923--*/
924static void vmbus_shutdown(struct device *child_device)
925{
926 struct driver_context *driver_ctx;
927
928 DPRINT_ENTER(VMBUS_DRV);
929
Bill Pemberton454f18a2009-07-27 16:47:24 -0400930 /* Special case root bus device */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700931 if (child_device->parent == NULL)
932 {
Bill Pemberton454f18a2009-07-27 16:47:24 -0400933 /* No-op since it is statically defined and handle in vmbus_bus_exit() */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700934 DPRINT_EXIT(VMBUS_DRV);
935 return;
936 }
937
Bill Pemberton454f18a2009-07-27 16:47:24 -0400938 /* The device may not be attached yet */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700939 if (!child_device->driver)
940 {
941 DPRINT_EXIT(VMBUS_DRV);
942 return;
943 }
944
945 driver_ctx = driver_to_driver_context(child_device->driver);
946
Bill Pemberton454f18a2009-07-27 16:47:24 -0400947 /* Let the specific open-source driver handles the removal if it can */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700948 if (driver_ctx->shutdown)
949 {
950 driver_ctx->shutdown(child_device);
951 }
952
953 DPRINT_EXIT(VMBUS_DRV);
954
955 return;
956}
957
958/*++
959
960Name: vmbus_bus_release()
961
962Desc: Final callback release of the vmbus root device
963
964--*/
965static void vmbus_bus_release(struct device *device)
966{
967 DPRINT_ENTER(VMBUS_DRV);
968 DPRINT_EXIT(VMBUS_DRV);
969}
970
971/*++
972
973Name: vmbus_device_release()
974
975Desc: Final callback release of the vmbus child device
976
977--*/
978static void vmbus_device_release(struct device *device)
979{
980 struct device_context *device_ctx = device_to_device_context(device);
981
982 DPRINT_ENTER(VMBUS_DRV);
983
Bill Pemberton454f18a2009-07-27 16:47:24 -0400984 /* vmbus_child_device_destroy(&device_ctx->device_obj); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700985 kfree(device_ctx);
986
Bill Pemberton454f18a2009-07-27 16:47:24 -0400987 /* !!DO NOT REFERENCE device_ctx anymore at this point!! */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700988
989 DPRINT_EXIT(VMBUS_DRV);
990
991 return;
992}
993
994/*++
995
996Name: vmbus_msg_dpc()
997
998Desc: Tasklet routine to handle hypervisor messages
999
1000--*/
1001static void vmbus_msg_dpc(unsigned long data)
1002{
1003 VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data;
1004
1005 DPRINT_ENTER(VMBUS_DRV);
1006
1007 ASSERT(vmbus_drv_obj->OnMsgDpc != NULL);
1008
Bill Pemberton454f18a2009-07-27 16:47:24 -04001009 /* Call to bus driver to handle interrupt */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001010 vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base);
1011
1012 DPRINT_EXIT(VMBUS_DRV);
1013}
1014
1015/*++
1016
1017Name: vmbus_msg_dpc()
1018
1019Desc: Tasklet routine to handle hypervisor events
1020
1021--*/
1022static void vmbus_event_dpc(unsigned long data)
1023{
1024 VMBUS_DRIVER_OBJECT* vmbus_drv_obj = (VMBUS_DRIVER_OBJECT*)data;
1025
1026 DPRINT_ENTER(VMBUS_DRV);
1027
1028 ASSERT(vmbus_drv_obj->OnEventDpc != NULL);
1029
Bill Pemberton454f18a2009-07-27 16:47:24 -04001030 /* Call to bus driver to handle interrupt */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001031 vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base);
1032
1033 DPRINT_EXIT(VMBUS_DRV);
1034}
1035
1036/*++
1037
1038Name: vmbus_msg_dpc()
1039
1040Desc: ISR routine
1041
1042--*/
Hank Janssen3e7ee492009-07-13 16:02:34 -07001043static irqreturn_t vmbus_isr(int irq, void* dev_id)
Hank Janssen3e7ee492009-07-13 16:02:34 -07001044{
1045 int ret=0;
1046 VMBUS_DRIVER_OBJECT* vmbus_driver_obj = &g_vmbus_drv.drv_obj;
1047
1048 DPRINT_ENTER(VMBUS_DRV);
1049
1050 ASSERT(vmbus_driver_obj->OnIsr != NULL);
1051
Bill Pemberton454f18a2009-07-27 16:47:24 -04001052 /* Call to bus driver to handle interrupt */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001053 ret = vmbus_driver_obj->OnIsr(&vmbus_driver_obj->Base);
1054
Bill Pemberton454f18a2009-07-27 16:47:24 -04001055 /* Schedules a dpc if necessary */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001056 if (ret > 0)
1057 {
1058 if (test_bit(0, (unsigned long*)&ret))
1059 {
1060 tasklet_schedule(&g_vmbus_drv.msg_dpc);
1061 }
1062
1063 if (test_bit(1, (unsigned long*)&ret))
1064 {
1065 tasklet_schedule(&g_vmbus_drv.event_dpc);
1066 }
1067
1068 DPRINT_EXIT(VMBUS_DRV);
1069 return IRQ_HANDLED;
1070 }
1071 else
1072 {
1073 DPRINT_EXIT(VMBUS_DRV);
1074 return IRQ_NONE;
1075 }
1076}
1077
1078MODULE_LICENSE("GPL");
1079
1080
1081/*++
1082
1083Name: vmbus_init()
1084
1085Desc: Main vmbus driver entry routine
1086
1087--*/
1088static int __init vmbus_init(void)
1089{
1090 int ret=0;
1091
1092 DPRINT_ENTER(VMBUS_DRV);
1093
1094 DPRINT_INFO(VMBUS_DRV,
1095 "Vmbus initializing.... current log level 0x%x (%x,%x)",
1096 vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel));
Bill Pemberton454f18a2009-07-27 16:47:24 -04001097/* Todo: it is used for loglevel, to be ported to new kernel. */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001098
1099 ret = vmbus_bus_init(VmbusInitialize);
1100
1101 DPRINT_EXIT(VMBUS_DRV);
1102 return ret;
1103}
1104
1105
1106
1107/*++
1108
1109Name: vmbus_init()
1110
1111Desc: Main vmbus driver exit routine
1112
1113--*/
1114static void __exit vmbus_exit(void)
1115{
1116 DPRINT_ENTER(VMBUS_DRV);
1117
1118 vmbus_bus_exit();
Bill Pemberton454f18a2009-07-27 16:47:24 -04001119/* Todo: it is used for loglevel, to be ported to new kernel. */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001120 DPRINT_EXIT(VMBUS_DRV);
1121
1122 return;
1123}
1124
Hank Janssen3e7ee492009-07-13 16:02:34 -07001125module_param(vmbus_irq, int, S_IRUGO);
1126module_param(vmbus_loglevel, int, S_IRUGO);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001127
1128module_init(vmbus_init);
1129module_exit(vmbus_exit);
Bill Pemberton454f18a2009-07-27 16:47:24 -04001130/* eof */