spapr_llan.c 16.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
 *
 * PAPR Inter-VM Logical Lan, aka ibmveth
 *
 * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */
27
#include "hw/hw.h"
P
Paolo Bonzini 已提交
28
#include "net/net.h"
29
#include "hw/qdev.h"
P
Paolo Bonzini 已提交
30 31
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
32 33 34 35 36 37 38 39 40

#include <libfdt.h>

#define ETH_ALEN        6
#define MAX_PACKET_SIZE 65536

/*#define DEBUG*/

#ifdef DEBUG
41
#define DPRINTF(fmt...) do { fprintf(stderr, fmt); } while (0)
42
#else
43
#define DPRINTF(fmt...)
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
#endif

/*
 * Virtual LAN device
 */

typedef uint64_t vlan_bd_t;

#define VLAN_BD_VALID        0x8000000000000000ULL
#define VLAN_BD_TOGGLE       0x4000000000000000ULL
#define VLAN_BD_NO_CSUM      0x0200000000000000ULL
#define VLAN_BD_CSUM_GOOD    0x0100000000000000ULL
#define VLAN_BD_LEN_MASK     0x00ffffff00000000ULL
#define VLAN_BD_LEN(bd)      (((bd) & VLAN_BD_LEN_MASK) >> 32)
#define VLAN_BD_ADDR_MASK    0x00000000ffffffffULL
#define VLAN_BD_ADDR(bd)     ((bd) & VLAN_BD_ADDR_MASK)

#define VLAN_VALID_BD(addr, len) (VLAN_BD_VALID | \
                                  (((len) << 32) & VLAN_BD_LEN_MASK) |  \
                                  (addr & VLAN_BD_ADDR_MASK))

#define VLAN_RXQC_TOGGLE     0x80
#define VLAN_RXQC_VALID      0x40
#define VLAN_RXQC_NO_CSUM    0x02
#define VLAN_RXQC_CSUM_GOOD  0x01

#define VLAN_RQ_ALIGNMENT    16
#define VLAN_RXQ_BD_OFF      0
#define VLAN_FILTER_BD_OFF   8
#define VLAN_RX_BDS_OFF      16
74
#define VLAN_MAX_BUFS        ((SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8)
75

76 77 78 79
#define TYPE_VIO_SPAPR_VLAN_DEVICE "spapr-vlan"
#define VIO_SPAPR_VLAN_DEVICE(obj) \
     OBJECT_CHECK(VIOsPAPRVLANDevice, (obj), TYPE_VIO_SPAPR_VLAN_DEVICE)

80 81 82 83
typedef struct VIOsPAPRVLANDevice {
    VIOsPAPRDevice sdev;
    NICConf nicconf;
    NICState *nic;
84
    bool isopen;
85
    target_ulong buf_list;
86
    uint32_t add_buf_ptr, use_buf_ptr, rx_bufs;
87 88 89
    target_ulong rxq_ptr;
} VIOsPAPRVLANDevice;

90
static int spapr_vlan_can_receive(NetClientState *nc)
91
{
J
Jason Wang 已提交
92
    VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
93 94 95 96

    return (dev->isopen && dev->rx_bufs > 0);
}

97
static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
98 99
                                  size_t size)
{
100 101
    VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
    VIOsPAPRDevice *sdev = VIO_SPAPR_DEVICE(dev);
102
    vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
103 104 105 106 107
    vlan_bd_t bd;
    int buf_ptr = dev->use_buf_ptr;
    uint64_t handle;
    uint8_t control;

108
    DPRINTF("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id,
109 110 111 112 113 114 115 116 117 118 119 120
            dev->rx_bufs);

    if (!dev->isopen) {
        return -1;
    }

    if (!dev->rx_bufs) {
        return -1;
    }

    do {
        buf_ptr += 8;
121
        if (buf_ptr >= SPAPR_TCE_PAGE_SIZE) {
122 123 124
            buf_ptr = VLAN_RX_BDS_OFF;
        }

125
        bd = vio_ldq(sdev, dev->buf_list + buf_ptr);
126
        DPRINTF("use_buf_ptr=%d bd=0x%016llx\n",
127 128 129 130 131 132 133 134 135 136 137 138
                buf_ptr, (unsigned long long)bd);
    } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8)))
             && (buf_ptr != dev->use_buf_ptr));

    if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) {
        /* Failed to find a suitable buffer */
        return -1;
    }

    /* Remove the buffer from the pool */
    dev->rx_bufs--;
    dev->use_buf_ptr = buf_ptr;
139
    vio_stq(sdev, dev->buf_list + dev->use_buf_ptr, 0);
140

