xen_backend.c 19.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/*
 *  xen backend driver infrastructure
 *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; under version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
15
 *  with this program; if not, see <http://www.gnu.org/licenses/>.
16 17 18
 *
 *  Contributions after 2012-01-13 are licensed under the terms of the
 *  GNU GPL, version 2 or (at your option) any later version.
19 20 21 22 23 24
 */

/*
 * TODO: add some xenbus / xenstore concepts overview here.
 */

P
Peter Maydell 已提交
25
#include "qemu/osdep.h"
26 27
#include <sys/signal.h>

28
#include "hw/hw.h"
29
#include "hw/sysbus.h"
30
#include "sysemu/char.h"
31
#include "qemu/log.h"
P
Paolo Bonzini 已提交
32
#include "hw/xen/xen_backend.h"
E
Emil Condrea 已提交
33
#include "hw/xen/xen_pvdev.h"
34

35 36
#include <xen/grant_table.h>

37 38 39 40
#define TYPE_XENSYSDEV "xensysdev"

DeviceState *xen_sysdev;

41 42 43
/* ------------------------------------------------------------- */

/* public */
44
xc_interface *xen_xc = NULL;
45
xenforeignmemory_handle *xen_fmem = NULL;
46
struct xs_handle *xenstore = NULL;
47
const char *xen_protocol;
48 49

/* private */
50 51 52 53 54 55 56
struct xs_dirs {
    char *xs_dir;
    QTAILQ_ENTRY(xs_dirs) list;
};
static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup =
    QTAILQ_HEAD_INITIALIZER(xs_cleanup);

E
Emil Condrea 已提交
57 58
static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs =
    QTAILQ_HEAD_INITIALIZER(xendevs);
E
Emil Condrea 已提交
59
static int debug;
60

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
static void xenstore_cleanup_dir(char *dir)
{
    struct xs_dirs *d;

    d = g_malloc(sizeof(*d));
    d->xs_dir = dir;
    QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
}

void xen_config_cleanup(void)
{
    struct xs_dirs *d;

    QTAILQ_FOREACH(d, &xs_cleanup, list) {
        xs_rm(xenstore, 0, d->xs_dir);
    }
}

int xenstore_mkdir(char *path, int p)
{
    struct xs_permissions perms[2] = {
        {
            .id    = 0, /* set owner: dom0 */
        }, {
            .id    = xen_domid,
            .perms = p,
        }
    };

    if (!xs_mkdir(xenstore, 0, path)) {
        xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", path);
        return -1;
    }
    xenstore_cleanup_dir(g_strdup(path));

    if (!xs_set_permissions(xenstore, 0, path, perms, 2)) {
        xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", path);
        return -1;
    }
    return 0;
}

103 104 105 106 107 108 109 110 111 112
int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
{
    return xenstore_write_str(xendev->be, node, val);
}

int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
{
    return xenstore_write_int(xendev->be, node, ival);
}

113 114 115 116 117
int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival)
{
    return xenstore_write_int64(xendev->be, node, ival);
}

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
{
    return xenstore_read_str(xendev->be, node);
}

int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
{
    return xenstore_read_int(xendev->be, node, ival);
}

char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
{
    return xenstore_read_str(xendev->fe, node);
}

int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
{
    return xenstore_read_int(xendev->fe, node, ival);
}

E
Emil Condrea 已提交
138 139
int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node,
                            uint64_t *uval)
140 141 142 143
{
    return xenstore_read_uint64(xendev->fe, node, uval);
}

144 145 146 147 148 149 150
/* ------------------------------------------------------------- */

int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
{
    int rc;

    rc = xenstore_write_be_int(xendev, "state", state);
151 152 153
    if (rc < 0) {
        return rc;
    }
154
    xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
155
                  xenbus_strstate(xendev->be_state), xenbus_strstate(state));
156 157 158 159 160 161 162 163 164 165
    xendev->be_state = state;
    return 0;
}

/* ------------------------------------------------------------- */

struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
{
    struct XenDevice *xendev;

B
Blue Swirl 已提交
166
    QTAILQ_FOREACH(xendev, &xendevs, next) {
167 168 169 170 171 172 173 174 175 176
        if (xendev->dom != dom) {
            continue;
        }
        if (xendev->dev != dev) {
            continue;
        }
        if (strcmp(xendev->type, type) != 0) {
            continue;
        }
        return xendev;
177 178 179 180 181 182 183 184 185 186 187 188 189
    }
    return NULL;
}

/*
 * get xen backend device, allocate a new one if it doesn't exist.
 */
static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
                                           struct XenDevOps *ops)
{
    struct XenDevice *xendev;

    xendev = xen_be_find_xendev(type, dom, dev);
190 191 192
    if (xendev) {
        return xendev;
    }
193 194

    /* init new xendev */
195
    xendev = g_malloc0(ops->size);
196 197 198 199 200
    xendev->type  = type;
    xendev->dom   = dom;
    xendev->dev   = dev;
    xendev->ops   = ops;

201 202
    snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
             xendev->type, xendev->dom, xendev->dev);
203
    snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
204
             xendev->type, xendev->dev);
205 206 207 208

    xendev->debug      = debug;
    xendev->local_port = -1;

209 210
    xendev->evtchndev = xenevtchn_open(NULL, 0);
    if (xendev->evtchndev == NULL) {
211
        xen_be_printf(NULL, 0, "can't open evtchn device\n");
212
        g_free(xendev);
213
        return NULL;
214
    }
215
    fcntl(xenevtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
216 217

    if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
218 219
        xendev->gnttabdev = xengnttab_open(NULL, 0);
        if (xendev->gnttabdev == NULL) {
220
            xen_be_printf(NULL, 0, "can't open gnttab device\n");
221
            xenevtchn_close(xendev->evtchndev);
222
            g_free(xendev);
223 224
            return NULL;
        }
225
    } else {
226
        xendev->gnttabdev = NULL;
227 228
    }

B
Blue Swirl 已提交
229
    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
230

231 232 233
    if (xendev->ops->alloc) {
        xendev->ops->alloc(xendev);
    }
234 235 236 237 238 239 240

    return xendev;
}

/*
 * release xen backend device.
 */
241
static void xen_be_del_xendev(struct XenDevice *xendev)
242
{
243 244 245
    if (xendev->ops->free) {
        xendev->ops->free(xendev);
    }
246

247 248 249 250 251 252
    if (xendev->fe) {
        char token[XEN_BUFSIZE];
        snprintf(token, sizeof(token), "fe:%p", xendev);
        xs_unwatch(xenstore, xendev->fe, token);
        g_free(xendev->fe);
    }
253

254 255
    if (xendev->evtchndev != NULL) {
        xenevtchn_close(xendev->evtchndev);
256
    }
257 258 259 260 261 262
    if (xendev->gnttabdev != NULL) {
        xengnttab_close(xendev->gnttabdev);
    }

    QTAILQ_REMOVE(&xendevs, xendev, next);
    g_free(xendev);
263 264 265 266 267 268 269 270 271 272
}

/*
 * Sync internal data structures on xenstore updates.
 * Node specifies the changed field.  node = NULL means
 * update all fields (used for initialization).
 */
static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
{
    if (node == NULL  ||  strcmp(node, "online") == 0) {
273 274 275
        if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
            xendev->online = 0;
        }
276 277 278
    }

    if (node) {
279 280 281 282
        xen_be_printf(xendev, 2, "backend update: %s\n", node);
        if (xendev->ops->backend_changed) {
            xendev->ops->backend_changed(xendev, node);
        }
283 284 285 286 287 288 289 290
    }
}

static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
{
    int fe_state;

    if (node == NULL  ||  strcmp(node, "state") == 0) {
291 292 293 294 295 296 297 298 299
        if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
            fe_state = XenbusStateUnknown;
        }
        if (xendev->fe_state != fe_state) {
            xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
                          xenbus_strstate(xendev->fe_state),
                          xenbus_strstate(fe_state));
        }
        xendev->fe_state = fe_state;
300 301
    }
    if (node == NULL  ||  strcmp(node, "protocol") == 0) {
302
        g_free(xendev->protocol);
303 304
        xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
        if (xendev->protocol) {
E
Emil Condrea 已提交
305 306
            xen_be_printf(xendev, 1, "frontend protocol: %s\n",
                          xendev->protocol);
307
        }
308 309 310
    }

    if (node) {
311 312 313 314
        xen_be_printf(xendev, 2, "frontend update: %s\n", node);
        if (xendev->ops->frontend_changed) {
            xendev->ops->frontend_changed(xendev, node);
        }
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
    }
}

