meson: convert hw/block
[qemu/ar7.git] / hw / net / rocker / rocker.c
blob15d66f6cbcf0dcb6d155e0ae6ab76fba6a54d495
1 /*
2 * QEMU rocker switch emulation - PCI device
4 * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
5 * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
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.
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.
18 #include "qemu/osdep.h"
19 #include "hw/pci/pci.h"
20 #include "hw/qdev-properties.h"
21 #include "migration/vmstate.h"
22 #include "hw/pci/msix.h"
23 #include "net/net.h"
24 #include "net/eth.h"
25 #include "qapi/error.h"
26 #include "qapi/qapi-commands-rocker.h"
27 #include "qemu/iov.h"
28 #include "qemu/module.h"
29 #include "qemu/bitops.h"
30 #include "qemu/log.h"
32 #include "rocker.h"
33 #include "rocker_hw.h"
34 #include "rocker_fp.h"
35 #include "rocker_desc.h"
36 #include "rocker_tlv.h"
37 #include "rocker_world.h"
38 #include "rocker_of_dpa.h"
40 struct rocker {
41 /* private */
42 PCIDevice parent_obj;
43 /* public */
45 MemoryRegion mmio;
46 MemoryRegion msix_bar;
48 /* switch configuration */
49 char *name; /* switch name */
50 char *world_name; /* world name */
51 uint32_t fp_ports; /* front-panel port count */
52 NICPeers *fp_ports_peers;
53 MACAddr fp_start_macaddr; /* front-panel port 0 mac addr */
54 uint64_t switch_id; /* switch id */
56 /* front-panel ports */
57 FpPort *fp_port[ROCKER_FP_PORTS_MAX];
59 /* register backings */
60 uint32_t test_reg;
61 uint64_t test_reg64;
62 dma_addr_t test_dma_addr;
63 uint32_t test_dma_size;
64 uint64_t lower32; /* lower 32-bit val in 2-part 64-bit access */
66 /* desc rings */
67 DescRing **rings;
69 /* switch worlds */
70 World *worlds[ROCKER_WORLD_TYPE_MAX];
71 World *world_dflt;
73 QLIST_ENTRY(rocker) next;
76 #define TYPE_ROCKER "rocker"
78 #define ROCKER(obj) \
79 OBJECT_CHECK(Rocker, (obj), TYPE_ROCKER)
81 static QLIST_HEAD(, rocker) rockers;
83 Rocker *rocker_find(const char *name)
85 Rocker *r;
87 QLIST_FOREACH(r, &rockers, next)
88 if (strcmp(r->name, name) == 0) {
89 return r;
92 return NULL;
95 World *rocker_get_world(Rocker *r, enum rocker_world_type type)
97 if (type < ROCKER_WORLD_TYPE_MAX) {
98 return r->worlds[type];
100 return NULL;
103 RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
105 RockerSwitch *rocker;
106 Rocker *r;
108 r = rocker_find(name);
109 if (!r) {
110 error_setg(errp, "rocker %s not found", name);
111 return NULL;
114 rocker = g_new0(RockerSwitch, 1);
115 rocker->name = g_strdup(r->name);
116 rocker->id = r->switch_id;
117 rocker->ports = r->fp_ports;
119 return rocker;
122 RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
124 RockerPortList *list = NULL;
125 Rocker *r;
126 int i;
128 r = rocker_find(name);
129 if (!r) {
130 error_setg(errp, "rocker %s not found", name);
131 return NULL;
134 for (i = r->fp_ports - 1; i >= 0; i--) {
135 RockerPortList *info = g_malloc0(sizeof(*info));
136 info->value = g_malloc0(sizeof(*info->value));
137 struct fp_port *port = r->fp_port[i];
139 fp_port_get_info(port, info);
140 info->next = list;
141 list = info;
144 return list;
147 uint32_t rocker_fp_ports(Rocker *r)
149 return r->fp_ports;
152 static uint32_t rocker_get_pport_by_tx_ring(Rocker *r,
153 DescRing *ring)
155 return (desc_ring_index(ring) - 2) / 2 + 1;
158 static int tx_consume(Rocker *r, DescInfo *info)
160 PCIDevice *dev = PCI_DEVICE(r);
161 char *buf = desc_get_buf(info, true);
162 RockerTlv *tlv_frag;
163 RockerTlv *tlvs[ROCKER_TLV_TX_MAX + 1];
164 struct iovec iov[ROCKER_TX_FRAGS_MAX] = { { 0, }, };
165 uint32_t pport;
166 uint32_t port;
167 uint16_t tx_offload = ROCKER_TX_OFFLOAD_NONE;
168 uint16_t tx_l3_csum_off = 0;
169 uint16_t tx_tso_mss = 0;
170 uint16_t tx_tso_hdr_len = 0;
171 int iovcnt = 0;
172 int err = ROCKER_OK;
173 int rem;
174 int i;
176 if (!buf) {
177 return -ROCKER_ENXIO;
180 rocker_tlv_parse(tlvs, ROCKER_TLV_TX_MAX, buf, desc_tlv_size(info));
182 if (!tlvs[ROCKER_TLV_TX_FRAGS]) {
183 return -ROCKER_EINVAL;
186 pport = rocker_get_pport_by_tx_ring(r, desc_get_ring(info));
187 if (!fp_port_from_pport(pport, &port)) {
188 return -ROCKER_EINVAL;
191 if (tlvs[ROCKER_TLV_TX_OFFLOAD]) {
192 tx_offload = rocker_tlv_get_u8(tlvs[ROCKER_TLV_TX_OFFLOAD]);
195 switch (tx_offload) {
196 case ROCKER_TX_OFFLOAD_L3_CSUM:
197 if (!tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
198 return -ROCKER_EINVAL;
200 break;
201 case ROCKER_TX_OFFLOAD_TSO:
202 if (!tlvs[ROCKER_TLV_TX_TSO_MSS] ||
203 !tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) {
204 return -ROCKER_EINVAL;
206 break;
209 if (tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
210 tx_l3_csum_off = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]);
211 qemu_log_mask(LOG_UNIMP, "rocker %s: L3 not implemented"
212 " (cksum off: %u)\n",
213 __func__, tx_l3_csum_off);
216 if (tlvs[ROCKER_TLV_TX_TSO_MSS]) {
217 tx_tso_mss = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_MSS]);
218 qemu_log_mask(LOG_UNIMP, "rocker %s: TSO not implemented (MSS: %u)\n",
219 __func__, tx_tso_mss);
222 if (tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) {
223 tx_tso_hdr_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]);
224 qemu_log_mask(LOG_UNIMP, "rocker %s: TSO not implemented"
225 " (hdr length: %u)\n",
226 __func__, tx_tso_hdr_len);
229 rocker_tlv_for_each_nested(tlv_frag, tlvs[ROCKER_TLV_TX_FRAGS], rem) {
230 hwaddr frag_addr;
231 uint16_t frag_len;
233 if (rocker_tlv_type(tlv_frag) != ROCKER_TLV_TX_FRAG) {
234 err = -ROCKER_EINVAL;
235 goto err_bad_attr;
238 rocker_tlv_parse_nested(tlvs, ROCKER_TLV_TX_FRAG_ATTR_MAX, tlv_frag);
240 if (!tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR] ||
241 !tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]) {
242 err = -ROCKER_EINVAL;
243 goto err_bad_attr;
246 frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR]);
247 frag_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]);
249 if (iovcnt >= ROCKER_TX_FRAGS_MAX) {
250 goto err_too_many_frags;
252 iov[iovcnt].iov_len = frag_len;
253 iov[iovcnt].iov_base = g_malloc(frag_len);
255 pci_dma_read(dev, frag_addr, iov[iovcnt].iov_base,
256 iov[iovcnt].iov_len);
258 iovcnt++;
261 err = fp_port_eg(r->fp_port[port], iov, iovcnt);
263 err_too_many_frags:
264 err_bad_attr:
265 for (i = 0; i < ROCKER_TX_FRAGS_MAX; i++) {
266 g_free(iov[i].iov_base);
269 return err;
272 static int cmd_get_port_settings(Rocker *r,
273 DescInfo *info, char *buf,
274 RockerTlv *cmd_info_tlv)
276 RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
277 RockerTlv *nest;
278 FpPort *fp_port;
279 uint32_t pport;
280 uint32_t port;
281 uint32_t speed;
282 uint8_t duplex;
283 uint8_t autoneg;
284 uint8_t learning;
285 char *phys_name;
286 MACAddr macaddr;
287 enum rocker_world_type mode;
288 size_t tlv_size;
289 int pos;
290 int err;
292 rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
293 cmd_info_tlv);
295 if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) {
296 return -ROCKER_EINVAL;
299 pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]);
300 if (!fp_port_from_pport(pport, &port)) {
301 return -ROCKER_EINVAL;
303 fp_port = r->fp_port[port];
305 err = fp_port_get_settings(fp_port, &speed, &duplex, &autoneg);
306 if (err) {
307 return err;
310 fp_port_get_macaddr(fp_port, &macaddr);
311 mode = world_type(fp_port_get_world(fp_port));
312 learning = fp_port_get_learning(fp_port);
313 phys_name = fp_port_get_name(fp_port);
315 tlv_size = rocker_tlv_total_size(0) + /* nest */
316 rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */
317 rocker_tlv_total_size(sizeof(uint32_t)) + /* speed */
318 rocker_tlv_total_size(sizeof(uint8_t)) + /* duplex */
319 rocker_tlv_total_size(sizeof(uint8_t)) + /* autoneg */
320 rocker_tlv_total_size(sizeof(macaddr.a)) + /* macaddr */
321 rocker_tlv_total_size(sizeof(uint8_t)) + /* mode */
322 rocker_tlv_total_size(sizeof(uint8_t)) + /* learning */
323 rocker_tlv_total_size(strlen(phys_name));
325 if (tlv_size > desc_buf_size(info)) {
326 return -ROCKER_EMSGSIZE;
329 pos = 0;
330 nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_CMD_INFO);
331 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT, pport);
332 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_SPEED, speed);
333 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX, duplex);
334 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG, autoneg);
335 rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR,
336 sizeof(macaddr.a), macaddr.a);
337 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MODE, mode);
338 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,
339 learning);
340 rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME,
341 strlen(phys_name), phys_name);
342 rocker_tlv_nest_end(buf, &pos, nest);
344 return desc_set_buf(info, tlv_size);
347 static int cmd_set_port_settings(Rocker *r,
348 RockerTlv *cmd_info_tlv)
350 RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
351 FpPort *fp_port;
352 uint32_t pport;
353 uint32_t port;
354 uint32_t speed;
355 uint8_t duplex;
356 uint8_t autoneg;
357 uint8_t learning;
358 MACAddr macaddr;
359 enum rocker_world_type mode;
360 int err;
362 rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
363 cmd_info_tlv);
365 if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) {
366 return -ROCKER_EINVAL;
369 pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]);
370 if (!fp_port_from_pport(pport, &port)) {
371 return -ROCKER_EINVAL;
373 fp_port = r->fp_port[port];
375 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED] &&
376 tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX] &&
377 tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]) {
379 speed = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED]);
380 duplex = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX]);
381 autoneg = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]);
383 err = fp_port_set_settings(fp_port, speed, duplex, autoneg);
384 if (err) {
385 return err;
389 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) {
390 if (rocker_tlv_len(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) !=
391 sizeof(macaddr.a)) {
392 return -ROCKER_EINVAL;
394 memcpy(macaddr.a,
395 rocker_tlv_data(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]),
396 sizeof(macaddr.a));
397 fp_port_set_macaddr(fp_port, &macaddr);
400 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]) {
401 mode = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]);
402 if (mode >= ROCKER_WORLD_TYPE_MAX) {
403 return -ROCKER_EINVAL;
405 /* We don't support world change. */
406 if (!fp_port_check_world(fp_port, r->worlds[mode])) {
407 return -ROCKER_EINVAL;
411 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]) {
412 learning =
413 rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]);
414 fp_port_set_learning(fp_port, learning);
417 return ROCKER_OK;
420 static int cmd_consume(Rocker *r, DescInfo *info)
422 char *buf = desc_get_buf(info, false);
423 RockerTlv *tlvs[ROCKER_TLV_CMD_MAX + 1];
424 RockerTlv *info_tlv;
425 World *world;
426 uint16_t cmd;
427 int err;
429 if (!buf) {
430 return -ROCKER_ENXIO;
433 rocker_tlv_parse(tlvs, ROCKER_TLV_CMD_MAX, buf, desc_tlv_size(info));
435 if (!tlvs[ROCKER_TLV_CMD_TYPE] || !tlvs[ROCKER_TLV_CMD_INFO]) {
436 return -ROCKER_EINVAL;
439 cmd = rocker_tlv_get_le16(tlvs[ROCKER_TLV_CMD_TYPE]);
440 info_tlv = tlvs[ROCKER_TLV_CMD_INFO];
442 /* This might be reworked to something like this:
443 * Every world will have an array of command handlers from
444 * ROCKER_TLV_CMD_TYPE_UNSPEC to ROCKER_TLV_CMD_TYPE_MAX. There is
445 * up to each world to implement whatever command it want.
446 * It can reference "generic" commands as cmd_set_port_settings or
447 * cmd_get_port_settings
450 switch (cmd) {
451 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD:
452 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD:
453 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL:
454 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS:
455 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD:
456 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD:
457 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL:
458 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS:
459 world = r->worlds[ROCKER_WORLD_TYPE_OF_DPA];
460 err = world_do_cmd(world, info, buf, cmd, info_tlv);
461 break;
462 case ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS:
463 err = cmd_get_port_settings(r, info, buf, info_tlv);
464 break;
465 case ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS:
466 err = cmd_set_port_settings(r, info_tlv);
467 break;
468 default:
469 err = -ROCKER_EINVAL;
470 break;
473 return err;
476 static void rocker_msix_irq(Rocker *r, unsigned vector)
478 PCIDevice *dev = PCI_DEVICE(r);
480 DPRINTF("MSI-X notify request for vector %d\n", vector);
481 if (vector >= ROCKER_MSIX_VEC_COUNT(r->fp_ports)) {
482 DPRINTF("incorrect vector %d\n", vector);
483 return;
485 msix_notify(dev, vector);
488 int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up)
490 DescRing *ring = r->rings[ROCKER_RING_EVENT];
491 DescInfo *info = desc_ring_fetch_desc(ring);
492 RockerTlv *nest;
493 char *buf;
494 size_t tlv_size;
495 int pos;
496 int err;
498 if (!info) {
499 return -ROCKER_ENOBUFS;
502 tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* event type */
503 rocker_tlv_total_size(0) + /* nest */
504 rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */
505 rocker_tlv_total_size(sizeof(uint8_t)); /* link up */
507 if (tlv_size > desc_buf_size(info)) {
508 err = -ROCKER_EMSGSIZE;
509 goto err_too_big;
512 buf = desc_get_buf(info, false);
513 if (!buf) {
514 err = -ROCKER_ENOMEM;
515 goto err_no_mem;
518 pos = 0;
519 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE,
520 ROCKER_TLV_EVENT_TYPE_LINK_CHANGED);
521 nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO);
522 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_PPORT, pport);
523 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP,
524 link_up ? 1 : 0);
525 rocker_tlv_nest_end(buf, &pos, nest);
527 err = desc_set_buf(info, tlv_size);
529 err_too_big:
530 err_no_mem:
531 if (desc_ring_post_desc(ring, err)) {
532 rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT);
535 return err;
538 int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr,
539 uint16_t vlan_id)
541 DescRing *ring = r->rings[ROCKER_RING_EVENT];
542 DescInfo *info;
543 FpPort *fp_port;
544 uint32_t port;
545 RockerTlv *nest;
546 char *buf;
547 size_t tlv_size;
548 int pos;
549 int err;
551 if (!fp_port_from_pport(pport, &port)) {
552 return -ROCKER_EINVAL;
554 fp_port = r->fp_port[port];
555 if (!fp_port_get_learning(fp_port)) {
556 return ROCKER_OK;
559 info = desc_ring_fetch_desc(ring);
560 if (!info) {
561 return -ROCKER_ENOBUFS;
564 tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* event type */
565 rocker_tlv_total_size(0) + /* nest */
566 rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */
567 rocker_tlv_total_size(ETH_ALEN) + /* mac addr */
568 rocker_tlv_total_size(sizeof(uint16_t)); /* vlan_id */
570 if (tlv_size > desc_buf_size(info)) {
571 err = -ROCKER_EMSGSIZE;
572 goto err_too_big;
575 buf = desc_get_buf(info, false);
576 if (!buf) {
577 err = -ROCKER_ENOMEM;
578 goto err_no_mem;
581 pos = 0;
582 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE,
583 ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN);
584 nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO);
585 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_PPORT, pport);
586 rocker_tlv_put(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_MAC, ETH_ALEN, addr);
587 rocker_tlv_put_u16(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID, vlan_id);
588 rocker_tlv_nest_end(buf, &pos, nest);
590 err = desc_set_buf(info, tlv_size);
592 err_too_big:
593 err_no_mem:
594 if (desc_ring_post_desc(ring, err)) {
595 rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT);
598 return err;
601 static DescRing *rocker_get_rx_ring_by_pport(Rocker *r,
602 uint32_t pport)
604 return r->rings[(pport - 1) * 2 + 3];
607 int rx_produce(World *world, uint32_t pport,
608 const struct iovec *iov, int iovcnt, uint8_t copy_to_cpu)
610 Rocker *r = world_rocker(world);
611 PCIDevice *dev = (PCIDevice *)r;
612 DescRing *ring = rocker_get_rx_ring_by_pport(r, pport);
613 DescInfo *info = desc_ring_fetch_desc(ring);
614 char *data;
615 size_t data_size = iov_size(iov, iovcnt);
616 char *buf;
617 uint16_t rx_flags = 0;
618 uint16_t rx_csum = 0;
619 size_t tlv_size;
620 RockerTlv *tlvs[ROCKER_TLV_RX_MAX + 1];
621 hwaddr frag_addr;
622 uint16_t frag_max_len;
623 int pos;
624 int err;
626 if (!info) {
627 return -ROCKER_ENOBUFS;
630 buf = desc_get_buf(info, false);
631 if (!buf) {
632 err = -ROCKER_ENXIO;
633 goto out;
635 rocker_tlv_parse(tlvs, ROCKER_TLV_RX_MAX, buf, desc_tlv_size(info));
637 if (!tlvs[ROCKER_TLV_RX_FRAG_ADDR] ||
638 !tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]) {
639 err = -ROCKER_EINVAL;
640 goto out;
643 frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_RX_FRAG_ADDR]);
644 frag_max_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]);
646 if (data_size > frag_max_len) {
647 err = -ROCKER_EMSGSIZE;
648 goto out;
651 if (copy_to_cpu) {
652 rx_flags |= ROCKER_RX_FLAGS_FWD_OFFLOAD;
655 /* XXX calc rx flags/csum */
657 tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* flags */
658 rocker_tlv_total_size(sizeof(uint16_t)) + /* scum */
659 rocker_tlv_total_size(sizeof(uint64_t)) + /* frag addr */
660 rocker_tlv_total_size(sizeof(uint16_t)) + /* frag max len */
661 rocker_tlv_total_size(sizeof(uint16_t)); /* frag len */
663 if (tlv_size > desc_buf_size(info)) {
664 err = -ROCKER_EMSGSIZE;
665 goto out;
668 /* TODO:
669 * iov dma write can be optimized in similar way e1000 does it in
670 * e1000_receive_iov. But maybe if would make sense to introduce
671 * generic helper iov_dma_write.
674 data = g_malloc(data_size);
676 iov_to_buf(iov, iovcnt, 0, data, data_size);
677 pci_dma_write(dev, frag_addr, data, data_size);
678 g_free(data);
680 pos = 0;
681 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FLAGS, rx_flags);
682 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_CSUM, rx_csum);
683 rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_RX_FRAG_ADDR, frag_addr);
684 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_MAX_LEN, frag_max_len);
685 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_LEN, data_size);
687 err = desc_set_buf(info, tlv_size);
689 out:
690 if (desc_ring_post_desc(ring, err)) {
691 rocker_msix_irq(r, ROCKER_MSIX_VEC_RX(pport - 1));
694 return err;
697 int rocker_port_eg(Rocker *r, uint32_t pport,
698 const struct iovec *iov, int iovcnt)
700 FpPort *fp_port;
701 uint32_t port;
703 if (!fp_port_from_pport(pport, &port)) {
704 return -ROCKER_EINVAL;
707 fp_port = r->fp_port[port];
709 return fp_port_eg(fp_port, iov, iovcnt);
712 static void rocker_test_dma_ctrl(Rocker *r, uint32_t val)
714 PCIDevice *dev = PCI_DEVICE(r);
715 char *buf;
716 int i;
718 buf = g_malloc(r->test_dma_size);
720 switch (val) {
721 case ROCKER_TEST_DMA_CTRL_CLEAR:
722 memset(buf, 0, r->test_dma_size);
723 break;
724 case ROCKER_TEST_DMA_CTRL_FILL:
725 memset(buf, 0x96, r->test_dma_size);
726 break;
727 case ROCKER_TEST_DMA_CTRL_INVERT:
728 pci_dma_read(dev, r->test_dma_addr, buf, r->test_dma_size);
729 for (i = 0; i < r->test_dma_size; i++) {
730 buf[i] = ~buf[i];
732 break;
733 default:
734 DPRINTF("not test dma control val=0x%08x\n", val);
735 goto err_out;
737 pci_dma_write(dev, r->test_dma_addr, buf, r->test_dma_size);
739 rocker_msix_irq(r, ROCKER_MSIX_VEC_TEST);
741 err_out:
742 g_free(buf);
745 static void rocker_reset(DeviceState *dev);
747 static void rocker_control(Rocker *r, uint32_t val)
749 if (val & ROCKER_CONTROL_RESET) {
750 rocker_reset(DEVICE(r));
754 static int rocker_pci_ring_count(Rocker *r)
756 /* There are:
757 * - command ring
758 * - event ring
759 * - tx and rx ring per each port
761 return 2 + (2 * r->fp_ports);
764 static bool rocker_addr_is_desc_reg(Rocker *r, hwaddr addr)
766 hwaddr start = ROCKER_DMA_DESC_BASE;
767 hwaddr end = start + (ROCKER_DMA_DESC_SIZE * rocker_pci_ring_count(r));
769 return addr >= start && addr < end;
772 static void rocker_port_phys_enable_write(Rocker *r, uint64_t new)
774 int i;
775 bool old_enabled;
776 bool new_enabled;
777 FpPort *fp_port;
779 for (i = 0; i < r->fp_ports; i++) {
780 fp_port = r->fp_port[i];
781 old_enabled = fp_port_enabled(fp_port);
782 new_enabled = (new >> (i + 1)) & 0x1;
783 if (new_enabled == old_enabled) {
784 continue;
786 if (new_enabled) {
787 fp_port_enable(r->fp_port[i]);
788 } else {
789 fp_port_disable(r->fp_port[i]);
794 static void rocker_io_writel(void *opaque, hwaddr addr, uint32_t val)
796 Rocker *r = opaque;
798 if (rocker_addr_is_desc_reg(r, addr)) {
799 unsigned index = ROCKER_RING_INDEX(addr);
800 unsigned offset = addr & ROCKER_DMA_DESC_MASK;
802 switch (offset) {
803 case ROCKER_DMA_DESC_ADDR_OFFSET:
804 r->lower32 = (uint64_t)val;
805 break;
806 case ROCKER_DMA_DESC_ADDR_OFFSET + 4:
807 desc_ring_set_base_addr(r->rings[index],
808 ((uint64_t)val) << 32 | r->lower32);
809 r->lower32 = 0;
810 break;
811 case ROCKER_DMA_DESC_SIZE_OFFSET:
812 desc_ring_set_size(r->rings[index], val);
813 break;
814 case ROCKER_DMA_DESC_HEAD_OFFSET:
815 if (desc_ring_set_head(r->rings[index], val)) {
816 rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index]));
818 break;
819 case ROCKER_DMA_DESC_CTRL_OFFSET:
820 desc_ring_set_ctrl(r->rings[index], val);
821 break;
822 case ROCKER_DMA_DESC_CREDITS_OFFSET:
823 if (desc_ring_ret_credits(r->rings[index], val)) {
824 rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index]));
826 break;
827 default:
828 DPRINTF("not implemented dma reg write(l) addr=0x" TARGET_FMT_plx
829 " val=0x%08x (ring %d, addr=0x%02x)\n",
830 addr, val, index, offset);
831 break;
833 return;
836 switch (addr) {
837 case ROCKER_TEST_REG:
838 r->test_reg = val;
839 break;
840 case ROCKER_TEST_REG64:
841 case ROCKER_TEST_DMA_ADDR:
842 case ROCKER_PORT_PHYS_ENABLE:
843 r->lower32 = (uint64_t)val;
844 break;
845 case ROCKER_TEST_REG64 + 4:
846 r->test_reg64 = ((uint64_t)val) << 32 | r->lower32;
847 r->lower32 = 0;
848 break;
849 case ROCKER_TEST_IRQ:
850 rocker_msix_irq(r, val);
851 break;
852 case ROCKER_TEST_DMA_SIZE:
853 r->test_dma_size = val & 0xFFFF;
854 break;
855 case ROCKER_TEST_DMA_ADDR + 4:
856 r->test_dma_addr = ((uint64_t)val) << 32 | r->lower32;
857 r->lower32 = 0;
858 break;
859 case ROCKER_TEST_DMA_CTRL:
860 rocker_test_dma_ctrl(r, val);
861 break;
862 case ROCKER_CONTROL:
863 rocker_control(r, val);
864 break;
865 case ROCKER_PORT_PHYS_ENABLE + 4:
866 rocker_port_phys_enable_write(r, ((uint64_t)val) << 32 | r->lower32);
867 r->lower32 = 0;
868 break;
869 default:
870 DPRINTF("not implemented write(l) addr=0x" TARGET_FMT_plx
871 " val=0x%08x\n", addr, val);
872 break;
876 static void rocker_io_writeq(void *opaque, hwaddr addr, uint64_t val)
878 Rocker *r = opaque;
880 if (rocker_addr_is_desc_reg(r, addr)) {
881 unsigned index = ROCKER_RING_INDEX(addr);
882 unsigned offset = addr & ROCKER_DMA_DESC_MASK;
884 switch (offset) {
885 case ROCKER_DMA_DESC_ADDR_OFFSET:
886 desc_ring_set_base_addr(r->rings[index], val);
887 break;
888 default:
889 DPRINTF("not implemented dma reg write(q) addr=0x" TARGET_FMT_plx
890 " val=0x" TARGET_FMT_plx " (ring %d, offset=0x%02x)\n",
891 addr, val, index, offset);
892 break;
894 return;
897 switch (addr) {
898 case ROCKER_TEST_REG64:
899 r->test_reg64 = val;
900 break;
901 case ROCKER_TEST_DMA_ADDR:
902 r->test_dma_addr = val;
903 break;
904 case ROCKER_PORT_PHYS_ENABLE:
905 rocker_port_phys_enable_write(r, val);
906 break;
907 default:
908 DPRINTF("not implemented write(q) addr=0x" TARGET_FMT_plx
909 " val=0x" TARGET_FMT_plx "\n", addr, val);
910 break;
914 #ifdef DEBUG_ROCKER
915 #define regname(reg) case (reg): return #reg
916 static const char *rocker_reg_name(void *opaque, hwaddr addr)
918 Rocker *r = opaque;
920 if (rocker_addr_is_desc_reg(r, addr)) {
921 unsigned index = ROCKER_RING_INDEX(addr);
922 unsigned offset = addr & ROCKER_DMA_DESC_MASK;
923 static char buf[100];
924 char ring_name[10];
926 switch (index) {
927 case 0:
928 sprintf(ring_name, "cmd");
929 break;
930 case 1:
931 sprintf(ring_name, "event");
932 break;
933 default:
934 sprintf(ring_name, "%s-%d", index % 2 ? "rx" : "tx",
935 (index - 2) / 2);
938 switch (offset) {
939 case ROCKER_DMA_DESC_ADDR_OFFSET:
940 sprintf(buf, "Ring[%s] ADDR", ring_name);
941 return buf;
942 case ROCKER_DMA_DESC_ADDR_OFFSET+4:
943 sprintf(buf, "Ring[%s] ADDR+4", ring_name);
944 return buf;
945 case ROCKER_DMA_DESC_SIZE_OFFSET:
946 sprintf(buf, "Ring[%s] SIZE", ring_name);
947 return buf;
948 case ROCKER_DMA_DESC_HEAD_OFFSET:
949 sprintf(buf, "Ring[%s] HEAD", ring_name);
950 return buf;
951 case ROCKER_DMA_DESC_TAIL_OFFSET:
952 sprintf(buf, "Ring[%s] TAIL", ring_name);
953 return buf;
954 case ROCKER_DMA_DESC_CTRL_OFFSET:
955 sprintf(buf, "Ring[%s] CTRL", ring_name);
956 return buf;
957 case ROCKER_DMA_DESC_CREDITS_OFFSET:
958 sprintf(buf, "Ring[%s] CREDITS", ring_name);
959 return buf;
960 default:
961 sprintf(buf, "Ring[%s] ???", ring_name);
962 return buf;
964 } else {
965 switch (addr) {
966 regname(ROCKER_BOGUS_REG0);
967 regname(ROCKER_BOGUS_REG1);
968 regname(ROCKER_BOGUS_REG2);
969 regname(ROCKER_BOGUS_REG3);
970 regname(ROCKER_TEST_REG);
971 regname(ROCKER_TEST_REG64);
972 regname(ROCKER_TEST_REG64+4);
973 regname(ROCKER_TEST_IRQ);
974 regname(ROCKER_TEST_DMA_ADDR);
975 regname(ROCKER_TEST_DMA_ADDR+4);
976 regname(ROCKER_TEST_DMA_SIZE);
977 regname(ROCKER_TEST_DMA_CTRL);
978 regname(ROCKER_CONTROL);
979 regname(ROCKER_PORT_PHYS_COUNT);
980 regname(ROCKER_PORT_PHYS_LINK_STATUS);
981 regname(ROCKER_PORT_PHYS_LINK_STATUS+4);
982 regname(ROCKER_PORT_PHYS_ENABLE);
983 regname(ROCKER_PORT_PHYS_ENABLE+4);
984 regname(ROCKER_SWITCH_ID);
985 regname(ROCKER_SWITCH_ID+4);
988 return "???";
990 #else
991 static const char *rocker_reg_name(void *opaque, hwaddr addr)
993 return NULL;
995 #endif
997 static void rocker_mmio_write(void *opaque, hwaddr addr, uint64_t val,
998 unsigned size)
1000 DPRINTF("Write %s addr " TARGET_FMT_plx
1001 ", size %u, val " TARGET_FMT_plx "\n",
1002 rocker_reg_name(opaque, addr), addr, size, val);
1004 switch (size) {
1005 case 4:
1006 rocker_io_writel(opaque, addr, val);
1007 break;
1008 case 8:
1009 rocker_io_writeq(opaque, addr, val);
1010 break;
1014 static uint64_t rocker_port_phys_link_status(Rocker *r)
1016 int i;
1017 uint64_t status = 0;
1019 for (i = 0; i < r->fp_ports; i++) {
1020 FpPort *port = r->fp_port[i];
1022 if (fp_port_get_link_up(port)) {
1023 status |= 1 << (i + 1);
1026 return status;
1029 static uint64_t rocker_port_phys_enable_read(Rocker *r)
1031 int i;
1032 uint64_t ret = 0;
1034 for (i = 0; i < r->fp_ports; i++) {
1035 FpPort *port = r->fp_port[i];
1037 if (fp_port_enabled(port)) {
1038 ret |= 1 << (i + 1);
1041 return ret;
1044 static uint32_t rocker_io_readl(void *opaque, hwaddr addr)
1046 Rocker *r = opaque;
1047 uint32_t ret;
1049 if (rocker_addr_is_desc_reg(r, addr)) {
1050 unsigned index = ROCKER_RING_INDEX(addr);
1051 unsigned offset = addr & ROCKER_DMA_DESC_MASK;
1053 switch (offset) {
1054 case ROCKER_DMA_DESC_ADDR_OFFSET:
1055 ret = (uint32_t)desc_ring_get_base_addr(r->rings[index]);
1056 break;
1057 case ROCKER_DMA_DESC_ADDR_OFFSET + 4:
1058 ret = (uint32_t)(desc_ring_get_base_addr(r->rings[index]) >> 32);
1059 break;
1060 case ROCKER_DMA_DESC_SIZE_OFFSET:
1061 ret = desc_ring_get_size(r->rings[index]);
1062 break;
1063 case ROCKER_DMA_DESC_HEAD_OFFSET:
1064 ret = desc_ring_get_head(r->rings[index]);
1065 break;
1066 case ROCKER_DMA_DESC_TAIL_OFFSET:
1067 ret = desc_ring_get_tail(r->rings[index]);
1068 break;
1069 case ROCKER_DMA_DESC_CREDITS_OFFSET:
1070 ret = desc_ring_get_credits(r->rings[index]);
1071 break;
1072 default:
1073 DPRINTF("not implemented dma reg read(l) addr=0x" TARGET_FMT_plx
1074 " (ring %d, addr=0x%02x)\n", addr, index, offset);
1075 ret = 0;
1076 break;
1078 return ret;
1081 switch (addr) {
1082 case ROCKER_BOGUS_REG0:
1083 case ROCKER_BOGUS_REG1:
1084 case ROCKER_BOGUS_REG2:
1085 case ROCKER_BOGUS_REG3:
1086 ret = 0xDEADBABE;
1087 break;
1088 case ROCKER_TEST_REG:
1089 ret = r->test_reg * 2;
1090 break;
1091 case ROCKER_TEST_REG64:
1092 ret = (uint32_t)(r->test_reg64 * 2);
1093 break;
1094 case ROCKER_TEST_REG64 + 4:
1095 ret = (uint32_t)((r->test_reg64 * 2) >> 32);
1096 break;
1097 case ROCKER_TEST_DMA_SIZE:
1098 ret = r->test_dma_size;
1099 break;
1100 case ROCKER_TEST_DMA_ADDR:
1101 ret = (uint32_t)r->test_dma_addr;
1102 break;
1103 case ROCKER_TEST_DMA_ADDR + 4:
1104 ret = (uint32_t)(r->test_dma_addr >> 32);
1105 break;
1106 case ROCKER_PORT_PHYS_COUNT:
1107 ret = r->fp_ports;
1108 break;
1109 case ROCKER_PORT_PHYS_LINK_STATUS:
1110 ret = (uint32_t)rocker_port_phys_link_status(r);
1111 break;
1112 case ROCKER_PORT_PHYS_LINK_STATUS + 4:
1113 ret = (uint32_t)(rocker_port_phys_link_status(r) >> 32);
1114 break;
1115 case ROCKER_PORT_PHYS_ENABLE:
1116 ret = (uint32_t)rocker_port_phys_enable_read(r);
1117 break;
1118 case ROCKER_PORT_PHYS_ENABLE + 4:
1119 ret = (uint32_t)(rocker_port_phys_enable_read(r) >> 32);
1120 break;
1121 case ROCKER_SWITCH_ID:
1122 ret = (uint32_t)r->switch_id;
1123 break;
1124 case ROCKER_SWITCH_ID + 4:
1125 ret = (uint32_t)(r->switch_id >> 32);
1126 break;
1127 default:
1128 DPRINTF("not implemented read(l) addr=0x" TARGET_FMT_plx "\n", addr);
1129 ret = 0;
1130 break;
1132 return ret;
1135 static uint64_t rocker_io_readq(void *opaque, hwaddr addr)
1137 Rocker *r = opaque;
1138 uint64_t ret;
1140 if (rocker_addr_is_desc_reg(r, addr)) {
1141 unsigned index = ROCKER_RING_INDEX(addr);
1142 unsigned offset = addr & ROCKER_DMA_DESC_MASK;
1144 switch (addr & ROCKER_DMA_DESC_MASK) {
1145 case ROCKER_DMA_DESC_ADDR_OFFSET:
1146 ret = desc_ring_get_base_addr(r->rings[index]);
1147 break;
1148 default:
1149 DPRINTF("not implemented dma reg read(q) addr=0x" TARGET_FMT_plx
1150 " (ring %d, addr=0x%02x)\n", addr, index, offset);
1151 ret = 0;
1152 break;
1154 return ret;
1157 switch (addr) {
1158 case ROCKER_BOGUS_REG0:
1159 case ROCKER_BOGUS_REG2:
1160 ret = 0xDEADBABEDEADBABEULL;
1161 break;
1162 case ROCKER_TEST_REG64:
1163 ret = r->test_reg64 * 2;
1164 break;
1165 case ROCKER_TEST_DMA_ADDR:
1166 ret = r->test_dma_addr;
1167 break;
1168 case ROCKER_PORT_PHYS_LINK_STATUS:
1169 ret = rocker_port_phys_link_status(r);
1170 break;
1171 case ROCKER_PORT_PHYS_ENABLE:
1172 ret = rocker_port_phys_enable_read(r);
1173 break;
1174 case ROCKER_SWITCH_ID:
1175 ret = r->switch_id;
1176 break;
1177 default:
1178 DPRINTF("not implemented read(q) addr=0x" TARGET_FMT_plx "\n", addr);
1179 ret = 0;
1180 break;
1182 return ret;
1185 static uint64_t rocker_mmio_read(void *opaque, hwaddr addr, unsigned size)
1187 DPRINTF("Read %s addr " TARGET_FMT_plx ", size %u\n",
1188 rocker_reg_name(opaque, addr), addr, size);
1190 switch (size) {
1191 case 4:
1192 return rocker_io_readl(opaque, addr);
1193 case 8:
1194 return rocker_io_readq(opaque, addr);
1197 return -1;
1200 static const MemoryRegionOps rocker_mmio_ops = {
1201 .read = rocker_mmio_read,
1202 .write = rocker_mmio_write,
1203 .endianness = DEVICE_LITTLE_ENDIAN,
1204 .valid = {
1205 .min_access_size = 4,
1206 .max_access_size = 8,
1208 .impl = {
1209 .min_access_size = 4,
1210 .max_access_size = 8,
1214 static void rocker_msix_vectors_unuse(Rocker *r,
1215 unsigned int num_vectors)
1217 PCIDevice *dev = PCI_DEVICE(r);
1218 int i;
1220 for (i = 0; i < num_vectors; i++) {
1221 msix_vector_unuse(dev, i);
1225 static int rocker_msix_vectors_use(Rocker *r,
1226 unsigned int num_vectors)
1228 PCIDevice *dev = PCI_DEVICE(r);
1229 int err;
1230 int i;
1232 for (i = 0; i < num_vectors; i++) {
1233 err = msix_vector_use(dev, i);
1234 if (err) {
1235 goto rollback;
1238 return 0;
1240 rollback:
1241 rocker_msix_vectors_unuse(r, i);
1242 return err;
1245 static int rocker_msix_init(Rocker *r, Error **errp)
1247 PCIDevice *dev = PCI_DEVICE(r);
1248 int err;
1250 err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports),
1251 &r->msix_bar,
1252 ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET,
1253 &r->msix_bar,
1254 ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET,
1255 0, errp);
1256 if (err) {
1257 return err;
1260 err = rocker_msix_vectors_use(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
1261 if (err) {
1262 goto err_msix_vectors_use;
1265 return 0;
1267 err_msix_vectors_use:
1268 msix_uninit(dev, &r->msix_bar, &r->msix_bar);
1269 return err;
1272 static void rocker_msix_uninit(Rocker *r)
1274 PCIDevice *dev = PCI_DEVICE(r);
1276 msix_uninit(dev, &r->msix_bar, &r->msix_bar);
1277 rocker_msix_vectors_unuse(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
1280 static World *rocker_world_type_by_name(Rocker *r, const char *name)
1282 int i;
1284 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1285 if (strcmp(name, world_name(r->worlds[i])) == 0) {
1286 return r->worlds[i];
1289 return NULL;
1292 static void pci_rocker_realize(PCIDevice *dev, Error **errp)
1294 Rocker *r = ROCKER(dev);
1295 const MACAddr zero = { .a = { 0, 0, 0, 0, 0, 0 } };
1296 const MACAddr dflt = { .a = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x01 } };
1297 static int sw_index;
1298 int i, err = 0;
1300 /* allocate worlds */
1302 r->worlds[ROCKER_WORLD_TYPE_OF_DPA] = of_dpa_world_alloc(r);
1304 if (!r->world_name) {
1305 r->world_name = g_strdup(world_name(r->worlds[ROCKER_WORLD_TYPE_OF_DPA]));
1308 r->world_dflt = rocker_world_type_by_name(r, r->world_name);
1309 if (!r->world_dflt) {
1310 error_setg(errp,
1311 "invalid argument requested world %s does not exist",
1312 r->world_name);
1313 goto err_world_type_by_name;
1316 /* set up memory-mapped region at BAR0 */
1318 memory_region_init_io(&r->mmio, OBJECT(r), &rocker_mmio_ops, r,
1319 "rocker-mmio", ROCKER_PCI_BAR0_SIZE);
1320 pci_register_bar(dev, ROCKER_PCI_BAR0_IDX,
1321 PCI_BASE_ADDRESS_SPACE_MEMORY, &r->mmio);
1323 /* set up memory-mapped region for MSI-X */
1325 memory_region_init(&r->msix_bar, OBJECT(r), "rocker-msix-bar",
1326 ROCKER_PCI_MSIX_BAR_SIZE);
1327 pci_register_bar(dev, ROCKER_PCI_MSIX_BAR_IDX,
1328 PCI_BASE_ADDRESS_SPACE_MEMORY, &r->msix_bar);
1330 /* MSI-X init */
1332 err = rocker_msix_init(r, errp);
1333 if (err) {
1334 goto err_msix_init;
1337 /* validate switch properties */
1339 if (!r->name) {
1340 r->name = g_strdup(TYPE_ROCKER);
1343 if (rocker_find(r->name)) {
1344 error_setg(errp, "%s already exists", r->name);
1345 goto err_duplicate;
1348 /* Rocker name is passed in port name requests to OS with the intention
1349 * that the name is used in interface names. Limit the length of the
1350 * rocker name to avoid naming problems in the OS. Also, adding the
1351 * port number as p# and unganged breakout b#, where # is at most 2
1352 * digits, so leave room for it too (-1 for string terminator, -3 for
1353 * p# and -3 for b#)
1355 #define ROCKER_IFNAMSIZ 16
1356 #define MAX_ROCKER_NAME_LEN (ROCKER_IFNAMSIZ - 1 - 3 - 3)
1357 if (strlen(r->name) > MAX_ROCKER_NAME_LEN) {
1358 error_setg(errp,
1359 "name too long; please shorten to at most %d chars",
1360 MAX_ROCKER_NAME_LEN);
1361 goto err_name_too_long;
1364 if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) {
1365 memcpy(&r->fp_start_macaddr, &dflt, sizeof(dflt));
1366 r->fp_start_macaddr.a[4] += (sw_index++);
1369 if (!r->switch_id) {
1370 memcpy(&r->switch_id, &r->fp_start_macaddr,
1371 sizeof(r->fp_start_macaddr));
1374 if (r->fp_ports > ROCKER_FP_PORTS_MAX) {
1375 r->fp_ports = ROCKER_FP_PORTS_MAX;
1378 r->rings = g_new(DescRing *, rocker_pci_ring_count(r));
1380 /* Rings are ordered like this:
1381 * - command ring
1382 * - event ring
1383 * - port0 tx ring
1384 * - port0 rx ring
1385 * - port1 tx ring
1386 * - port1 rx ring
1387 * .....
1390 for (i = 0; i < rocker_pci_ring_count(r); i++) {
1391 DescRing *ring = desc_ring_alloc(r, i);
1393 if (i == ROCKER_RING_CMD) {
1394 desc_ring_set_consume(ring, cmd_consume, ROCKER_MSIX_VEC_CMD);
1395 } else if (i == ROCKER_RING_EVENT) {
1396 desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_EVENT);
1397 } else if (i % 2 == 0) {
1398 desc_ring_set_consume(ring, tx_consume,
1399 ROCKER_MSIX_VEC_TX((i - 2) / 2));
1400 } else if (i % 2 == 1) {
1401 desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_RX((i - 3) / 2));
1404 r->rings[i] = ring;
1407 for (i = 0; i < r->fp_ports; i++) {
1408 FpPort *port =
1409 fp_port_alloc(r, r->name, &r->fp_start_macaddr,
1410 i, &r->fp_ports_peers[i]);
1412 r->fp_port[i] = port;
1413 fp_port_set_world(port, r->world_dflt);
1416 QLIST_INSERT_HEAD(&rockers, r, next);
1418 return;
1420 err_name_too_long:
1421 err_duplicate:
1422 rocker_msix_uninit(r);
1423 err_msix_init:
1424 object_unparent(OBJECT(&r->msix_bar));
1425 object_unparent(OBJECT(&r->mmio));
1426 err_world_type_by_name:
1427 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1428 if (r->worlds[i]) {
1429 world_free(r->worlds[i]);
1434 static void pci_rocker_uninit(PCIDevice *dev)
1436 Rocker *r = ROCKER(dev);
1437 int i;
1439 QLIST_REMOVE(r, next);
1441 for (i = 0; i < r->fp_ports; i++) {
1442 FpPort *port = r->fp_port[i];
1444 fp_port_free(port);
1445 r->fp_port[i] = NULL;
1448 for (i = 0; i < rocker_pci_ring_count(r); i++) {
1449 if (r->rings[i]) {
1450 desc_ring_free(r->rings[i]);
1453 g_free(r->rings);
1455 rocker_msix_uninit(r);
1456 object_unparent(OBJECT(&r->msix_bar));
1457 object_unparent(OBJECT(&r->mmio));
1459 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1460 if (r->worlds[i]) {
1461 world_free(r->worlds[i]);
1464 g_free(r->fp_ports_peers);
1467 static void rocker_reset(DeviceState *dev)
1469 Rocker *r = ROCKER(dev);
1470 int i;
1472 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1473 if (r->worlds[i]) {
1474 world_reset(r->worlds[i]);
1477 for (i = 0; i < r->fp_ports; i++) {
1478 fp_port_reset(r->fp_port[i]);
1479 fp_port_set_world(r->fp_port[i], r->world_dflt);
1482 r->test_reg = 0;
1483 r->test_reg64 = 0;
1484 r->test_dma_addr = 0;
1485 r->test_dma_size = 0;
1487 for (i = 0; i < rocker_pci_ring_count(r); i++) {
1488 desc_ring_reset(r->rings[i]);
1491 DPRINTF("Reset done\n");
1494 static Property rocker_properties[] = {
1495 DEFINE_PROP_STRING("name", Rocker, name),
1496 DEFINE_PROP_STRING("world", Rocker, world_name),
1497 DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker,
1498 fp_start_macaddr),
1499 DEFINE_PROP_UINT64("switch_id", Rocker,
1500 switch_id, 0),
1501 DEFINE_PROP_ARRAY("ports", Rocker, fp_ports,
1502 fp_ports_peers, qdev_prop_netdev, NICPeers),
1503 DEFINE_PROP_END_OF_LIST(),
1506 static const VMStateDescription rocker_vmsd = {
1507 .name = TYPE_ROCKER,
1508 .unmigratable = 1,
1511 static void rocker_class_init(ObjectClass *klass, void *data)
1513 DeviceClass *dc = DEVICE_CLASS(klass);
1514 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1516 k->realize = pci_rocker_realize;
1517 k->exit = pci_rocker_uninit;
1518 k->vendor_id = PCI_VENDOR_ID_REDHAT;
1519 k->device_id = PCI_DEVICE_ID_REDHAT_ROCKER;
1520 k->revision = ROCKER_PCI_REVISION;
1521 k->class_id = PCI_CLASS_NETWORK_OTHER;
1522 set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1523 dc->desc = "Rocker Switch";
1524 dc->reset = rocker_reset;
1525 device_class_set_props(dc, rocker_properties);
1526 dc->vmsd = &rocker_vmsd;
1529 static const TypeInfo rocker_info = {
1530 .name = TYPE_ROCKER,
1531 .parent = TYPE_PCI_DEVICE,
1532 .instance_size = sizeof(Rocker),
1533 .class_init = rocker_class_init,
1534 .interfaces = (InterfaceInfo[]) {
1535 { INTERFACE_CONVENTIONAL_PCI_DEVICE },
1536 { },
1540 static void rocker_register_types(void)
1542 type_register_static(&rocker_info);
1545 type_init(rocker_register_types)