141
    DPRINTF("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs);
142 143

    /* Transfer the packet data */
144
    if (spapr_vio_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
145 146 147
        return -1;
    }

148
    DPRINTF("spapr_vlan_receive: DMA write completed\n");
149 150 151 152 153 154 155

    /* Update the receive queue */
    control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID;
    if (rxq_bd & VLAN_BD_TOGGLE) {
        control ^= VLAN_RXQC_TOGGLE;
    }

156 157 158 159 160
    handle = vio_ldq(sdev, VLAN_BD_ADDR(bd));
    vio_stq(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 8, handle);
    vio_stl(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 4, size);
    vio_sth(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8);
    vio_stb(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control);
161

162
    DPRINTF("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n",
163
            (unsigned long long)dev->rxq_ptr,
164
            (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
165
                                        dev->rxq_ptr),
166
            (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
167 168 169 170 171
                                        dev->rxq_ptr + 8));

    dev->rxq_ptr += 16;
    if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) {
        dev->rxq_ptr = 0;
172
        vio_stq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF, rxq_bd ^ VLAN_BD_TOGGLE);
173 174 175
    }

    if (sdev->signal_state & 1) {
176
        qemu_irq_pulse(spapr_vio_qirq(sdev));
177 178 179 180 181
    }

    return size;
}

182 183 184 185 186 187 188
static void spapr_vlan_cleanup(NetClientState *nc)
{
    VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);

    dev->nic = NULL;
}

189
static NetClientInfo net_spapr_vlan_info = {
190
    .type = NET_CLIENT_OPTIONS_KIND_NIC,
191 192 193
    .size = sizeof(NICState),
    .can_receive = spapr_vlan_can_receive,
    .receive = spapr_vlan_receive,
194
    .cleanup = spapr_vlan_cleanup,
195 196
};

197 198
static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
{
199
    VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
200 201 202 203 204 205

    dev->buf_list = 0;
    dev->rx_bufs = 0;
    dev->isopen = 0;
}

206 207
static int spapr_vlan_init(VIOsPAPRDevice *sdev)
{
208
    VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
209 210 211 212

    qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);

    dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
213
                            object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
J
Jason Wang 已提交
214
    qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
215 216 217 218

    return 0;
}

219
void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
220 221 222 223 224 225 226 227 228 229 230 231
{
    DeviceState *dev;

    dev = qdev_create(&bus->bus, "spapr-vlan");

    qdev_set_nic_properties(dev, nd);

    qdev_init_nofail(dev);
}

static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
{
232
    VIOsPAPRVLANDevice *vdev = VIO_SPAPR_VLAN_DEVICE(dev);
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
    uint8_t padded_mac[8] = {0, 0};
    int ret;

    /* Some old phyp versions give the mac address in an 8-byte
     * property.  The kernel driver has an insane workaround for this;
     * rather than doing the obvious thing and checking the property
     * length, it checks whether the first byte has 0b10 in the low
     * bits.  If a correct 6-byte property has a different first byte
     * the kernel will get the wrong mac address, overrunning its
     * buffer in the process (read only, thank goodness).
     *
     * Here we workaround the kernel workaround by always supplying an
     * 8-byte property, with the mac address in the last six bytes */
    memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN);
    ret = fdt_setprop(fdt, node_off, "local-mac-address",
                      padded_mac, sizeof(padded_mac));
    if (ret < 0) {
        return ret;
    }

    ret = fdt_setprop_cell(fdt, node_off, "ibm,mac-address-filters", 0);
    if (ret < 0) {
        return ret;
    }

    return 0;
}

static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
                    target_ulong alignment)
{
    if ((VLAN_BD_ADDR(bd) % alignment)
        || (VLAN_BD_LEN(bd) % alignment)) {
        return -1;
    }

269 270 271 272
    if (!spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
                             VLAN_BD_LEN(bd), DMA_DIRECTION_FROM_DEVICE)
        || !spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
                                VLAN_BD_LEN(bd), DMA_DIRECTION_TO_DEVICE)) {
273 274 275 276 277 278
        return -1;
    }

    return 0;
}

279
static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
280 281 282 283 284 285 286 287 288
                                           sPAPREnvironment *spapr,
                                           target_ulong opcode,
                                           target_ulong *args)
{
    target_ulong reg = args[0];
    target_ulong buf_list = args[1];
    target_ulong rec_queue = args[2];
    target_ulong filter_list = args[3];
    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
289
    VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
290 291 292 293 294 295 296 297 298 299 300 301
    vlan_bd_t filter_list_bd;

    if (!dev) {
        return H_PARAMETER;
    }

    if (dev->isopen) {
        hcall_dprintf("H_REGISTER_LOGICAL_LAN called twice without "
                      "H_FREE_LOGICAL_LAN\n");
        return H_RESOURCE;
    }

302 303
    if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_TCE_PAGE_SIZE),
                 SPAPR_TCE_PAGE_SIZE) < 0) {
304
        hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list);
