blob: b1e6cc4ed821cec25ba2ff1b8266f38baa7eb177 [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>
K. Y. Srinivasan52e5c1c2011-03-15 15:03:34 -070020 *
21 * 3/9/2011: K. Y. Srinivasan - Significant restructuring and cleanup
Hank Janssen3e7ee492009-07-13 16:02:34 -070022 */
Hank Janssen0a466182011-03-29 13:58:47 -070023#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24
Hank Janssen3e7ee492009-07-13 16:02:34 -070025#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-Hartman9a775db2010-02-25 16:42:10 -080031#include <linux/pci.h>
Greg Kroah-Hartmanc22090f2010-02-25 16:43:15 -080032#include <linux/dmi.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Haiyang Zhang8b5d6d32010-05-28 23:22:44 +000034#include <linux/completion.h>
Greg Kroah-Hartman2d82f6c2010-05-05 22:52:28 -070035#include "version_info.h"
K. Y. Srinivasane3fe0bb2011-02-11 10:00:12 -080036#include "hv_api.h"
Greg Kroah-Hartman645954c2009-08-28 16:22:59 -070037#include "logging.h"
Greg Kroah-Hartman870cde82009-08-19 16:21:28 -070038#include "vmbus.h"
Greg Kroah-Hartman150b19d2010-10-20 16:07:11 -070039#include "channel.h"
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -080040#include "vmbus_private.h"
Hank Janssen3e7ee492009-07-13 16:02:34 -070041
Hank Janssen3e7ee492009-07-13 16:02:34 -070042
K. Y. Srinivasanef58f5d2011-04-29 13:45:05 -070043static struct pci_dev *hv_pci_dev;
K. Y. Srinivasan1168ac22011-03-15 15:03:32 -070044
K. Y. Srinivasan59c0e4f2011-04-29 13:45:06 -070045static struct tasklet_struct msg_dpc;
K. Y. Srinivasan66d92292011-04-29 13:45:07 -070046static struct tasklet_struct event_dpc;
K. Y. Srinivasan59c0e4f2011-04-29 13:45:06 -070047
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070048unsigned int vmbus_loglevel = (ALL_MODULES << 16 | INFO_LVL);
Hank Janssen3e7ee492009-07-13 16:02:34 -070049EXPORT_SYMBOL(vmbus_loglevel);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -070050 /* (ALL_MODULES << 16 | DEBUG_LVL_ENTEREXIT); */
51 /* (((VMBUS | VMBUS_DRV)<<16) | DEBUG_LVL_ENTEREXIT); */
Hank Janssen3e7ee492009-07-13 16:02:34 -070052
K. Y. Srinivasan71a66552011-04-29 13:45:04 -070053static int pci_probe_error;
54static struct completion probe_event;
Hank Janssen3e7ee492009-07-13 16:02:34 -070055
K. Y. Srinivasan98db4332011-03-15 15:03:44 -070056static void get_channel_info(struct hv_device *device,
57 struct hv_device_info *info)
58{
59 struct vmbus_channel_debug_info debug_info;
60
61 if (!device->channel)
62 return;
63
64 vmbus_get_debug_info(device->channel, &debug_info);
65
66 info->chn_id = debug_info.relid;
67 info->chn_state = debug_info.state;
68 memcpy(&info->chn_type, &debug_info.interfacetype,
69 sizeof(struct hv_guid));
70 memcpy(&info->chn_instance, &debug_info.interface_instance,
71 sizeof(struct hv_guid));
72
73 info->monitor_id = debug_info.monitorid;
74
75 info->server_monitor_pending = debug_info.servermonitor_pending;
76 info->server_monitor_latency = debug_info.servermonitor_latency;
77 info->server_monitor_conn_id = debug_info.servermonitor_connectionid;
78
79 info->client_monitor_pending = debug_info.clientmonitor_pending;
80 info->client_monitor_latency = debug_info.clientmonitor_latency;
81 info->client_monitor_conn_id = debug_info.clientmonitor_connectionid;
82
83 info->inbound.int_mask = debug_info.inbound.current_interrupt_mask;
84 info->inbound.read_idx = debug_info.inbound.current_read_index;
85 info->inbound.write_idx = debug_info.inbound.current_write_index;
86 info->inbound.bytes_avail_toread =
87 debug_info.inbound.bytes_avail_toread;
88 info->inbound.bytes_avail_towrite =
89 debug_info.inbound.bytes_avail_towrite;
90
91 info->outbound.int_mask =
92 debug_info.outbound.current_interrupt_mask;
93 info->outbound.read_idx = debug_info.outbound.current_read_index;
94 info->outbound.write_idx = debug_info.outbound.current_write_index;
95 info->outbound.bytes_avail_toread =
96 debug_info.outbound.bytes_avail_toread;
97 info->outbound.bytes_avail_towrite =
98 debug_info.outbound.bytes_avail_towrite;
99}
100
101/*
102 * vmbus_show_device_attr - Show the device attribute in sysfs.
103 *
104 * This is invoked when user does a
105 * "cat /sys/bus/vmbus/devices/<busdevice>/<attr name>"
106 */
107static ssize_t vmbus_show_device_attr(struct device *dev,
108 struct device_attribute *dev_attr,
109 char *buf)
110{
111 struct hv_device *device_ctx = device_to_hv_device(dev);
112 struct hv_device_info device_info;
113
114 memset(&device_info, 0, sizeof(struct hv_device_info));
115
116 get_channel_info(device_ctx, &device_info);
117
118 if (!strcmp(dev_attr->attr.name, "class_id")) {
119 return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
120 "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
121 device_info.chn_type.data[3],
122 device_info.chn_type.data[2],
123 device_info.chn_type.data[1],
124 device_info.chn_type.data[0],
125 device_info.chn_type.data[5],
126 device_info.chn_type.data[4],
127 device_info.chn_type.data[7],
128 device_info.chn_type.data[6],
129 device_info.chn_type.data[8],
130 device_info.chn_type.data[9],
131 device_info.chn_type.data[10],
132 device_info.chn_type.data[11],
133 device_info.chn_type.data[12],
134 device_info.chn_type.data[13],
135 device_info.chn_type.data[14],
136 device_info.chn_type.data[15]);
137 } else if (!strcmp(dev_attr->attr.name, "device_id")) {
138 return sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
139 "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
140 device_info.chn_instance.data[3],
141 device_info.chn_instance.data[2],
142 device_info.chn_instance.data[1],
143 device_info.chn_instance.data[0],
144 device_info.chn_instance.data[5],
145 device_info.chn_instance.data[4],
146 device_info.chn_instance.data[7],
147 device_info.chn_instance.data[6],
148 device_info.chn_instance.data[8],
149 device_info.chn_instance.data[9],
150 device_info.chn_instance.data[10],
151 device_info.chn_instance.data[11],
152 device_info.chn_instance.data[12],
153 device_info.chn_instance.data[13],
154 device_info.chn_instance.data[14],
155 device_info.chn_instance.data[15]);
156 } else if (!strcmp(dev_attr->attr.name, "state")) {
157 return sprintf(buf, "%d\n", device_info.chn_state);
158 } else if (!strcmp(dev_attr->attr.name, "id")) {
159 return sprintf(buf, "%d\n", device_info.chn_id);
160 } else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) {
161 return sprintf(buf, "%d\n", device_info.outbound.int_mask);
162 } else if (!strcmp(dev_attr->attr.name, "out_read_index")) {
163 return sprintf(buf, "%d\n", device_info.outbound.read_idx);
164 } else if (!strcmp(dev_attr->attr.name, "out_write_index")) {
165 return sprintf(buf, "%d\n", device_info.outbound.write_idx);
166 } else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) {
167 return sprintf(buf, "%d\n",
168 device_info.outbound.bytes_avail_toread);
169 } else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) {
170 return sprintf(buf, "%d\n",
171 device_info.outbound.bytes_avail_towrite);
172 } else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) {
173 return sprintf(buf, "%d\n", device_info.inbound.int_mask);
174 } else if (!strcmp(dev_attr->attr.name, "in_read_index")) {
175 return sprintf(buf, "%d\n", device_info.inbound.read_idx);
176 } else if (!strcmp(dev_attr->attr.name, "in_write_index")) {
177 return sprintf(buf, "%d\n", device_info.inbound.write_idx);
178 } else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) {
179 return sprintf(buf, "%d\n",
180 device_info.inbound.bytes_avail_toread);
181 } else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) {
182 return sprintf(buf, "%d\n",
183 device_info.inbound.bytes_avail_towrite);
184 } else if (!strcmp(dev_attr->attr.name, "monitor_id")) {
185 return sprintf(buf, "%d\n", device_info.monitor_id);
186 } else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) {
187 return sprintf(buf, "%d\n", device_info.server_monitor_pending);
188 } else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) {
189 return sprintf(buf, "%d\n", device_info.server_monitor_latency);
190 } else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) {
191 return sprintf(buf, "%d\n",
192 device_info.server_monitor_conn_id);
193 } else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) {
194 return sprintf(buf, "%d\n", device_info.client_monitor_pending);
195 } else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) {
196 return sprintf(buf, "%d\n", device_info.client_monitor_latency);
197 } else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) {
198 return sprintf(buf, "%d\n",
199 device_info.client_monitor_conn_id);
200 } else {
201 return 0;
202 }
203}
204
Bill Pemberton454f18a2009-07-27 16:47:24 -0400205/* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */
Hank Janssen3e7ee492009-07-13 16:02:34 -0700206static struct device_attribute vmbus_device_attrs[] = {
207 __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL),
208 __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL),
209 __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL),
210 __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL),
211 __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL),
212
213 __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
214 __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
215 __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
216
217 __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
218 __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
219 __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
220
221 __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
222 __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
223 __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
224 __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
225 __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
226
227 __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
228 __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
229 __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
230 __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
231 __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
232 __ATTR_NULL
233};
Hank Janssen3e7ee492009-07-13 16:02:34 -0700234
K. Y. Srinivasan793be9c2011-03-15 15:03:43 -0700235
K. Y. Srinivasanadde2482011-03-15 15:03:37 -0700236/*
237 * vmbus_uevent - add uevent for our device
238 *
239 * This routine is invoked when a device is added or removed on the vmbus to
240 * generate a uevent to udev in the userspace. The udev will then look at its
241 * rule and the uevent generated here to load the appropriate driver
242 */
243static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
244{
245 struct hv_device *dev = device_to_hv_device(device);
246 int ret;
247
K. Y. Srinivasanadde2482011-03-15 15:03:37 -0700248 ret = add_uevent_var(env, "VMBUS_DEVICE_CLASS_GUID={"
249 "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
250 "%02x%02x%02x%02x%02x%02x%02x%02x}",
251 dev->dev_type.data[3],
252 dev->dev_type.data[2],
253 dev->dev_type.data[1],
254 dev->dev_type.data[0],
255 dev->dev_type.data[5],
256 dev->dev_type.data[4],
257 dev->dev_type.data[7],
258 dev->dev_type.data[6],
259 dev->dev_type.data[8],
260 dev->dev_type.data[9],
261 dev->dev_type.data[10],
262 dev->dev_type.data[11],
263 dev->dev_type.data[12],
264 dev->dev_type.data[13],
265 dev->dev_type.data[14],
266 dev->dev_type.data[15]);
267
268 if (ret)
269 return ret;
270
271 ret = add_uevent_var(env, "VMBUS_DEVICE_DEVICE_GUID={"
272 "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
273 "%02x%02x%02x%02x%02x%02x%02x%02x}",
274 dev->dev_instance.data[3],
275 dev->dev_instance.data[2],
276 dev->dev_instance.data[1],
277 dev->dev_instance.data[0],
278 dev->dev_instance.data[5],
279 dev->dev_instance.data[4],
280 dev->dev_instance.data[7],
281 dev->dev_instance.data[6],
282 dev->dev_instance.data[8],
283 dev->dev_instance.data[9],
284 dev->dev_instance.data[10],
285 dev->dev_instance.data[11],
286 dev->dev_instance.data[12],
287 dev->dev_instance.data[13],
288 dev->dev_instance.data[14],
289 dev->dev_instance.data[15]);
290 if (ret)
291 return ret;
292
293 return 0;
294}
295
K. Y. Srinivasanb7fc1472011-03-15 15:03:38 -0700296
297/*
298 * vmbus_match - Attempt to match the specified device to the specified driver
299 */
300static int vmbus_match(struct device *device, struct device_driver *driver)
301{
302 int match = 0;
303 struct hv_driver *drv = drv_to_hv_drv(driver);
304 struct hv_device *device_ctx = device_to_hv_device(device);
305
306 /* We found our driver ? */
307 if (memcmp(&device_ctx->dev_type, &drv->dev_type,
K. Y. Srinivasande632a22011-04-26 09:20:24 -0700308 sizeof(struct hv_guid)) == 0)
K. Y. Srinivasanb7fc1472011-03-15 15:03:38 -0700309 match = 1;
K. Y. Srinivasande632a22011-04-26 09:20:24 -0700310
K. Y. Srinivasanb7fc1472011-03-15 15:03:38 -0700311 return match;
312}
313
K. Y. Srinivasanf1f0d672011-03-15 15:03:39 -0700314/*
315 * vmbus_probe - Add the new vmbus's child device
316 */
317static int vmbus_probe(struct device *child_device)
318{
319 int ret = 0;
320 struct hv_driver *drv =
321 drv_to_hv_drv(child_device->driver);
K. Y. Srinivasan9efd21e2011-04-29 13:45:10 -0700322 struct hv_device *dev = device_to_hv_device(child_device);
K. Y. Srinivasanf1f0d672011-03-15 15:03:39 -0700323
K. Y. Srinivasan9efd21e2011-04-29 13:45:10 -0700324 if (drv->probe) {
325 ret = drv->probe(dev);
K. Y. Srinivasanb14a7b32011-04-29 13:45:03 -0700326 if (ret != 0)
Hank Janssen0a466182011-03-29 13:58:47 -0700327 pr_err("probe failed for device %s (%d)\n",
328 dev_name(child_device), ret);
K. Y. Srinivasanf1f0d672011-03-15 15:03:39 -0700329
K. Y. Srinivasanf1f0d672011-03-15 15:03:39 -0700330 } else {
Hank Janssen0a466182011-03-29 13:58:47 -0700331 pr_err("probe not set for driver %s\n",
332 dev_name(child_device));
K. Y. Srinivasanf1f0d672011-03-15 15:03:39 -0700333 ret = -1;
334 }
335 return ret;
336}
337
K. Y. Srinivasanc5dce3d2011-03-15 15:03:40 -0700338/*
339 * vmbus_remove - Remove a vmbus device
340 */
341static int vmbus_remove(struct device *child_device)
342{
343 int ret;
344 struct hv_driver *drv;
345
K. Y. Srinivasan415b0232011-04-29 13:45:12 -0700346 struct hv_device *dev = device_to_hv_device(child_device);
K. Y. Srinivasanc5dce3d2011-03-15 15:03:40 -0700347
348 if (child_device->driver) {
349 drv = drv_to_hv_drv(child_device->driver);
350
K. Y. Srinivasan415b0232011-04-29 13:45:12 -0700351 if (drv->remove) {
352 ret = drv->remove(dev);
K. Y. Srinivasanc5dce3d2011-03-15 15:03:40 -0700353 } else {
Hank Janssen0a466182011-03-29 13:58:47 -0700354 pr_err("remove not set for driver %s\n",
355 dev_name(child_device));
K. Y. Srinivasanc5dce3d2011-03-15 15:03:40 -0700356 ret = -1;
357 }
358 }
359
360 return 0;
361}
362
K. Y. Srinivasaneb1bb252011-03-15 15:03:41 -0700363
364/*
365 * vmbus_shutdown - Shutdown a vmbus device
366 */
367static void vmbus_shutdown(struct device *child_device)
368{
369 struct hv_driver *drv;
370
371
372 /* The device may not be attached yet */
373 if (!child_device->driver)
374 return;
375
376 drv = drv_to_hv_drv(child_device->driver);
377
378 /* Let the specific open-source driver handles the removal if it can */
379 if (drv->driver.shutdown)
380 drv->driver.shutdown(child_device);
381
382 return;
383}
384
K. Y. Srinivasan086e7a52011-03-15 15:03:42 -0700385
386/*
387 * vmbus_device_release - Final callback release of the vmbus child device
388 */
389static void vmbus_device_release(struct device *device)
390{
391 struct hv_device *device_ctx = device_to_hv_device(device);
392
393 kfree(device_ctx);
394
395}
396
Bill Pemberton454f18a2009-07-27 16:47:24 -0400397/* The one and only one */
K. Y. Srinivasan9adcac52011-04-29 13:45:08 -0700398static struct bus_type hv_bus = {
399 .name = "vmbus",
400 .match = vmbus_match,
401 .shutdown = vmbus_shutdown,
402 .remove = vmbus_remove,
403 .probe = vmbus_probe,
404 .uevent = vmbus_uevent,
405 .dev_attrs = vmbus_device_attrs,
Hank Janssen3e7ee492009-07-13 16:02:34 -0700406};
407
Haiyang Zhangadf874c2011-01-26 12:12:09 -0800408static const char *driver_name = "hyperv";
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800409
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800410
Timo Teräsbf6506f2010-12-15 20:48:08 +0200411struct onmessage_work_context {
412 struct work_struct work;
413 struct hv_message msg;
414};
415
416static void vmbus_onmessage_work(struct work_struct *work)
417{
418 struct onmessage_work_context *ctx;
419
420 ctx = container_of(work, struct onmessage_work_context,
421 work);
422 vmbus_onmessage(&ctx->msg);
423 kfree(ctx);
424}
425
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800426/*
427 * vmbus_on_msg_dpc - DPC routine to handle messages from the hypervisior
428 */
K. Y. Srinivasan62c10592011-03-10 14:04:53 -0800429static void vmbus_on_msg_dpc(unsigned long data)
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800430{
431 int cpu = smp_processor_id();
432 void *page_addr = hv_context.synic_message_page[cpu];
433 struct hv_message *msg = (struct hv_message *)page_addr +
434 VMBUS_MESSAGE_SINT;
Timo Teräsbf6506f2010-12-15 20:48:08 +0200435 struct onmessage_work_context *ctx;
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800436
437 while (1) {
438 if (msg->header.message_type == HVMSG_NONE) {
439 /* no msg */
440 break;
441 } else {
Timo Teräsbf6506f2010-12-15 20:48:08 +0200442 ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
443 if (ctx == NULL)
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800444 continue;
Timo Teräsbf6506f2010-12-15 20:48:08 +0200445 INIT_WORK(&ctx->work, vmbus_onmessage_work);
446 memcpy(&ctx->msg, msg, sizeof(*msg));
Haiyang Zhangda9fcb72011-01-26 12:12:14 -0800447 queue_work(vmbus_connection.work_queue, &ctx->work);
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800448 }
449
450 msg->header.message_type = HVMSG_NONE;
451
452 /*
453 * Make sure the write to MessageType (ie set to
454 * HVMSG_NONE) happens before we read the
455 * MessagePending and EOMing. Otherwise, the EOMing
456 * will not deliver any more messages since there is
457 * no empty slot
458 */
459 mb();
460
461 if (msg->header.message_flags.msg_pending) {
462 /*
463 * This will cause message queue rescan to
464 * possibly deliver another msg from the
465 * hypervisor
466 */
467 wrmsrl(HV_X64_MSR_EOM, 0);
468 }
469 }
470}
471
472/*
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800473 * vmbus_on_isr - ISR routine
474 */
K. Y. Srinivasan480ae582011-03-10 14:06:06 -0800475static int vmbus_on_isr(void)
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800476{
477 int ret = 0;
478 int cpu = smp_processor_id();
479 void *page_addr;
480 struct hv_message *msg;
481 union hv_synic_event_flags *event;
482
483 page_addr = hv_context.synic_message_page[cpu];
484 msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
485
486 /* Check if there are actual msgs to be process */
Hank Janssen98e08702011-03-29 13:58:44 -0700487 if (msg->header.message_type != HVMSG_NONE)
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800488 ret |= 0x1;
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800489
490 /* TODO: Check if there are events to be process */
491 page_addr = hv_context.synic_event_page[cpu];
492 event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
493
494 /* Since we are a child, we only need to check bit 0 */
Greg Kroah-Hartman32235b02011-04-13 12:14:05 -0700495 if (sync_test_and_clear_bit(0, (unsigned long *) &event->flags32[0]))
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800496 ret |= 0x2;
Greg Kroah-Hartman36199a92010-12-02 11:59:22 -0800497
498 return ret;
499}
500
K. Y. Srinivasan793be9c2011-03-15 15:03:43 -0700501
502static irqreturn_t vmbus_isr(int irq, void *dev_id)
503{
504 int ret;
505
506 ret = vmbus_on_isr();
507
508 /* Schedules a dpc if necessary */
509 if (ret > 0) {
510 if (test_bit(0, (unsigned long *)&ret))
K. Y. Srinivasan59c0e4f2011-04-29 13:45:06 -0700511 tasklet_schedule(&msg_dpc);
K. Y. Srinivasan793be9c2011-03-15 15:03:43 -0700512
513 if (test_bit(1, (unsigned long *)&ret))
K. Y. Srinivasan66d92292011-04-29 13:45:07 -0700514 tasklet_schedule(&event_dpc);
K. Y. Srinivasan793be9c2011-03-15 15:03:43 -0700515
516 return IRQ_HANDLED;
517 } else {
518 return IRQ_NONE;
519 }
520}
521
Hank Janssen3e189512010-03-04 22:11:00 +0000522/*
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700523 * vmbus_bus_init -Main vmbus driver initialization routine.
524 *
525 * Here, we
Lars Lindley0686e4f2010-03-11 23:51:23 +0100526 * - initialize the vmbus driver context
Lars Lindley0686e4f2010-03-11 23:51:23 +0100527 * - invoke the vmbus hv main init routine
528 * - get the irq resource
Lars Lindley0686e4f2010-03-11 23:51:23 +0100529 * - retrieve the channel offers
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700530 */
K. Y. Srinivasan52e5c1c2011-03-15 15:03:34 -0700531static int vmbus_bus_init(struct pci_dev *pdev)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700532{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700533 int ret;
534 unsigned int vector;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700535
Greg Kroah-Hartman6d26e38fa22010-12-02 12:08:08 -0800536 /* Hypervisor initialization...setup hypercall page..etc */
537 ret = hv_init();
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700538 if (ret != 0) {
Hank Janssen0a466182011-03-29 13:58:47 -0700539 pr_err("Unable to initialize the hypervisor - 0x%x\n", ret);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700540 goto cleanup;
541 }
542
Bill Pemberton454f18a2009-07-27 16:47:24 -0400543 /* Initialize the bus context */
K. Y. Srinivasan59c0e4f2011-04-29 13:45:06 -0700544 tasklet_init(&msg_dpc, vmbus_on_msg_dpc, 0);
K. Y. Srinivasan66d92292011-04-29 13:45:07 -0700545 tasklet_init(&event_dpc, vmbus_on_event, 0);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700546
K. Y. Srinivasana6e4d8e2011-03-10 14:03:51 -0800547 /* Now, register the bus with LDM */
K. Y. Srinivasan9adcac52011-04-29 13:45:08 -0700548 ret = bus_register(&hv_bus);
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700549 if (ret) {
Bill Pembertonc19fbca2009-07-27 16:47:35 -0400550 ret = -1;
551 goto cleanup;
552 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700553
Bill Pemberton454f18a2009-07-27 16:47:24 -0400554 /* Get the interrupt resource */
K. Y. Srinivasan52e5c1c2011-03-15 15:03:34 -0700555 ret = request_irq(pdev->irq, vmbus_isr,
556 IRQF_SHARED | IRQF_SAMPLE_RANDOM,
557 driver_name, pdev);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700558
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700559 if (ret != 0) {
Hank Janssen0a466182011-03-29 13:58:47 -0700560 pr_err("Unable to request IRQ %d\n",
K. Y. Srinivasan52e5c1c2011-03-15 15:03:34 -0700561 pdev->irq);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700562
K. Y. Srinivasan9adcac52011-04-29 13:45:08 -0700563 bus_unregister(&hv_bus);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700564
565 ret = -1;
566 goto cleanup;
567 }
Hank Janssen3e7ee492009-07-13 16:02:34 -0700568
K. Y. Srinivasan52e5c1c2011-03-15 15:03:34 -0700569 vector = IRQ0_VECTOR + pdev->irq;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700570
K. Y. Srinivasan800b6902011-03-15 15:03:33 -0700571 /*
572 * Notify the hypervisor of our irq and
573 * connect to the host.
574 */
575 on_each_cpu(hv_synic_init, (void *)&vector, 1);
576 ret = vmbus_connect();
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700577 if (ret) {
K. Y. Srinivasan52e5c1c2011-03-15 15:03:34 -0700578 free_irq(pdev->irq, pdev);
K. Y. Srinivasan9adcac52011-04-29 13:45:08 -0700579 bus_unregister(&hv_bus);
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400580 goto cleanup;
581 }
582
K. Y. Srinivasan800b6902011-03-15 15:03:33 -0700583
Greg Kroah-Hartman2d6e8822010-12-02 08:50:58 -0800584 vmbus_request_offers();
Haiyang Zhang8b5d6d32010-05-28 23:22:44 +0000585 wait_for_completion(&hv_channel_ready);
586
Hank Janssen3e7ee492009-07-13 16:02:34 -0700587cleanup:
Hank Janssen3e7ee492009-07-13 16:02:34 -0700588 return ret;
589}
590
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700591/**
Hank Janssen3e189512010-03-04 22:11:00 +0000592 * vmbus_child_driver_register() - Register a vmbus's child driver
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800593 * @drv: Pointer to driver structure you want to register
Hank Janssen3e189512010-03-04 22:11:00 +0000594 *
Hank Janssen3e189512010-03-04 22:11:00 +0000595 *
596 * Registers the given driver with Linux through the 'driver_register()' call
597 * And sets up the hyper-v vmbus handling for this driver.
598 * It will return the state of the 'driver_register()' call.
599 *
600 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700601 */
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800602int vmbus_child_driver_register(struct device_driver *drv)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700603{
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400604 int ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700605
Hank Janssen0a466182011-03-29 13:58:47 -0700606 pr_info("child driver registering - name %s\n", drv->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700607
Bill Pemberton454f18a2009-07-27 16:47:24 -0400608 /* The child driver on this vmbus */
K. Y. Srinivasan9adcac52011-04-29 13:45:08 -0700609 drv->bus = &hv_bus;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700610
K. Y. Srinivasanc643269d2011-03-07 13:23:43 -0800611 ret = driver_register(drv);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700612
Greg Kroah-Hartman2d6e8822010-12-02 08:50:58 -0800613 vmbus_request_offers();
Hank Janssen3e7ee492009-07-13 16:02:34 -0700614
Bill Pemberton5d48a1c2009-07-27 16:47:36 -0400615 return ret;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700616}
Hank Janssen3e7ee492009-07-13 16:02:34 -0700617EXPORT_SYMBOL(vmbus_child_driver_register);
618
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700619/**
Hank Janssen3e189512010-03-04 22:11:00 +0000620 * vmbus_child_driver_unregister() - Unregister a vmbus's child driver
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800621 * @drv: Pointer to driver structure you want to un-register
Hank Janssen3e189512010-03-04 22:11:00 +0000622 *
Hank Janssen3e189512010-03-04 22:11:00 +0000623 *
624 * Un-register the given driver with Linux through the 'driver_unregister()'
625 * call. And ungegisters the driver from the Hyper-V vmbus handler.
626 *
627 * Mainly used by Hyper-V drivers.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700628 */
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800629void vmbus_child_driver_unregister(struct device_driver *drv)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700630{
Hank Janssen0a466182011-03-29 13:58:47 -0700631 pr_info("child driver unregistering - name %s\n", drv->name);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700632
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800633 driver_unregister(drv);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700634
K. Y. Srinivasan06de23f2011-03-07 13:24:23 -0800635 drv->bus = NULL;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700636}
Hank Janssen3e7ee492009-07-13 16:02:34 -0700637EXPORT_SYMBOL(vmbus_child_driver_unregister);
638
Hank Janssen3e189512010-03-04 22:11:00 +0000639/*
Hank Janssen3e189512010-03-04 22:11:00 +0000640 * vmbus_child_device_create - Creates and registers a new child device
641 * on the vmbus.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700642 */
Greg Kroah-Hartman89733aa2010-12-02 08:22:41 -0800643struct hv_device *vmbus_child_device_create(struct hv_guid *type,
644 struct hv_guid *instance,
645 struct vmbus_channel *channel)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700646{
Nicolas Palix3d3b5512009-07-28 17:32:53 +0200647 struct hv_device *child_device_obj;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700648
Bill Pemberton454f18a2009-07-27 16:47:24 -0400649 /* Allocate the new child device */
K. Y. Srinivasan6bad88d2011-03-07 13:35:48 -0800650 child_device_obj = kzalloc(sizeof(struct hv_device), GFP_KERNEL);
651 if (!child_device_obj) {
Hank Janssen0a466182011-03-29 13:58:47 -0700652 pr_err("Unable to allocate device object for child device\n");
Hank Janssen3e7ee492009-07-13 16:02:34 -0700653 return NULL;
654 }
655
Greg Kroah-Hartmancae5b842010-10-21 09:05:27 -0700656 child_device_obj->channel = channel;
Haiyang Zhangca623ad2011-01-26 12:12:11 -0800657 memcpy(&child_device_obj->dev_type, type, sizeof(struct hv_guid));
658 memcpy(&child_device_obj->dev_instance, instance,
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700659 sizeof(struct hv_guid));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700660
Hank Janssen3e7ee492009-07-13 16:02:34 -0700661
Hank Janssen3e7ee492009-07-13 16:02:34 -0700662 return child_device_obj;
663}
664
Hank Janssen3e189512010-03-04 22:11:00 +0000665/*
K. Y. Srinivasane13a0b52011-03-10 14:07:44 -0800666 * vmbus_child_device_register - Register the child device
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700667 */
K. Y. Srinivasan3ca07cb2011-03-10 14:07:21 -0800668int vmbus_child_device_register(struct hv_device *child_device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700669{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700670 int ret = 0;
K. Y. Srinivasan6bad88d2011-03-07 13:35:48 -0800671
Bill Pembertonf4888412009-07-29 17:00:12 -0400672 static atomic_t device_num = ATOMIC_INIT(0);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700673
Haiyang Zhang1bb40a22009-10-23 18:14:24 +0000674 /* Set the device name. Otherwise, device_register() will fail. */
K. Y. Srinivasan6bad88d2011-03-07 13:35:48 -0800675 dev_set_name(&child_device_obj->device, "vmbus_0_%d",
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700676 atomic_inc_return(&device_num));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700677
Bill Pemberton454f18a2009-07-27 16:47:24 -0400678 /* The new device belongs to this bus */
K. Y. Srinivasan9adcac52011-04-29 13:45:08 -0700679 child_device_obj->device.bus = &hv_bus; /* device->dev.bus; */
K. Y. Srinivasan800b6902011-03-15 15:03:33 -0700680 child_device_obj->device.parent = &hv_pci_dev->dev;
K. Y. Srinivasan6bad88d2011-03-07 13:35:48 -0800681 child_device_obj->device.release = vmbus_device_release;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700682
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700683 /*
684 * Register with the LDM. This will kick off the driver/device
685 * binding...which will eventually call vmbus_match() and vmbus_probe()
686 */
K. Y. Srinivasan6bad88d2011-03-07 13:35:48 -0800687 ret = device_register(&child_device_obj->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700688
Hank Janssen3e7ee492009-07-13 16:02:34 -0700689 if (ret)
Hank Janssen0a466182011-03-29 13:58:47 -0700690 pr_err("Unable to register child device\n");
Hank Janssen3e7ee492009-07-13 16:02:34 -0700691 else
Hank Janssen0a466182011-03-29 13:58:47 -0700692 pr_info("child device %s registered\n",
693 dev_name(&child_device_obj->device));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700694
Hank Janssen3e7ee492009-07-13 16:02:34 -0700695 return ret;
696}
697
Hank Janssen3e189512010-03-04 22:11:00 +0000698/*
699 * vmbus_child_device_unregister - Remove the specified child device
700 * from the vmbus.
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700701 */
Greg Kroah-Hartman9d8bd712010-12-02 08:34:45 -0800702void vmbus_child_device_unregister(struct hv_device *device_obj)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700703{
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700704 /*
705 * Kick off the process of unregistering the device.
706 * This will call vmbus_remove() and eventually vmbus_device_release()
707 */
K. Y. Srinivasan6bad88d2011-03-07 13:35:48 -0800708 device_unregister(&device_obj->device);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700709
Hank Janssen0a466182011-03-29 13:58:47 -0700710 pr_info("child device %s unregistered\n",
711 dev_name(&device_obj->device));
Hank Janssen3e7ee492009-07-13 16:02:34 -0700712}
713
Hank Janssen3e7ee492009-07-13 16:02:34 -0700714
K. Y. Srinivasan1168ac22011-03-15 15:03:32 -0700715static int __devinit hv_pci_probe(struct pci_dev *pdev,
716 const struct pci_device_id *ent)
Hank Janssen3e7ee492009-07-13 16:02:34 -0700717{
K. Y. Srinivasan1168ac22011-03-15 15:03:32 -0700718 hv_pci_dev = pdev;
Greg Kroah-Hartmanc22090f2010-02-25 16:43:15 -0800719
K. Y. Srinivasan71a66552011-04-29 13:45:04 -0700720 pci_probe_error = pci_enable_device(pdev);
721 if (pci_probe_error)
722 goto probe_cleanup;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700723
K. Y. Srinivasan71a66552011-04-29 13:45:04 -0700724 pci_probe_error = vmbus_bus_init(pdev);
725 if (pci_probe_error)
K. Y. Srinivasan1168ac22011-03-15 15:03:32 -0700726 pci_disable_device(pdev);
727
K. Y. Srinivasan71a66552011-04-29 13:45:04 -0700728probe_cleanup:
729 complete(&probe_event);
730 return pci_probe_error;
Hank Janssen3e7ee492009-07-13 16:02:34 -0700731}
732
Greg Kroah-Hartman9a775db2010-02-25 16:42:10 -0800733/*
734 * We use a PCI table to determine if we should autoload this driver This is
735 * needed by distro tools to determine if the hyperv drivers should be
736 * installed and/or configured. We don't do anything else with the table, but
737 * it needs to be present.
Greg Kroah-Hartman9a775db2010-02-25 16:42:10 -0800738 */
Tobias Klauser15f0beb2010-05-20 10:39:38 +0200739static const struct pci_device_id microsoft_hv_pci_table[] = {
Greg Kroah-Hartman9a775db2010-02-25 16:42:10 -0800740 { PCI_DEVICE(0x1414, 0x5353) }, /* VGA compatible controller */
741 { 0 }
742};
743MODULE_DEVICE_TABLE(pci, microsoft_hv_pci_table);
744
K. Y. Srinivasan1168ac22011-03-15 15:03:32 -0700745static struct pci_driver hv_bus_driver = {
746 .name = "hv_bus",
747 .probe = hv_pci_probe,
748 .id_table = microsoft_hv_pci_table,
749};
750
751static int __init hv_pci_init(void)
752{
K. Y. Srinivasan71a66552011-04-29 13:45:04 -0700753 int ret;
754 init_completion(&probe_event);
755 ret = pci_register_driver(&hv_bus_driver);
756 if (ret)
757 return ret;
758 /*
759 * All the vmbus initialization occurs within the
760 * hv_pci_probe() function. Wait for hv_pci_probe()
761 * to complete.
762 */
763 wait_for_completion(&probe_event);
764
765 if (pci_probe_error)
766 pci_unregister_driver(&hv_bus_driver);
767 return pci_probe_error;
K. Y. Srinivasan1168ac22011-03-15 15:03:32 -0700768}
769
K. Y. Srinivasan1168ac22011-03-15 15:03:32 -0700770
Greg Kroah-Hartman90c99602009-09-02 07:11:14 -0700771MODULE_LICENSE("GPL");
Hank Janssen26c14cc2010-02-11 23:02:42 +0000772MODULE_VERSION(HV_DRV_VERSION);
Olaf Hering13399cb2011-04-16 18:50:42 +0200773module_param(vmbus_loglevel, int, S_IRUGO|S_IWUSR);
Hank Janssen3e7ee492009-07-13 16:02:34 -0700774
K. Y. Srinivasan1168ac22011-03-15 15:03:32 -0700775module_init(hv_pci_init);