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"
26 #include "qapi/error.h"
27 #include "qapi/qapi-commands-rocker.h"
29 #include "qemu/module.h"
30 #include "qemu/bitops.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"
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 */
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 */
71 World
*worlds
[ROCKER_WORLD_TYPE_MAX
];
74 QLIST_ENTRY(rocker
) next
;
77 static QLIST_HEAD(, rocker
) rockers
;
79 Rocker
*rocker_find(const char *name
)
83 QLIST_FOREACH(r
, &rockers
, next
)
84 if (strcmp(r
->name
, name
) == 0) {
91 World
*rocker_get_world(Rocker
*r
, enum rocker_world_type type
)
93 if (type
< ROCKER_WORLD_TYPE_MAX
) {
94 return r
->worlds
[type
];
99 RockerSwitch
*qmp_query_rocker(const char *name
, Error
**errp
)
101 RockerSwitch
*rocker
;
104 r
= rocker_find(name
);
106 error_setg(errp
, "rocker %s not found", name
);
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
;
118 RockerPortList
*qmp_query_rocker_ports(const char *name
, Error
**errp
)
120 RockerPortList
*list
= NULL
;
124 r
= rocker_find(name
);
126 error_setg(errp
, "rocker %s not found", name
);
130 for (i
= r
->fp_ports
- 1; i
>= 0; i
--) {
131 QAPI_LIST_PREPEND(list
, fp_port_get_info(r
->fp_port
[i
]));
137 uint32_t rocker_fp_ports(Rocker
*r
)
142 static uint32_t rocker_get_pport_by_tx_ring(Rocker
*r
,
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);
153 RockerTlv
*tlvs
[ROCKER_TLV_TX_MAX
+ 1];
154 struct iovec iov
[ROCKER_TX_FRAGS_MAX
] = { { 0, }, };
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;
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
;
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
;
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
) {
223 if (rocker_tlv_type(tlv_frag
) != ROCKER_TLV_TX_FRAG
) {
224 err
= -ROCKER_EINVAL
;
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
;
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
);
251 err
= fp_port_eg(r
->fp_port
[port
], iov
, iovcnt
);
255 for (i
= 0; i
< ROCKER_TX_FRAGS_MAX
; i
++) {
256 g_free(iov
[i
].iov_base
);
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];
277 enum rocker_world_type mode
;
282 rocker_tlv_parse_nested(tlvs
, ROCKER_TLV_CMD_PORT_SETTINGS_MAX
,
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
);
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
;
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
,
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];
349 enum rocker_world_type mode
;
352 rocker_tlv_parse_nested(tlvs
, ROCKER_TLV_CMD_PORT_SETTINGS_MAX
,
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
);
379 if (tlvs
[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR
]) {
380 if (rocker_tlv_len(tlvs
[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR
]) !=
382 return -ROCKER_EINVAL
;
385 rocker_tlv_data(tlvs
[ROCKER_TLV_CMD_PORT_SETTINGS_MACADDR
]),
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
]) {
403 rocker_tlv_get_u8(tlvs
[ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING
]);
404 fp_port_set_learning(fp_port
, learning
);
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];
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
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
);
452 case ROCKER_TLV_CMD_TYPE_GET_PORT_SETTINGS
:
453 err
= cmd_get_port_settings(r
, info
, buf
, info_tlv
);
455 case ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS
:
456 err
= cmd_set_port_settings(r
, info_tlv
);
459 err
= -ROCKER_EINVAL
;
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
);
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
);
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
;
502 buf
= desc_get_buf(info
, false);
504 err
= -ROCKER_ENOMEM
;
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
,
515 rocker_tlv_nest_end(buf
, &pos
, nest
);
517 err
= desc_set_buf(info
, tlv_size
);
521 if (desc_ring_post_desc(ring
, err
)) {
522 rocker_msix_irq(r
, ROCKER_MSIX_VEC_EVENT
);
528 int rocker_event_mac_vlan_seen(Rocker
*r
, uint32_t pport
, uint8_t *addr
,
531 DescRing
*ring
= r
->rings
[ROCKER_RING_EVENT
];
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
)) {
549 info
= desc_ring_fetch_desc(ring
);
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
;
565 buf
= desc_get_buf(info
, false);
567 err
= -ROCKER_ENOMEM
;
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
);
584 if (desc_ring_post_desc(ring
, err
)) {
585 rocker_msix_irq(r
, ROCKER_MSIX_VEC_EVENT
);
591 static DescRing
*rocker_get_rx_ring_by_pport(Rocker
*r
,
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
);
605 size_t data_size
= iov_size(iov
, iovcnt
);
607 uint16_t rx_flags
= 0;
608 uint16_t rx_csum
= 0;
610 RockerTlv
*tlvs
[ROCKER_TLV_RX_MAX
+ 1];
612 uint16_t frag_max_len
;
617 return -ROCKER_ENOBUFS
;
620 buf
= desc_get_buf(info
, false);
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
;
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
;
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
;
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
);
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
);
680 if (desc_ring_post_desc(ring
, err
)) {
681 rocker_msix_irq(r
, ROCKER_MSIX_VEC_RX(pport
- 1));
687 int rocker_port_eg(Rocker
*r
, uint32_t pport
,
688 const struct iovec
*iov
, int iovcnt
)
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
);
708 buf
= g_malloc(r
->test_dma_size
);
711 case ROCKER_TEST_DMA_CTRL_CLEAR
:
712 memset(buf
, 0, r
->test_dma_size
);
714 case ROCKER_TEST_DMA_CTRL_FILL
:
715 memset(buf
, 0x96, r
->test_dma_size
);
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
++) {
724 DPRINTF("not test dma control val=0x%08x\n", val
);
727 pci_dma_write(dev
, r
->test_dma_addr
, buf
, r
->test_dma_size
);
729 rocker_msix_irq(r
, ROCKER_MSIX_VEC_TEST
);
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
)
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)
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
) {
777 fp_port_enable(r
->fp_port
[i
]);
779 fp_port_disable(r
->fp_port
[i
]);
784 static void rocker_io_writel(void *opaque
, hwaddr addr
, uint32_t val
)
788 if (rocker_addr_is_desc_reg(r
, addr
)) {
789 unsigned index
= ROCKER_RING_INDEX(addr
);
790 unsigned offset
= addr
& ROCKER_DMA_DESC_MASK
;
793 case ROCKER_DMA_DESC_ADDR_OFFSET
:
794 r
->lower32
= (uint64_t)val
;
796 case ROCKER_DMA_DESC_ADDR_OFFSET
+ 4:
797 desc_ring_set_base_addr(r
->rings
[index
],
798 ((uint64_t)val
) << 32 | r
->lower32
);
801 case ROCKER_DMA_DESC_SIZE_OFFSET
:
802 desc_ring_set_size(r
->rings
[index
], val
);
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
]));
809 case ROCKER_DMA_DESC_CTRL_OFFSET
:
810 desc_ring_set_ctrl(r
->rings
[index
], val
);
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
]));
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
);
827 case ROCKER_TEST_REG
:
830 case ROCKER_TEST_REG64
:
831 case ROCKER_TEST_DMA_ADDR
:
832 case ROCKER_PORT_PHYS_ENABLE
:
833 r
->lower32
= (uint64_t)val
;
835 case ROCKER_TEST_REG64
+ 4:
836 r
->test_reg64
= ((uint64_t)val
) << 32 | r
->lower32
;
839 case ROCKER_TEST_IRQ
:
840 rocker_msix_irq(r
, val
);
842 case ROCKER_TEST_DMA_SIZE
:
843 r
->test_dma_size
= val
& 0xFFFF;
845 case ROCKER_TEST_DMA_ADDR
+ 4:
846 r
->test_dma_addr
= ((uint64_t)val
) << 32 | r
->lower32
;
849 case ROCKER_TEST_DMA_CTRL
:
850 rocker_test_dma_ctrl(r
, val
);
853 rocker_control(r
, val
);
855 case ROCKER_PORT_PHYS_ENABLE
+ 4:
856 rocker_port_phys_enable_write(r
, ((uint64_t)val
) << 32 | r
->lower32
);
860 DPRINTF("not implemented write(l) addr=0x" TARGET_FMT_plx
861 " val=0x%08x\n", addr
, val
);
866 static void rocker_io_writeq(void *opaque
, hwaddr addr
, uint64_t val
)
870 if (rocker_addr_is_desc_reg(r
, addr
)) {
871 unsigned index
= ROCKER_RING_INDEX(addr
);
872 unsigned offset
= addr
& ROCKER_DMA_DESC_MASK
;
875 case ROCKER_DMA_DESC_ADDR_OFFSET
:
876 desc_ring_set_base_addr(r
->rings
[index
], val
);
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
);
888 case ROCKER_TEST_REG64
:
891 case ROCKER_TEST_DMA_ADDR
:
892 r
->test_dma_addr
= val
;
894 case ROCKER_PORT_PHYS_ENABLE
:
895 rocker_port_phys_enable_write(r
, val
);
898 DPRINTF("not implemented write(q) addr=0x" TARGET_FMT_plx
899 " val=0x" TARGET_FMT_plx
"\n", addr
, val
);
905 #define regname(reg) case (reg): return #reg
906 static const char *rocker_reg_name(void *opaque
, hwaddr addr
)
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];
918 sprintf(ring_name
, "cmd");
921 sprintf(ring_name
, "event");
924 sprintf(ring_name
, "%s-%d", index
% 2 ? "rx" : "tx",
929 case ROCKER_DMA_DESC_ADDR_OFFSET
:
930 sprintf(buf
, "Ring[%s] ADDR", ring_name
);
932 case ROCKER_DMA_DESC_ADDR_OFFSET
+4:
933 sprintf(buf
, "Ring[%s] ADDR+4", ring_name
);
935 case ROCKER_DMA_DESC_SIZE_OFFSET
:
936 sprintf(buf
, "Ring[%s] SIZE", ring_name
);
938 case ROCKER_DMA_DESC_HEAD_OFFSET
:
939 sprintf(buf
, "Ring[%s] HEAD", ring_name
);
941 case ROCKER_DMA_DESC_TAIL_OFFSET
:
942 sprintf(buf
, "Ring[%s] TAIL", ring_name
);
944 case ROCKER_DMA_DESC_CTRL_OFFSET
:
945 sprintf(buf
, "Ring[%s] CTRL", ring_name
);
947 case ROCKER_DMA_DESC_CREDITS_OFFSET
:
948 sprintf(buf
, "Ring[%s] CREDITS", ring_name
);
951 sprintf(buf
, "Ring[%s] ???", ring_name
);
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);
981 static const char *rocker_reg_name(void *opaque
, hwaddr addr
)
987 static void rocker_mmio_write(void *opaque
, hwaddr addr
, uint64_t val
,
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
);
996 rocker_io_writel(opaque
, addr
, val
);
999 rocker_io_writeq(opaque
, addr
, val
);
1004 static uint64_t rocker_port_phys_link_status(Rocker
*r
)
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);
1019 static uint64_t rocker_port_phys_enable_read(Rocker
*r
)
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);
1034 static uint32_t rocker_io_readl(void *opaque
, hwaddr addr
)
1039 if (rocker_addr_is_desc_reg(r
, addr
)) {
1040 unsigned index
= ROCKER_RING_INDEX(addr
);
1041 unsigned offset
= addr
& ROCKER_DMA_DESC_MASK
;
1044 case ROCKER_DMA_DESC_ADDR_OFFSET
:
1045 ret
= (uint32_t)desc_ring_get_base_addr(r
->rings
[index
]);
1047 case ROCKER_DMA_DESC_ADDR_OFFSET
+ 4:
1048 ret
= (uint32_t)(desc_ring_get_base_addr(r
->rings
[index
]) >> 32);
1050 case ROCKER_DMA_DESC_SIZE_OFFSET
:
1051 ret
= desc_ring_get_size(r
->rings
[index
]);
1053 case ROCKER_DMA_DESC_HEAD_OFFSET
:
1054 ret
= desc_ring_get_head(r
->rings
[index
]);
1056 case ROCKER_DMA_DESC_TAIL_OFFSET
:
1057 ret
= desc_ring_get_tail(r
->rings
[index
]);
1059 case ROCKER_DMA_DESC_CREDITS_OFFSET
:
1060 ret
= desc_ring_get_credits(r
->rings
[index
]);
1063 DPRINTF("not implemented dma reg read(l) addr=0x" TARGET_FMT_plx
1064 " (ring %d, addr=0x%02x)\n", addr
, index
, offset
);
1072 case ROCKER_BOGUS_REG0
:
1073 case ROCKER_BOGUS_REG1
:
1074 case ROCKER_BOGUS_REG2
:
1075 case ROCKER_BOGUS_REG3
:
1078 case ROCKER_TEST_REG
:
1079 ret
= r
->test_reg
* 2;
1081 case ROCKER_TEST_REG64
:
1082 ret
= (uint32_t)(r
->test_reg64
* 2);
1084 case ROCKER_TEST_REG64
+ 4:
1085 ret
= (uint32_t)((r
->test_reg64
* 2) >> 32);
1087 case ROCKER_TEST_DMA_SIZE
:
1088 ret
= r
->test_dma_size
;
1090 case ROCKER_TEST_DMA_ADDR
:
1091 ret
= (uint32_t)r
->test_dma_addr
;
1093 case ROCKER_TEST_DMA_ADDR
+ 4:
1094 ret
= (uint32_t)(r
->test_dma_addr
>> 32);
1096 case ROCKER_PORT_PHYS_COUNT
:
1099 case ROCKER_PORT_PHYS_LINK_STATUS
:
1100 ret
= (uint32_t)rocker_port_phys_link_status(r
);
1102 case ROCKER_PORT_PHYS_LINK_STATUS
+ 4:
1103 ret
= (uint32_t)(rocker_port_phys_link_status(r
) >> 32);
1105 case ROCKER_PORT_PHYS_ENABLE
:
1106 ret
= (uint32_t)rocker_port_phys_enable_read(r
);
1108 case ROCKER_PORT_PHYS_ENABLE
+ 4:
1109 ret
= (uint32_t)(rocker_port_phys_enable_read(r
) >> 32);
1111 case ROCKER_SWITCH_ID
:
1112 ret
= (uint32_t)r
->switch_id
;
1114 case ROCKER_SWITCH_ID
+ 4:
1115 ret
= (uint32_t)(r
->switch_id
>> 32);
1118 DPRINTF("not implemented read(l) addr=0x" TARGET_FMT_plx
"\n", addr
);
1125 static uint64_t rocker_io_readq(void *opaque
, hwaddr addr
)
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
]);
1139 DPRINTF("not implemented dma reg read(q) addr=0x" TARGET_FMT_plx
1140 " (ring %d, addr=0x%02x)\n", addr
, index
, offset
);
1148 case ROCKER_BOGUS_REG0
:
1149 case ROCKER_BOGUS_REG2
:
1150 ret
= 0xDEADBABEDEADBABEULL
;
1152 case ROCKER_TEST_REG64
:
1153 ret
= r
->test_reg64
* 2;
1155 case ROCKER_TEST_DMA_ADDR
:
1156 ret
= r
->test_dma_addr
;
1158 case ROCKER_PORT_PHYS_LINK_STATUS
:
1159 ret
= rocker_port_phys_link_status(r
);
1161 case ROCKER_PORT_PHYS_ENABLE
:
1162 ret
= rocker_port_phys_enable_read(r
);
1164 case ROCKER_SWITCH_ID
:
1168 DPRINTF("not implemented read(q) addr=0x" TARGET_FMT_plx
"\n", addr
);
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
);
1182 return rocker_io_readl(opaque
, addr
);
1184 return rocker_io_readq(opaque
, addr
);
1190 static const MemoryRegionOps rocker_mmio_ops
= {
1191 .read
= rocker_mmio_read
,
1192 .write
= rocker_mmio_write
,
1193 .endianness
= DEVICE_LITTLE_ENDIAN
,
1195 .min_access_size
= 4,
1196 .max_access_size
= 8,
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
);
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
);
1222 for (i
= 0; i
< num_vectors
; i
++) {
1223 err
= msix_vector_use(dev
, i
);
1231 rocker_msix_vectors_unuse(r
, i
);
1235 static int rocker_msix_init(Rocker
*r
, Error
**errp
)
1237 PCIDevice
*dev
= PCI_DEVICE(r
);
1240 err
= msix_init(dev
, ROCKER_MSIX_VEC_COUNT(r
->fp_ports
),
1242 ROCKER_PCI_MSIX_BAR_IDX
, ROCKER_PCI_MSIX_TABLE_OFFSET
,
1244 ROCKER_PCI_MSIX_BAR_IDX
, ROCKER_PCI_MSIX_PBA_OFFSET
,
1250 err
= rocker_msix_vectors_use(r
, ROCKER_MSIX_VEC_COUNT(r
->fp_ports
));
1252 goto err_msix_vectors_use
;
1257 err_msix_vectors_use
:
1258 msix_uninit(dev
, &r
->msix_bar
, &r
->msix_bar
);
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
)
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
];
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
;
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
) {
1301 "invalid argument requested world %s does not exist",
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
);
1322 err
= rocker_msix_init(r
, errp
);
1327 /* validate switch properties */
1330 r
->name
= g_strdup(TYPE_ROCKER
);
1333 if (rocker_find(r
->name
)) {
1334 error_setg(errp
, "%s already exists", r
->name
);
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
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
) {
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:
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));
1397 for (i
= 0; i
< r
->fp_ports
; i
++) {
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
);
1412 rocker_msix_uninit(r
);
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
++) {
1419 world_free(r
->worlds
[i
]);
1424 static void pci_rocker_uninit(PCIDevice
*dev
)
1426 Rocker
*r
= ROCKER(dev
);
1429 QLIST_REMOVE(r
, next
);
1431 for (i
= 0; i
< r
->fp_ports
; i
++) {
1432 FpPort
*port
= r
->fp_port
[i
];
1435 r
->fp_port
[i
] = NULL
;
1438 for (i
= 0; i
< rocker_pci_ring_count(r
); i
++) {
1440 desc_ring_free(r
->rings
[i
]);
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
++) {
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
);
1462 for (i
= 0; i
< ROCKER_WORLD_TYPE_MAX
; 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
);
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
,
1489 DEFINE_PROP_UINT64("switch_id", Rocker
,
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
,
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
},
1530 static void rocker_register_types(void)
1532 type_register_static(&rocker_info
);
1535 type_init(rocker_register_types
)