305 306 307
        return H_PARAMETER;
    }

308 309
    filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_TCE_PAGE_SIZE);
    if (check_bd(dev, filter_list_bd, SPAPR_TCE_PAGE_SIZE) < 0) {
310
        hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list);
311 312 313 314 315
        return H_PARAMETER;
    }

    if (!(rec_queue & VLAN_BD_VALID)
        || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
316
        hcall_dprintf("Bad receive queue\n");
317 318 319 320 321 322 323 324 325
        return H_PARAMETER;
    }

    dev->buf_list = buf_list;
    sdev->signal_state = 0;

    rec_queue &= ~VLAN_BD_TOGGLE;

    /* Initialize the buffer list */
326 327 328 329
    vio_stq(sdev, buf_list, rec_queue);
    vio_stq(sdev, buf_list + 8, filter_list_bd);
    spapr_vio_dma_set(sdev, buf_list + VLAN_RX_BDS_OFF, 0,
                      SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF);
330 331 332 333 334 335
    dev->add_buf_ptr = VLAN_RX_BDS_OFF - 8;
    dev->use_buf_ptr = VLAN_RX_BDS_OFF - 8;
    dev->rx_bufs = 0;
    dev->rxq_ptr = 0;

    /* Initialize the receive queue */
336
    spapr_vio_dma_set(sdev, VLAN_BD_ADDR(rec_queue), 0, VLAN_BD_LEN(rec_queue));
337 338

    dev->isopen = 1;
339 340
    qemu_flush_queued_packets(qemu_get_queue(dev->nic));

341 342 343 344
    return H_SUCCESS;
}


345
static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
346 347 348 349
                                       target_ulong opcode, target_ulong *args)
{
    target_ulong reg = args[0];
    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
350
    VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
351 352 353 354 355 356 357 358 359 360 361

    if (!dev) {
        return H_PARAMETER;
    }

    if (!dev->isopen) {
        hcall_dprintf("H_FREE_LOGICAL_LAN called without "
                      "H_REGISTER_LOGICAL_LAN\n");
        return H_RESOURCE;
    }

362
    spapr_vlan_reset(sdev);
363 364 365
    return H_SUCCESS;
}

366
static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
367 368 369 370 371 372 373
                                             sPAPREnvironment *spapr,
                                             target_ulong opcode,
                                             target_ulong *args)
{
    target_ulong reg = args[0];
    target_ulong buf = args[1];
    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
374
    VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
375 376
    vlan_bd_t bd;

377
    DPRINTF("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
378 379 380
            ", 0x" TARGET_FMT_lx ")\n", reg, buf);

    if (!sdev) {
381
        hcall_dprintf("Bad device\n");
382 383 384 385 386
        return H_PARAMETER;
    }

    if ((check_bd(dev, buf, 4) < 0)
        || (VLAN_BD_LEN(buf) < 16)) {
387
        hcall_dprintf("Bad buffer enqueued\n");
388 389 390 391 392 393 394 395 396
        return H_PARAMETER;
    }

    if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) {
        return H_RESOURCE;
    }

    do {
        dev->add_buf_ptr += 8;
397
        if (dev->add_buf_ptr >= SPAPR_TCE_PAGE_SIZE) {
398 399 400
            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
        }

401
        bd = vio_ldq(sdev, dev->buf_list + dev->add_buf_ptr);
402 403
    } while (bd & VLAN_BD_VALID);

404
    vio_stq(sdev, dev->buf_list + dev->add_buf_ptr, buf);
405 406 407

    dev->rx_bufs++;

408 409
    qemu_flush_queued_packets(qemu_get_queue(dev->nic));

410
    DPRINTF("h_add_logical_lan_buffer():  Added buf  ptr=%d  rx_bufs=%d"
411 412 413 414 415 416
            " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
            (unsigned long long)buf);

    return H_SUCCESS;
}

