qemu/hw/net/rocker/rocker.c
<<
>>
Prefs
   1/*
   2 * QEMU rocker switch emulation - PCI device
   3 *
   4 * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
   5 * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 * GNU General Public License for more details.
  16 */
  17
  18#include "qemu/osdep.h"
  19#include "hw/hw.h"
  20#include "hw/pci/pci.h"
  21#include "hw/pci/msix.h"
  22#include "net/net.h"
  23#include "net/eth.h"
  24#include "qemu/iov.h"
  25#include "qemu/bitops.h"
  26#include "qmp-commands.h"
  27
  28#include "rocker.h"
  29#include "rocker_hw.h"
  30#include "rocker_fp.h"
  31#include "rocker_desc.h"
  32#include "rocker_tlv.h"
  33#include "rocker_world.h"
  34#include "rocker_of_dpa.h"
  35
  36struct rocker {
  37    /* private */
  38    PCIDevice parent_obj;
  39    /* public */
  40
  41    MemoryRegion mmio;
  42    MemoryRegion msix_bar;
  43
  44    /* switch configuration */
  45    char *name;                  /* switch name */
  46    char *world_name;            /* world name */
  47    uint32_t fp_ports;           /* front-panel port count */
  48    NICPeers *fp_ports_peers;
  49    MACAddr fp_start_macaddr;    /* front-panel port 0 mac addr */
  50    uint64_t switch_id;          /* switch id */
  51
  52    /* front-panel ports */
  53    FpPort *fp_port[ROCKER_FP_PORTS_MAX];
  54
  55    /* register backings */
  56    uint32_t test_reg;
  57    uint64_t test_reg64;
  58    dma_addr_t test_dma_addr;
  59    uint32_t test_dma_size;
  60    uint64_t lower32;            /* lower 32-bit val in 2-part 64-bit access */
  61
  62    /* desc rings */
  63    DescRing **rings;
  64
  65    /* switch worlds */
  66    World *worlds[ROCKER_WORLD_TYPE_MAX];
  67    World *world_dflt;
  68
  69    QLIST_ENTRY(rocker) next;
  70};
  71
  72#define ROCKER "rocker"
  73
  74#define to_rocker(obj) \
  75    OBJECT_CHECK(Rocker, (obj), ROCKER)
  76
  77static QLIST_HEAD(, rocker) rockers;
  78
  79Rocker *rocker_find(const char *name)
  80{
  81    Rocker *r;
  82
  83    QLIST_FOREACH(r, &rockers, next)
  84        if (strcmp(r->name, name) == 0) {
  85            return r;
  86        }
  87
  88    return NULL;
  89}
  90
  91World *rocker_get_world(Rocker *r, enum rocker_world_type type)
  92{
  93    if (type < ROCKER_WORLD_TYPE_MAX) {
  94        return r->worlds[type];
  95    }
  96    return NULL;
  97}
  98
  99RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
 100{
 101    RockerSwitch *rocker;
 102    Rocker *r;
 103
 104    r = rocker_find(name);
 105    if (!r) {
 106        error_setg(errp, "rocker %s not found", name);
 107        return NULL;
 108    }
 109
 110    rocker = g_new0(RockerSwitch, 1);
 111    rocker->name = g_strdup(r->name);
 112    rocker->id = r->switch_id;
 113    rocker->ports = r->fp_ports;
 114
 115    return rocker;
 116}
 117
 118RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
 119{
 120    RockerPortList *list = NULL;
 121    Rocker *r;
 122    int i;
 123
 124    r = rocker_find(name);
 125    if (!r) {
 126        error_setg(errp, "rocker %s not found", name);
 127        return NULL;
 128    }
 129
 130    for (i = r->fp_ports - 1; i >= 0; i--) {
 131        RockerPortList *info = g_malloc0(sizeof(*info));
 132        info->value = g_malloc0(sizeof(*info->value));
 133        struct fp_port *port = r->fp_port[i];
 134
 135        fp_port_get_info(port, info);
 136        info->next = list;
 137        list = info;
 138    }
 139
 140    return list;
 141}
 142
 143uint32_t rocker_fp_ports(Rocker *r)
 144{
 145    return r->fp_ports;
 146}
 147
 148static uint32_t rocker_get_pport_by_tx_ring(Rocker *r,
 149                                            DescRing *ring)
 150{
 151    return (desc_ring_index(ring) - 2) / 2 + 1;
 152}
 153
 154static int tx_consume(Rocker *r, DescInfo *info)
 155{
 156    PCIDevice *dev = PCI_DEVICE(r);
 157    char *buf = desc_get_buf(info, true);
 158    RockerTlv *tlv_frag;
 159    RockerTlv *tlvs[ROCKER_TLV_TX_MAX + 1];
 160    struct iovec iov[ROCKER_TX_FRAGS_MAX] = { { 0, }, };
 161    uint32_t pport;
 162    uint32_t port;
 163    uint16_t tx_offload = ROCKER_TX_OFFLOAD_NONE;
 164    uint16_t tx_l3_csum_off = 0;
 165    uint16_t tx_tso_mss = 0;
 166    uint16_t tx_tso_hdr_len = 0;
 167    int iovcnt = 0;
 168    int err = ROCKER_OK;
 169    int rem;
 170    int i;
 171
 172    if (!buf) {
 173        return -ROCKER_ENXIO;
 174    }
 175
 176    rocker_tlv_parse(tlvs, ROCKER_TLV_TX_MAX, buf, desc_tlv_size(info));
 177
 178    if (!tlvs[ROCKER_TLV_TX_FRAGS]) {
 179        return -ROCKER_EINVAL;
 180    }
 181
 182    pport = rocker_get_pport_by_tx_ring(r, desc_get_ring(info));
 183    if (!fp_port_from_pport(pport, &port)) {
 184        return -ROCKER_EINVAL;
 185    }
 186
 187    if (tlvs[ROCKER_TLV_TX_OFFLOAD]) {
 188        tx_offload = rocker_tlv_get_u8(tlvs[ROCKER_TLV_TX_OFFLOAD]);
 189    }
 190
 191    switch (tx_offload) {
 192    case ROCKER_TX_OFFLOAD_L3_CSUM:
 193        if (!tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
 194            return -ROCKER_EINVAL;
 195        }
 196        break;
 197    case ROCKER_TX_OFFLOAD_TSO:
 198        if (!tlvs[ROCKER_TLV_TX_TSO_MSS] ||
 199            !tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) {
 200            return -ROCKER_EINVAL;
 201        }
 202        break;
 203    }
 204
 205    if (tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
 206        tx_l3_csum_off = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]);
 207    }
 208
 209    if (tlvs[ROCKER_TLV_TX_TSO_MSS]) {
 210        tx_tso_mss = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_MSS]);
 211    }
 212
 213    if (tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) {
 214        tx_tso_hdr_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]);
 215    }
 216
 217    rocker_tlv_for_each_nested(tlv_frag, tlvs[ROCKER_TLV_TX_FRAGS], rem) {
 218        hwaddr frag_addr;
 219        uint16_t frag_len;
 220
 221        if (rocker_tlv_type(tlv_frag) != ROCKER_TLV_TX_FRAG) {
 222            err = -ROCKER_EINVAL;
 223            goto err_bad_attr;
 224        }
 225
 226        rocker_tlv_parse_nested(tlvs, ROCKER_TLV_TX_FRAG_ATTR_MAX, tlv_frag);
 227
 228        if (!tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR] ||
 229            !tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]) {
 230            err = -ROCKER_EINVAL;
 231            goto err_bad_attr;
 232        }
 233
 234        frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR]);
 235        frag_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]);
 236
 237        if (iovcnt >= ROCKER_TX_FRAGS_MAX) {
 238            goto err_too_many_frags;
 239        }
 240        iov[iovcnt].iov_len = frag_len;
 241        iov[iovcnt].iov_base = g_malloc(frag_len);
 242        if (!iov[iovcnt].iov_base) {
 243            err = -ROCKER_ENOMEM;
 244            goto err_no_mem;
 245        }
 246
 247        if (pci_dma_read(dev, frag_addr, iov[iovcnt].iov_base,
 248                     iov[iovcnt].iov_len)) {
 249            err = -ROCKER_ENXIO;
 250            goto err_bad_io;
 251        }
 252        iovcnt++;
 253    }
 254
 255    if (iovcnt) {
 256        /* XXX perform Tx offloads */
 257        /* XXX   silence compiler for now */
 258        tx_l3_csum_off += tx_tso_mss = tx_tso_hdr_len = 0;
 259    }
 260
 261    err = fp_port_eg(r->fp_port[port], iov, iovcnt);
 262
 263err_too_many_frags:
 264err_bad_io:
 265err_no_mem:
 266err_bad_attr:
 267    for (i = 0; i < ROCKER_TX_FRAGS_MAX; i++) {
 268        g_free(iov[i].iov_base);
 269    }
 270
 271    return err;
 272}
 273
 274static int cmd_get_port_settings(Rocker *r,
 275                                 DescInfo *info, char *buf,
 276                                 RockerTlv *cmd_info_tlv)
 277{
 278    RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
 279    RockerTlv *nest;
 280    FpPort *fp_port;
 281    uint32_t pport;
 282    uint32_t port;
 283    uint32_t speed;
 284    uint8_t duplex;
 285    uint8_t autoneg;
 286    uint8_t learning;
 287    char *phys_name;
 288    MACAddr macaddr;
 289    enum rocker_world_type mode;
 290    size_t tlv_size;
 291    int pos;
 292    int err;
 293
 294    rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
 295                            cmd_info_tlv);
 296
 297    if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) {
 298        return -ROCKER_EINVAL;
 299    }
 300
 301    pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]);
 302    if (!fp_port_from_pport(pport, &port)) {
 303        return -ROCKER_EINVAL;
 304    }
 305    fp_port = r->fp_port[port];
 306
 307    err = fp_port_get_settings(fp_port, &speed, &duplex, &autoneg);
 308    if (err) {
 309        return err;
 310    }
 311
 312    fp_port_get_macaddr(fp_port, &macaddr);
 313    mode = world_type(fp_port_get_world(fp_port));
 314    learning = fp_port_get_learning(fp_port);
 315    phys_name = fp_port_get_name(fp_port);
 316
 317    tlv_size = rocker_tlv_total_size(0) +                 /* nest */
 318               rocker_tlv_total_size(sizeof(uint32_t)) +  /*   pport */
 319               rocker_tlv_total_size(sizeof(uint32_t)) +  /*   speed */
 320               rocker_tlv_total_size(sizeof(uint8_t)) +   /*   duplex */
 321               rocker_tlv_total_size(sizeof(uint8_t)) +   /*   autoneg */
 322               rocker_tlv_total_size(sizeof(macaddr.a)) + /*   macaddr */
 323               rocker_tlv_total_size(sizeof(uint8_t)) +   /*   mode */
 324               rocker_tlv_total_size(sizeof(uint8_t)) +   /*   learning */
 325               rocker_tlv_total_size(strlen(phys_name));
 326
 327    if (tlv_size > desc_buf_size(info)) {
 328        return -ROCKER_EMSGSIZE;
 329    }
 330
 331    pos = 0;
 332    nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_CMD_INFO);
 333    rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT, pport);
 334    rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_SPEED, speed);
 335    rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX, duplex);
 336    rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG, autoneg);
 337    rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR,
 338                   sizeof(macaddr.a), macaddr.a);
 339    rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MODE, mode);
 340    rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,
 341                      learning);
 342    rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME,
 343                   strlen(phys_name), phys_name);
 344    rocker_tlv_nest_end(buf, &pos, nest);
 345
 346    return desc_set_buf(info, tlv_size);
 347}
 348
 349static int cmd_set_port_settings(Rocker *r,
 350                                 RockerTlv *cmd_info_tlv)
 351{
 352    RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
 353    FpPort *fp_port;
 354    uint32_t pport;
 355    uint32_t port;
 356    uint32_t speed;
 357    uint8_t duplex;
 358    uint8_t autoneg;
 359    uint8_t learning;
 360    MACAddr macaddr;
 361    enum rocker_world_type mode;
 362    int err;
 363
 364    rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
 365                            cmd_info_tlv);
 366
 367    if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) {
 368        return -ROCKER_EINVAL;
 369    }
 370
 371    pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]);
 372    if (!fp_port_from_pport(pport, &port)) {
 373        return -ROCKER_EINVAL;
 374    }
 375    fp_port = r->fp_port[port];
 376
 377    if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED] &&
 378        tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX] &&
 379        tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]) {
 380
 381        speed = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED]);
 382        duplex = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX]);
 383        autoneg = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]);
 384
 385        err = fp_port_set_settings(fp_port, speed, duplex, autoneg);
 386        if (err) {
 387            return err;
 388        }
 389    }
 390
 391    if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) {
 392        if (rocker_tlv_len(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) !=
 393            sizeof(macaddr.a)) {
 394            return -ROCKER_EINVAL;
 395        }
 396        memcpy(macaddr.a,
 397               rocker_tlv_data(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]),
 398               sizeof(macaddr.a));
 399        fp_port_set_macaddr(fp_port, &macaddr);
 400    }
 401
 402    if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]) {
 403        mode = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]);
 404        if (mode >= ROCKER_WORLD_TYPE_MAX) {
 405            return -ROCKER_EINVAL;
 406        }
 407        /* We don't support world change. */
 408        if (!fp_port_check_world(fp_port, r->worlds[mode])) {
 409            return -ROCKER_EINVAL;
 410        }
 411    }
 412
 413    if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]) {
 414        learning =
 415            rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]);
 416        fp_port_set_learning(fp_port, learning);
 417    }
 418
 419    return ROCKER_OK;
 420}
 421
 422static int cmd_consume(Rocker *r, DescInfo *info)
 423{
 424    char *buf = desc_get_buf(info, false);
 425    RockerTlv *tlvs[ROCKER_TLV_CMD_MAX + 1];
 426    RockerTlv *info_tlv;
 427    World *world;
 428    uint16_t cmd;
 429    int err;
 430
 431    if (!buf) {
 432        return -ROCKER_ENXIO;
 433    }
 434
 435    rocker_tlv_parse(tlvs, ROCKER_TLV_CMD_MAX, buf, desc_tlv_size(info));
 436
 437    if (!tlvs[ROCKER_TLV_CMD_TYPE] || !tlvs[ROCKER_TLV_CMD_INFO]) {
 438        return -ROCKER_EINVAL;
 439    }
 440
 441    cmd = rocker_tlv_get_le16(tlvs[ROCKER_TLV_CMD_TYPE]);
 442    info_tlv = tlvs[ROCKER_TLV_CMD_INFO];
 443
 444    /* This might be reworked to something like this:
 445     * Every world will have an array of command handlers from
 446     * ROCKER_TLV_CMD_TYPE_UNSPEC to ROCKER_TLV_CMD_TYPE_MAX. There is
 447     * up to each world to implement whatever command it want.
 448     * It can reference "generic" commands as cmd_set_port_settings or
 449     * cmd_get_port_settings
 450     */
 451
 452    switch (cmd) {
 453    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD:
 454    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD:
 455    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL:
 456    case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS:
 457    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD:
 458    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD:
 459    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL:
 460    case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS:
 461        world = r->worlds[ROCKER_WORLD_TYPE_OF_DPA];
 462        err = world_do_cmd(world, info, buf, cmd, info_tlv);
 463        break;
 464    case ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS:
 465        err = cmd_get_port_settings(r, info, buf, info_tlv);
 466        break;
 467    case ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS:
 468        err = cmd_set_port_settings(r, info_tlv);
 469        break;
 470    default:
 471        err = -ROCKER_EINVAL;
 472        break;
 473    }
 474
 475    return err;
 476}
 477
 478static void rocker_msix_irq(Rocker *r, unsigned vector)
 479{
 480    PCIDevice *dev = PCI_DEVICE(r);
 481
 482    DPRINTF("MSI-X notify request for vector %d\n", vector);
 483    if (vector >= ROCKER_MSIX_VEC_COUNT(r->fp_ports)) {
 484        DPRINTF("incorrect vector %d\n", vector);
 485        return;
 486    }
 487    msix_notify(dev, vector);
 488}
 489
 490int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up)
 491{
 492    DescRing *ring = r->rings[ROCKER_RING_EVENT];
 493    DescInfo *info = desc_ring_fetch_desc(ring);
 494    RockerTlv *nest;
 495    char *buf;
 496    size_t tlv_size;
 497    int pos;
 498    int err;
 499
 500    if (!info) {
 501        return -ROCKER_ENOBUFS;
 502    }
 503
 504    tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) +  /* event type */
 505               rocker_tlv_total_size(0) +                 /* nest */
 506               rocker_tlv_total_size(sizeof(uint32_t)) +  /*   pport */
 507               rocker_tlv_total_size(sizeof(uint8_t));    /*   link up */
 508
 509    if (tlv_size > desc_buf_size(info)) {
 510        err = -ROCKER_EMSGSIZE;
 511        goto err_too_big;
 512    }
 513
 514    buf = desc_get_buf(info, false);
 515    if (!buf) {
 516        err = -ROCKER_ENOMEM;
 517        goto err_no_mem;
 518    }
 519
 520    pos = 0;
 521    rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE,
 522                        ROCKER_TLV_EVENT_TYPE_LINK_CHANGED);
 523    nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO);
 524    rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_PPORT, pport);
 525    rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP,
 526                      link_up ? 1 : 0);
 527    rocker_tlv_nest_end(buf, &pos, nest);
 528
 529    err = desc_set_buf(info, tlv_size);
 530
 531err_too_big:
 532err_no_mem:
 533    if (desc_ring_post_desc(ring, err)) {
 534        rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT);
 535    }
 536
 537    return err;
 538}
 539
 540int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr,
 541                               uint16_t vlan_id)
 542{
 543    DescRing *ring = r->rings[ROCKER_RING_EVENT];
 544    DescInfo *info;
 545    FpPort *fp_port;
 546    uint32_t port;
 547    RockerTlv *nest;
 548    char *buf;
 549    size_t tlv_size;
 550    int pos;
 551    int err;
 552
 553    if (!fp_port_from_pport(pport, &port)) {
 554        return -ROCKER_EINVAL;
 555    }
 556    fp_port = r->fp_port[port];
 557    if (!fp_port_get_learning(fp_port)) {
 558        return ROCKER_OK;
 559    }
 560
 561    info = desc_ring_fetch_desc(ring);
 562    if (!info) {
 563        return -ROCKER_ENOBUFS;
 564    }
 565
 566    tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) +  /* event type */
 567               rocker_tlv_total_size(0) +                 /* nest */
 568               rocker_tlv_total_size(sizeof(uint32_t)) +  /*   pport */
 569               rocker_tlv_total_size(ETH_ALEN) +          /*   mac addr */
 570               rocker_tlv_total_size(sizeof(uint16_t));   /*   vlan_id */
 571
 572    if (tlv_size > desc_buf_size(info)) {
 573        err = -ROCKER_EMSGSIZE;
 574        goto err_too_big;
 575    }
 576
 577    buf = desc_get_buf(info, false);
 578    if (!buf) {
 579        err = -ROCKER_ENOMEM;
 580        goto err_no_mem;
 581    }
 582
 583    pos = 0;
 584    rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE,
 585                        ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN);
 586    nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO);
 587    rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_PPORT, pport);
 588    rocker_tlv_put(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_MAC, ETH_ALEN, addr);
 589    rocker_tlv_put_u16(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID, vlan_id);
 590    rocker_tlv_nest_end(buf, &pos, nest);
 591
 592    err = desc_set_buf(info, tlv_size);
 593
 594err_too_big:
 595err_no_mem:
 596    if (desc_ring_post_desc(ring, err)) {
 597        rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT);
 598    }
 599
 600    return err;
 601}
 602
 603static DescRing *rocker_get_rx_ring_by_pport(Rocker *r,
 604                                                     uint32_t pport)
 605{
 606    return r->rings[(pport - 1) * 2 + 3];
 607}
 608
 609int rx_produce(World *world, uint32_t pport,
 610               const struct iovec *iov, int iovcnt, uint8_t copy_to_cpu)
 611{
 612    Rocker *r = world_rocker(world);
 613    PCIDevice *dev = (PCIDevice *)r;
 614    DescRing *ring = rocker_get_rx_ring_by_pport(r, pport);
 615    DescInfo *info = desc_ring_fetch_desc(ring);
 616    char *data;
 617    size_t data_size = iov_size(iov, iovcnt);
 618    char *buf;
 619    uint16_t rx_flags = 0;
 620    uint16_t rx_csum = 0;
 621    size_t tlv_size;
 622    RockerTlv *tlvs[ROCKER_TLV_RX_MAX + 1];
 623    hwaddr frag_addr;
 624    uint16_t frag_max_len;
 625    int pos;
 626    int err;
 627
 628    if (!info) {
 629        return -ROCKER_ENOBUFS;
 630    }
 631
 632    buf = desc_get_buf(info, false);
 633    if (!buf) {
 634        err = -ROCKER_ENXIO;
 635        goto out;
 636    }
 637    rocker_tlv_parse(tlvs, ROCKER_TLV_RX_MAX, buf, desc_tlv_size(info));
 638
 639    if (!tlvs[ROCKER_TLV_RX_FRAG_ADDR] ||
 640        !tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]) {
 641        err = -ROCKER_EINVAL;
 642        goto out;
 643    }
 644
 645    frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_RX_FRAG_ADDR]);
 646    frag_max_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]);
 647
 648    if (data_size > frag_max_len) {
 649        err = -ROCKER_EMSGSIZE;
 650        goto out;
 651    }
 652
 653    if (copy_to_cpu) {
 654        rx_flags |= ROCKER_RX_FLAGS_FWD_OFFLOAD;
 655    }
 656
 657    /* XXX calc rx flags/csum */
 658
 659    tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* flags */
 660               rocker_tlv_total_size(sizeof(uint16_t)) + /* scum */
 661               rocker_tlv_total_size(sizeof(uint64_t)) + /* frag addr */
 662               rocker_tlv_total_size(sizeof(uint16_t)) + /* frag max len */
 663               rocker_tlv_total_size(sizeof(uint16_t));  /* frag len */
 664
 665    if (tlv_size > desc_buf_size(info)) {
 666        err = -ROCKER_EMSGSIZE;
 667        goto out;
 668    }
 669
 670    /* TODO:
 671     * iov dma write can be optimized in similar way e1000 does it in
 672     * e1000_receive_iov. But maybe if would make sense to introduce
 673     * generic helper iov_dma_write.
 674     */
 675
 676    data = g_malloc(data_size);
 677    if (!data) {
 678        err = -ROCKER_ENOMEM;
 679        goto out;
 680    }
 681    iov_to_buf(iov, iovcnt, 0, data, data_size);
 682    pci_dma_write(dev, frag_addr, data, data_size);
 683    g_free(data);
 684
 685    pos = 0;
 686    rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FLAGS, rx_flags);
 687    rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_CSUM, rx_csum);
 688    rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_RX_FRAG_ADDR, frag_addr);
 689    rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_MAX_LEN, frag_max_len);
 690    rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_LEN, data_size);
 691
 692    err = desc_set_buf(info, tlv_size);
 693
 694out:
 695    if (desc_ring_post_desc(ring, err)) {
 696        rocker_msix_irq(r, ROCKER_MSIX_VEC_RX(pport - 1));
 697    }
 698
 699    return err;
 700}
 701
 702int rocker_port_eg(Rocker *r, uint32_t pport,
 703                   const struct iovec *iov, int iovcnt)
 704{
 705    FpPort *fp_port;
 706    uint32_t port;
 707
 708    if (!fp_port_from_pport(pport, &port)) {
 709        return -ROCKER_EINVAL;
 710    }
 711
 712    fp_port = r->fp_port[port];
 713
 714    return fp_port_eg(fp_port, iov, iovcnt);
 715}
 716
 717static void rocker_test_dma_ctrl(Rocker *r, uint32_t val)
 718{
 719    PCIDevice *dev = PCI_DEVICE(r);
 720    char *buf;
 721    int i;
 722
 723    buf = g_malloc(r->test_dma_size);
 724
 725    if (!buf) {
 726        DPRINTF("test dma buffer alloc failed");
 727        return;
 728    }
 729
 730    switch (val) {
 731    case ROCKER_TEST_DMA_CTRL_CLEAR:
 732        memset(buf, 0, r->test_dma_size);
 733        break;
 734    case ROCKER_TEST_DMA_CTRL_FILL:
 735        memset(buf, 0x96, r->test_dma_size);
 736        break;
 737    case ROCKER_TEST_DMA_CTRL_INVERT:
 738        pci_dma_read(dev, r->test_dma_addr, buf, r->test_dma_size);
 739        for (i = 0; i < r->test_dma_size; i++) {
 740            buf[i] = ~buf[i];
 741        }
 742        break;
 743    default:
 744        DPRINTF("not test dma control val=0x%08x\n", val);
 745        goto err_out;
 746    }
 747    pci_dma_write(dev, r->test_dma_addr, buf, r->test_dma_size);
 748
 749    rocker_msix_irq(r, ROCKER_MSIX_VEC_TEST);
 750
 751err_out:
 752    g_free(buf);
 753}
 754
 755static void rocker_reset(DeviceState *dev);
 756
 757static void rocker_control(Rocker *r, uint32_t val)
 758{
 759    if (val & ROCKER_CONTROL_RESET) {
 760        rocker_reset(DEVICE(r));
 761    }
 762}
 763
 764static int rocker_pci_ring_count(Rocker *r)
 765{
 766    /* There are:
 767     * - command ring
 768     * - event ring
 769     * - tx and rx ring per each port
 770     */
 771    return 2 + (2 * r->fp_ports);
 772}
 773
 774static bool rocker_addr_is_desc_reg(Rocker *r, hwaddr addr)
 775{
 776    hwaddr start = ROCKER_DMA_DESC_BASE;
 777    hwaddr end = start + (ROCKER_DMA_DESC_SIZE * rocker_pci_ring_count(r));
 778
 779    return addr >= start && addr < end;
 780}
 781
 782static void rocker_port_phys_enable_write(Rocker *r, uint64_t new)
 783{
 784    int i;
 785    bool old_enabled;
 786    bool new_enabled;
 787    FpPort *fp_port;
 788
 789    for (i = 0; i < r->fp_ports; i++) {
 790        fp_port = r->fp_port[i];
 791        old_enabled = fp_port_enabled(fp_port);
 792        new_enabled = (new >> (i + 1)) & 0x1;
 793        if (new_enabled == old_enabled) {
 794            continue;
 795        }
 796        if (new_enabled) {
 797            fp_port_enable(r->fp_port[i]);
 798        } else {
 799            fp_port_disable(r->fp_port[i]);
 800        }
 801    }
 802}
 803
 804static void rocker_io_writel(void *opaque, hwaddr addr, uint32_t val)
 805{
 806    Rocker *r = opaque;
 807
 808    if (rocker_addr_is_desc_reg(r, addr)) {
 809        unsigned index = ROCKER_RING_INDEX(addr);
 810        unsigned offset = addr & ROCKER_DMA_DESC_MASK;
 811
 812        switch (offset) {
 813        case ROCKER_DMA_DESC_ADDR_OFFSET:
 814            r->lower32 = (uint64_t)val;
 815            break;
 816        case ROCKER_DMA_DESC_ADDR_OFFSET + 4:
 817            desc_ring_set_base_addr(r->rings[index],
 818                                    ((uint64_t)val) << 32 | r->lower32);
 819            r->lower32 = 0;
 820            break;
 821        case ROCKER_DMA_DESC_SIZE_OFFSET:
 822            desc_ring_set_size(r->rings[index], val);
 823            break;
 824        case ROCKER_DMA_DESC_HEAD_OFFSET:
 825            if (desc_ring_set_head(r->rings[index], val)) {
 826                rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index]));
 827            }
 828            break;
 829        case ROCKER_DMA_DESC_CTRL_OFFSET:
 830            desc_ring_set_ctrl(r->rings[index], val);
 831            break;
 832        case ROCKER_DMA_DESC_CREDITS_OFFSET:
 833            if (desc_ring_ret_credits(r->rings[index], val)) {
 834                rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index]));
 835            }
 836            break;
 837        default:
 838            DPRINTF("not implemented dma reg write(l) addr=0x" TARGET_FMT_plx
 839                    " val=0x%08x (ring %d, addr=0x%02x)\n",
 840                    addr, val, index, offset);
 841            break;
 842        }
 843        return;
 844    }
 845
 846    switch (addr) {
 847    case ROCKER_TEST_REG:
 848        r->test_reg = val;
 849        break;
 850    case ROCKER_TEST_REG64:
 851    case ROCKER_TEST_DMA_ADDR:
 852    case ROCKER_PORT_PHYS_ENABLE:
 853        r->lower32 = (uint64_t)val;
 854        break;
 855    case ROCKER_TEST_REG64 + 4:
 856        r->test_reg64 = ((uint64_t)val) << 32 | r->lower32;
 857        r->lower32 = 0;
 858        break;
 859    case ROCKER_TEST_IRQ:
 860        rocker_msix_irq(r, val);
 861        break;
 862    case ROCKER_TEST_DMA_SIZE:
 863        r->test_dma_size = val;
 864        break;
 865    case ROCKER_TEST_DMA_ADDR + 4:
 866        r->test_dma_addr = ((uint64_t)val) << 32 | r->lower32;
 867        r->lower32 = 0;
 868        break;
 869    case ROCKER_TEST_DMA_CTRL:
 870        rocker_test_dma_ctrl(r, val);
 871        break;
 872    case ROCKER_CONTROL:
 873        rocker_control(r, val);
 874        break;
 875    case ROCKER_PORT_PHYS_ENABLE + 4:
 876        rocker_port_phys_enable_write(r, ((uint64_t)val) << 32 | r->lower32);
 877        r->lower32 = 0;
 878        break;
 879    default:
 880        DPRINTF("not implemented write(l) addr=0x" TARGET_FMT_plx
 881                " val=0x%08x\n", addr, val);
 882        break;
 883    }
 884}
 885
 886static void rocker_io_writeq(void *opaque, hwaddr addr, uint64_t val)
 887{
 888    Rocker *r = opaque;
 889
 890    if (rocker_addr_is_desc_reg(r, addr)) {
 891        unsigned index = ROCKER_RING_INDEX(addr);
 892        unsigned offset = addr & ROCKER_DMA_DESC_MASK;
 893
 894        switch (offset) {
 895        case ROCKER_DMA_DESC_ADDR_OFFSET:
 896            desc_ring_set_base_addr(r->rings[index], val);
 897            break;
 898        default:
 899            DPRINTF("not implemented dma reg write(q) addr=0x" TARGET_FMT_plx
 900                    " val=0x" TARGET_FMT_plx " (ring %d, offset=0x%02x)\n",
 901                    addr, val, index, offset);
 902            break;
 903        }
 904        return;
 905    }
 906
 907    switch (addr) {
 908    case ROCKER_TEST_REG64:
 909        r->test_reg64 = val;
 910        break;
 911    case ROCKER_TEST_DMA_ADDR:
 912        r->test_dma_addr = val;
 913        break;
 914    case ROCKER_PORT_PHYS_ENABLE:
 915        rocker_port_phys_enable_write(r, val);
 916        break;
 917    default:
 918        DPRINTF("not implemented write(q) addr=0x" TARGET_FMT_plx
 919                " val=0x" TARGET_FMT_plx "\n", addr, val);
 920        break;
 921    }
 922}
 923
 924#ifdef DEBUG_ROCKER
 925#define regname(reg) case (reg): return #reg
 926static const char *rocker_reg_name(void *opaque, hwaddr addr)
 927{
 928    Rocker *r = opaque;
 929
 930    if (rocker_addr_is_desc_reg(r, addr)) {
 931        unsigned index = ROCKER_RING_INDEX(addr);
 932        unsigned offset = addr & ROCKER_DMA_DESC_MASK;
 933        static char buf[100];
 934        char ring_name[10];
 935
 936        switch (index) {
 937        case 0:
 938            sprintf(ring_name, "cmd");
 939            break;
 940        case 1:
 941            sprintf(ring_name, "event");
 942            break;
 943        default:
 944            sprintf(ring_name, "%s-%d", index % 2 ? "rx" : "tx",
 945                    (index - 2) / 2);
 946        }
 947
 948        switch (offset) {
 949        case ROCKER_DMA_DESC_ADDR_OFFSET:
 950            sprintf(buf, "Ring[%s] ADDR", ring_name);
 951            return buf;
 952        case ROCKER_DMA_DESC_ADDR_OFFSET+4:
 953            sprintf(buf, "Ring[%s] ADDR+4", ring_name);
 954            return buf;
 955        case ROCKER_DMA_DESC_SIZE_OFFSET:
 956            sprintf(buf, "Ring[%s] SIZE", ring_name);
 957            return buf;
 958        case ROCKER_DMA_DESC_HEAD_OFFSET:
 959            sprintf(buf, "Ring[%s] HEAD", ring_name);
 960            return buf;
 961        case ROCKER_DMA_DESC_TAIL_OFFSET:
 962            sprintf(buf, "Ring[%s] TAIL", ring_name);
 963            return buf;
 964        case ROCKER_DMA_DESC_CTRL_OFFSET:
 965            sprintf(buf, "Ring[%s] CTRL", ring_name);
 966            return buf;
 967        case ROCKER_DMA_DESC_CREDITS_OFFSET:
 968            sprintf(buf, "Ring[%s] CREDITS", ring_name);
 969            return buf;
 970        default:
 971            sprintf(buf, "Ring[%s] ???", ring_name);
 972            return buf;
 973        }
 974    } else {
 975        switch (addr) {
 976            regname(ROCKER_BOGUS_REG0);
 977            regname(ROCKER_BOGUS_REG1);
 978            regname(ROCKER_BOGUS_REG2);
 979            regname(ROCKER_BOGUS_REG3);
 980            regname(ROCKER_TEST_REG);
 981            regname(ROCKER_TEST_REG64);
 982            regname(ROCKER_TEST_REG64+4);
 983            regname(ROCKER_TEST_IRQ);
 984            regname(ROCKER_TEST_DMA_ADDR);
 985            regname(ROCKER_TEST_DMA_ADDR+4);
 986            regname(ROCKER_TEST_DMA_SIZE);
 987            regname(ROCKER_TEST_DMA_CTRL);
 988            regname(ROCKER_CONTROL);
 989            regname(ROCKER_PORT_PHYS_COUNT);
 990            regname(ROCKER_PORT_PHYS_LINK_STATUS);
 991            regname(ROCKER_PORT_PHYS_LINK_STATUS+4);
 992            regname(ROCKER_PORT_PHYS_ENABLE);
 993            regname(ROCKER_PORT_PHYS_ENABLE+4);
 994            regname(ROCKER_SWITCH_ID);
 995            regname(ROCKER_SWITCH_ID+4);
 996        }
 997    }
 998    return "???";
 999}
