blob: d2a82aa3bbd8297b945825505708961cc9e31862 [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>
Hank Janssen26c14cc2010-02-11 23:02:42 +000030#include "VersionInfo.h"
Greg Kroah-Hartman4983b392009-08-19 16:14:47 -070031#include "osd.h"
Greg Kroah-Hartman645954c2009-08-28 16:22:59 -070032#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/* FIXME! We need to do this dynamically for PIC and APIC system */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070037#define VMBUS_IRQ 0x5
38#define VMBUS_IRQ_VECTOR IRQ5_VECTOR
Bill Pemberton454f18a2009-07-27 16:47:24 -040039
40/* Main vmbus driver data structure */
Hank Janssen3e7ee492009-07-13 16:02:34 -070041struct vmbus_driver_context {
Bill Pemberton454f18a2009-07-27 16:47:24 -040042 /* !! These must be the first 2 fields !! */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070043 /* FIXME, this is a bug */
Bill Pemberton454f18a2009-07-27 16:47:24 -040044 /* The driver field is not used in here. Instead, the bus field is */
45 /* used to represent the driver */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070046 struct driver_context drv_ctx;
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -070047 struct vmbus_driver drv_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -070048
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070049 struct bus_type bus;
50 struct tasklet_struct msg_dpc;
51 struct tasklet_struct event_dpc;
Hank Janssen3e7ee492009-07-13 16:02:34 -070052
Bill Pemberton454f18a2009-07-27 16:47:24 -040053 /* The bus root device */
Haiyang Zhangf916a342010-02-17 20:58:47 +000054 struct vm_device device_ctx;
Hank Janssen3e7ee492009-07-13 16:02:34 -070055};
56
Hank Janssen3e7ee492009-07-13 16:02:34 -070057static int vmbus_match(struct device *device, struct device_driver *driver);
58static int vmbus_probe(struct device *device);
59static int vmbus_remove(struct device *device);
60static void vmbus_shutdown(struct device *device);
Hank Janssen3e7ee492009-07-13 16:02:34 -070061static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env);
Hank Janssen3e7ee492009-07-13 16:02:34 -070062static void vmbus_msg_dpc(unsigned long data);
63static void vmbus_event_dpc(unsigned long data);
64
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070065static irqreturn_t vmbus_isr(int irq, void *dev_id);
Hank Janssen3e7ee492009-07-13 16:02:34 -070066
67static void vmbus_device_release(struct device *device);
68static void vmbus_bus_release(struct device *device);
69
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070070static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
71 struct hv_guid *instance,
72 void *context);
Nicolas Palix3d3b5512009-07-28 17:32:53 +020073static void vmbus_child_device_destroy(struct hv_device *device_obj);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070074static int vmbus_child_device_register(struct hv_device *root_device_obj,
75 struct hv_device *child_device_obj);
Nicolas Palix3d3b5512009-07-28 17:32:53 +020076static void vmbus_child_device_unregister(struct hv_device *child_device_obj);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070077static void vmbus_child_device_get_info(struct hv_device *device_obj,
78 struct hv_device_info *device_info);
79static ssize_t vmbus_show_device_attr(struct device *dev,
80 struct device_attribute *dev_attr,
81 char *buf);
Hank Janssen3e7ee492009-07-13 16:02:34 -070082
Hank Janssen3e7ee492009-07-13 16:02:34 -070083
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070084unsigned int vmbus_loglevel = (ALL_MODULES << 16 | INFO_LVL);
Hank Janssen3e7ee492009-07-13 16:02:34 -070085EXPORT_SYMBOL(vmbus_loglevel);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070086 /* (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT); */
87 /* (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT); */
Hank Janssen3e7ee492009-07-13 16:02:34 -070088
89static int vmbus_irq = VMBUS_IRQ;
90
Bill Pemberton454f18a2009-07-27 16:47:24 -040091/* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */
Hank Janssen3e7ee492009-07-13 16:02:34 -070092static struct device_attribute vmbus_device_attrs[] = {
93 __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL),
94 __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL),
95 __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL),
96 __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL),
97 __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL),
98
99 __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
100 __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
101 __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
102
103 __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
104 __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
105 __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
106
107 __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
108 __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
109 __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
110 __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
111 __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
112
113 __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
114 __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
115 __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
116 __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
117 __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
118 __ATTR_NULL
119};
Hank Janssen3e7ee492009-07-13 16:02:34 -0700120
Bill Pemberton454f18a2009-07-27 16:47:24 -0400121/* The one and only one */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700122static struct vmbus_driver_context g_vmbus_drv = {
123 .bus.name = "vmbus",
124 .bus.match = vmbus_match,
125 .bus.shutdown = vmbus_shutdown,
126 .bus.remove = vmbus_remove,
127 .bus.probe = vmbus_probe,
128 .bus.uevent = vmbus_uevent,
129 .bus.dev_attrs = vmbus_device_attrs,
Hank Janssen3e7ee492009-07-13 16:02:34 -0700130};
131
Hank Janssen3e189512010-03-04 22:11:00 +0000132/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700133 * vmbus_show_device_attr - Show the device attribute in sysfs.
134 *
135 * This is invoked when user does a
136 * "cat /sys/bus/vmbus/devices/<busdevice>/<attr name>"
137 */
138static ssize_t vmbus_show_device_attr(struct device *dev,
139 struct device_attribute *dev_attr,
140 char *buf)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700141{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000142 struct vm_device *device_ctx = device_to_vm_device(dev);
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700143 struct hv_device_info device_info;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700144
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700145 memset(&device_info, 0, sizeof(struct hv_device_info));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700146
147 vmbus_child_device_get_info(&device_ctx->device_obj, &device_info);
148
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700149 if (!strcmp(dev_attr->attr.name, "class_id")) {
150 return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
151 "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
152 device_info.ChannelType.data[3],
153 device_info.ChannelType.data[2],
154 device_info.ChannelType.data[1],
155 device_info.ChannelType.data[0],
156 device_info.ChannelType.data[5],
157 device_info.ChannelType.data[4],
158 device_info.ChannelType.data[7],
159 device_info.ChannelType.data[6],
160 device_info.ChannelType.data[8],
161 device_info.ChannelType.data[9],
162 device_info.ChannelType.data[10],
163 device_info.ChannelType.data[11],
164 device_info.ChannelType.data[12],
165 device_info.ChannelType.data[13],
166 device_info.ChannelType.data[14],
167 device_info.ChannelType.data[15]);
168 } else if (!strcmp(dev_attr->attr.name, "device_id")) {
169 return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
170 "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
171 device_info.ChannelInstance.data[3],
172 device_info.ChannelInstance.data[2],
173 device_info.ChannelInstance.data[1],
174 device_info.ChannelInstance.data[0],
175 device_info.ChannelInstance.data[5],
176 device_info.ChannelInstance.data[4],
177 device_info.ChannelInstance.data[7],
178 device_info.ChannelInstance.data[6],
179 device_info.ChannelInstance.data[8],
180 device_info.ChannelInstance.data[9],
181 device_info.ChannelInstance.data[10],
182 device_info.ChannelInstance.data[11],
183 device_info.ChannelInstance.data[12],
184 device_info.ChannelInstance.data[13],
185 device_info.ChannelInstance.data[14],
186 device_info.ChannelInstance.data[15]);
187 } else if (!strcmp(dev_attr->attr.name, "state")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700188 return sprintf(buf, "%d\n", device_info.ChannelState);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700189 } else if (!strcmp(dev_attr->attr.name, "id")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700190 return sprintf(buf, "%d\n", device_info.ChannelId);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700191 } else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700192 return sprintf(buf, "%d\n", device_info.Outbound.InterruptMask);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700193 } else if (!strcmp(dev_attr->attr.name, "out_read_index")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700194 return sprintf(buf, "%d\n", device_info.Outbound.ReadIndex);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700195 } else if (!strcmp(dev_attr->attr.name, "out_write_index")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700196 return sprintf(buf, "%d\n", device_info.Outbound.WriteIndex);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700197 } else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) {
198 return sprintf(buf, "%d\n",
199 device_info.Outbound.BytesAvailToRead);
200 } else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) {
201 return sprintf(buf, "%d\n",
202 device_info.Outbound.BytesAvailToWrite);
203 } else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700204 return sprintf(buf, "%d\n", device_info.Inbound.InterruptMask);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700205 } else if (!strcmp(dev_attr->attr.name, "in_read_index")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700206 return sprintf(buf, "%d\n", device_info.Inbound.ReadIndex);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700207 } else if (!strcmp(dev_attr->attr.name, "in_write_index")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700208 return sprintf(buf, "%d\n", device_info.Inbound.WriteIndex);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700209 } else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) {
210 return sprintf(buf, "%d\n",
211 device_info.Inbound.BytesAvailToRead);
212 } else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) {
213 return sprintf(buf, "%d\n",
214 device_info.Inbound.BytesAvailToWrite);
215 } else if (!strcmp(dev_attr->attr.name, "monitor_id")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700216 return sprintf(buf, "%d\n", device_info.MonitorId);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700217 } else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700218 return sprintf(buf, "%d\n", device_info.ServerMonitorPending);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700219 } else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700220 return sprintf(buf, "%d\n", device_info.ServerMonitorLatency);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700221 } else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) {
222 return sprintf(buf, "%d\n",
223 device_info.ServerMonitorConnectionId);
224 } else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700225 return sprintf(buf, "%d\n", device_info.ClientMonitorPending);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700226 } else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700227 return sprintf(buf, "%d\n", device_info.ClientMonitorLatency);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700228 } else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) {
229 return sprintf(buf, "%d\n",
230 device_info.ClientMonitorConnectionId);
231 } else {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700232 return 0;
233 }
234}
235
Hank Janssen3e189512010-03-04 22:11:00 +0000236/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700237 * vmbus_bus_init -Main vmbus driver initialization routine.
238 *
239 * Here, we
Lars Lindley0686e4f2010-03-11 23:51:23 +0100240 * - initialize the vmbus driver context
241 * - setup various driver entry points
242 * - invoke the vmbus hv main init routine
243 * - get the irq resource
244 * - invoke the vmbus to add the vmbus root device
245 * - setup the vmbus root device
246 * - retrieve the channel offers
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700247 */
Greg Kroah-Hartman21707be2009-09-02 11:53:59 -0700248static int vmbus_bus_init(int (*drv_init)(struct hv_driver *drv))
Hank Janssen3e7ee492009-07-13 16:02:34 -0700249{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700250 struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv;
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700251 struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
Haiyang Zhangf916a342010-02-17 20:58:47 +0000252 struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700253 int ret;
254 unsigned int vector;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700255
256 DPRINT_ENTER(VMBUS_DRV);
257
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700258 /*
259 * Set this up to allow lower layer to callback to add/remove child
260 * devices on the bus
261 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700262 vmbus_drv_obj->OnChildDeviceCreate = vmbus_child_device_create;
263 vmbus_drv_obj->OnChildDeviceDestroy = vmbus_child_device_destroy;
264 vmbus_drv_obj->OnChildDeviceAdd = vmbus_child_device_register;
265 vmbus_drv_obj->OnChildDeviceRemove = vmbus_child_device_unregister;
266
Bill Pemberton454f18a2009-07-27 16:47:24 -0400267 /* Call to bus driver to initialize */
Greg Kroah-Hartman21707be2009-09-02 11:53:59 -0700268 ret = drv_init(&vmbus_drv_obj->Base);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700269 if (ret != 0) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700270 DPRINT_ERR(VMBUS_DRV, "Unable to initialize vmbus (%d)", ret);
271 goto cleanup;
272 }
273
Bill Pemberton454f18a2009-07-27 16:47:24 -0400274 /* Sanity checks */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700275 if (!vmbus_drv_obj->Base.OnDeviceAdd) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700276 DPRINT_ERR(VMBUS_DRV, "OnDeviceAdd() routine not set");
277 ret = -1;
278 goto cleanup;
279 }
280
281 vmbus_drv_ctx->bus.name = vmbus_drv_obj->Base.name;
282
Bill Pemberton454f18a2009-07-27 16:47:24 -0400283 /* Initialize the bus context */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700284 tasklet_init(&vmbus_drv_ctx->msg_dpc, vmbus_msg_dpc,
285 (unsigned long)vmbus_drv_obj);
286 tasklet_init(&vmbus_drv_ctx->event_dpc, vmbus_event_dpc,
287 (unsigned long)vmbus_drv_obj);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700288
Bill Pemberton454f18a2009-07-27 16:47:24 -0400289 /* Now, register the bus driver with LDM */
Bill Pembertonc19fbca2009-07-27 16:47:35 -0400290 ret = bus_register(&vmbus_drv_ctx->bus);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700291 if (ret) {
Bill Pembertonc19fbca2009-07-27 16:47:35 -0400292 ret = -1;
293 goto cleanup;
294 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700295
Bill Pemberton454f18a2009-07-27 16:47:24 -0400296 /* Get the interrupt resource */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700297 ret = request_irq(vmbus_irq, vmbus_isr, IRQF_SAMPLE_RANDOM,
298 vmbus_drv_obj->Base.name, NULL);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700299
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700300 if (ret != 0) {
301 DPRINT_ERR(VMBUS_DRV, "ERROR - Unable to request IRQ %d",
302 vmbus_irq);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700303
304 bus_unregister(&vmbus_drv_ctx->bus);
305
306 ret = -1;
307 goto cleanup;
308 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700309 vector = VMBUS_IRQ_VECTOR;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700310
311 DPRINT_INFO(VMBUS_DRV, "irq 0x%x vector 0x%x", vmbus_irq, vector);
312
Bill Pemberton454f18a2009-07-27 16:47:24 -0400313 /* Call to bus driver to add the root device */
Haiyang Zhangf916a342010-02-17 20:58:47 +0000314 memset(dev_ctx, 0, sizeof(struct vm_device));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700315
316 ret = vmbus_drv_obj->Base.OnDeviceAdd(&dev_ctx->device_obj, &vector);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700317 if (ret != 0) {
318 DPRINT_ERR(VMBUS_DRV,
319 "ERROR - Unable to add vmbus root device");
Hank Janssen3e7ee492009-07-13 16:02:34 -0700320
321 free_irq(vmbus_irq, NULL);
322
323 bus_unregister(&vmbus_drv_ctx->bus);
324
325 ret = -1;
326 goto cleanup;
327 }
Bill Pemberton454f18a2009-07-27 16:47:24 -0400328 /* strcpy(dev_ctx->device.bus_id, dev_ctx->device_obj.name); */
Greg Kroah-Hartman09d50ff2009-07-13 17:09:34 -0700329 dev_set_name(&dev_ctx->device, "vmbus_0_0");
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700330 memcpy(&dev_ctx->class_id, &dev_ctx->device_obj.deviceType,
331 sizeof(struct hv_guid));
332 memcpy(&dev_ctx->device_id, &dev_ctx->device_obj.deviceInstance,
333 sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700334
Bill Pemberton454f18a2009-07-27 16:47:24 -0400335 /* No need to bind a driver to the root device. */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700336 dev_ctx->device.parent = NULL;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700337 /* NULL; vmbus_remove() does not get invoked */
338 dev_ctx->device.bus = &vmbus_drv_ctx->bus;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700339
Bill Pemberton454f18a2009-07-27 16:47:24 -0400340 /* Setup the device dispatch table */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700341 dev_ctx->device.release = vmbus_bus_release;
342
Bill Pemberton454f18a2009-07-27 16:47:24 -0400343 /* Setup the bus as root device */
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400344 ret = device_register(&dev_ctx->device);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700345 if (ret) {
346 DPRINT_ERR(VMBUS_DRV,
347 "ERROR - Unable to register vmbus root device");
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400348
349 free_irq(vmbus_irq, NULL);
350 bus_unregister(&vmbus_drv_ctx->bus);
351
352 ret = -1;
353 goto cleanup;
354 }
355
Hank Janssen3e7ee492009-07-13 16:02:34 -0700356
357 vmbus_drv_obj->GetChannelOffers();
358
359cleanup:
360 DPRINT_EXIT(VMBUS_DRV);
361
362 return ret;
363}
364
Hank Janssen3e189512010-03-04 22:11:00 +0000365/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700366 * vmbus_bus_exit - Terminate the vmbus driver.
367 *
368 * This routine is opposite of vmbus_bus_init()
369 */
Greg Kroah-Hartmanbd1de702009-07-29 09:04:51 -0700370static void vmbus_bus_exit(void)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700371{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700372 struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700373 struct vmbus_driver_context *vmbus_drv_ctx = &g_vmbus_drv;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700374
Haiyang Zhangf916a342010-02-17 20:58:47 +0000375 struct vm_device *dev_ctx = &g_vmbus_drv.device_ctx;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700376
377 DPRINT_ENTER(VMBUS_DRV);
378
Bill Pemberton454f18a2009-07-27 16:47:24 -0400379 /* Remove the root device */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700380 if (vmbus_drv_obj->Base.OnDeviceRemove)
381 vmbus_drv_obj->Base.OnDeviceRemove(&dev_ctx->device_obj);
382
383 if (vmbus_drv_obj->Base.OnCleanup)
384 vmbus_drv_obj->Base.OnCleanup(&vmbus_drv_obj->Base);
385
Bill Pemberton454f18a2009-07-27 16:47:24 -0400386 /* Unregister the root bus device */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700387 device_unregister(&dev_ctx->device);
388
389 bus_unregister(&vmbus_drv_ctx->bus);
390
391 free_irq(vmbus_irq, NULL);
392
393 tasklet_kill(&vmbus_drv_ctx->msg_dpc);
394 tasklet_kill(&vmbus_drv_ctx->event_dpc);
395
396 DPRINT_EXIT(VMBUS_DRV);
397
398 return;
399}
400
Hank Janssen3e189512010-03-04 22:11:00 +0000401
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700402/**
Hank Janssen3e189512010-03-04 22:11:00 +0000403 * vmbus_child_driver_register() - Register a vmbus's child driver
404 * @driver_ctx: Pointer to driver structure you want to register
405 *
406 * @driver_ctx is of type &struct driver_context
407 *
408 * Registers the given driver with Linux through the 'driver_register()' call
409 * And sets up the hyper-v vmbus handling for this driver.
410 * It will return the state of the 'driver_register()' call.
411 *
412 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700413 */
414int vmbus_child_driver_register(struct driver_context *driver_ctx)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700415{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700416 struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400417 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700418
419 DPRINT_ENTER(VMBUS_DRV);
420
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700421 DPRINT_INFO(VMBUS_DRV, "child driver (%p) registering - name %s",
422 driver_ctx, driver_ctx->driver.name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700423
Bill Pemberton454f18a2009-07-27 16:47:24 -0400424 /* The child driver on this vmbus */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700425 driver_ctx->driver.bus = &g_vmbus_drv.bus;
426
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400427 ret = driver_register(&driver_ctx->driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700428
429 vmbus_drv_obj->GetChannelOffers();
430
431 DPRINT_EXIT(VMBUS_DRV);
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400432
433 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700434}
Hank Janssen3e7ee492009-07-13 16:02:34 -0700435EXPORT_SYMBOL(vmbus_child_driver_register);
436
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700437/**
Hank Janssen3e189512010-03-04 22:11:00 +0000438 * vmbus_child_driver_unregister() - Unregister a vmbus's child driver
439 * @driver_ctx: Pointer to driver structure you want to un-register
440 *
441 * @driver_ctx is of type &struct driver_context
442 *
443 * Un-register the given driver with Linux through the 'driver_unregister()'
444 * call. And ungegisters the driver from the Hyper-V vmbus handler.
445 *
446 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700447 */
448void vmbus_child_driver_unregister(struct driver_context *driver_ctx)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700449{
450 DPRINT_ENTER(VMBUS_DRV);
451
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700452 DPRINT_INFO(VMBUS_DRV, "child driver (%p) unregistering - name %s",
453 driver_ctx, driver_ctx->driver.name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700454
455 driver_unregister(&driver_ctx->driver);
456
457 driver_ctx->driver.bus = NULL;
458
459 DPRINT_EXIT(VMBUS_DRV);
460}
Hank Janssen3e7ee492009-07-13 16:02:34 -0700461EXPORT_SYMBOL(vmbus_child_driver_unregister);
462
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700463/**
Hank Janssen3e189512010-03-04 22:11:00 +0000464 * vmbus_get_interface() - Get the vmbus channel interface.
465 * @interface: Pointer to channel interface structure
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700466 *
Hank Janssen3e189512010-03-04 22:11:00 +0000467 * Get the Hyper-V channel used for the driver.
468 *
469 * @interface is of type &struct vmbus_channel_interface
470 * This is invoked by child/client driver that sits above vmbus.
471 *
472 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700473 */
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700474void vmbus_get_interface(struct vmbus_channel_interface *interface)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700475{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700476 struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700477
478 vmbus_drv_obj->GetChannelInterface(interface);
479}
Hank Janssen3e7ee492009-07-13 16:02:34 -0700480EXPORT_SYMBOL(vmbus_get_interface);
481
Hank Janssen3e189512010-03-04 22:11:00 +0000482/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700483 * vmbus_child_device_get_info - Get the vmbus child device info.
484 *
485 * This is invoked to display various device attributes in sysfs.
486 */
487static void vmbus_child_device_get_info(struct hv_device *device_obj,
488 struct hv_device_info *device_info)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700489{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700490 struct vmbus_driver *vmbus_drv_obj = &g_vmbus_drv.drv_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700491
492 vmbus_drv_obj->GetChannelInfo(device_obj, device_info);
493}
494
Hank Janssen3e189512010-03-04 22:11:00 +0000495/*
496 * vmbus_child_device_create - Creates and registers a new child device
497 * on the vmbus.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700498 */
Greg Kroah-Hartmandaaa8cc2009-08-19 16:18:56 -0700499static struct hv_device *vmbus_child_device_create(struct hv_guid *type,
500 struct hv_guid *instance,
501 void *context)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700502{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000503 struct vm_device *child_device_ctx;
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200504 struct hv_device *child_device_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700505
506 DPRINT_ENTER(VMBUS_DRV);
507
Bill Pemberton454f18a2009-07-27 16:47:24 -0400508 /* Allocate the new child device */
Haiyang Zhangf916a342010-02-17 20:58:47 +0000509 child_device_ctx = kzalloc(sizeof(struct vm_device), GFP_KERNEL);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700510 if (!child_device_ctx) {
511 DPRINT_ERR(VMBUS_DRV,
512 "unable to allocate device_context for child device");
Hank Janssen3e7ee492009-07-13 16:02:34 -0700513 DPRINT_EXIT(VMBUS_DRV);
514
515 return NULL;
516 }
517
518 DPRINT_DBG(VMBUS_DRV, "child device (%p) allocated - "
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700519 "type {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
520 "%02x%02x%02x%02x%02x%02x%02x%02x},"
521 "id {%02x%02x%02x%02x-%02x%02x-%02x%02x-"
522 "%02x%02x%02x%02x%02x%02x%02x%02x}",
Hank Janssen3e7ee492009-07-13 16:02:34 -0700523 &child_device_ctx->device,
Greg Kroah-Hartmandaaa8cc2009-08-19 16:18:56 -0700524 type->data[3], type->data[2], type->data[1], type->data[0],
525 type->data[5], type->data[4], type->data[7], type->data[6],
526 type->data[8], type->data[9], type->data[10], type->data[11],
527 type->data[12], type->data[13], type->data[14], type->data[15],
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700528 instance->data[3], instance->data[2],
529 instance->data[1], instance->data[0],
530 instance->data[5], instance->data[4],
531 instance->data[7], instance->data[6],
532 instance->data[8], instance->data[9],
533 instance->data[10], instance->data[11],
534 instance->data[12], instance->data[13],
535 instance->data[14], instance->data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700536
537 child_device_obj = &child_device_ctx->device_obj;
538 child_device_obj->context = context;
Milan Dadok9fb5cce2009-10-28 23:23:27 +0100539 memcpy(&child_device_obj->deviceType, type, sizeof(struct hv_guid));
540 memcpy(&child_device_obj->deviceInstance, instance,
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700541 sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700542
Milan Dadok9fb5cce2009-10-28 23:23:27 +0100543 memcpy(&child_device_ctx->class_id, type, sizeof(struct hv_guid));
544 memcpy(&child_device_ctx->device_id, instance, sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700545
546 DPRINT_EXIT(VMBUS_DRV);
547
548 return child_device_obj;
549}
550
Hank Janssen3e189512010-03-04 22:11:00 +0000551/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700552 * vmbus_child_device_register - Register the child device on the specified bus
553 */
554static int vmbus_child_device_register(struct hv_device *root_device_obj,
555 struct hv_device *child_device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700556{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700557 int ret = 0;
Haiyang Zhangf916a342010-02-17 20:58:47 +0000558 struct vm_device *root_device_ctx =
559 to_vm_device(root_device_obj);
560 struct vm_device *child_device_ctx =
561 to_vm_device(child_device_obj);
Bill Pembertonf4888412009-07-29 17:00:12 -0400562 static atomic_t device_num = ATOMIC_INIT(0);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700563
564 DPRINT_ENTER(VMBUS_DRV);
565
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700566 DPRINT_DBG(VMBUS_DRV, "child device (%p) registering",
567 child_device_ctx);
Bill Pemberton454f18a2009-07-27 16:47:24 -0400568
Haiyang Zhang1bb40a22009-10-23 18:14:24 +0000569 /* Set the device name. Otherwise, device_register() will fail. */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700570 dev_set_name(&child_device_ctx->device, "vmbus_0_%d",
571 atomic_inc_return(&device_num));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700572
Bill Pemberton454f18a2009-07-27 16:47:24 -0400573 /* The new device belongs to this bus */
574 child_device_ctx->device.bus = &g_vmbus_drv.bus; /* device->dev.bus; */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700575 child_device_ctx->device.parent = &root_device_ctx->device;
576 child_device_ctx->device.release = vmbus_device_release;
577
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700578 /*
579 * Register with the LDM. This will kick off the driver/device
580 * binding...which will eventually call vmbus_match() and vmbus_probe()
581 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700582 ret = device_register(&child_device_ctx->device);
583
Bill Pemberton454f18a2009-07-27 16:47:24 -0400584 /* vmbus_probe() error does not get propergate to device_register(). */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700585 ret = child_device_ctx->probe_error;
586
587 if (ret)
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700588 DPRINT_ERR(VMBUS_DRV, "unable to register child device (%p)",
589 &child_device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700590 else
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700591 DPRINT_INFO(VMBUS_DRV, "child device (%p) registered",
592 &child_device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700593
Hank Janssen3e7ee492009-07-13 16:02:34 -0700594 DPRINT_EXIT(VMBUS_DRV);
595
596 return ret;
597}
598
Hank Janssen3e189512010-03-04 22:11:00 +0000599/*
600 * vmbus_child_device_unregister - Remove the specified child device
601 * from the vmbus.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700602 */
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200603static void vmbus_child_device_unregister(struct hv_device *device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700604{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000605 struct vm_device *device_ctx = to_vm_device(device_obj);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700606
607 DPRINT_ENTER(VMBUS_DRV);
608
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700609 DPRINT_INFO(VMBUS_DRV, "unregistering child device (%p)",
610 &device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700611
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700612 /*
613 * Kick off the process of unregistering the device.
614 * This will call vmbus_remove() and eventually vmbus_device_release()
615 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700616 device_unregister(&device_ctx->device);
617
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700618 DPRINT_INFO(VMBUS_DRV, "child device (%p) unregistered",
619 &device_ctx->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700620
621 DPRINT_EXIT(VMBUS_DRV);
622}
623
Hank Janssen3e189512010-03-04 22:11:00 +0000624/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700625 * vmbus_child_device_destroy - Destroy the specified child device on the vmbus.
626 */
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200627static void vmbus_child_device_destroy(struct hv_device *device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700628{
629 DPRINT_ENTER(VMBUS_DRV);
630
631 DPRINT_EXIT(VMBUS_DRV);
632}
633
Hank Janssen3e189512010-03-04 22:11:00 +0000634/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700635 * vmbus_uevent - add uevent for our device
636 *
637 * This routine is invoked when a device is added or removed on the vmbus to
638 * generate a uevent to udev in the userspace. The udev will then look at its
639 * rule and the uevent generated here to load the appropriate driver
640 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700641static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
642{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000643 struct vm_device *device_ctx = device_to_vm_device(device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700644 int ret;
645
646 DPRINT_ENTER(VMBUS_DRV);
647
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700648 DPRINT_INFO(VMBUS_DRV, "generating uevent - VMBUS_DEVICE_CLASS_GUID={"
649 "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
650 "%02x%02x%02x%02x%02x%02x%02x%02x}",
651 device_ctx->class_id.data[3], device_ctx->class_id.data[2],
652 device_ctx->class_id.data[1], device_ctx->class_id.data[0],
653 device_ctx->class_id.data[5], device_ctx->class_id.data[4],
654 device_ctx->class_id.data[7], device_ctx->class_id.data[6],
655 device_ctx->class_id.data[8], device_ctx->class_id.data[9],
656 device_ctx->class_id.data[10],
657 device_ctx->class_id.data[11],
658 device_ctx->class_id.data[12],
659 device_ctx->class_id.data[13],
660 device_ctx->class_id.data[14],
661 device_ctx->class_id.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700662
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700663 ret = add_uevent_var(env, "VMBUS_DEVICE_CLASS_GUID={"
664 "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
665 "%02x%02x%02x%02x%02x%02x%02x%02x}",
666 device_ctx->class_id.data[3],
667 device_ctx->class_id.data[2],
668 device_ctx->class_id.data[1],
669 device_ctx->class_id.data[0],
670 device_ctx->class_id.data[5],
671 device_ctx->class_id.data[4],
672 device_ctx->class_id.data[7],
673 device_ctx->class_id.data[6],
674 device_ctx->class_id.data[8],
675 device_ctx->class_id.data[9],
676 device_ctx->class_id.data[10],
677 device_ctx->class_id.data[11],
678 device_ctx->class_id.data[12],
679 device_ctx->class_id.data[13],
680 device_ctx->class_id.data[14],
681 device_ctx->class_id.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700682
683 if (ret)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700684 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700685
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700686 ret = add_uevent_var(env, "VMBUS_DEVICE_DEVICE_GUID={"
687 "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
688 "%02x%02x%02x%02x%02x%02x%02x%02x}",
689 device_ctx->device_id.data[3],
690 device_ctx->device_id.data[2],
691 device_ctx->device_id.data[1],
692 device_ctx->device_id.data[0],
693 device_ctx->device_id.data[5],
694 device_ctx->device_id.data[4],
695 device_ctx->device_id.data[7],
696 device_ctx->device_id.data[6],
697 device_ctx->device_id.data[8],
698 device_ctx->device_id.data[9],
699 device_ctx->device_id.data[10],
700 device_ctx->device_id.data[11],
701 device_ctx->device_id.data[12],
702 device_ctx->device_id.data[13],
703 device_ctx->device_id.data[14],
704 device_ctx->device_id.data[15]);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700705 if (ret)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700706 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700707
Hank Janssen3e7ee492009-07-13 16:02:34 -0700708 DPRINT_EXIT(VMBUS_DRV);
709
710 return 0;
711}
712
Hank Janssen3e189512010-03-04 22:11:00 +0000713/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700714 * vmbus_match - Attempt to match the specified device to the specified driver
715 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700716static int vmbus_match(struct device *device, struct device_driver *driver)
717{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700718 int match = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700719 struct driver_context *driver_ctx = driver_to_driver_context(driver);
Haiyang Zhangf916a342010-02-17 20:58:47 +0000720 struct vm_device *device_ctx = device_to_vm_device(device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700721
722 DPRINT_ENTER(VMBUS_DRV);
723
Bill Pemberton454f18a2009-07-27 16:47:24 -0400724 /* We found our driver ? */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700725 if (memcmp(&device_ctx->class_id, &driver_ctx->class_id,
726 sizeof(struct hv_guid)) == 0) {
727 /*
728 * !! NOTE: The driver_ctx is not a vmbus_drv_ctx. We typecast
729 * it here to access the struct hv_driver field
730 */
731 struct vmbus_driver_context *vmbus_drv_ctx =
732 (struct vmbus_driver_context *)driver_ctx;
733
Hank Janssen3e7ee492009-07-13 16:02:34 -0700734 device_ctx->device_obj.Driver = &vmbus_drv_ctx->drv_obj.Base;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700735 DPRINT_INFO(VMBUS_DRV,
736 "device object (%p) set to driver object (%p)",
737 &device_ctx->device_obj,
738 device_ctx->device_obj.Driver);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700739
740 match = 1;
741 }
742
743 DPRINT_EXIT(VMBUS_DRV);
744
745 return match;
746}
747
Hank Janssen3e189512010-03-04 22:11:00 +0000748/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700749 * vmbus_probe_failed_cb - Callback when a driver probe failed in vmbus_probe()
750 *
751 * We need a callback because we cannot invoked device_unregister() inside
752 * vmbus_probe() since vmbus_probe() may be invoked inside device_register()
753 * i.e. we cannot call device_unregister() inside device_register()
754 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700755static void vmbus_probe_failed_cb(struct work_struct *context)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700756{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000757 struct vm_device *device_ctx = (struct vm_device *)context;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700758
759 DPRINT_ENTER(VMBUS_DRV);
760
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700761 /*
762 * Kick off the process of unregistering the device.
763 * This will call vmbus_remove() and eventually vmbus_device_release()
764 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700765 device_unregister(&device_ctx->device);
766
Bill Pemberton454f18a2009-07-27 16:47:24 -0400767 /* put_device(&device_ctx->device); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700768 DPRINT_EXIT(VMBUS_DRV);
769}
770
Hank Janssen3e189512010-03-04 22:11:00 +0000771/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700772 * vmbus_probe - Add the new vmbus's child device
773 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700774static int vmbus_probe(struct device *child_device)
775{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700776 int ret = 0;
777 struct driver_context *driver_ctx =
778 driver_to_driver_context(child_device->driver);
Haiyang Zhangf916a342010-02-17 20:58:47 +0000779 struct vm_device *device_ctx =
780 device_to_vm_device(child_device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700781
782 DPRINT_ENTER(VMBUS_DRV);
783
Bill Pemberton454f18a2009-07-27 16:47:24 -0400784 /* Let the specific open-source driver handles the probe if it can */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700785 if (driver_ctx->probe) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700786 ret = device_ctx->probe_error = driver_ctx->probe(child_device);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700787 if (ret != 0) {
788 DPRINT_ERR(VMBUS_DRV, "probe() failed for device %s "
789 "(%p) on driver %s (%d)...",
790 dev_name(child_device), child_device,
791 child_device->driver->name, ret);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700792
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700793 INIT_WORK(&device_ctx->probe_failed_work_item,
794 vmbus_probe_failed_cb);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700795 schedule_work(&device_ctx->probe_failed_work_item);
796 }
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700797 } else {
798 DPRINT_ERR(VMBUS_DRV, "probe() method not set for driver - %s",
799 child_device->driver->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700800 ret = -1;
801 }
802
803 DPRINT_EXIT(VMBUS_DRV);
804 return ret;
805}
806
Hank Janssen3e189512010-03-04 22:11:00 +0000807/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700808 * vmbus_remove - Remove a vmbus device
809 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700810static int vmbus_remove(struct device *child_device)
811{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700812 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700813 struct driver_context *driver_ctx;
814
815 DPRINT_ENTER(VMBUS_DRV);
816
Bill Pemberton454f18a2009-07-27 16:47:24 -0400817 /* Special case root bus device */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700818 if (child_device->parent == NULL) {
819 /*
820 * No-op since it is statically defined and handle in
821 * vmbus_bus_exit()
822 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700823 DPRINT_EXIT(VMBUS_DRV);
824 return 0;
825 }
826
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700827 if (child_device->driver) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700828 driver_ctx = driver_to_driver_context(child_device->driver);
829
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700830 /*
831 * Let the specific open-source driver handles the removal if
832 * it can
833 */
834 if (driver_ctx->remove) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700835 ret = driver_ctx->remove(child_device);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700836 } else {
837 DPRINT_ERR(VMBUS_DRV,
838 "remove() method not set for driver - %s",
839 child_device->driver->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700840 ret = -1;
841 }
842 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700843
844 DPRINT_EXIT(VMBUS_DRV);
845
846 return 0;
847}
848
Hank Janssen3e189512010-03-04 22:11:00 +0000849/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700850 * vmbus_shutdown - Shutdown a vmbus device
851 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700852static void vmbus_shutdown(struct device *child_device)
853{
854 struct driver_context *driver_ctx;
855
856 DPRINT_ENTER(VMBUS_DRV);
857
Bill Pemberton454f18a2009-07-27 16:47:24 -0400858 /* Special case root bus device */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700859 if (child_device->parent == NULL) {
860 /*
861 * No-op since it is statically defined and handle in
862 * vmbus_bus_exit()
863 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700864 DPRINT_EXIT(VMBUS_DRV);
865 return;
866 }
867
Bill Pemberton454f18a2009-07-27 16:47:24 -0400868 /* The device may not be attached yet */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700869 if (!child_device->driver) {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700870 DPRINT_EXIT(VMBUS_DRV);
871 return;
872 }
873
874 driver_ctx = driver_to_driver_context(child_device->driver);
875
Bill Pemberton454f18a2009-07-27 16:47:24 -0400876 /* Let the specific open-source driver handles the removal if it can */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700877 if (driver_ctx->shutdown)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700878 driver_ctx->shutdown(child_device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700879
880 DPRINT_EXIT(VMBUS_DRV);
881
882 return;
883}
884
Hank Janssen3e189512010-03-04 22:11:00 +0000885/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700886 * vmbus_bus_release - Final callback release of the vmbus root device
887 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700888static void vmbus_bus_release(struct device *device)
889{
890 DPRINT_ENTER(VMBUS_DRV);
Greg Kroah-Hartman689bf402009-09-01 20:12:58 -0700891 /* FIXME */
892 /* Empty release functions are a bug, or a major sign
893 * of a problem design, this MUST BE FIXED! */
894 dev_err(device, "%s needs to be fixed!\n", __func__);
895 WARN_ON(1);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700896 DPRINT_EXIT(VMBUS_DRV);
897}
898
Hank Janssen3e189512010-03-04 22:11:00 +0000899/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700900 * vmbus_device_release - Final callback release of the vmbus child device
901 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700902static void vmbus_device_release(struct device *device)
903{
Haiyang Zhangf916a342010-02-17 20:58:47 +0000904 struct vm_device *device_ctx = device_to_vm_device(device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700905
906 DPRINT_ENTER(VMBUS_DRV);
907
Bill Pemberton454f18a2009-07-27 16:47:24 -0400908 /* vmbus_child_device_destroy(&device_ctx->device_obj); */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700909 kfree(device_ctx);
910
Bill Pemberton454f18a2009-07-27 16:47:24 -0400911 /* !!DO NOT REFERENCE device_ctx anymore at this point!! */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700912 DPRINT_EXIT(VMBUS_DRV);
913
914 return;
915}
916
Hank Janssen3e189512010-03-04 22:11:00 +0000917/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700918 * vmbus_msg_dpc - Tasklet routine to handle hypervisor messages
919 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700920static void vmbus_msg_dpc(unsigned long data)
921{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700922 struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700923
924 DPRINT_ENTER(VMBUS_DRV);
925
926 ASSERT(vmbus_drv_obj->OnMsgDpc != NULL);
927
Bill Pemberton454f18a2009-07-27 16:47:24 -0400928 /* Call to bus driver to handle interrupt */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700929 vmbus_drv_obj->OnMsgDpc(&vmbus_drv_obj->Base);
930
931 DPRINT_EXIT(VMBUS_DRV);
932}
933
Hank Janssen3e189512010-03-04 22:11:00 +0000934/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700935 * vmbus_msg_dpc - Tasklet routine to handle hypervisor events
936 */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700937static void vmbus_event_dpc(unsigned long data)
938{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700939 struct vmbus_driver *vmbus_drv_obj = (struct vmbus_driver *)data;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700940
941 DPRINT_ENTER(VMBUS_DRV);
942
943 ASSERT(vmbus_drv_obj->OnEventDpc != NULL);
944
Bill Pemberton454f18a2009-07-27 16:47:24 -0400945 /* Call to bus driver to handle interrupt */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700946 vmbus_drv_obj->OnEventDpc(&vmbus_drv_obj->Base);
947
948 DPRINT_EXIT(VMBUS_DRV);
949}
950
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700951static irqreturn_t vmbus_isr(int irq, void *dev_id)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700952{
Greg Kroah-Hartmanee3d7dd2009-08-20 12:17:36 -0700953 struct vmbus_driver *vmbus_driver_obj = &g_vmbus_drv.drv_obj;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700954 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700955
956 DPRINT_ENTER(VMBUS_DRV);
957
958 ASSERT(vmbus_driver_obj->OnIsr != NULL);
959
Bill Pemberton454f18a2009-07-27 16:47:24 -0400960 /* Call to bus driver to handle interrupt */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700961 ret = vmbus_driver_obj->OnIsr(&vmbus_driver_obj->Base);
962
Bill Pemberton454f18a2009-07-27 16:47:24 -0400963 /* Schedules a dpc if necessary */
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700964 if (ret > 0) {
965 if (test_bit(0, (unsigned long *)&ret))
Hank Janssen3e7ee492009-07-13 16:02:34 -0700966 tasklet_schedule(&g_vmbus_drv.msg_dpc);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700967
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700968 if (test_bit(1, (unsigned long *)&ret))
Hank Janssen3e7ee492009-07-13 16:02:34 -0700969 tasklet_schedule(&g_vmbus_drv.event_dpc);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700970
971 DPRINT_EXIT(VMBUS_DRV);
972 return IRQ_HANDLED;
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700973 } else {
Hank Janssen3e7ee492009-07-13 16:02:34 -0700974 DPRINT_EXIT(VMBUS_DRV);
975 return IRQ_NONE;
976 }
977}
978
Greg Kroah-Hartmanc22090f2010-02-25 16:43:15 -0800979static struct dmi_system_id __initdata microsoft_hv_dmi_table[] = {
980 {
981 .ident = "Hyper-V",
982 .matches = {
983 DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
984 DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
985 DMI_MATCH(DMI_BOARD_NAME, "Virtual Machine"),
986 },
987 },
988 { },
989};
990MODULE_DEVICE_TABLE(dmi, microsoft_hv_dmi_table);
991
Hank Janssen3e7ee492009-07-13 16:02:34 -0700992static int __init vmbus_init(void)
993{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700994 int ret = 0;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700995
996 DPRINT_ENTER(VMBUS_DRV);
997
998 DPRINT_INFO(VMBUS_DRV,
999 "Vmbus initializing.... current log level 0x%x (%x,%x)",
1000 vmbus_loglevel, HIWORD(vmbus_loglevel), LOWORD(vmbus_loglevel));
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001001 /* Todo: it is used for loglevel, to be ported to new kernel. */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001002
Greg Kroah-Hartmanc22090f2010-02-25 16:43:15 -08001003 if (!dmi_check_system(microsoft_hv_dmi_table))
1004 return -ENODEV;
1005
Hank Janssen3e7ee492009-07-13 16:02:34 -07001006 ret = vmbus_bus_init(VmbusInitialize);
1007
1008 DPRINT_EXIT(VMBUS_DRV);
1009 return ret;
1010}
1011
Hank Janssen3e7ee492009-07-13 16:02:34 -07001012static void __exit vmbus_exit(void)
1013{
1014 DPRINT_ENTER(VMBUS_DRV);
1015
1016 vmbus_bus_exit();
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001017 /* Todo: it is used for loglevel, to be ported to new kernel. */
Hank Janssen3e7ee492009-07-13 16:02:34 -07001018 DPRINT_EXIT(VMBUS_DRV);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001019 return;
1020}
1021
Greg Kroah-Hartman9a775db2010-02-25 16:42:10 -08001022/*
1023 * We use a PCI table to determine if we should autoload this driver This is
1024 * needed by distro tools to determine if the hyperv drivers should be
1025 * installed and/or configured. We don't do anything else with the table, but
1026 * it needs to be present.
Greg Kroah-Hartman9a775db2010-02-25 16:42:10 -08001027 */
1028const static struct pci_device_id microsoft_hv_pci_table[] = {
1029 { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
1030 { 0 }
1031};
1032MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table);
1033
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -07001034MODULE_LICENSE("GPL");
Hank Janssen26c14cc2010-02-11 23:02:42 +00001035MODULE_VERSION(HV_DRV_VERSION);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001036module_param(vmbus_irq, int, S_IRUGO);
1037module_param(vmbus_loglevel, int, S_IRUGO);
Hank Janssen3e7ee492009-07-13 16:02:34 -07001038
1039module_init(vmbus_init);
1040module_exit(vmbus_exit);