hw/timer/cmsdk-apb-timer: Convert to use Clock input
[qemu/ar7.git] / hw / net / rocker / rocker.c
blob31f2340fb910963bbfb77cf7e41980b36a28b67c
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 "hw/qdev-properties-system.h"
22 #include "migration/vmstate.h"
23 #include "hw/pci/msix.h"
24 #include "net/net.h"
25 #include "net/eth.h"
26 #include "qapi/error.h"
27 #include "qapi/qapi-commands-rocker.h"
28 #include "qemu/iov.h"
29 #include "qemu/module.h"
30 #include "qemu/bitops.h"
31 #include "qemu/log.h"
33 #include "rocker.h"
34 #include "rocker_hw.h"
35 #include "rocker_fp.h"
36 #include "rocker_desc.h"
37 #include "rocker_tlv.h"
38 #include "rocker_world.h"
39 #include "rocker_of_dpa.h"
41 struct rocker {
42 /* private */
43 PCIDevice parent_obj;
44 /* public */
46 MemoryRegion mmio;
47 MemoryRegion msix_bar;
49 /* switch configuration */
50 char *name; /* switch name */
51 char *world_name; /* world name */
52 uint32_t fp_ports; /* front-panel port count */
53 NICPeers *fp_ports_peers;
54 MACAddr fp_start_macaddr; /* front-panel port 0 mac addr */
55 uint64_t switch_id; /* switch id */
57 /* front-panel ports */
58 FpPort *fp_port[ROCKER_FP_PORTS_MAX];
60 /* register backings */
61 uint32_t test_reg;
62 uint64_t test_reg64;
63 dma_addr_t test_dma_addr;
64 uint32_t test_dma_size;
65 uint64_t lower32; /* lower 32-bit val in 2-part 64-bit access */
67 /* desc rings */
68 DescRing **rings;
70 /* switch worlds */
71 World *worlds[ROCKER_WORLD_TYPE_MAX];
72 World *world_dflt;
74 QLIST_ENTRY(rocker) next;
77 static QLIST_HEAD(, rocker) rockers;
79 Rocker *rocker_find(const char *name)
81 Rocker *r;
83 QLIST_FOREACH(r, &rockers, next)
84 if (strcmp(r->name, name) == 0) {
85 return r;
88 return NULL;
91 World *rocker_get_world(Rocker *r, enum rocker_world_type type)
93 if (type < ROCKER_WORLD_TYPE_MAX) {
94 return r->worlds[type];
96 return NULL;
99 RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
101 RockerSwitch *rocker;
102 Rocker *r;
104 r = rocker_find(name);
105 if (!r) {
106 error_setg(errp, "rocker %s not found", name);
107 return NULL;
110 rocker = g_new0(RockerSwitch, 1);
111 rocker->name = g_strdup(r->name);
112 rocker->id = r->switch_id;
113 rocker->ports = r->fp_ports;
115 return rocker;
118 RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
120 RockerPortList *list = NULL;
121 Rocker *r;
122 int i;
124 r = rocker_find(name);
125 if (!r) {
126 error_setg(errp, "rocker %s not found", name);
127 return NULL;
130 for (i = r->fp_ports - 1; i >= 0; i--) {
131 QAPI_LIST_PREPEND(list, fp_port_get_info(r->fp_port[i]));
134 return list;
137 uint32_t rocker_fp_ports(Rocker *r)
139 return r->fp_ports;
142 static uint32_t rocker_get_pport_by_tx_ring(Rocker *r,
143 DescRing *ring)
145 return (desc_ring_index(ring) - 2) / 2 + 1;
148 static int tx_consume(Rocker *r, DescInfo *info)
150 PCIDevice *dev = PCI_DEVICE(r);
151 char *buf = desc_get_buf(info, true);
152 RockerTlv *tlv_frag;
153 RockerTlv *tlvs[ROCKER_TLV_TX_MAX + 1];
154 struct iovec iov[ROCKER_TX_FRAGS_MAX] = { { 0, }, };
155 uint32_t pport;
156 uint32_t port;
157 uint16_t tx_offload = ROCKER_TX_OFFLOAD_NONE;
158 uint16_t tx_l3_csum_off = 0;
159 uint16_t tx_tso_mss = 0;
160 uint16_t tx_tso_hdr_len = 0;
161 int iovcnt = 0;
162 int err = ROCKER_OK;
163 int rem;
164 int i;
166 if (!buf) {
167 return -ROCKER_ENXIO;
170 rocker_tlv_parse(tlvs, ROCKER_TLV_TX_MAX, buf, desc_tlv_size(info));
172 if (!tlvs[ROCKER_TLV_TX_FRAGS]) {
173 return -ROCKER_EINVAL;
176 pport = rocker_get_pport_by_tx_ring(r, desc_get_ring(info));
177 if (!fp_port_from_pport(pport, &port)) {
178 return -ROCKER_EINVAL;
181 if (tlvs[ROCKER_TLV_TX_OFFLOAD]) {
182 tx_offload = rocker_tlv_get_u8(tlvs[ROCKER_TLV_TX_OFFLOAD]);
185 switch (tx_offload) {
186 case ROCKER_TX_OFFLOAD_L3_CSUM:
187 if (!tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
188 return -ROCKER_EINVAL;
190 break;
191 case ROCKER_TX_OFFLOAD_TSO:
192 if (!tlvs[ROCKER_TLV_TX_TSO_MSS] ||
193 !tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) {
194 return -ROCKER_EINVAL;
196 break;
199 if (tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
200 tx_l3_csum_off = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]);
201 qemu_log_mask(LOG_UNIMP, "rocker %s: L3 not implemented"
202 " (cksum off: %u)\n",
203 __func__, tx_l3_csum_off);
206 if (tlvs[ROCKER_TLV_TX_TSO_MSS]) {
207 tx_tso_mss = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_MSS]);
208 qemu_log_mask(LOG_UNIMP, "rocker %s: TSO not implemented (MSS: %u)\n",
209 __func__, tx_tso_mss);
212 if (tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]) {
213 tx_tso_hdr_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_TSO_HDR_LEN]);
214 qemu_log_mask(LOG_UNIMP, "rocker %s: TSO not implemented"
215 " (hdr length: %u)\n",
216 __func__, tx_tso_hdr_len);
219 rocker_tlv_for_each_nested(tlv_frag, tlvs[ROCKER_TLV_TX_FRAGS], rem) {
220 hwaddr frag_addr;
221 uint16_t frag_len;
223 if (rocker_tlv_type(tlv_frag) != ROCKER_TLV_TX_FRAG) {
224 err = -ROCKER_EINVAL;
225 goto err_bad_attr;
228 rocker_tlv_parse_nested(tlvs, ROCKER_TLV_TX_FRAG_ATTR_MAX, tlv_frag);
230 if (!tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR] ||
231 !tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]) {
232 err = -ROCKER_EINVAL;
233 goto err_bad_attr;
236 frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_TX_FRAG_ATTR_ADDR]);
237 frag_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_TX_FRAG_ATTR_LEN]);
239 if (iovcnt >= ROCKER_TX_FRAGS_MAX) {
240 goto err_too_many_frags;
242 iov[iovcnt].iov_len = frag_len;
243 iov[iovcnt].iov_base = g_malloc(frag_len);
245 pci_dma_read(dev, frag_addr, iov[iovcnt].iov_base,
246 iov[iovcnt].iov_len);
248 iovcnt++;
251 err = fp_port_eg(r->fp_port[port], iov, iovcnt);
253 err_too_many_frags:
254 err_bad_attr:
255 for (i = 0; i < ROCKER_TX_FRAGS_MAX; i++) {
256 g_free(iov[i].iov_base);
259 return err;
262 static int cmd_get_port_settings(Rocker *r,
263 DescInfo *info, char *buf,
264 RockerTlv *cmd_info_tlv)
266 RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
267 RockerTlv *nest;
268 FpPort *fp_port;
269 uint32_t pport;
270 uint32_t port;
271 uint32_t speed;
272 uint8_t duplex;
273 uint8_t autoneg;
274 uint8_t learning;
275 char *phys_name;
276 MACAddr macaddr;
277 enum rocker_world_type mode;
278 size_t tlv_size;
279 int pos;
280 int err;
282 rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
283 cmd_info_tlv);
285 if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) {
286 return -ROCKER_EINVAL;
289 pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]);
290 if (!fp_port_from_pport(pport, &port)) {
291 return -ROCKER_EINVAL;
293 fp_port = r->fp_port[port];
295 err = fp_port_get_settings(fp_port, &speed, &duplex, &autoneg);
296 if (err) {
297 return err;
300 fp_port_get_macaddr(fp_port, &macaddr);
301 mode = world_type(fp_port_get_world(fp_port));
302 learning = fp_port_get_learning(fp_port);
303 phys_name = fp_port_get_name(fp_port);
305 tlv_size = rocker_tlv_total_size(0) + /* nest */
306 rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */
307 rocker_tlv_total_size(sizeof(uint32_t)) + /* speed */
308 rocker_tlv_total_size(sizeof(uint8_t)) + /* duplex */
309 rocker_tlv_total_size(sizeof(uint8_t)) + /* autoneg */
310 rocker_tlv_total_size(sizeof(macaddr.a)) + /* macaddr */
311 rocker_tlv_total_size(sizeof(uint8_t)) + /* mode */
312 rocker_tlv_total_size(sizeof(uint8_t)) + /* learning */
313 rocker_tlv_total_size(strlen(phys_name));
315 if (tlv_size > desc_buf_size(info)) {
316 return -ROCKER_EMSGSIZE;
319 pos = 0;
320 nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_CMD_INFO);
321 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT, pport);
322 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_SPEED, speed);
323 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX, duplex);
324 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG, autoneg);
325 rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR,
326 sizeof(macaddr.a), macaddr.a);
327 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_MODE, mode);
328 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING,
329 learning);
330 rocker_tlv_put(buf, &pos, ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME,
331 strlen(phys_name), phys_name);
332 rocker_tlv_nest_end(buf, &pos, nest);
334 return desc_set_buf(info, tlv_size);
337 static int cmd_set_port_settings(Rocker *r,
338 RockerTlv *cmd_info_tlv)
340 RockerTlv *tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MAX + 1];
341 FpPort *fp_port;
342 uint32_t pport;
343 uint32_t port;
344 uint32_t speed;
345 uint8_t duplex;
346 uint8_t autoneg;
347 uint8_t learning;
348 MACAddr macaddr;
349 enum rocker_world_type mode;
350 int err;
352 rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
353 cmd_info_tlv);
355 if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) {
356 return -ROCKER_EINVAL;
359 pport = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]);
360 if (!fp_port_from_pport(pport, &port)) {
361 return -ROCKER_EINVAL;
363 fp_port = r->fp_port[port];
365 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED] &&
366 tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX] &&
367 tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]) {
369 speed = rocker_tlv_get_le32(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_SPEED]);
370 duplex = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_DUPLEX]);
371 autoneg = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_AUTONEG]);
373 err = fp_port_set_settings(fp_port, speed, duplex, autoneg);
374 if (err) {
375 return err;
379 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) {
380 if (rocker_tlv_len(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]) !=
381 sizeof(macaddr.a)) {
382 return -ROCKER_EINVAL;
384 memcpy(macaddr.a,
385 rocker_tlv_data(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR]),
386 sizeof(macaddr.a));
387 fp_port_set_macaddr(fp_port, &macaddr);
390 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]) {
391 mode = rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_MODE]);
392 if (mode >= ROCKER_WORLD_TYPE_MAX) {
393 return -ROCKER_EINVAL;
395 /* We don't support world change. */
396 if (!fp_port_check_world(fp_port, r->worlds[mode])) {
397 return -ROCKER_EINVAL;
401 if (tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]) {
402 learning =
403 rocker_tlv_get_u8(tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING]);
404 fp_port_set_learning(fp_port, learning);
407 return ROCKER_OK;
410 static int cmd_consume(Rocker *r, DescInfo *info)
412 char *buf = desc_get_buf(info, false);
413 RockerTlv *tlvs[ROCKER_TLV_CMD_MAX + 1];
414 RockerTlv *info_tlv;
415 World *world;
416 uint16_t cmd;
417 int err;
419 if (!buf) {
420 return -ROCKER_ENXIO;
423 rocker_tlv_parse(tlvs, ROCKER_TLV_CMD_MAX, buf, desc_tlv_size(info));
425 if (!tlvs[ROCKER_TLV_CMD_TYPE] || !tlvs[ROCKER_TLV_CMD_INFO]) {
426 return -ROCKER_EINVAL;
429 cmd = rocker_tlv_get_le16(tlvs[ROCKER_TLV_CMD_TYPE]);
430 info_tlv = tlvs[ROCKER_TLV_CMD_INFO];
432 /* This might be reworked to something like this:
433 * Every world will have an array of command handlers from
434 * ROCKER_TLV_CMD_TYPE_UNSPEC to ROCKER_TLV_CMD_TYPE_MAX. There is
435 * up to each world to implement whatever command it want.
436 * It can reference "generic" commands as cmd_set_port_settings or
437 * cmd_get_port_settings
440 switch (cmd) {
441 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD:
442 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD:
443 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL:
444 case ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_GET_STATS:
445 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD:
446 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD:
447 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL:
448 case ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS:
449 world = r->worlds[ROCKER_WORLD_TYPE_OF_DPA];
450 err = world_do_cmd(world, info, buf, cmd, info_tlv);
451 break;
452 case ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS:
453 err = cmd_get_port_settings(r, info, buf, info_tlv);
454 break;
455 case ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS:
456 err = cmd_set_port_settings(r, info_tlv);
457 break;
458 default:
459 err = -ROCKER_EINVAL;
460 break;
463 return err;
466 static void rocker_msix_irq(Rocker *r, unsigned vector)
468 PCIDevice *dev = PCI_DEVICE(r);
470 DPRINTF("MSI-X notify request for vector %d\n", vector);
471 if (vector >= ROCKER_MSIX_VEC_COUNT(r->fp_ports)) {
472 DPRINTF("incorrect vector %d\n", vector);
473 return;
475 msix_notify(dev, vector);
478 int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up)
480 DescRing *ring = r->rings[ROCKER_RING_EVENT];
481 DescInfo *info = desc_ring_fetch_desc(ring);
482 RockerTlv *nest;
483 char *buf;
484 size_t tlv_size;
485 int pos;
486 int err;
488 if (!info) {
489 return -ROCKER_ENOBUFS;
492 tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* event type */
493 rocker_tlv_total_size(0) + /* nest */
494 rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */
495 rocker_tlv_total_size(sizeof(uint8_t)); /* link up */
497 if (tlv_size > desc_buf_size(info)) {
498 err = -ROCKER_EMSGSIZE;
499 goto err_too_big;
502 buf = desc_get_buf(info, false);
503 if (!buf) {
504 err = -ROCKER_ENOMEM;
505 goto err_no_mem;
508 pos = 0;
509 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE,
510 ROCKER_TLV_EVENT_TYPE_LINK_CHANGED);
511 nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO);
512 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_PPORT, pport);
513 rocker_tlv_put_u8(buf, &pos, ROCKER_TLV_EVENT_LINK_CHANGED_LINKUP,
514 link_up ? 1 : 0);
515 rocker_tlv_nest_end(buf, &pos, nest);
517 err = desc_set_buf(info, tlv_size);
519 err_too_big:
520 err_no_mem:
521 if (desc_ring_post_desc(ring, err)) {
522 rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT);
525 return err;
528 int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr,
529 uint16_t vlan_id)
531 DescRing *ring = r->rings[ROCKER_RING_EVENT];
532 DescInfo *info;
533 FpPort *fp_port;
534 uint32_t port;
535 RockerTlv *nest;
536 char *buf;
537 size_t tlv_size;
538 int pos;
539 int err;
541 if (!fp_port_from_pport(pport, &port)) {
542 return -ROCKER_EINVAL;
544 fp_port = r->fp_port[port];
545 if (!fp_port_get_learning(fp_port)) {
546 return ROCKER_OK;
549 info = desc_ring_fetch_desc(ring);
550 if (!info) {
551 return -ROCKER_ENOBUFS;
554 tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* event type */
555 rocker_tlv_total_size(0) + /* nest */
556 rocker_tlv_total_size(sizeof(uint32_t)) + /* pport */
557 rocker_tlv_total_size(ETH_ALEN) + /* mac addr */
558 rocker_tlv_total_size(sizeof(uint16_t)); /* vlan_id */
560 if (tlv_size > desc_buf_size(info)) {
561 err = -ROCKER_EMSGSIZE;
562 goto err_too_big;
565 buf = desc_get_buf(info, false);
566 if (!buf) {
567 err = -ROCKER_ENOMEM;
568 goto err_no_mem;
571 pos = 0;
572 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_TYPE,
573 ROCKER_TLV_EVENT_TYPE_MAC_VLAN_SEEN);
574 nest = rocker_tlv_nest_start(buf, &pos, ROCKER_TLV_EVENT_INFO);
575 rocker_tlv_put_le32(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_PPORT, pport);
576 rocker_tlv_put(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_MAC, ETH_ALEN, addr);
577 rocker_tlv_put_u16(buf, &pos, ROCKER_TLV_EVENT_MAC_VLAN_VLAN_ID, vlan_id);
578 rocker_tlv_nest_end(buf, &pos, nest);
580 err = desc_set_buf(info, tlv_size);
582 err_too_big:
583 err_no_mem:
584 if (desc_ring_post_desc(ring, err)) {
585 rocker_msix_irq(r, ROCKER_MSIX_VEC_EVENT);
588 return err;
591 static DescRing *rocker_get_rx_ring_by_pport(Rocker *r,
592 uint32_t pport)
594 return r->rings[(pport - 1) * 2 + 3];
597 int rx_produce(World *world, uint32_t pport,
598 const struct iovec *iov, int iovcnt, uint8_t copy_to_cpu)
600 Rocker *r = world_rocker(world);
601 PCIDevice *dev = (PCIDevice *)r;
602 DescRing *ring = rocker_get_rx_ring_by_pport(r, pport);
603 DescInfo *info = desc_ring_fetch_desc(ring);
604 char *data;
605 size_t data_size = iov_size(iov, iovcnt);
606 char *buf;
607 uint16_t rx_flags = 0;
608 uint16_t rx_csum = 0;
609 size_t tlv_size;
610 RockerTlv *tlvs[ROCKER_TLV_RX_MAX + 1];
611 hwaddr frag_addr;
612 uint16_t frag_max_len;
613 int pos;
614 int err;
616 if (!info) {
617 return -ROCKER_ENOBUFS;
620 buf = desc_get_buf(info, false);
621 if (!buf) {
622 err = -ROCKER_ENXIO;
623 goto out;
625 rocker_tlv_parse(tlvs, ROCKER_TLV_RX_MAX, buf, desc_tlv_size(info));
627 if (!tlvs[ROCKER_TLV_RX_FRAG_ADDR] ||
628 !tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]) {
629 err = -ROCKER_EINVAL;
630 goto out;
633 frag_addr = rocker_tlv_get_le64(tlvs[ROCKER_TLV_RX_FRAG_ADDR]);
634 frag_max_len = rocker_tlv_get_le16(tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]);
636 if (data_size > frag_max_len) {
637 err = -ROCKER_EMSGSIZE;
638 goto out;
641 if (copy_to_cpu) {
642 rx_flags |= ROCKER_RX_FLAGS_FWD_OFFLOAD;
645 /* XXX calc rx flags/csum */
647 tlv_size = rocker_tlv_total_size(sizeof(uint16_t)) + /* flags */
648 rocker_tlv_total_size(sizeof(uint16_t)) + /* scum */
649 rocker_tlv_total_size(sizeof(uint64_t)) + /* frag addr */
650 rocker_tlv_total_size(sizeof(uint16_t)) + /* frag max len */
651 rocker_tlv_total_size(sizeof(uint16_t)); /* frag len */
653 if (tlv_size > desc_buf_size(info)) {
654 err = -ROCKER_EMSGSIZE;
655 goto out;
658 /* TODO:
659 * iov dma write can be optimized in similar way e1000 does it in
660 * e1000_receive_iov. But maybe if would make sense to introduce
661 * generic helper iov_dma_write.
664 data = g_malloc(data_size);
666 iov_to_buf(iov, iovcnt, 0, data, data_size);
667 pci_dma_write(dev, frag_addr, data, data_size);
668 g_free(data);
670 pos = 0;
671 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FLAGS, rx_flags);
672 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_CSUM, rx_csum);
673 rocker_tlv_put_le64(buf, &pos, ROCKER_TLV_RX_FRAG_ADDR, frag_addr);
674 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_MAX_LEN, frag_max_len);
675 rocker_tlv_put_le16(buf, &pos, ROCKER_TLV_RX_FRAG_LEN, data_size);
677 err = desc_set_buf(info, tlv_size);
679 out:
680 if (desc_ring_post_desc(ring, err)) {
681 rocker_msix_irq(r, ROCKER_MSIX_VEC_RX(pport - 1));
684 return err;
687 int rocker_port_eg(Rocker *r, uint32_t pport,
688 const struct iovec *iov, int iovcnt)
690 FpPort *fp_port;
691 uint32_t port;
693 if (!fp_port_from_pport(pport, &port)) {
694 return -ROCKER_EINVAL;
697 fp_port = r->fp_port[port];
699 return fp_port_eg(fp_port, iov, iovcnt);
702 static void rocker_test_dma_ctrl(Rocker *r, uint32_t val)
704 PCIDevice *dev = PCI_DEVICE(r);
705 char *buf;
706 int i;
708 buf = g_malloc(r->test_dma_size);
710 switch (val) {
711 case ROCKER_TEST_DMA_CTRL_CLEAR:
712 memset(buf, 0, r->test_dma_size);
713 break;
714 case ROCKER_TEST_DMA_CTRL_FILL:
715 memset(buf, 0x96, r->test_dma_size);
716 break;
717 case ROCKER_TEST_DMA_CTRL_INVERT:
718 pci_dma_read(dev, r->test_dma_addr, buf, r->test_dma_size);
719 for (i = 0; i < r->test_dma_size; i++) {
720 buf[i] = ~buf[i];
722 break;
723 default:
724 DPRINTF("not test dma control val=0x%08x\n", val);
725 goto err_out;
727 pci_dma_write(dev, r->test_dma_addr, buf, r->test_dma_size);
729 rocker_msix_irq(r, ROCKER_MSIX_VEC_TEST);
731 err_out:
732 g_free(buf);
735 static void rocker_reset(DeviceState *dev);
737 static void rocker_control(Rocker *r, uint32_t val)
739 if (val & ROCKER_CONTROL_RESET) {
740 rocker_reset(DEVICE(r));
744 static int rocker_pci_ring_count(Rocker *r)
746 /* There are:
747 * - command ring
748 * - event ring
749 * - tx and rx ring per each port
751 return 2 + (2 * r->fp_ports);
754 static bool rocker_addr_is_desc_reg(Rocker *r, hwaddr addr)
756 hwaddr start = ROCKER_DMA_DESC_BASE;
757 hwaddr end = start + (ROCKER_DMA_DESC_SIZE * rocker_pci_ring_count(r));
759 return addr >= start && addr < end;
762 static void rocker_port_phys_enable_write(Rocker *r, uint64_t new)
764 int i;
765 bool old_enabled;
766 bool new_enabled;
767 FpPort *fp_port;
769 for (i = 0; i < r->fp_ports; i++) {
770 fp_port = r->fp_port[i];
771 old_enabled = fp_port_enabled(fp_port);
772 new_enabled = (new >> (i + 1)) & 0x1;
773 if (new_enabled == old_enabled) {
774 continue;
776 if (new_enabled) {
777 fp_port_enable(r->fp_port[i]);
778 } else {
779 fp_port_disable(r->fp_port[i]);
784 static void rocker_io_writel(void *opaque, hwaddr addr, uint32_t val)
786 Rocker *r = opaque;
788 if (rocker_addr_is_desc_reg(r, addr)) {
789 unsigned index = ROCKER_RING_INDEX(addr);
790 unsigned offset = addr & ROCKER_DMA_DESC_MASK;
792 switch (offset) {
793 case ROCKER_DMA_DESC_ADDR_OFFSET:
794 r->lower32 = (uint64_t)val;
795 break;
796 case ROCKER_DMA_DESC_ADDR_OFFSET + 4:
797 desc_ring_set_base_addr(r->rings[index],
798 ((uint64_t)val) << 32 | r->lower32);
799 r->lower32 = 0;
800 break;
801 case ROCKER_DMA_DESC_SIZE_OFFSET:
802 desc_ring_set_size(r->rings[index], val);
803 break;
804 case ROCKER_DMA_DESC_HEAD_OFFSET:
805 if (desc_ring_set_head(r->rings[index], val)) {
806 rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index]));
808 break;
809 case ROCKER_DMA_DESC_CTRL_OFFSET:
810 desc_ring_set_ctrl(r->rings[index], val);
811 break;
812 case ROCKER_DMA_DESC_CREDITS_OFFSET:
813 if (desc_ring_ret_credits(r->rings[index], val)) {
814 rocker_msix_irq(r, desc_ring_get_msix_vector(r->rings[index]));
816 break;
817 default:
818 DPRINTF("not implemented dma reg write(l) addr=0x" TARGET_FMT_plx
819 " val=0x%08x (ring %d, addr=0x%02x)\n",
820 addr, val, index, offset);
821 break;
823 return;
826 switch (addr) {
827 case ROCKER_TEST_REG:
828 r->test_reg = val;
829 break;
830 case ROCKER_TEST_REG64:
831 case ROCKER_TEST_DMA_ADDR:
832 case ROCKER_PORT_PHYS_ENABLE:
833 r->lower32 = (uint64_t)val;
834 break;
835 case ROCKER_TEST_REG64 + 4:
836 r->test_reg64 = ((uint64_t)val) << 32 | r->lower32;
837 r->lower32 = 0;
838 break;
839 case ROCKER_TEST_IRQ:
840 rocker_msix_irq(r, val);
841 break;
842 case ROCKER_TEST_DMA_SIZE:
843 r->test_dma_size = val & 0xFFFF;
844 break;
845 case ROCKER_TEST_DMA_ADDR + 4:
846 r->test_dma_addr = ((uint64_t)val) << 32 | r->lower32;
847 r->lower32 = 0;
848 break;
849 case ROCKER_TEST_DMA_CTRL:
850 rocker_test_dma_ctrl(r, val);
851 break;
852 case ROCKER_CONTROL:
853 rocker_control(r, val);
854 break;
855 case ROCKER_PORT_PHYS_ENABLE + 4:
856 rocker_port_phys_enable_write(r, ((uint64_t)val) << 32 | r->lower32);
857 r->lower32 = 0;
858 break;
859 default:
860 DPRINTF("not implemented write(l) addr=0x" TARGET_FMT_plx
861 " val=0x%08x\n", addr, val);
862 break;
866 static void rocker_io_writeq(void *opaque, hwaddr addr, uint64_t val)
868 Rocker *r = opaque;
870 if (rocker_addr_is_desc_reg(r, addr)) {
871 unsigned index = ROCKER_RING_INDEX(addr);
872 unsigned offset = addr & ROCKER_DMA_DESC_MASK;
874 switch (offset) {
875 case ROCKER_DMA_DESC_ADDR_OFFSET:
876 desc_ring_set_base_addr(r->rings[index], val);
877 break;
878 default:
879 DPRINTF("not implemented dma reg write(q) addr=0x" TARGET_FMT_plx
880 " val=0x" TARGET_FMT_plx " (ring %d, offset=0x%02x)\n",
881 addr, val, index, offset);
882 break;
884 return;
887 switch (addr) {
888 case ROCKER_TEST_REG64:
889 r->test_reg64 = val;
890 break;
891 case ROCKER_TEST_DMA_ADDR:
892 r->test_dma_addr = val;
893 break;
894 case ROCKER_PORT_PHYS_ENABLE:
895 rocker_port_phys_enable_write(r, val);
896 break;
897 default:
898 DPRINTF("not implemented write(q) addr=0x" TARGET_FMT_plx
899 " val=0x" TARGET_FMT_plx "\n", addr, val);
900 break;
904 #ifdef DEBUG_ROCKER
905 #define regname(reg) case (reg): return #reg
906 static const char *rocker_reg_name(void *opaque, hwaddr addr)
908 Rocker *r = opaque;
910 if (rocker_addr_is_desc_reg(r, addr)) {
911 unsigned index = ROCKER_RING_INDEX(addr);
912 unsigned offset = addr & ROCKER_DMA_DESC_MASK;
913 static char buf[100];
914 char ring_name[10];
916 switch (index) {
917 case 0:
918 sprintf(ring_name, "cmd");
919 break;
920 case 1:
921 sprintf(ring_name, "event");
922 break;
923 default:
924 sprintf(ring_name, "%s-%d", index % 2 ? "rx" : "tx",
925 (index - 2) / 2);
928 switch (offset) {
929 case ROCKER_DMA_DESC_ADDR_OFFSET:
930 sprintf(buf, "Ring[%s] ADDR", ring_name);
931 return buf;
932 case ROCKER_DMA_DESC_ADDR_OFFSET+4:
933 sprintf(buf, "Ring[%s] ADDR+4", ring_name);
934 return buf;
935 case ROCKER_DMA_DESC_SIZE_OFFSET:
936 sprintf(buf, "Ring[%s] SIZE", ring_name);
937 return buf;
938 case ROCKER_DMA_DESC_HEAD_OFFSET:
939 sprintf(buf, "Ring[%s] HEAD", ring_name);
940 return buf;
941 case ROCKER_DMA_DESC_TAIL_OFFSET:
942 sprintf(buf, "Ring[%s] TAIL", ring_name);
943 return buf;
944 case ROCKER_DMA_DESC_CTRL_OFFSET:
945 sprintf(buf, "Ring[%s] CTRL", ring_name);
946 return buf;
947 case ROCKER_DMA_DESC_CREDITS_OFFSET:
948 sprintf(buf, "Ring[%s] CREDITS", ring_name);
949 return buf;
950 default:
951 sprintf(buf, "Ring[%s] ???", ring_name);
952 return buf;
954 } else {
955 switch (addr) {
956 regname(ROCKER_BOGUS_REG0);
957 regname(ROCKER_BOGUS_REG1);
958 regname(ROCKER_BOGUS_REG2);
959 regname(ROCKER_BOGUS_REG3);
960 regname(ROCKER_TEST_REG);
961 regname(ROCKER_TEST_REG64);
962 regname(ROCKER_TEST_REG64+4);
963 regname(ROCKER_TEST_IRQ);
964 regname(ROCKER_TEST_DMA_ADDR);
965 regname(ROCKER_TEST_DMA_ADDR+4);
966 regname(ROCKER_TEST_DMA_SIZE);
967 regname(ROCKER_TEST_DMA_CTRL);
968 regname(ROCKER_CONTROL);
969 regname(ROCKER_PORT_PHYS_COUNT);
970 regname(ROCKER_PORT_PHYS_LINK_STATUS);
971 regname(ROCKER_PORT_PHYS_LINK_STATUS+4);
972 regname(ROCKER_PORT_PHYS_ENABLE);
973 regname(ROCKER_PORT_PHYS_ENABLE+4);
974 regname(ROCKER_SWITCH_ID);
975 regname(ROCKER_SWITCH_ID+4);
978 return "???";
980 #else
981 static const char *rocker_reg_name(void *opaque, hwaddr addr)
983 return NULL;
985 #endif
987 static void rocker_mmio_write(void *opaque, hwaddr addr, uint64_t val,
988 unsigned size)
990 DPRINTF("Write %s addr " TARGET_FMT_plx
991 ", size %u, val " TARGET_FMT_plx "\n",
992 rocker_reg_name(opaque, addr), addr, size, val);
994 switch (size) {
995 case 4:
996 rocker_io_writel(opaque, addr, val);
997 break;
998 case 8:
999 rocker_io_writeq(opaque, addr, val);
1000 break;
1004 static uint64_t rocker_port_phys_link_status(Rocker *r)
1006 int i;
1007 uint64_t status = 0;
1009 for (i = 0; i < r->fp_ports; i++) {
1010 FpPort *port = r->fp_port[i];
1012 if (fp_port_get_link_up(port)) {
1013 status |= 1 << (i + 1);
1016 return status;
1019 static uint64_t rocker_port_phys_enable_read(Rocker *r)
1021 int i;
1022 uint64_t ret = 0;
1024 for (i = 0; i < r->fp_ports; i++) {
1025 FpPort *port = r->fp_port[i];
1027 if (fp_port_enabled(port)) {
1028 ret |= 1 << (i + 1);
1031 return ret;
1034 static uint32_t rocker_io_readl(void *opaque, hwaddr addr)
1036 Rocker *r = opaque;
1037 uint32_t ret;
1039 if (rocker_addr_is_desc_reg(r, addr)) {
1040 unsigned index = ROCKER_RING_INDEX(addr);
1041 unsigned offset = addr & ROCKER_DMA_DESC_MASK;
1043 switch (offset) {
1044 case ROCKER_DMA_DESC_ADDR_OFFSET:
1045 ret = (uint32_t)desc_ring_get_base_addr(r->rings[index]);
1046 break;
1047 case ROCKER_DMA_DESC_ADDR_OFFSET + 4:
1048 ret = (uint32_t)(desc_ring_get_base_addr(r->rings[index]) >> 32);
1049 break;
1050 case ROCKER_DMA_DESC_SIZE_OFFSET:
1051 ret = desc_ring_get_size(r->rings[index]);
1052 break;
1053 case ROCKER_DMA_DESC_HEAD_OFFSET:
1054 ret = desc_ring_get_head(r->rings[index]);
1055 break;
1056 case ROCKER_DMA_DESC_TAIL_OFFSET:
1057 ret = desc_ring_get_tail(r->rings[index]);
1058 break;
1059 case ROCKER_DMA_DESC_CREDITS_OFFSET:
1060 ret = desc_ring_get_credits(r->rings[index]);
1061 break;
1062 default:
1063 DPRINTF("not implemented dma reg read(l) addr=0x" TARGET_FMT_plx
1064 " (ring %d, addr=0x%02x)\n", addr, index, offset);
1065 ret = 0;
1066 break;
1068 return ret;
1071 switch (addr) {
1072 case ROCKER_BOGUS_REG0:
1073 case ROCKER_BOGUS_REG1:
1074 case ROCKER_BOGUS_REG2:
1075 case ROCKER_BOGUS_REG3:
1076 ret = 0xDEADBABE;
1077 break;
1078 case ROCKER_TEST_REG:
1079 ret = r->test_reg * 2;
1080 break;
1081 case ROCKER_TEST_REG64:
1082 ret = (uint32_t)(r->test_reg64 * 2);
1083 break;
1084 case ROCKER_TEST_REG64 + 4:
1085 ret = (uint32_t)((r->test_reg64 * 2) >> 32);
1086 break;
1087 case ROCKER_TEST_DMA_SIZE:
1088 ret = r->test_dma_size;
1089 break;
1090 case ROCKER_TEST_DMA_ADDR:
1091 ret = (uint32_t)r->test_dma_addr;
1092 break;
1093 case ROCKER_TEST_DMA_ADDR + 4:
1094 ret = (uint32_t)(r->test_dma_addr >> 32);
1095 break;
1096 case ROCKER_PORT_PHYS_COUNT:
1097 ret = r->fp_ports;
1098 break;
1099 case ROCKER_PORT_PHYS_LINK_STATUS:
1100 ret = (uint32_t)rocker_port_phys_link_status(r);
1101 break;
1102 case ROCKER_PORT_PHYS_LINK_STATUS + 4:
1103 ret = (uint32_t)(rocker_port_phys_link_status(r) >> 32);
1104 break;
1105 case ROCKER_PORT_PHYS_ENABLE:
1106 ret = (uint32_t)rocker_port_phys_enable_read(r);
1107 break;
1108 case ROCKER_PORT_PHYS_ENABLE + 4:
1109 ret = (uint32_t)(rocker_port_phys_enable_read(r) >> 32);
1110 break;
1111 case ROCKER_SWITCH_ID:
1112 ret = (uint32_t)r->switch_id;
1113 break;
1114 case ROCKER_SWITCH_ID + 4:
1115 ret = (uint32_t)(r->switch_id >> 32);
1116 break;
1117 default:
1118 DPRINTF("not implemented read(l) addr=0x" TARGET_FMT_plx "\n", addr);
1119 ret = 0;
1120 break;
1122 return ret;
1125 static uint64_t rocker_io_readq(void *opaque, hwaddr addr)
1127 Rocker *r = opaque;
1128 uint64_t ret;
1130 if (rocker_addr_is_desc_reg(r, addr)) {
1131 unsigned index = ROCKER_RING_INDEX(addr);
1132 unsigned offset = addr & ROCKER_DMA_DESC_MASK;
1134 switch (addr & ROCKER_DMA_DESC_MASK) {
1135 case ROCKER_DMA_DESC_ADDR_OFFSET:
1136 ret = desc_ring_get_base_addr(r->rings[index]);
1137 break;
1138 default:
1139 DPRINTF("not implemented dma reg read(q) addr=0x" TARGET_FMT_plx
1140 " (ring %d, addr=0x%02x)\n", addr, index, offset);
1141 ret = 0;
1142 break;
1144 return ret;
1147 switch (addr) {
1148 case ROCKER_BOGUS_REG0:
1149 case ROCKER_BOGUS_REG2:
1150 ret = 0xDEADBABEDEADBABEULL;
1151 break;
1152 case ROCKER_TEST_REG64:
1153 ret = r->test_reg64 * 2;
1154 break;
1155 case ROCKER_TEST_DMA_ADDR:
1156 ret = r->test_dma_addr;
1157 break;
1158 case ROCKER_PORT_PHYS_LINK_STATUS:
1159 ret = rocker_port_phys_link_status(r);
1160 break;
1161 case ROCKER_PORT_PHYS_ENABLE:
1162 ret = rocker_port_phys_enable_read(r);
1163 break;
1164 case ROCKER_SWITCH_ID:
1165 ret = r->switch_id;
1166 break;
1167 default:
1168 DPRINTF("not implemented read(q) addr=0x" TARGET_FMT_plx "\n", addr);
1169 ret = 0;
1170 break;
1172 return ret;
1175 static uint64_t rocker_mmio_read(void *opaque, hwaddr addr, unsigned size)
1177 DPRINTF("Read %s addr " TARGET_FMT_plx ", size %u\n",
1178 rocker_reg_name(opaque, addr), addr, size);
1180 switch (size) {
1181 case 4:
1182 return rocker_io_readl(opaque, addr);
1183 case 8:
1184 return rocker_io_readq(opaque, addr);
1187 return -1;
1190 static const MemoryRegionOps rocker_mmio_ops = {
1191 .read = rocker_mmio_read,
1192 .write = rocker_mmio_write,
1193 .endianness = DEVICE_LITTLE_ENDIAN,
1194 .valid = {
1195 .min_access_size = 4,
1196 .max_access_size = 8,
1198 .impl = {
1199 .min_access_size = 4,
1200 .max_access_size = 8,
1204 static void rocker_msix_vectors_unuse(Rocker *r,
1205 unsigned int num_vectors)
1207 PCIDevice *dev = PCI_DEVICE(r);
1208 int i;
1210 for (i = 0; i < num_vectors; i++) {
1211 msix_vector_unuse(dev, i);
1215 static int rocker_msix_vectors_use(Rocker *r,
1216 unsigned int num_vectors)
1218 PCIDevice *dev = PCI_DEVICE(r);
1219 int err;
1220 int i;
1222 for (i = 0; i < num_vectors; i++) {
1223 err = msix_vector_use(dev, i);
1224 if (err) {
1225 goto rollback;
1228 return 0;
1230 rollback:
1231 rocker_msix_vectors_unuse(r, i);
1232 return err;
1235 static int rocker_msix_init(Rocker *r, Error **errp)
1237 PCIDevice *dev = PCI_DEVICE(r);
1238 int err;
1240 err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports),
1241 &r->msix_bar,
1242 ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET,
1243 &r->msix_bar,
1244 ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET,
1245 0, errp);
1246 if (err) {
1247 return err;
1250 err = rocker_msix_vectors_use(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
1251 if (err) {
1252 goto err_msix_vectors_use;
1255 return 0;
1257 err_msix_vectors_use:
1258 msix_uninit(dev, &r->msix_bar, &r->msix_bar);
1259 return err;
1262 static void rocker_msix_uninit(Rocker *r)
1264 PCIDevice *dev = PCI_DEVICE(r);
1266 msix_uninit(dev, &r->msix_bar, &r->msix_bar);
1267 rocker_msix_vectors_unuse(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
1270 static World *rocker_world_type_by_name(Rocker *r, const char *name)
1272 int i;
1274 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1275 if (strcmp(name, world_name(r->worlds[i])) == 0) {
1276 return r->worlds[i];
1279 return NULL;
1282 static void pci_rocker_realize(PCIDevice *dev, Error **errp)
1284 Rocker *r = ROCKER(dev);
1285 const MACAddr zero = { .a = { 0, 0, 0, 0, 0, 0 } };
1286 const MACAddr dflt = { .a = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x01 } };
1287 static int sw_index;
1288 int i, err = 0;
1290 /* allocate worlds */
1292 r->worlds[ROCKER_WORLD_TYPE_OF_DPA] = of_dpa_world_alloc(r);
1294 if (!r->world_name) {
1295 r->world_name = g_strdup(world_name(r->worlds[ROCKER_WORLD_TYPE_OF_DPA]));
1298 r->world_dflt = rocker_world_type_by_name(r, r->world_name);
1299 if (!r->world_dflt) {
1300 error_setg(errp,
1301 "invalid argument requested world %s does not exist",
1302 r->world_name);
1303 goto err_world_type_by_name;
1306 /* set up memory-mapped region at BAR0 */
1308 memory_region_init_io(&r->mmio, OBJECT(r), &rocker_mmio_ops, r,
1309 "rocker-mmio", ROCKER_PCI_BAR0_SIZE);
1310 pci_register_bar(dev, ROCKER_PCI_BAR0_IDX,
1311 PCI_BASE_ADDRESS_SPACE_MEMORY, &r->mmio);
1313 /* set up memory-mapped region for MSI-X */
1315 memory_region_init(&r->msix_bar, OBJECT(r), "rocker-msix-bar",
1316 ROCKER_PCI_MSIX_BAR_SIZE);
1317 pci_register_bar(dev, ROCKER_PCI_MSIX_BAR_IDX,
1318 PCI_BASE_ADDRESS_SPACE_MEMORY, &r->msix_bar);
1320 /* MSI-X init */
1322 err = rocker_msix_init(r, errp);
1323 if (err) {
1324 goto err_msix_init;
1327 /* validate switch properties */
1329 if (!r->name) {
1330 r->name = g_strdup(TYPE_ROCKER);
1333 if (rocker_find(r->name)) {
1334 error_setg(errp, "%s already exists", r->name);
1335 goto err_duplicate;
1338 /* Rocker name is passed in port name requests to OS with the intention
1339 * that the name is used in interface names. Limit the length of the
1340 * rocker name to avoid naming problems in the OS. Also, adding the
1341 * port number as p# and unganged breakout b#, where # is at most 2
1342 * digits, so leave room for it too (-1 for string terminator, -3 for
1343 * p# and -3 for b#)
1345 #define ROCKER_IFNAMSIZ 16
1346 #define MAX_ROCKER_NAME_LEN (ROCKER_IFNAMSIZ - 1 - 3 - 3)
1347 if (strlen(r->name) > MAX_ROCKER_NAME_LEN) {
1348 error_setg(errp,
1349 "name too long; please shorten to at most %d chars",
1350 MAX_ROCKER_NAME_LEN);
1351 goto err_name_too_long;
1354 if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) {
1355 memcpy(&r->fp_start_macaddr, &dflt, sizeof(dflt));
1356 r->fp_start_macaddr.a[4] += (sw_index++);
1359 if (!r->switch_id) {
1360 memcpy(&r->switch_id, &r->fp_start_macaddr,
1361 sizeof(r->fp_start_macaddr));
1364 if (r->fp_ports > ROCKER_FP_PORTS_MAX) {
1365 r->fp_ports = ROCKER_FP_PORTS_MAX;
1368 r->rings = g_new(DescRing *, rocker_pci_ring_count(r));
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 * .....
1380 for (i = 0; i < rocker_pci_ring_count(r); i++) {
1381 DescRing *ring = desc_ring_alloc(r, i);
1383 if (i == ROCKER_RING_CMD) {
1384 desc_ring_set_consume(ring, cmd_consume, ROCKER_MSIX_VEC_CMD);
1385 } else if (i == ROCKER_RING_EVENT) {
1386 desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_EVENT);
1387 } else if (i % 2 == 0) {
1388 desc_ring_set_consume(ring, tx_consume,
1389 ROCKER_MSIX_VEC_TX((i - 2) / 2));
1390 } else if (i % 2 == 1) {
1391 desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_RX((i - 3) / 2));
1394 r->rings[i] = ring;
1397 for (i = 0; i < r->fp_ports; i++) {
1398 FpPort *port =
1399 fp_port_alloc(r, r->name, &r->fp_start_macaddr,
1400 i, &r->fp_ports_peers[i]);
1402 r->fp_port[i] = port;
1403 fp_port_set_world(port, r->world_dflt);
1406 QLIST_INSERT_HEAD(&rockers, r, next);
1408 return;
1410 err_name_too_long:
1411 err_duplicate:
1412 rocker_msix_uninit(r);
1413 err_msix_init:
1414 object_unparent(OBJECT(&r->msix_bar));
1415 object_unparent(OBJECT(&r->mmio));
1416 err_world_type_by_name:
1417 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1418 if (r->worlds[i]) {
1419 world_free(r->worlds[i]);
1424 static void pci_rocker_uninit(PCIDevice *dev)
1426 Rocker *r = ROCKER(dev);
1427 int i;
1429 QLIST_REMOVE(r, next);
1431 for (i = 0; i < r->fp_ports; i++) {
1432 FpPort *port = r->fp_port[i];
1434 fp_port_free(port);
1435 r->fp_port[i] = NULL;
1438 for (i = 0; i < rocker_pci_ring_count(r); i++) {
1439 if (r->rings[i]) {
1440 desc_ring_free(r->rings[i]);
1443 g_free(r->rings);
1445 rocker_msix_uninit(r);
1446 object_unparent(OBJECT(&r->msix_bar));
1447 object_unparent(OBJECT(&r->mmio));
1449 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1450 if (r->worlds[i]) {
1451 world_free(r->worlds[i]);
1454 g_free(r->fp_ports_peers);
1457 static void rocker_reset(DeviceState *dev)
1459 Rocker *r = ROCKER(dev);
1460 int i;
1462 for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1463 if (r->worlds[i]) {
1464 world_reset(r->worlds[i]);
1467 for (i = 0; i < r->fp_ports; i++) {
1468 fp_port_reset(r->fp_port[i]);
1469 fp_port_set_world(r->fp_port[i], r->world_dflt);
1472 r->test_reg = 0;
1473 r->test_reg64 = 0;
1474 r->test_dma_addr = 0;
1475 r->test_dma_size = 0;
1477 for (i = 0; i < rocker_pci_ring_count(r); i++) {
1478 desc_ring_reset(r->rings[i]);
1481 DPRINTF("Reset done\n");
1484 static Property rocker_properties[] = {
1485 DEFINE_PROP_STRING("name", Rocker, name),
1486 DEFINE_PROP_STRING("world", Rocker, world_name),
1487 DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker,
1488 fp_start_macaddr),
1489 DEFINE_PROP_UINT64("switch_id", Rocker,
1490 switch_id, 0),
1491 DEFINE_PROP_ARRAY("ports", Rocker, fp_ports,
1492 fp_ports_peers, qdev_prop_netdev, NICPeers),
1493 DEFINE_PROP_END_OF_LIST(),
1496 static const VMStateDescription rocker_vmsd = {
1497 .name = TYPE_ROCKER,
1498 .unmigratable = 1,
1501 static void rocker_class_init(ObjectClass *klass, void *data)
1503 DeviceClass *dc = DEVICE_CLASS(klass);
1504 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1506 k->realize = pci_rocker_realize;
1507 k->exit = pci_rocker_uninit;
1508 k->vendor_id = PCI_VENDOR_ID_REDHAT;
1509 k->device_id = PCI_DEVICE_ID_REDHAT_ROCKER;
1510 k->revision = ROCKER_PCI_REVISION;
1511 k->class_id = PCI_CLASS_NETWORK_OTHER;
1512 set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1513 dc->desc = "Rocker Switch";
1514 dc->reset = rocker_reset;
1515 device_class_set_props(dc, rocker_properties);
1516 dc->vmsd = &rocker_vmsd;
1519 static const TypeInfo rocker_info = {
1520 .name = TYPE_ROCKER,
1521 .parent = TYPE_PCI_DEVICE,
1522 .instance_size = sizeof(Rocker),
1523 .class_init = rocker_class_init,
1524 .interfaces = (InterfaceInfo[]) {
1525 { INTERFACE_CONVENTIONAL_PCI_DEVICE },
1526 { },
1530 static void rocker_register_types(void)
1532 type_register_static(&rocker_info);
1535 type_init(rocker_register_types)