/* ------------------------------------------------------------- */
/* Check for possible state transitions and perform them.        */

/*
 * Initial xendev setup.  Read frontend path, register watch for it.
 * Should succeed once xend finished setting up the backend device.
 *
 * Also sets initial state (-> Initializing) when done.  Which
 * only affects the xendev->be_state variable as xenbus should
 * already be put into that state by xend.
 */
static int xen_be_try_setup(struct XenDevice *xendev)
{
    char token[XEN_BUFSIZE];
    int be_state;

    if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
335 336
        xen_be_printf(xendev, 0, "reading backend state failed\n");
        return -1;
337 338 339
    }

    if (be_state != XenbusStateInitialising) {
340 341 342
        xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
                      xenbus_strstate(be_state));
        return -1;
343 344 345 346
    }

    xendev->fe = xenstore_read_be_str(xendev, "frontend");
    if (xendev->fe == NULL) {
347 348
        xen_be_printf(xendev, 0, "reading frontend path failed\n");
        return -1;
349 350 351 352 353
    }

    /* setup frontend watch */
    snprintf(token, sizeof(token), "fe:%p", xendev);
    if (!xs_watch(xenstore, xendev->fe, token)) {
354 355 356
        xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
                      xendev->fe);
        return -1;
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
    }
    xen_be_set_state(xendev, XenbusStateInitialising);

    xen_be_backend_changed(xendev, NULL);
    xen_be_frontend_changed(xendev, NULL);
    return 0;
}

/*
 * Try initialize xendev.  Prepare everything the backend can do
 * without synchronizing with the frontend.  Fakes hotplug-status.  No
 * hotplug involved here because this is about userspace drivers, thus
 * there are kernel backend devices which could invoke hotplug.
 *
 * Goes to InitWait on success.
 */
static int xen_be_try_init(struct XenDevice *xendev)
{
    int rc = 0;

    if (!xendev->online) {
378 379
        xen_be_printf(xendev, 1, "not online\n");
        return -1;
380 381
    }

382 383 384
    if (xendev->ops->init) {
        rc = xendev->ops->init(xendev);
    }
385
    if (rc != 0) {
386 387
        xen_be_printf(xendev, 1, "init() failed\n");
        return rc;
388 389 390 391 392 393 394 395
    }

    xenstore_write_be_str(xendev, "hotplug-status", "connected");
    xen_be_set_state(xendev, XenbusStateInitWait);
    return 0;
}

/*
396
 * Try to initialise xendev.  Depends on the frontend being ready
397 398 399 400 401
 * for it (shared ring and evtchn info in xenstore, state being
 * Initialised or Connected).
 *
 * Goes to Connected on success.
 */
402
static int xen_be_try_initialise(struct XenDevice *xendev)
403 404 405 406
{
    int rc = 0;

    if (xendev->fe_state != XenbusStateInitialised  &&
407 408 409 410 411 412 413
        xendev->fe_state != XenbusStateConnected) {
        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
        } else {
            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
            return -1;
        }
414 415
    }

416 417
    if (xendev->ops->initialise) {
        rc = xendev->ops->initialise(xendev);
418
    }
419
    if (rc != 0) {
420
        xen_be_printf(xendev, 0, "initialise() failed\n");
421
        return rc;
422 423 424 425 426 427
    }

    xen_be_set_state(xendev, XenbusStateConnected);
    return 0;
}

428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
/*
 * Try to let xendev know that it is connected.  Depends on the
 * frontend being Connected.  Note that this may be called more
 * than once since the backend state is not modified.
 */
static void xen_be_try_connected(struct XenDevice *xendev)
{
    if (!xendev->ops->connected) {
        return;
    }

    if (xendev->fe_state != XenbusStateConnected) {
        if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
            xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
        } else {
            xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
            return;
        }
    }

    xendev->ops->connected(xendev);
}

451 452 453 454 455 456 457 458 459
/*
 * Teardown connection.
 *
 * Goes to Closed when done.
 */