1000#else
1001static const char *rocker_reg_name(void *opaque, hwaddr addr)
1002{
1003    return NULL;
1004}
1005#endif
1006
1007static void rocker_mmio_write(void *opaque, hwaddr addr, uint64_t val,
1008                              unsigned size)
1009{
1010    DPRINTF("Write %s addr " TARGET_FMT_plx
1011            ", size %u, val " TARGET_FMT_plx "\n",
1012            rocker_reg_name(opaque, addr), addr, size, val);
1013
1014    switch (size) {
1015    case 4:
1016        rocker_io_writel(opaque, addr, val);
1017        break;
1018    case 8:
1019        rocker_io_writeq(opaque, addr, val);
1020        break;
1021    }
1022}
1023
1024static uint64_t rocker_port_phys_link_status(Rocker *r)
1025{
1026    int i;
1027    uint64_t status = 0;
1028
1029    for (i = 0; i < r->fp_ports; i++) {
1030        FpPort *port = r->fp_port[i];
1031
1032        if (fp_port_get_link_up(port)) {
1033            status |= 1 << (i + 1);
1034        }
1035    }
1036    return status;
1037}
1038
1039static uint64_t rocker_port_phys_enable_read(Rocker *r)
1040{
1041    int i;
1042    uint64_t ret = 0;
1043
1044    for (i = 0; i < r->fp_ports; i++) {
1045        FpPort *port = r->fp_port[i];
1046
1047        if (fp_port_enabled(port)) {
1048            ret |= 1 << (i + 1);
1049        }
1050    }
1051    return ret;
1052}
1053
1054static uint32_t rocker_io_readl(void *opaque, hwaddr addr)
1055{
1056    Rocker *r = opaque;
1057    uint32_t ret;
1058
1059    if (rocker_addr_is_desc_reg(r, addr)) {
1060        unsigned index = ROCKER_RING_INDEX(addr);
1061        unsigned offset = addr & ROCKER_DMA_DESC_MASK;
1062
1063        switch (offset) {
1064        case ROCKER_DMA_DESC_ADDR_OFFSET:
1065            ret = (uint32_t)desc_ring_get_base_addr(r->rings[index]);
1066            break;
1067        case ROCKER_DMA_DESC_ADDR_OFFSET + 4:
1068            ret = (uint32_t)(desc_ring_get_base_addr(r->rings[index]) >> 32);
1069            break;
1070        case ROCKER_DMA_DESC_SIZE_OFFSET:
1071            ret = desc_ring_get_size(r->rings[index]);
1072            break;
1073        case ROCKER_DMA_DESC_HEAD_OFFSET:
1074            ret = desc_ring_get_head(r->rings[index]);
1075            break;
1076        case ROCKER_DMA_DESC_TAIL_OFFSET:
1077            ret = desc_ring_get_tail(r->rings[index]);
1078            break;
1079        case ROCKER_DMA_DESC_CREDITS_OFFSET:
1080            ret = desc_ring_get_credits(r->rings[index]);
1081            break;
1082        default:
1083            DPRINTF("not implemented dma reg read(l) addr=0x" TARGET_FMT_plx
1084                    " (ring %d, addr=0x%02x)\n", addr, index, offset);
1085            ret = 0;
1086            break;
1087        }
1088        return ret;
1089    }
1090
1091    switch (addr) {
1092    case ROCKER_BOGUS_REG0:
1093    case ROCKER_BOGUS_REG1:
1094    case ROCKER_BOGUS_REG2:
1095    case ROCKER_BOGUS_REG3:
1096        ret = 0xDEADBABE;
1097        break;
1098    case ROCKER_TEST_REG:
1099        ret = r->test_reg * 2;
1100        break;
1101    case ROCKER_TEST_REG64:
1102        ret = (uint32_t)(r->test_reg64 * 2);
1103        break;
1104    case ROCKER_TEST_REG64 + 4:
1105        ret = (uint32_t)((r->test_reg64 * 2) >> 32);
1106        break;
1107    case ROCKER_TEST_DMA_SIZE:
1108        ret = r->test_dma_size;
1109        break;
1110    case ROCKER_TEST_DMA_ADDR:
1111        ret = (uint32_t)r->test_dma_addr;
1112        break;
1113    case ROCKER_TEST_DMA_ADDR + 4:
1114        ret = (uint32_t)(r->test_dma_addr >> 32);
1115        break;
1116    case ROCKER_PORT_PHYS_COUNT:
1117        ret = r->fp_ports;
1118        break;
1119    case ROCKER_PORT_PHYS_LINK_STATUS:
1120        ret = (uint32_t)rocker_port_phys_link_status(r);
1121        break;
1122    case ROCKER_PORT_PHYS_LINK_STATUS + 4:
1123        ret = (uint32_t)(rocker_port_phys_link_status(r) >> 32);
1124        break;
1125    case ROCKER_PORT_PHYS_ENABLE:
1126        ret = (uint32_t)rocker_port_phys_enable_read(r);
1127        break;
1128    case ROCKER_PORT_PHYS_ENABLE + 4:
1129        ret = (uint32_t)(rocker_port_phys_enable_read(r) >> 32);
1130        break;
1131    case ROCKER_SWITCH_ID:
1132        ret = (uint32_t)r->switch_id;
1133        break;
1134    case ROCKER_SWITCH_ID + 4:
1135        ret = (uint32_t)(r->switch_id >> 32);
1136        break;
1137    default:
1138        DPRINTF("not implemented read(l) addr=0x" TARGET_FMT_plx "\n", addr);
1139        ret = 0;
1140        break;
1141    }
1142    return ret;
1143}
1144
1145static uint64_t rocker_io_readq(void *opaque, hwaddr addr)
1146{
1147    Rocker *r = opaque;
1148    uint64_t ret;
1149
1150    if (rocker_addr_is_desc_reg(r, addr)) {
1151        unsigned index = ROCKER_RING_INDEX(addr);
1152        unsigned offset = addr & ROCKER_DMA_DESC_MASK;
1153
1154        switch (addr & ROCKER_DMA_DESC_MASK) {
1155        case ROCKER_DMA_DESC_ADDR_OFFSET:
1156            ret = desc_ring_get_base_addr(r->rings[index]);
1157            break;
1158        default:
1159            DPRINTF("not implemented dma reg read(q) addr=0x" TARGET_FMT_plx
1160                    " (ring %d, addr=0x%02x)\n", addr, index, offset);
1161            ret = 0;
1162            break;
1163        }
1164        return ret;
1165    }
1166
1167    switch (addr) {
1168    case ROCKER_BOGUS_REG0:
1169    case ROCKER_BOGUS_REG2:
1170        ret = 0xDEADBABEDEADBABEULL;
1171        break;
1172    case ROCKER_TEST_REG64:
1173        ret = r->test_reg64 * 2;
1174        break;
1175    case ROCKER_TEST_DMA_ADDR:
1176        ret = r->test_dma_addr;
1177        break;
1178    case ROCKER_PORT_PHYS_LINK_STATUS:
1179        ret = rocker_port_phys_link_status(r);
1180        break;
1181    case ROCKER_PORT_PHYS_ENABLE:
1182        ret = rocker_port_phys_enable_read(r);
1183        break;
1184    case ROCKER_SWITCH_ID:
1185        ret = r->switch_id;
1186        break;
1187    default:
1188        DPRINTF("not implemented read(q) addr=0x" TARGET_FMT_plx "\n", addr);
1189        ret = 0;
1190        break;
1191    }
1192    return ret;
1193}
1194
1195static uint64_t rocker_mmio_read(void *opaque, hwaddr addr, unsigned size)
1196{
1197    DPRINTF("Read %s addr " TARGET_FMT_plx ", size %u\n",
1198            rocker_reg_name(opaque, addr), addr, size);
1199
1200    switch (size) {
1201    case 4:
1202        return rocker_io_readl(opaque, addr);
1203    case 8:
1204        return rocker_io_readq(opaque, addr);
1205    }
1206
1207    return -1;
1208}
1209
1210static const MemoryRegionOps rocker_mmio_ops = {
1211    .read = rocker_mmio_read,
1212    .write = rocker_mmio_write,
1213    .endianness = DEVICE_LITTLE_ENDIAN,
1214    .valid = {
1215        .min_access_size = 4,
1216        .max_access_size = 8,
1217    },
1218    .impl = {
1219        .min_access_size = 4,
1220        .max_access_size = 8,
1221    },
1222};
1223
1224static void rocker_msix_vectors_unuse(Rocker *r,
1225                                      unsigned int num_vectors)
1226{
1227    PCIDevice *dev = PCI_DEVICE(r);
1228    int i;
1229
1230    for (i = 0; i < num_vectors; i++) {
1231        msix_vector_unuse(dev, i);
1232    }
1233}
1234
1235static int rocker_msix_vectors_use(Rocker *r,
1236                                   unsigned int num_vectors)
1237{
1238    PCIDevice *dev = PCI_DEVICE(r);
1239    int err;
1240    int i;
1241
1242    for (i = 0; i < num_vectors; i++) {
1243        err = msix_vector_use(dev, i);
1244        if (err) {
1245            goto rollback;
1246        }
1247    }
1248    return 0;
1249
1250rollback:
1251    rocker_msix_vectors_unuse(r, i);
1252    return err;
1253}
1254
1255static int rocker_msix_init(Rocker *r)
1256{
1257    PCIDevice *dev = PCI_DEVICE(r);
1258    int err;
1259
1260    err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports),
1261                    &r->msix_bar,
1262                    ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET,
1263                    &r->msix_bar,
1264                    ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET,
1265                    0);
1266    if (err) {
1267        return err;
1268    }
1269
1270    err = rocker_msix_vectors_use(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
1271    if (err) {
1272        goto err_msix_vectors_use;
1273    }
1274
1275    return 0;
1276
1277err_msix_vectors_use:
1278    msix_uninit(dev, &r->msix_bar, &r->msix_bar);
1279    return err;
1280}
1281
1282static void rocker_msix_uninit(Rocker *r)
1283{
1284    PCIDevice *dev = PCI_DEVICE(r);
1285
1286    msix_uninit(dev, &r->msix_bar, &r->msix_bar);
1287    rocker_msix_vectors_unuse(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
1288}
1289
1290static World *rocker_world_type_by_name(Rocker *r, const char *name)
1291{
1292    int i;
1293
1294    for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1295        if (strcmp(name, world_name(r->worlds[i])) == 0) {
1296            return r->worlds[i];
1297        }
1298    }
1299    return NULL;
1300}
1301
1302static int pci_rocker_init(PCIDevice *dev)
1303{
1304    Rocker *r = to_rocker(dev);
1305    const MACAddr zero = { .a = { 0, 0, 0, 0, 0, 0 } };
1306    const MACAddr dflt = { .a = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x01 } };
1307    static int sw_index;
1308    int i, err = 0;
1309
1310    /* allocate worlds */
1311
1312    r->worlds[ROCKER_WORLD_TYPE_OF_DPA] = of_dpa_world_alloc(r);
1313
1314    for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1315        if (!r->worlds[i]) {
1316            err = -ENOMEM;
1317            goto err_world_alloc;
1318        }
1319    }
1320
1321    if (!r->world_name) {
1322        r->world_name = g_strdup(world_name(r->worlds[ROCKER_WORLD_TYPE_OF_DPA]));
1323    }
1324
1325    r->world_dflt = rocker_world_type_by_name(r, r->world_name);
1326    if (!r->world_dflt) {
1327        fprintf(stderr,
1328                "rocker: requested world \"%s\" does not exist\n",
1329                r->world_name);
1330        err = -EINVAL;
1331        goto err_world_type_by_name;
1332    }
1333
1334    /* set up memory-mapped region at BAR0 */
1335
1336    memory_region_init_io(&r->mmio, OBJECT(r), &rocker_mmio_ops, r,
1337                          "rocker-mmio", ROCKER_PCI_BAR0_SIZE);
1338    pci_register_bar(dev, ROCKER_PCI_BAR0_IDX,
1339                     PCI_BASE_ADDRESS_SPACE_MEMORY, &r->mmio);
1340
1341    /* set up memory-mapped region for MSI-X */
1342
1343    memory_region_init(&r->msix_bar, OBJECT(r), "rocker-msix-bar",
1344                       ROCKER_PCI_MSIX_BAR_SIZE);
1345    pci_register_bar(dev, ROCKER_PCI_MSIX_BAR_IDX,
1346                     PCI_BASE_ADDRESS_SPACE_MEMORY, &r->msix_bar);
1347
1348    /* MSI-X init */
1349
1350    err = rocker_msix_init(r);
1351    if (err) {
1352        goto err_msix_init;
1353    }
1354
1355    /* validate switch properties */
1356
1357    if (!r->name) {
1358        r->name = g_strdup(ROCKER);
1359    }
1360
1361    if (rocker_find(r->name)) {
1362        err = -EEXIST;
1363        goto err_duplicate;
1364    }
1365
1366    /* Rocker name is passed in port name requests to OS with the intention
1367     * that the name is used in interface names. Limit the length of the
1368     * rocker name to avoid naming problems in the OS. Also, adding the
1369     * port number as p# and unganged breakout b#, where # is at most 2
1370     * digits, so leave room for it too (-1 for string terminator, -3 for
1371     * p# and -3 for b#)
1372     */
1373#define ROCKER_IFNAMSIZ 16
1374#define MAX_ROCKER_NAME_LEN  (ROCKER_IFNAMSIZ - 1 - 3 - 3)
1375    if (strlen(r->name) > MAX_ROCKER_NAME_LEN) {
1376        fprintf(stderr,
1377                "rocker: name too long; please shorten to at most %d chars\n",
1378                MAX_ROCKER_NAME_LEN);
1379        return -EINVAL;
1380    }
1381
1382    if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) {
1383        memcpy(&r->fp_start_macaddr, &dflt, sizeof(dflt));
1384        r->fp_start_macaddr.a[4] += (sw_index++);
1385    }
1386
1387    if (!r->switch_id) {
1388        memcpy(&r->switch_id, &r->fp_start_macaddr,
1389               sizeof(r->fp_start_macaddr));
1390    }
1391
1392    if (r->fp_ports > ROCKER_FP_PORTS_MAX) {
1393        r->fp_ports = ROCKER_FP_PORTS_MAX;
1394    }
1395
1396    r->rings = g_new(DescRing *, rocker_pci_ring_count(r));
1397    if (!r->rings) {
1398        goto err_rings_alloc;
1399    }
1400
1401    /* Rings are ordered like this:
1402     * - command ring
1403     * - event ring
1404     * - port0 tx ring
1405     * - port0 rx ring
1406     * - port1 tx ring
1407     * - port1 rx ring
1408     * .....
1409     */
1410
1411    err = -ENOMEM;
1412    for (i = 0; i < rocker_pci_ring_count(r); i++) {
1413        DescRing *ring = desc_ring_alloc(r, i);
1414
1415        if (!ring) {
1416            goto err_ring_alloc;
1417        }
1418
1419        if (i == ROCKER_RING_CMD) {
1420            desc_ring_set_consume(ring, cmd_consume, ROCKER_MSIX_VEC_CMD);
1421        } else if (i == ROCKER_RING_EVENT) {
1422            desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_EVENT);
1423        } else if (i % 2 == 0) {
1424            desc_ring_set_consume(ring, tx_consume,
1425                                  ROCKER_MSIX_VEC_TX((i - 2) / 2));
1426        } else if (i % 2 == 1) {
1427            desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_RX((i - 3) / 2));
1428        }
1429
1430        r->rings[i] = ring;
1431    }
1432
1433    for (i = 0; i < r->fp_ports; i++) {
1434        FpPort *port =
1435            fp_port_alloc(r, r->name, &r->fp_start_macaddr,
1436                          i, &r->fp_ports_peers[i]);
1437
1438        if (!port) {
1439            goto err_port_alloc;
1440        }
1441
1442        r->fp_port[i] = port;
1443        fp_port_set_world(port, r->world_dflt);
1444    }
1445
1446    QLIST_INSERT_HEAD(&rockers, r, next);
1447
1448    return 0;
1449
1450err_port_alloc:
1451    for (--i; i >= 0; i--) {
1452        FpPort *port = r->fp_port[i];
1453        fp_port_free(port);
1454    }
1455    i = rocker_pci_ring_count(r);
1456err_ring_alloc:
1457    for (--i; i >= 0; i--) {
1458        desc_ring_free(r->rings[i]);
1459    }
1460    g_free(r->rings);
1461err_rings_alloc:
1462err_duplicate:
1463    rocker_msix_uninit(r);
1464err_msix_init:
1465    object_unparent(OBJECT(&r->msix_bar));
1466    object_unparent(OBJECT(&r->mmio));
1467err_world_type_by_name:
1468err_world_alloc:
1469    for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1470        if (r->worlds[i]) {
1471            world_free(r->worlds[i]);
1472        }
1473    }
1474    return err;
1475}
1476
1477static void pci_rocker_uninit(PCIDevice *dev)
1478{
1479    Rocker *r = to_rocker(dev);
1480    int i;
1481
1482    QLIST_REMOVE(r, next);
1483
1484    for (i = 0; i < r->fp_ports; i++) {
1485        FpPort *port = r->fp_port[i];
1486
1487        fp_port_free(port);
1488        r->fp_port[i] = NULL;
1489    }
1490
1491    for (i = 0; i < rocker_pci_ring_count(r); i++) {
1492        if (r->rings[i]) {
1493            desc_ring_free(r->rings[i]);
1494        }
1495    }
1496    g_free(r->rings);
1497
1498    rocker_msix_uninit(r);
1499    object_unparent(OBJECT(&r->msix_bar));
1500    object_unparent(OBJECT(&r->mmio));
1501
1502    for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1503        if (r->worlds[i]) {
1504            world_free(r->worlds[i]);
1505        }
1506    }
1507    g_free(r->fp_ports_peers);
1508}
1509
1510static void rocker_reset(DeviceState *dev)
1511{
1512    Rocker *r = to_rocker(dev);
1513    int i;
1514
1515    for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1516        if (r->worlds[i]) {
1517            world_reset(r->worlds[i]);
1518        }
1519    }
1520    for (i = 0; i < r->fp_ports; i++) {
1521        fp_port_reset(r->fp_port[i]);
1522        fp_port_set_world(r->fp_port[i], r->world_dflt);
1523    }
1524
1525    r->test_reg = 0;
1526    r->test_reg64 = 0;
1527    r->test_dma_addr = 0;
1528    r->test_dma_size = 0;
1529
1530    for (i = 0; i < rocker_pci_ring_count(r); i++) {
1531        desc_ring_reset(r->rings[i]);
1532    }
1533
1534    DPRINTF("Reset done\n");
1535}
1536
1537static Property rocker_properties[] = {
1538    DEFINE_PROP_STRING("name", Rocker, name),
1539    DEFINE_PROP_STRING("world", Rocker, world_name),
1540    DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker,
1541                        fp_start_macaddr),
1542    DEFINE_PROP_UINT64("switch_id", Rocker,
1543                       switch_id, 0),
1544    DEFINE_PROP_ARRAY("ports", Rocker, fp_ports,
1545                      fp_ports_peers, qdev_prop_netdev, NICPeers),
1546    DEFINE_PROP_END_OF_LIST(),
1547};
1548
1549static const VMStateDescription rocker_vmsd = {
1550    .name = ROCKER,
1551    .unmigratable = 1,
1552};
1553
1554static void rocker_class_init(ObjectClass *klass, void *data)
1555{
1556    DeviceClass *dc = DEVICE_CLASS(klass);
1557    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1558
1559    k->init = pci_rocker_init;
1560    k->exit = pci_rocker_uninit;
1561    k->vendor_id = PCI_VENDOR_ID_REDHAT;
1562    k->device_id = PCI_DEVICE_ID_REDHAT_ROCKER;
1563    k->revision = ROCKER_PCI_REVISION;
1564    k->class_id = PCI_CLASS_NETWORK_OTHER;
1565    set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1566    dc->desc = "Rocker Switch";
1567    dc->reset = rocker_reset;
1568    dc->props = rocker_properties;
1569    dc->vmsd = &rocker_vmsd;
1570}
1571
1572static const TypeInfo rocker_info = {
1573    .name          = ROCKER,
1574    .parent        = TYPE_PCI_DEVICE,
1575    .instance_size = sizeof(Rocker),
1576    .class_init    = rocker_class_init,
1577};
1578
1579static void rocker_register_types(void)
1580{
1581    type_register_static(&rocker_info);
1582}
1583
1584type_init(rocker_register_types)
1585