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