spapr_llan.c 16.9 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
#include "sysemu/sysemu.h"
33 34 35 36 37 38 39 40 41

#include <libfdt.h>

#define ETH_ALEN        6
#define MAX_PACKET_SIZE 65536

/*#define DEBUG*/

#ifdef DEBUG
42
#define DPRINTF(fmt...) do { fprintf(stderr, fmt); } while (0)
43
#else
44
#define DPRINTF(fmt...)
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 74
#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
75
#define VLAN_MAX_BUFS        ((SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8)
76

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

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

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

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

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

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

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

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

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

126
        bd = vio_ldq(sdev, dev->buf_list + buf_ptr);
127
        DPRINTF("use_buf_ptr=%d bd=0x%016llx\n",
128 129 130 131 132 133 134 135 136 137 138 139
                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;
140
    vio_stq(sdev, dev->buf_list + dev->use_buf_ptr, 0);
141

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

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

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

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

157 158 159 160 161
    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);
162

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

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

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

    return size;
}

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

    dev->nic = NULL;
}

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

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

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

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

    qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);

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

217 218
    add_boot_device_path(dev->nicconf.bootindex, DEVICE(dev), "");

219 220 221
    return 0;
}

222
void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
223 224 225 226 227 228 229 230 231 232 233 234
{
    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)
{
235
    VIOsPAPRVLANDevice *vdev = VIO_SPAPR_VLAN_DEVICE(dev);
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 269 270 271
    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;
    }

272 273 274 275
    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)) {
276 277 278 279 280 281
        return -1;
    }

    return 0;
}

282
static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
283 284 285 286 287 288 289 290 291
                                           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);
292
    VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
293 294 295 296 297 298 299 300 301 302 303 304
    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;
    }

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

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

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

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

    rec_queue &= ~VLAN_BD_TOGGLE;

    /* Initialize the buffer list */
329 330 331 332
    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);
333 334 335 336 337 338
    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 */
339
    spapr_vio_dma_set(sdev, VLAN_BD_ADDR(rec_queue), 0, VLAN_BD_LEN(rec_queue));
340 341

    dev->isopen = 1;
342 343
    qemu_flush_queued_packets(qemu_get_queue(dev->nic));

344 345 346 347
    return H_SUCCESS;
}


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

    if (!dev) {
        return H_PARAMETER;
    }

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

365
    spapr_vlan_reset(sdev);
366 367 368
    return H_SUCCESS;
}

369
static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
370 371 372 373 374 375 376
                                             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);
377
    VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
378 379
    vlan_bd_t bd;

380
    DPRINTF("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
381 382 383
            ", 0x" TARGET_FMT_lx ")\n", reg, buf);

    if (!sdev) {
384
        hcall_dprintf("Bad device\n");
385 386 387 388 389
        return H_PARAMETER;
    }

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

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

    do {
        dev->add_buf_ptr += 8;
400
        if (dev->add_buf_ptr >= SPAPR_TCE_PAGE_SIZE) {
401 402 403
            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
        }

404
        bd = vio_ldq(sdev, dev->buf_list + dev->add_buf_ptr);
405 406
    } while (bd & VLAN_BD_VALID);

407
    vio_stq(sdev, dev->buf_list + dev->add_buf_ptr, buf);
408 409 410

    dev->rx_bufs++;

411 412
    qemu_flush_queued_packets(qemu_get_queue(dev->nic));

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

    return H_SUCCESS;
}

420
static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
421 422 423 424 425 426
                                       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);
427
    VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
428 429 430 431 432
    unsigned total_len;
    uint8_t *lbuf, *p;
    int i, nbufs;
    int ret;

433
    DPRINTF("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x"
434 435 436 437 438 439
            TARGET_FMT_lx ")\n", reg, continue_token);

    if (!sdev) {
        return H_PARAMETER;
    }

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

    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++) {
452
        DPRINTF("   buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]);
453 454 455 456 457 458 459
        if (!(bufs[i] & VLAN_BD_VALID)) {
            break;
        }
        total_len += VLAN_BD_LEN(bufs[i]);
    }

    nbufs = i;
460
    DPRINTF("h_send_logical_lan() %d buffers, total length 0x%x\n",
461 462 463 464 465 466 467 468 469 470 471 472 473 474
            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++) {
475
        ret = spapr_vio_dma_read(sdev, VLAN_BD_ADDR(bufs[i]),
476 477 478 479 480 481 482 483
                                 p, VLAN_BD_LEN(bufs[i]));
        if (ret < 0) {
            return ret;
        }

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

J
Jason Wang 已提交
484
    qemu_send_packet(qemu_get_queue(dev->nic), lbuf, total_len);
485 486 487 488

    return H_SUCCESS;
}

489
static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPREnvironment *spapr,
490 491 492 493 494 495 496 497 498 499 500 501
                                     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;
}

502
static Property spapr_vlan_properties[] = {
503
    DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev),
504 505 506 507
    DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
    DEFINE_PROP_END_OF_LIST(),
};

508 509 510 511
static const VMStateDescription vmstate_spapr_llan = {
    .name = "spapr_llan",
    .version_id = 1,
    .minimum_version_id = 1,
512
    .fields = (VMStateField[]) {
513 514 515 516 517 518 519 520 521 522 523 524 525
        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()
    },
};

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

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

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

A
Andreas Färber 已提交
551
static void spapr_vlan_register_types(void)
552
{
D
David Gibson 已提交
553 554 555 556 557 558
    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);
559
    type_register_static(&spapr_vlan_info);
560
}
A
Andreas Färber 已提交
561 562

type_init(spapr_vlan_register_types)