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