417
static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
418 419 420 421 422 423
                                       target_ulong opcode, target_ulong *args)
{
    target_ulong reg = args[0];
    target_ulong *bufs = args + 1;
    target_ulong continue_token = args[7];
    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
424
    VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
425 426 427 428 429
    unsigned total_len;
    uint8_t *lbuf, *p;
    int i, nbufs;
    int ret;

430
    DPRINTF("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x"
431 432 433 434 435 436
            TARGET_FMT_lx ")\n", reg, continue_token);

    if (!sdev) {
        return H_PARAMETER;
    }

437
    DPRINTF("rxbufs = %d\n", dev->rx_bufs);
438 439 440 441 442 443 444 445 446 447 448

    if (!dev->isopen) {
        return H_DROPPED;
    }

    if (continue_token) {
        return H_HARDWARE; /* FIXME actually handle this */
    }

    total_len = 0;
    for (i = 0; i < 6; i++) {
449
        DPRINTF("   buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]);
450 451 452 453 454 455 456
        if (!(bufs[i] & VLAN_BD_VALID)) {
            break;
        }
        total_len += VLAN_BD_LEN(bufs[i]);
    }

    nbufs = i;
457
    DPRINTF("h_send_logical_lan() %d buffers, total length 0x%x\n",
458 459 460 461 462 463 464 465 466 467 468 469 470 471
            nbufs, total_len);

    if (total_len == 0) {
        return H_SUCCESS;
    }

    if (total_len > MAX_PACKET_SIZE) {
        /* Don't let the guest force too large an allocation */
        return H_RESOURCE;
    }

    lbuf = alloca(total_len);
    p = lbuf;
    for (i = 0; i < nbufs; i++) {
472
        ret = spapr_vio_dma_read(sdev, VLAN_BD_ADDR(bufs[i]),
473 474 475 476 477 478 479 480
                                 p, VLAN_BD_LEN(bufs[i]));
        if (ret < 0) {
            return ret;
        }

        p += VLAN_BD_LEN(bufs[i]);
    }

J
Jason Wang 已提交
481
    qemu_send_packet(qemu_get_queue(dev->nic), lbuf, total_len);
482 483 484 485

    return H_SUCCESS;
}

486
static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPREnvironment *spapr,
487 488 489 490 491 492 493 494 495 496 497 498
                                     target_ulong opcode, target_ulong *args)
{
    target_ulong reg = args[0];
    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);

    if (!dev) {
        return H_PARAMETER;
    }

    return H_SUCCESS;
}

499
static Property spapr_vlan_properties[] = {
500
    DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev),
501 502 503 504
    DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
    DEFINE_PROP_END_OF_LIST(),
};

505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
static const VMStateDescription vmstate_spapr_llan = {
    .name = "spapr_llan",
    .version_id = 1,
    .minimum_version_id = 1,
    .minimum_version_id_old = 1,
    .fields      = (VMStateField []) {
        VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVLANDevice),
        /* LLAN state */
        VMSTATE_BOOL(isopen, VIOsPAPRVLANDevice),
        VMSTATE_UINTTL(buf_list, VIOsPAPRVLANDevice),
        VMSTATE_UINT32(add_buf_ptr, VIOsPAPRVLANDevice),
        VMSTATE_UINT32(use_buf_ptr, VIOsPAPRVLANDevice),
        VMSTATE_UINT32(rx_bufs, VIOsPAPRVLANDevice),
        VMSTATE_UINTTL(rxq_ptr, VIOsPAPRVLANDevice),

        VMSTATE_END_OF_LIST()
    },
};

524 525
static void spapr_vlan_class_init(ObjectClass *klass, void *data)
{
526
    DeviceClass *dc = DEVICE_CLASS(klass);
527 528 529
    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);

    k->init = spapr_vlan_init;
530
    k->reset = spapr_vlan_reset;
531 532 533 534 535
    k->devnode = spapr_vlan_devnode;
    k->dt_name = "l-lan";
    k->dt_type = "network";
    k->dt_compatible = "IBM,l-lan";
    k->signal_mask = 0x1;
536
    set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
537
    dc->props = spapr_vlan_properties;
538
    k->rtce_window_size = 0x10000000;
539
    dc->vmsd = &vmstate_spapr_llan;
540 541
}

542
static const TypeInfo spapr_vlan_info = {
543
    .name          = TYPE_VIO_SPAPR_VLAN_DEVICE,
544 545 546
    .parent        = TYPE_VIO_SPAPR_DEVICE,
    .instance_size = sizeof(VIOsPAPRVLANDevice),
    .class_init    = spapr_vlan_class_init,
547 548
};

A
Andreas Färber 已提交
549
static void spapr_vlan_register_types(void)
550
{
D
David Gibson 已提交
551 552 553 554 555 556
    spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
    spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
    spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
    spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
                             h_add_logical_lan_buffer);
    spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
557
    type_register_static(&spapr_vlan_info);
558
}
A
Andreas Färber 已提交
559 560

type_init(spapr_vlan_register_types)