static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
{
    if (xendev->be_state != XenbusStateClosing &&
        xendev->be_state != XenbusStateClosed  &&
460 461 462 463
        xendev->ops->disconnect) {
        xendev->ops->disconnect(xendev);
    }
    if (xendev->be_state != state) {
464
        xen_be_set_state(xendev, state);
465
    }
466 467 468 469 470 471 472
}

/*
 * Try to reset xendev, for reconnection by another frontend instance.
 */
static int xen_be_try_reset(struct XenDevice *xendev)
{
473
    if (xendev->fe_state != XenbusStateInitialising) {
474
        return -1;
475
    }
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490

    xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
    xen_be_set_state(xendev, XenbusStateInitialising);
    return 0;
}

/*
 * state change dispatcher function
 */
void xen_be_check_state(struct XenDevice *xendev)
{
    int rc = 0;

    /* frontend may request shutdown from almost anywhere */
    if (xendev->fe_state == XenbusStateClosing ||
491 492 493
        xendev->fe_state == XenbusStateClosed) {
        xen_be_disconnect(xendev, xendev->fe_state);
        return;
494 495 496 497
    }

    /* check for possible backend state transitions */
    for (;;) {
498 499 500 501 502 503 504 505
        switch (xendev->be_state) {
        case XenbusStateUnknown:
            rc = xen_be_try_setup(xendev);
            break;
        case XenbusStateInitialising:
            rc = xen_be_try_init(xendev);
            break;
        case XenbusStateInitWait:
506 507 508 509 510 511
            rc = xen_be_try_initialise(xendev);
            break;
        case XenbusStateConnected:
            /* xendev->be_state doesn't change */
            xen_be_try_connected(xendev);
            rc = -1;
512
            break;
513 514 515
        case XenbusStateClosed:
            rc = xen_be_try_reset(xendev);
            break;
516 517 518 519 520 521
        default:
            rc = -1;
        }
        if (rc != 0) {
            break;
        }
522 523 524 525 526 527 528 529 530
    }
}

/* ------------------------------------------------------------- */

static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
{
    struct XenDevice *xendev;
    char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
531
    char **dev = NULL;
532 533 534 535
    unsigned int cdev, j;

    /* setup watch */
    snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
536
    snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
537
    if (!xs_watch(xenstore, path, token)) {
E
Emil Condrea 已提交
538 539
        xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n",
                      path);
540
        return -1;
541 542 543 544
    }

    /* look for backends */
    dev = xs_directory(xenstore, 0, path, &cdev);
545 546 547
    if (!dev) {
        return 0;
    }
548
    for (j = 0; j < cdev; j++) {
549 550 551 552 553
        xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
        if (xendev == NULL) {
            continue;
        }
        xen_be_check_state(xendev);
554 555 556 557 558
    }
    free(dev);
    return 0;
}

559 560
void xenstore_update_be(char *watch, char *type, int dom,
                        struct XenDevOps *ops)
561 562
{
    struct XenDevice *xendev;
563
    char path[XEN_BUFSIZE], *bepath;
564 565
    unsigned int len, dev;

566
    len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
567 568 569
    if (strncmp(path, watch, len) != 0) {
        return;
    }
570
    if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
571 572 573 574 575 576 577
        strcpy(path, "");
        if (sscanf(watch+len, "/%u", &dev) != 1) {
            dev = -1;
        }
    }
    if (dev == -1) {
        return;
578 579 580 581
    }

    xendev = xen_be_get_xendev(type, dom, dev, ops);
    if (xendev != NULL) {
582 583
        bepath = xs_read(xenstore, 0, xendev->be, &len);
        if (bepath == NULL) {
584
            xen_be_del_xendev(xendev);
585 586 587 588 589
        } else {
            free(bepath);
            xen_be_backend_changed(xendev, path);
            xen_be_check_state(xendev);
        }
590 591 592
    }
}

