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