linux/drivers/hv/vmbus_drv.c
<<
>>
Prefs
   1/*
   2 * 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>
  20 *   K. Y. Srinivasan <kys@microsoft.com>
  21 *
  22 */
  23#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  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>
  31#include <linux/slab.h>
  32#include <linux/acpi.h>
  33#include <acpi/acpi_bus.h>
  34#include <linux/completion.h>
  35#include <linux/hyperv.h>
  36#include <asm/hyperv.h>
  37#include "hyperv_vmbus.h"
  38
  39
  40static struct acpi_device  *hv_acpi_dev;
  41
  42static struct tasklet_struct msg_dpc;
  43static struct tasklet_struct event_dpc;
  44static struct completion probe_event;
  45static int irq;
  46
  47struct hv_device_info {
  48        u32 chn_id;
  49        u32 chn_state;
  50        uuid_le chn_type;
  51        uuid_le chn_instance;
  52
  53        u32 monitor_id;
  54        u32 server_monitor_pending;
  55        u32 server_monitor_latency;
  56        u32 server_monitor_conn_id;
  57        u32 client_monitor_pending;
  58        u32 client_monitor_latency;
  59        u32 client_monitor_conn_id;
  60
  61        struct hv_dev_port_info inbound;
  62        struct hv_dev_port_info outbound;
  63};
  64
  65static int vmbus_exists(void)
  66{
  67        if (hv_acpi_dev == NULL)
  68                return -ENODEV;
  69
  70        return 0;
  71}
  72
  73
  74static void get_channel_info(struct hv_device *device,
  75                             struct hv_device_info *info)
  76{
  77        struct vmbus_channel_debug_info debug_info;
  78
  79        if (!device->channel)
  80                return;
  81
  82        vmbus_get_debug_info(device->channel, &debug_info);
  83
  84        info->chn_id = debug_info.relid;
  85        info->chn_state = debug_info.state;
  86        memcpy(&info->chn_type, &debug_info.interfacetype,
  87               sizeof(uuid_le));
  88        memcpy(&info->chn_instance, &debug_info.interface_instance,
  89               sizeof(uuid_le));
  90
  91        info->monitor_id = debug_info.monitorid;
  92
  93        info->server_monitor_pending = debug_info.servermonitor_pending;
  94        info->server_monitor_latency = debug_info.servermonitor_latency;
  95        info->server_monitor_conn_id = debug_info.servermonitor_connectionid;
  96
  97        info->client_monitor_pending = debug_info.clientmonitor_pending;
  98        info->client_monitor_latency = debug_info.clientmonitor_latency;
  99        info->client_monitor_conn_id = debug_info.clientmonitor_connectionid;
 100
 101        info->inbound.int_mask = debug_info.inbound.current_interrupt_mask;
 102        info->inbound.read_idx = debug_info.inbound.current_read_index;
 103        info->inbound.write_idx = debug_info.inbound.current_write_index;
 104        info->inbound.bytes_avail_toread =
 105                debug_info.inbound.bytes_avail_toread;
 106        info->inbound.bytes_avail_towrite =
 107                debug_info.inbound.bytes_avail_towrite;
 108
 109        info->outbound.int_mask =
 110                debug_info.outbound.current_interrupt_mask;
 111        info->outbound.read_idx = debug_info.outbound.current_read_index;
 112        info->outbound.write_idx = debug_info.outbound.current_write_index;
 113        info->outbound.bytes_avail_toread =
 114                debug_info.outbound.bytes_avail_toread;
 115        info->outbound.bytes_avail_towrite =
 116                debug_info.outbound.bytes_avail_towrite;
 117}
 118
 119#define VMBUS_ALIAS_LEN ((sizeof((struct hv_vmbus_device_id *)0)->guid) * 2)
 120static void print_alias_name(struct hv_device *hv_dev, char *alias_name)
 121{
 122        int i;
 123        for (i = 0; i < VMBUS_ALIAS_LEN; i += 2)
 124                sprintf(&alias_name[i], "%02x", hv_dev->dev_type.b[i/2]);
 125}
 126
 127/*
 128 * vmbus_show_device_attr - Show the device attribute in sysfs.
 129 *
 130 * This is invoked when user does a
 131 * "cat /sys/bus/vmbus/devices/<busdevice>/<attr name>"
 132 */
 133static ssize_t vmbus_show_device_attr(struct device *dev,
 134                                      struct device_attribute *dev_attr,
 135                                      char *buf)
 136{
 137        struct hv_device *hv_dev = device_to_hv_device(dev);
 138        struct hv_device_info *device_info;
 139        char alias_name[VMBUS_ALIAS_LEN + 1];
 140        int ret = 0;
 141
 142        device_info = kzalloc(sizeof(struct hv_device_info), GFP_KERNEL);
 143        if (!device_info)
 144                return ret;
 145
 146        get_channel_info(hv_dev, device_info);
 147
 148        if (!strcmp(dev_attr->attr.name, "class_id")) {
 149                ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
 150                               "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
 151                               device_info->chn_type.b[3],
 152                               device_info->chn_type.b[2],
 153                               device_info->chn_type.b[1],
 154                               device_info->chn_type.b[0],
 155                               device_info->chn_type.b[5],
 156                               device_info->chn_type.b[4],
 157                               device_info->chn_type.b[7],
 158                               device_info->chn_type.b[6],
 159                               device_info->chn_type.b[8],
 160                               device_info->chn_type.b[9],
 161                               device_info->chn_type.b[10],
 162                               device_info->chn_type.b[11],
 163                               device_info->chn_type.b[12],
 164                               device_info->chn_type.b[13],
 165                               device_info->chn_type.b[14],
 166                               device_info->chn_type.b[15]);
 167        } else if (!strcmp(dev_attr->attr.name, "device_id")) {
 168                ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
 169                               "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
 170                               device_info->chn_instance.b[3],
 171                               device_info->chn_instance.b[2],
 172                               device_info->chn_instance.b[1],
 173                               device_info->chn_instance.b[0],
 174                               device_info->chn_instance.b[5],
 175                               device_info->chn_instance.b[4],
 176                               device_info->chn_instance.b[7],
 177                               device_info->chn_instance.b[6],
 178                               device_info->chn_instance.b[8],
 179                               device_info->chn_instance.b[9],
 180                               device_info->chn_instance.b[10],
 181                               device_info->chn_instance.b[11],
 182                               device_info->chn_instance.b[12],
 183                               device_info->chn_instance.b[13],
 184                               device_info->chn_instance.b[14],
 185                               device_info->chn_instance.b[15]);
 186        } else if (!strcmp(dev_attr->attr.name, "modalias")) {
 187                print_alias_name(hv_dev, alias_name);
 188                ret = sprintf(buf, "vmbus:%s\n", alias_name);
 189        } else if (!strcmp(dev_attr->attr.name, "state")) {
 190                ret = sprintf(buf, "%d\n", device_info->chn_state);
 191        } else if (!strcmp(dev_attr->attr.name, "id")) {
 192                ret = sprintf(buf, "%d\n", device_info->chn_id);
 193        } else if (!strcmp(dev_attr->attr.name, "out_intr_mask")) {
 194                ret = sprintf(buf, "%d\n", device_info->outbound.int_mask);
 195        } else if (!strcmp(dev_attr->attr.name, "out_read_index")) {
 196                ret = sprintf(buf, "%d\n", device_info->outbound.read_idx);
 197        } else if (!strcmp(dev_attr->attr.name, "out_write_index")) {
 198                ret = sprintf(buf, "%d\n", device_info->outbound.write_idx);
 199        } else if (!strcmp(dev_attr->attr.name, "out_read_bytes_avail")) {
 200                ret = sprintf(buf, "%d\n",
 201                               device_info->outbound.bytes_avail_toread);
 202        } else if (!strcmp(dev_attr->attr.name, "out_write_bytes_avail")) {
 203                ret = sprintf(buf, "%d\n",
 204                               device_info->outbound.bytes_avail_towrite);
 205        } else if (!strcmp(dev_attr->attr.name, "in_intr_mask")) {
 206                ret = sprintf(buf, "%d\n", device_info->inbound.int_mask);
 207        } else if (!strcmp(dev_attr->attr.name, "in_read_index")) {
 208                ret = sprintf(buf, "%d\n", device_info->inbound.read_idx);
 209        } else if (!strcmp(dev_attr->attr.name, "in_write_index")) {
 210                ret = sprintf(buf, "%d\n", device_info->inbound.write_idx);
 211        } else if (!strcmp(dev_attr->attr.name, "in_read_bytes_avail")) {
 212                ret = sprintf(buf, "%d\n",
 213                               device_info->inbound.bytes_avail_toread);
 214        } else if (!strcmp(dev_attr->attr.name, "in_write_bytes_avail")) {
 215                ret = sprintf(buf, "%d\n",
 216                               device_info->inbound.bytes_avail_towrite);
 217        } else if (!strcmp(dev_attr->attr.name, "monitor_id")) {
 218                ret = sprintf(buf, "%d\n", device_info->monitor_id);
 219        } else if (!strcmp(dev_attr->attr.name, "server_monitor_pending")) {
 220                ret = sprintf(buf, "%d\n", device_info->server_monitor_pending);
 221        } else if (!strcmp(dev_attr->attr.name, "server_monitor_latency")) {
 222                ret = sprintf(buf, "%d\n", device_info->server_monitor_latency);
 223        } else if (!strcmp(dev_attr->attr.name, "server_monitor_conn_id")) {
 224                ret = sprintf(buf, "%d\n",
 225                               device_info->server_monitor_conn_id);
 226        } else if (!strcmp(dev_attr->attr.name, "client_monitor_pending")) {
 227                ret = sprintf(buf, "%d\n", device_info->client_monitor_pending);
 228        } else if (!strcmp(dev_attr->attr.name, "client_monitor_latency")) {
 229                ret = sprintf(buf, "%d\n", device_info->client_monitor_latency);
 230        } else if (!strcmp(dev_attr->attr.name, "client_monitor_conn_id")) {
 231                ret = sprintf(buf, "%d\n",
 232                               device_info->client_monitor_conn_id);
 233        }
 234
 235        kfree(device_info);
 236        return ret;
 237}
 238
 239/* Set up per device attributes in /sys/bus/vmbus/devices/<bus device> */
 240static struct device_attribute vmbus_device_attrs[] = {
 241        __ATTR(id, S_IRUGO, vmbus_show_device_attr, NULL),
 242        __ATTR(state, S_IRUGO, vmbus_show_device_attr, NULL),
 243        __ATTR(class_id, S_IRUGO, vmbus_show_device_attr, NULL),
 244        __ATTR(device_id, S_IRUGO, vmbus_show_device_attr, NULL),
 245        __ATTR(monitor_id, S_IRUGO, vmbus_show_device_attr, NULL),
 246        __ATTR(modalias, S_IRUGO, vmbus_show_device_attr, NULL),
 247
 248        __ATTR(server_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
 249        __ATTR(server_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
 250        __ATTR(server_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
 251
 252        __ATTR(client_monitor_pending, S_IRUGO, vmbus_show_device_attr, NULL),
 253        __ATTR(client_monitor_latency, S_IRUGO, vmbus_show_device_attr, NULL),
 254        __ATTR(client_monitor_conn_id, S_IRUGO, vmbus_show_device_attr, NULL),
 255
 256        __ATTR(out_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
 257        __ATTR(out_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
 258        __ATTR(out_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
 259        __ATTR(out_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
 260        __ATTR(out_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
 261
 262        __ATTR(in_intr_mask, S_IRUGO, vmbus_show_device_attr, NULL),
 263        __ATTR(in_read_index, S_IRUGO, vmbus_show_device_attr, NULL),
 264        __ATTR(in_write_index, S_IRUGO, vmbus_show_device_attr, NULL),
 265        __ATTR(in_read_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
 266        __ATTR(in_write_bytes_avail, S_IRUGO, vmbus_show_device_attr, NULL),
 267        __ATTR_NULL
 268};
 269
 270
 271/*
 272 * vmbus_uevent - add uevent for our device
 273 *
 274 * This routine is invoked when a device is added or removed on the vmbus to
 275 * generate a uevent to udev in the userspace. The udev will then look at its
 276 * rule and the uevent generated here to load the appropriate driver
 277 *
 278 * The alias string will be of the form vmbus:guid where guid is the string
 279 * representation of the device guid (each byte of the guid will be
 280 * represented with two hex characters.
 281 */
 282static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env)
 283{
 284        struct hv_device *dev = device_to_hv_device(device);
 285        int ret;
 286        char alias_name[VMBUS_ALIAS_LEN + 1];
 287
 288        print_alias_name(dev, alias_name);
 289        ret = add_uevent_var(env, "MODALIAS=vmbus:%s", alias_name);
 290        return ret;
 291}
 292
 293static uuid_le null_guid;
 294
 295static inline bool is_null_guid(const __u8 *guid)
 296{
 297        if (memcmp(guid, &null_guid, sizeof(uuid_le)))
 298                return false;
 299        return true;
 300}
 301
 302/*
 303 * Return a matching hv_vmbus_device_id pointer.
 304 * If there is no match, return NULL.
 305 */
 306static const struct hv_vmbus_device_id *hv_vmbus_get_id(
 307                                        const struct hv_vmbus_device_id *id,
 308                                        __u8 *guid)
 309{
 310        for (; !is_null_guid(id->guid); id++)
 311                if (!memcmp(&id->guid, guid, sizeof(uuid_le)))
 312                        return id;
 313
 314        return NULL;
 315}
 316
 317
 318
 319/*
 320 * vmbus_match - Attempt to match the specified device to the specified driver
 321 */
 322static int vmbus_match(struct device *device, struct device_driver *driver)
 323{
 324        struct hv_driver *drv = drv_to_hv_drv(driver);
 325        struct hv_device *hv_dev = device_to_hv_device(device);
 326
 327        if (hv_vmbus_get_id(drv->id_table, hv_dev->dev_type.b))
 328                return 1;
 329
 330        return 0;
 331}
 332
 333/*
 334 * vmbus_probe - Add the new vmbus's child device
 335 */
 336static int vmbus_probe(struct device *child_device)
 337{
 338        int ret = 0;
 339        struct hv_driver *drv =
 340                        drv_to_hv_drv(child_device->driver);
 341        struct hv_device *dev = device_to_hv_device(child_device);
 342        const struct hv_vmbus_device_id *dev_id;
 343
 344        dev_id = hv_vmbus_get_id(drv->id_table, dev->dev_type.b);
 345        if (drv->probe) {
 346                ret = drv->probe(dev, dev_id);
 347                if (ret != 0)
 348                        pr_err("probe failed for device %s (%d)\n",
 349                               dev_name(child_device), ret);
 350
 351        } else {
 352                pr_err("probe not set for driver %s\n",
 353                       dev_name(child_device));
 354                ret = -ENODEV;
 355        }
 356        return ret;
 357}
 358
 359/*
 360 * vmbus_remove - Remove a vmbus device
 361 */
 362static int vmbus_remove(struct device *child_device)
 363{
 364        struct hv_driver *drv = drv_to_hv_drv(child_device->driver);
 365        struct hv_device *dev = device_to_hv_device(child_device);
 366
 367        if (drv->remove)
 368                drv->remove(dev);
 369        else
 370                pr_err("remove not set for driver %s\n",
 371                        dev_name(child_device));
 372
 373        return 0;
 374}
 375
 376
 377/*
 378 * vmbus_shutdown - Shutdown a vmbus device
 379 */
 380static void vmbus_shutdown(struct device *child_device)
 381{
 382        struct hv_driver *drv;
 383        struct hv_device *dev = device_to_hv_device(child_device);
 384
 385
 386        /* The device may not be attached yet */
 387        if (!child_device->driver)
 388                return;
 389
 390        drv = drv_to_hv_drv(child_device->driver);
 391
 392        if (drv->shutdown)
 393                drv->shutdown(dev);
 394
 395        return;
 396}
 397
 398
 399/*
 400 * vmbus_device_release - Final callback release of the vmbus child device
 401 */
 402static void vmbus_device_release(struct device *device)
 403{
 404        struct hv_device *hv_dev = device_to_hv_device(device);
 405
 406        kfree(hv_dev);
 407
 408}
 409
 410/* The one and only one */
 411static struct bus_type  hv_bus = {
 412        .name =         "vmbus",
 413        .match =                vmbus_match,
 414        .shutdown =             vmbus_shutdown,
 415        .remove =               vmbus_remove,
 416        .probe =                vmbus_probe,
 417        .uevent =               vmbus_uevent,
 418        .dev_attrs =    vmbus_device_attrs,
 419};
 420
 421static const char *driver_name = "hyperv";
 422
 423
 424struct onmessage_work_context {
 425        struct work_struct work;
 426        struct hv_message msg;
 427};
 428
 429static void vmbus_onmessage_work(struct work_struct *work)
 430{
 431        struct onmessage_work_context *ctx;
 432
 433        ctx = container_of(work, struct onmessage_work_context,
 434                           work);
 435        vmbus_onmessage(&ctx->msg);
 436        kfree(ctx);
 437}
 438
 439static void vmbus_on_msg_dpc(unsigned long data)
 440{
 441        int cpu = smp_processor_id();
 442        void *page_addr = hv_context.synic_message_page[cpu];
 443        struct hv_message *msg = (struct hv_message *)page_addr +
 444                                  VMBUS_MESSAGE_SINT;
 445        struct onmessage_work_context *ctx;
 446
 447        while (1) {
 448                if (msg->header.message_type == HVMSG_NONE) {
 449                        /* no msg */
 450                        break;
 451                } else {
 452                        ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
 453                        if (ctx == NULL)
 454                                continue;
 455                        INIT_WORK(&ctx->work, vmbus_onmessage_work);
 456                        memcpy(&ctx->msg, msg, sizeof(*msg));
 457                        queue_work(vmbus_connection.work_queue, &ctx->work);
 458                }
 459
 460                msg->header.message_type = HVMSG_NONE;
 461
 462                /*
 463                 * Make sure the write to MessageType (ie set to
 464                 * HVMSG_NONE) happens before we read the
 465                 * MessagePending and EOMing. Otherwise, the EOMing
 466                 * will not deliver any more messages since there is
 467                 * no empty slot
 468                 */
 469                smp_mb();
 470
 471                if (msg->header.message_flags.msg_pending) {
 472                        /*
 473                         * This will cause message queue rescan to
 474                         * possibly deliver another msg from the
 475                         * hypervisor
 476                         */
 477                        wrmsrl(HV_X64_MSR_EOM, 0);
 478                }
 479        }
 480}
 481
 482static irqreturn_t vmbus_isr(int irq, void *dev_id)
 483{
 484        int cpu = smp_processor_id();
 485        void *page_addr;
 486        struct hv_message *msg;
 487        union hv_synic_event_flags *event;
 488        bool handled = false;
 489
 490        /*
 491         * Check for events before checking for messages. This is the order
 492         * in which events and messages are checked in Windows guests on
 493         * Hyper-V, and the Windows team suggested we do the same.
 494         */
 495
 496        page_addr = hv_context.synic_event_page[cpu];
 497        event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT;
 498
 499        /* Since we are a child, we only need to check bit 0 */
 500        if (sync_test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) {
 501                handled = true;
 502                tasklet_schedule(&event_dpc);
 503        }
 504
 505        page_addr = hv_context.synic_message_page[cpu];
 506        msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
 507
 508        /* Check if there are actual msgs to be processed */
 509        if (msg->header.message_type != HVMSG_NONE) {
 510                handled = true;
 511                tasklet_schedule(&msg_dpc);
 512        }
 513
 514        if (handled)
 515                return IRQ_HANDLED;
 516        else
 517                return IRQ_NONE;
 518}
 519
 520/*
 521 * vmbus_bus_init -Main vmbus driver initialization routine.
 522 *
 523 * Here, we
 524 *      - initialize the vmbus driver context
 525 *      - invoke the vmbus hv main init routine
 526 *      - get the irq resource
 527 *      - retrieve the channel offers
 528 */
 529static int vmbus_bus_init(int irq)
 530{
 531        int ret;
 532        unsigned int vector;
 533
 534        /* Hypervisor initialization...setup hypercall page..etc */
 535        ret = hv_init();
 536        if (ret != 0) {
 537                pr_err("Unable to initialize the hypervisor - 0x%x\n", ret);
 538                return ret;
 539        }
 540
 541        tasklet_init(&msg_dpc, vmbus_on_msg_dpc, 0);
 542        tasklet_init(&event_dpc, vmbus_on_event, 0);
 543
 544        ret = bus_register(&hv_bus);
 545        if (ret)
 546                goto err_cleanup;
 547
 548        ret = request_irq(irq, vmbus_isr, 0, driver_name, hv_acpi_dev);
 549
 550        if (ret != 0) {
 551                pr_err("Unable to request IRQ %d\n",
 552                           irq);
 553                goto err_unregister;
 554        }
 555
 556        vector = IRQ0_VECTOR + irq;
 557
 558        /*
 559         * Notify the hypervisor of our irq and
 560         * connect to the host.
 561         */
 562        on_each_cpu(hv_synic_init, (void *)&vector, 1);
 563        ret = vmbus_connect();
 564        if (ret)
 565                goto err_irq;
 566
 567        vmbus_request_offers();
 568
 569        return 0;
 570
 571err_irq:
 572        free_irq(irq, hv_acpi_dev);
 573
 574err_unregister:
 575        bus_unregister(&hv_bus);
 576
 577err_cleanup:
 578        hv_cleanup();
 579
 580        return ret;
 581}
 582
 583/**
 584 * __vmbus_child_driver_register - Register a vmbus's driver
 585 * @drv: Pointer to driver structure you want to register
 586 * @owner: owner module of the drv
 587 * @mod_name: module name string
 588 *
 589 * Registers the given driver with Linux through the 'driver_register()' call
 590 * and sets up the hyper-v vmbus handling for this driver.
 591 * It will return the state of the 'driver_register()' call.
 592 *
 593 */
 594int __vmbus_driver_register(struct hv_driver *hv_driver, struct module *owner, const char *mod_name)
 595{
 596        int ret;
 597
 598        pr_info("registering driver %s\n", hv_driver->name);
 599
 600        ret = vmbus_exists();
 601        if (ret < 0)
 602                return ret;
 603
 604        hv_driver->driver.name = hv_driver->name;
 605        hv_driver->driver.owner = owner;
 606        hv_driver->driver.mod_name = mod_name;
 607        hv_driver->driver.bus = &hv_bus;
 608
 609        ret = driver_register(&hv_driver->driver);
 610
 611        vmbus_request_offers();
 612
 613        return ret;
 614}
 615EXPORT_SYMBOL_GPL(__vmbus_driver_register);
 616
 617/**
 618 * vmbus_driver_unregister() - Unregister a vmbus's driver
 619 * @drv: Pointer to driver structure you want to un-register
 620 *
 621 * Un-register the given driver that was previous registered with a call to
 622 * vmbus_driver_register()
 623 */
 624void vmbus_driver_unregister(struct hv_driver *hv_driver)
 625{
 626        pr_info("unregistering driver %s\n", hv_driver->name);
 627
 628        if (!vmbus_exists())
 629                driver_unregister(&hv_driver->driver);
 630}
 631EXPORT_SYMBOL_GPL(vmbus_driver_unregister);
 632
 633/*
 634 * vmbus_device_create - Creates and registers a new child device
 635 * on the vmbus.
 636 */
 637struct hv_device *vmbus_device_create(uuid_le *type,
 638                                            uuid_le *instance,
 639                                            struct vmbus_channel *channel)
 640{
 641        struct hv_device *child_device_obj;
 642
 643        child_device_obj = kzalloc(sizeof(struct hv_device), GFP_KERNEL);
 644        if (!child_device_obj) {
 645                pr_err("Unable to allocate device object for child device\n");
 646                return NULL;
 647        }
 648
 649        child_device_obj->channel = channel;
 650        memcpy(&child_device_obj->dev_type, type, sizeof(uuid_le));
 651        memcpy(&child_device_obj->dev_instance, instance,
 652               sizeof(uuid_le));
 653
 654
 655        return child_device_obj;
 656}
 657
 658/*
 659 * vmbus_device_register - Register the child device
 660 */
 661int vmbus_device_register(struct hv_device *child_device_obj)
 662{
 663        int ret = 0;
 664
 665        static atomic_t device_num = ATOMIC_INIT(0);
 666
 667        dev_set_name(&child_device_obj->device, "vmbus_0_%d",
 668                     atomic_inc_return(&device_num));
 669
 670        child_device_obj->device.bus = &hv_bus;
 671        child_device_obj->device.parent = &hv_acpi_dev->dev;
 672        child_device_obj->device.release = vmbus_device_release;
 673
 674        /*
 675         * Register with the LDM. This will kick off the driver/device
 676         * binding...which will eventually call vmbus_match() and vmbus_probe()
 677         */
 678        ret = device_register(&child_device_obj->device);
 679
 680        if (ret)
 681                pr_err("Unable to register child device\n");
 682        else
 683                pr_info("child device %s registered\n",
 684                        dev_name(&child_device_obj->device));
 685
 686        return ret;
 687}
 688
 689/*
 690 * vmbus_device_unregister - Remove the specified child device
 691 * from the vmbus.
 692 */
 693void vmbus_device_unregister(struct hv_device *device_obj)
 694{
 695        /*
 696         * Kick off the process of unregistering the device.
 697         * This will call vmbus_remove() and eventually vmbus_device_release()
 698         */
 699        device_unregister(&device_obj->device);
 700
 701        pr_info("child device %s unregistered\n",
 702                dev_name(&device_obj->device));
 703}
 704
 705
 706/*
 707 * VMBUS is an acpi enumerated device. Get the the IRQ information
 708 * from DSDT.
 709 */
 710
 711static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *irq)
 712{
 713
 714        if (res->type == ACPI_RESOURCE_TYPE_IRQ) {
 715                struct acpi_resource_irq *irqp;
 716                irqp = &res->data.irq;
 717
 718                *((unsigned int *)irq) = irqp->interrupts[0];
 719        }
 720
 721        return AE_OK;
 722}
 723
 724static int vmbus_acpi_add(struct acpi_device *device)
 725{
 726        acpi_status result;
 727
 728        hv_acpi_dev = device;
 729
 730        result = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
 731                                        vmbus_walk_resources, &irq);
 732
 733        if (ACPI_FAILURE(result)) {
 734                complete(&probe_event);
 735                return -ENODEV;
 736        }
 737        complete(&probe_event);
 738        return 0;
 739}
 740
 741static const struct acpi_device_id vmbus_acpi_device_ids[] = {
 742        {"VMBUS", 0},
 743        {"VMBus", 0},
 744        {"", 0},
 745};
 746MODULE_DEVICE_TABLE(acpi, vmbus_acpi_device_ids);
 747
 748static struct acpi_driver vmbus_acpi_driver = {
 749        .name = "vmbus",
 750        .ids = vmbus_acpi_device_ids,
 751        .ops = {
 752                .add = vmbus_acpi_add,
 753        },
 754};
 755
 756static int __init hv_acpi_init(void)
 757{
 758        int ret, t;
 759
 760        init_completion(&probe_event);
 761
 762        /*
 763         * Get irq resources first.
 764         */
 765
 766        ret = acpi_bus_register_driver(&vmbus_acpi_driver);
 767
 768        if (ret)
 769                return ret;
 770
 771        t = wait_for_completion_timeout(&probe_event, 5*HZ);
 772        if (t == 0) {
 773                ret = -ETIMEDOUT;
 774                goto cleanup;
 775        }
 776
 777        if (irq <= 0) {
 778                ret = -ENODEV;
 779                goto cleanup;
 780        }
 781
 782        ret = vmbus_bus_init(irq);
 783        if (ret)
 784                goto cleanup;
 785
 786        return 0;
 787
 788cleanup:
 789        acpi_bus_unregister_driver(&vmbus_acpi_driver);
 790        hv_acpi_dev = NULL;
 791        return ret;
 792}
 793
 794static void __exit vmbus_exit(void)
 795{
 796
 797        free_irq(irq, hv_acpi_dev);
 798        vmbus_free_channels();
 799        bus_unregister(&hv_bus);
 800        hv_cleanup();
 801        acpi_bus_unregister_driver(&vmbus_acpi_driver);
 802}
 803
 804
 805MODULE_LICENSE("GPL");
 806MODULE_VERSION(HV_DRV_VERSION);
 807
 808subsys_initcall(hv_acpi_init);
 809module_exit(vmbus_exit);
 810
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.