593
void xenstore_update_fe(char *watch, struct XenDevice *xendev)
594 595 596 597 598
{
    char *node;
    unsigned int len;

    len = strlen(xendev->fe);
599 600 601 602 603 604
    if (strncmp(xendev->fe, watch, len) != 0) {
        return;
    }
    if (watch[len] != '/') {
        return;
    }
605 606 607 608 609 610 611 612 613 614
    node = watch + len + 1;

    xen_be_frontend_changed(xendev, node);
    xen_be_check_state(xendev);
}
static void xen_be_evtchn_event(void *opaque)
{
    struct XenDevice *xendev = opaque;
    evtchn_port_t port;

615
    port = xenevtchn_pending(xendev->evtchndev);
616
    if (port != xendev->local_port) {
617 618
        xen_be_printf(xendev, 0,
                      "xenevtchn_pending returned %d (expected %d)\n",
619 620
                      port, xendev->local_port);
        return;
621
    }
622
    xenevtchn_unmask(xendev->evtchndev, port);
623

624 625 626
    if (xendev->ops->event) {
        xendev->ops->event(xendev);
    }
627 628 629 630 631 632 633 634
}

/* -------------------------------------------------------------------- */

int xen_be_init(void)
{
    xenstore = xs_daemon_open();
    if (!xenstore) {
635 636
        xen_be_printf(NULL, 0, "can't connect to xenstored\n");
        return -1;
637 638
    }

639
    qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL);
640

641
    if (xen_xc == NULL || xen_fmem == NULL) {
A
Anthony PERARD 已提交
642
        /* Check if xen_init() have been called */
643
        goto err;
644
    }
645 646 647 648

    xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV);
    qdev_init_nofail(xen_sysdev);

649 650 651 652 653 654 655 656 657 658 659 660
    return 0;

err:
    qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
    xs_daemon_close(xenstore);
    xenstore = NULL;

    return -1;
}

int xen_be_register(const char *type, struct XenDevOps *ops)
{
661 662 663 664 665 666 667 668 669 670 671 672 673 674
    char path[50];
    int rc;

    if (ops->backend_register) {
        rc = ops->backend_register();
        if (rc) {
            return rc;
        }
    }

    snprintf(path, sizeof(path), "device-model/%u/backends/%s", xen_domid,
             type);
    xenstore_mkdir(path, XS_PERM_NONE);

675 676 677
    return xenstore_scan(type, xen_domid, ops);
}

678 679 680 681 682 683 684 685 686 687
void xen_be_register_common(void)
{
    xen_be_register("console", &xen_console_ops);
    xen_be_register("vkbd", &xen_kbdmouse_ops);
    xen_be_register("qdisk", &xen_blkdev_ops);
#ifdef CONFIG_USB_LIBUSB
    xen_be_register("qusb", &xen_usb_ops);
#endif
}

688 689
int xen_be_bind_evtchn(struct XenDevice *xendev)
{
690 691 692
    if (xendev->local_port != -1) {
        return 0;
    }
693
    xendev->local_port = xenevtchn_bind_interdomain
694
        (xendev->evtchndev, xendev->dom, xendev->remote_port);
695
    if (xendev->local_port == -1) {
696
        xen_be_printf(xendev, 0, "xenevtchn_bind_interdomain failed\n");
697
        return -1;
698 699
    }
    xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
700
    qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev),
701
                        xen_be_evtchn_event, NULL, xendev);
702 703 704 705 706
    return 0;
}

void xen_be_unbind_evtchn(struct XenDevice *xendev)
{
707 708 709
    if (xendev->local_port == -1) {
        return;
    }
710 711
    qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
    xenevtchn_unbind(xendev->evtchndev, xendev->local_port);
712 713 714 715 716 717
    xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
    xendev->local_port = -1;
}

int xen_be_send_notify(struct XenDevice *xendev)
{
718
    return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
719 720
}

721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752

static int xen_sysdev_init(SysBusDevice *dev)
{
    return 0;
}

static Property xen_sysdev_properties[] = {
    {/* end of property list */},
};

static void xen_sysdev_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);

    k->init = xen_sysdev_init;
    dc->props = xen_sysdev_properties;
}

static const TypeInfo xensysdev_info = {
    .name          = TYPE_XENSYSDEV,
    .parent        = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(SysBusDevice),
    .class_init    = xen_sysdev_class_init,
};

static void xenbe_register_types(void)
{
    type_register_static(&xensysdev_info);
}

type_init(xenbe_register_types);