qemu/hw/spapr_llan.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
   3 *
   4 * PAPR Inter-VM Logical Lan, aka ibmveth
   5 *
   6 * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
   7 *
   8 * Permission is hereby granted, free of charge, to any person obtaining a copy
   9 * of this software and associated documentation files (the "Software"), to deal
  10 * in the Software without restriction, including without limitation the rights
  11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 * copies of the Software, and to permit persons to whom the Software is
  13 * furnished to do so, subject to the following conditions:
  14 *
  15 * The above copyright notice and this permission notice shall be included in
  16 * all copies or substantial portions of the Software.
  17 *
  18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 * THE SOFTWARE.
  25 *
  26 */
  27#include "hw.h"
  28#include "net.h"
  29#include "hw/qdev.h"
  30#include "hw/spapr.h"
  31#include "hw/spapr_vio.h"
  32
  33#include <libfdt.h>
  34
  35#define ETH_ALEN        6
  36#define MAX_PACKET_SIZE 65536
  37
  38/*#define DEBUG*/
  39
  40#ifdef DEBUG
  41#define dprintf(fmt...) do { fprintf(stderr, fmt); } while (0)
  42#else
  43#define dprintf(fmt...)
  44#endif
  45
  46/*
  47 * Virtual LAN device
  48 */
  49
  50typedef uint64_t vlan_bd_t;
  51
  52#define VLAN_BD_VALID        0x8000000000000000ULL
  53#define VLAN_BD_TOGGLE       0x4000000000000000ULL
  54#define VLAN_BD_NO_CSUM      0x0200000000000000ULL
  55#define VLAN_BD_CSUM_GOOD    0x0100000000000000ULL
  56#define VLAN_BD_LEN_MASK     0x00ffffff00000000ULL
  57#define VLAN_BD_LEN(bd)      (((bd) & VLAN_BD_LEN_MASK) >> 32)
  58#define VLAN_BD_ADDR_MASK    0x00000000ffffffffULL
  59#define VLAN_BD_ADDR(bd)     ((bd) & VLAN_BD_ADDR_MASK)
  60
  61#define VLAN_VALID_BD(addr, len) (VLAN_BD_VALID | \
  62                                  (((len) << 32) & VLAN_BD_LEN_MASK) |  \
  63                                  (addr & VLAN_BD_ADDR_MASK))
  64
  65#define VLAN_RXQC_TOGGLE     0x80
  66#define VLAN_RXQC_VALID      0x40
  67#define VLAN_RXQC_NO_CSUM    0x02
  68#define VLAN_RXQC_CSUM_GOOD  0x01
  69
  70#define VLAN_RQ_ALIGNMENT    16
  71#define VLAN_RXQ_BD_OFF      0
  72#define VLAN_FILTER_BD_OFF   8
  73#define VLAN_RX_BDS_OFF      16
  74#define VLAN_MAX_BUFS        ((SPAPR_VIO_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8)
  75
  76typedef struct VIOsPAPRVLANDevice {
  77    VIOsPAPRDevice sdev;
  78    NICConf nicconf;
  79    NICState *nic;
  80    int isopen;
  81    target_ulong buf_list;
  82    int add_buf_ptr, use_buf_ptr, rx_bufs;
  83    target_ulong rxq_ptr;
  84} VIOsPAPRVLANDevice;
  85
  86static int spapr_vlan_can_receive(VLANClientState *nc)
  87{
  88    VIOsPAPRVLANDevice *dev = DO_UPCAST(NICState, nc, nc)->opaque;
  89
  90    return (dev->isopen && dev->rx_bufs > 0);
  91}
  92
  93static ssize_t spapr_vlan_receive(VLANClientState *nc, const uint8_t *buf,
  94                                  size_t size)
  95{
  96    VIOsPAPRDevice *sdev = DO_UPCAST(NICState, nc, nc)->opaque;
  97    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
  98    vlan_bd_t rxq_bd = ldq_tce(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
  99    vlan_bd_t bd;
 100    int buf_ptr = dev->use_buf_ptr;
 101    uint64_t handle;
 102    uint8_t control;
 103
 104    dprintf("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id,
 105            dev->rx_bufs);
 106
 107    if (!dev->isopen) {
 108        return -1;
 109    }
 110
 111    if (!dev->rx_bufs) {
 112        return -1;
 113    }
 114
 115    do {
 116        buf_ptr += 8;
 117        if (buf_ptr >= SPAPR_VIO_TCE_PAGE_SIZE) {
 118            buf_ptr = VLAN_RX_BDS_OFF;
 119        }
 120
 121        bd = ldq_tce(sdev, dev->buf_list + buf_ptr);
 122        dprintf("use_buf_ptr=%d bd=0x%016llx\n",
 123                buf_ptr, (unsigned long long)bd);
 124    } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8)))
 125             && (buf_ptr != dev->use_buf_ptr));
 126
 127    if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) {
 128        /* Failed to find a suitable buffer */
 129        return -1;
 130    }
 131
 132    /* Remove the buffer from the pool */
 133    dev->rx_bufs--;
 134    dev->use_buf_ptr = buf_ptr;
 135    stq_tce(sdev, dev->buf_list + dev->use_buf_ptr, 0);
 136
 137    dprintf("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs);
 138
 139    /* Transfer the packet data */
 140    if (spapr_tce_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
 141        return -1;
 142    }
 143
 144    dprintf("spapr_vlan_receive: DMA write completed\n");
 145
 146    /* Update the receive queue */
 147    control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID;
 148    if (rxq_bd & VLAN_BD_TOGGLE) {
 149        control ^= VLAN_RXQC_TOGGLE;
 150    }
 151
 152    handle = ldq_tce(sdev, VLAN_BD_ADDR(bd));
 153    stq_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 8, handle);
 154    stw_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 4, size);
 155    sth_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8);
 156    stb_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control);
 157
 158    dprintf("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n",
 159            (unsigned long long)dev->rxq_ptr,
 160            (unsigned long long)ldq_tce(sdev, VLAN_BD_ADDR(rxq_bd) +
 161                                        dev->rxq_ptr),
 162            (unsigned long long)ldq_tce(sdev, VLAN_BD_ADDR(rxq_bd) +
 163                                        dev->rxq_ptr + 8));
 164
 165    dev->rxq_ptr += 16;
 166    if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) {
 167        dev->rxq_ptr = 0;
 168        stq_tce(sdev, dev->buf_list + VLAN_RXQ_BD_OFF, rxq_bd ^ VLAN_BD_TOGGLE);
 169    }
 170
 171    if (sdev->signal_state & 1) {
 172        qemu_irq_pulse(sdev->qirq);
 173    }
 174
 175    return size;
 176}
 177
 178static NetClientInfo net_spapr_vlan_info = {
 179    .type = NET_CLIENT_TYPE_NIC,
 180    .size = sizeof(NICState),
 181    .can_receive = spapr_vlan_can_receive,
 182    .receive = spapr_vlan_receive,
 183};
 184
 185static int spapr_vlan_init(VIOsPAPRDevice *sdev)
 186{
 187    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
 188
 189    qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
 190
 191    dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
 192                            sdev->qdev.info->name, sdev->qdev.id, dev);
 193    qemu_format_nic_info_str(&dev->nic->nc, dev->nicconf.macaddr.a);
 194
 195    return 0;
 196}
 197
 198void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
 199                       qemu_irq qirq, uint32_t vio_irq_num)
 200{
 201    DeviceState *dev;
 202    VIOsPAPRDevice *sdev;
 203
 204    dev = qdev_create(&bus->bus, "spapr-vlan");
 205    qdev_prop_set_uint32(dev, "reg", reg);
 206
 207    qdev_set_nic_properties(dev, nd);
 208
 209    qdev_init_nofail(dev);
 210    sdev = (VIOsPAPRDevice *)dev;
 211    sdev->qirq = qirq;
 212    sdev->vio_irq_num = vio_irq_num;
 213}
 214
 215static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
 216{
 217    VIOsPAPRVLANDevice *vdev = (VIOsPAPRVLANDevice *)dev;
 218    uint8_t padded_mac[8] = {0, 0};
 219    int ret;
 220
 221    /* Some old phyp versions give the mac address in an 8-byte
 222     * property.  The kernel driver has an insane workaround for this;
 223     * rather than doing the obvious thing and checking the property
 224     * length, it checks whether the first byte has 0b10 in the low
 225     * bits.  If a correct 6-byte property has a different first byte
 226     * the kernel will get the wrong mac address, overrunning its
 227     * buffer in the process (read only, thank goodness).
 228     *
 229     * Here we workaround the kernel workaround by always supplying an
 230     * 8-byte property, with the mac address in the last six bytes */
 231    memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN);
 232    ret = fdt_setprop(fdt, node_off, "local-mac-address",
 233                      padded_mac, sizeof(padded_mac));
 234    if (ret < 0) {
 235        return ret;
 236    }
 237
 238    ret = fdt_setprop_cell(fdt, node_off, "ibm,mac-address-filters", 0);
 239    if (ret < 0) {
 240        return ret;
 241    }
 242
 243    return 0;
 244}
 245
 246static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
 247                    target_ulong alignment)
 248{
 249    if ((VLAN_BD_ADDR(bd) % alignment)
 250        || (VLAN_BD_LEN(bd) % alignment)) {
 251        return -1;
 252    }
 253
 254    if (spapr_vio_check_tces(&dev->sdev, VLAN_BD_ADDR(bd),
 255                             VLAN_BD_LEN(bd), SPAPR_TCE_RW) != 0) {
 256        return -1;
 257    }
 258
 259    return 0;
 260}
 261
 262static target_ulong h_register_logical_lan(CPUState *env,
 263                                           sPAPREnvironment *spapr,
 264                                           target_ulong opcode,
 265                                           target_ulong *args)
 266{
 267    target_ulong reg = args[0];
 268    target_ulong buf_list = args[1];
 269    target_ulong rec_queue = args[2];
 270    target_ulong filter_list = args[3];
 271    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
 272    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
 273    vlan_bd_t filter_list_bd;
 274
 275    if (!dev) {
 276        return H_PARAMETER;
 277    }
 278
 279    if (dev->isopen) {
 280        hcall_dprintf("H_REGISTER_LOGICAL_LAN called twice without "
 281                      "H_FREE_LOGICAL_LAN\n");
 282        return H_RESOURCE;
 283    }
 284
 285    if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_VIO_TCE_PAGE_SIZE),
 286                 SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
 287        hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx " for "
 288                      "H_REGISTER_LOGICAL_LAN\n", buf_list);
 289        return H_PARAMETER;
 290    }
 291
 292    filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_VIO_TCE_PAGE_SIZE);
 293    if (check_bd(dev, filter_list_bd, SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
 294        hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx " for "
 295                      "H_REGISTER_LOGICAL_LAN\n", filter_list);
 296        return H_PARAMETER;
 297    }
 298
 299    if (!(rec_queue & VLAN_BD_VALID)
 300        || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
 301        hcall_dprintf("Bad receive queue for H_REGISTER_LOGICAL_LAN\n");
 302        return H_PARAMETER;
 303    }
 304
 305    dev->buf_list = buf_list;
 306    sdev->signal_state = 0;
 307
 308    rec_queue &= ~VLAN_BD_TOGGLE;
 309
 310    /* Initialize the buffer list */
 311    stq_tce(sdev, buf_list, rec_queue);
 312    stq_tce(sdev, buf_list + 8, filter_list_bd);
 313    spapr_tce_dma_zero(sdev, buf_list + VLAN_RX_BDS_OFF,
 314                       SPAPR_VIO_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF);
 315    dev->add_buf_ptr = VLAN_RX_BDS_OFF - 8;
 316    dev->use_buf_ptr = VLAN_RX_BDS_OFF - 8;
 317    dev->rx_bufs = 0;
 318    dev->rxq_ptr = 0;
 319
 320    /* Initialize the receive queue */
 321    spapr_tce_dma_zero(sdev, VLAN_BD_ADDR(rec_queue), VLAN_BD_LEN(rec_queue));
 322
 323    dev->isopen = 1;
 324    return H_SUCCESS;
 325}
 326
 327
 328static target_ulong h_free_logical_lan(CPUState *env, sPAPREnvironment *spapr,
 329                                       target_ulong opcode, target_ulong *args)
 330{
 331    target_ulong reg = args[0];
 332    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
 333    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
 334
 335    if (!dev) {
 336        return H_PARAMETER;
 337    }
 338
 339    if (!dev->isopen) {
 340        hcall_dprintf("H_FREE_LOGICAL_LAN called without "
 341                      "H_REGISTER_LOGICAL_LAN\n");
 342        return H_RESOURCE;
 343    }
 344
 345    dev->buf_list = 0;
 346    dev->rx_bufs = 0;
 347    dev->isopen = 0;
 348    return H_SUCCESS;
 349}
 350
 351static target_ulong h_add_logical_lan_buffer(CPUState *env,
 352                                             sPAPREnvironment *spapr,
 353                                             target_ulong opcode,
 354                                             target_ulong *args)
 355{
 356    target_ulong reg = args[0];
 357    target_ulong buf = args[1];
 358    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
 359    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
 360    vlan_bd_t bd;
 361
 362    dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
 363            ", 0x" TARGET_FMT_lx ")\n", reg, buf);
 364
 365    if (!sdev) {
 366        hcall_dprintf("Wrong device in h_add_logical_lan_buffer\n");
 367        return H_PARAMETER;
 368    }
 369
 370    if ((check_bd(dev, buf, 4) < 0)
 371        || (VLAN_BD_LEN(buf) < 16)) {
 372        hcall_dprintf("Bad buffer enqueued in h_add_logical_lan_buffer\n");
 373        return H_PARAMETER;
 374    }
 375
 376    if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) {
 377        return H_RESOURCE;
 378    }
 379
 380    do {
 381        dev->add_buf_ptr += 8;
 382        if (dev->add_buf_ptr >= SPAPR_VIO_TCE_PAGE_SIZE) {
 383            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
 384        }
 385
 386        bd = ldq_tce(sdev, dev->buf_list + dev->add_buf_ptr);
 387    } while (bd & VLAN_BD_VALID);
 388
 389    stq_tce(sdev, dev->buf_list + dev->add_buf_ptr, buf);
 390
 391    dev->rx_bufs++;
 392
 393    dprintf("h_add_logical_lan_buffer():  Added buf  ptr=%d  rx_bufs=%d"
 394            " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
 395            (unsigned long long)buf);
 396
 397    return H_SUCCESS;
 398}
 399
 400static target_ulong h_send_logical_lan(CPUState *env, sPAPREnvironment *spapr,
 401                                       target_ulong opcode, target_ulong *args)
 402{
 403    target_ulong reg = args[0];
 404    target_ulong *bufs = args + 1;
 405    target_ulong continue_token = args[7];
 406    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
 407    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
 408    unsigned total_len;
 409    uint8_t *lbuf, *p;
 410    int i, nbufs;
 411    int ret;
 412
 413    dprintf("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x"
 414            TARGET_FMT_lx ")\n", reg, continue_token);
 415
 416    if (!sdev) {
 417        return H_PARAMETER;
 418    }
 419
 420    dprintf("rxbufs = %d\n", dev->rx_bufs);
 421
 422    if (!dev->isopen) {
 423        return H_DROPPED;
 424    }
 425
 426    if (continue_token) {
 427        return H_HARDWARE; /* FIXME actually handle this */
 428    }
 429
 430    total_len = 0;
 431    for (i = 0; i < 6; i++) {
 432        dprintf("   buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]);
 433        if (!(bufs[i] & VLAN_BD_VALID)) {
 434            break;
 435        }
 436        total_len += VLAN_BD_LEN(bufs[i]);
 437    }
 438
 439    nbufs = i;
 440    dprintf("h_send_logical_lan() %d buffers, total length 0x%x\n",
 441            nbufs, total_len);
 442
 443    if (total_len == 0) {
 444        return H_SUCCESS;
 445    }
 446
 447    if (total_len > MAX_PACKET_SIZE) {
 448        /* Don't let the guest force too large an allocation */
 449        return H_RESOURCE;
 450    }
 451
 452    lbuf = alloca(total_len);
 453    p = lbuf;
 454    for (i = 0; i < nbufs; i++) {
 455        ret = spapr_tce_dma_read(sdev, VLAN_BD_ADDR(bufs[i]),
 456                                 p, VLAN_BD_LEN(bufs[i]));
 457        if (ret < 0) {
 458            return ret;
 459        }
 460
 461        p += VLAN_BD_LEN(bufs[i]);
 462    }
 463
 464    qemu_send_packet(&dev->nic->nc, lbuf, total_len);
 465
 466    return H_SUCCESS;
 467}
 468
 469static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr,
 470                                     target_ulong opcode, target_ulong *args)
 471{
 472    target_ulong reg = args[0];
 473    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
 474
 475    if (!dev) {
 476        return H_PARAMETER;
 477    }
 478
 479    return H_SUCCESS;
 480}
 481
 482static void vlan_hcalls(VIOsPAPRBus *bus)
 483{
 484    spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
 485    spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
 486    spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
 487    spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
 488                             h_add_logical_lan_buffer);
 489    spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
 490}
 491
 492static VIOsPAPRDeviceInfo spapr_vlan = {
 493    .init = spapr_vlan_init,
 494    .devnode = spapr_vlan_devnode,
 495    .dt_name = "l-lan",
 496    .dt_type = "network",
 497    .dt_compatible = "IBM,l-lan",
 498    .signal_mask = 0x1,
 499    .hcalls = vlan_hcalls,
 500    .qdev.name = "spapr-vlan",
 501    .qdev.size = sizeof(VIOsPAPRVLANDevice),
 502    .qdev.props = (Property[]) {
 503        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x1000),
 504        DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice, rtce_window_size,
 505                           0x10000000),
 506        DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
 507        DEFINE_PROP_END_OF_LIST(),
 508    },
 509};
 510
 511static void spapr_vlan_register(void)
 512{
 513    spapr_vio_bus_register_withprop(&spapr_vlan);
 514}
 515device_init(spapr_vlan_register);
 516