qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

rocker.c (43359B)


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