xref: /openbmc/qemu/hw/net/rocker/rocker.c (revision 883f2c59)
1 /*
2  * QEMU rocker switch emulation - PCI device
3  *
4  * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
5  * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  */
17 
18 #include "qemu/osdep.h"
19 #include "hw/pci/pci_device.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"
32 
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"
40 
41 struct rocker {
42     /* private */
43     PCIDevice parent_obj;
44     /* public */
45 
46     MemoryRegion mmio;
47     MemoryRegion msix_bar;
48 
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 */
56 
57     /* front-panel ports */
58     FpPort *fp_port[ROCKER_FP_PORTS_MAX];
59 
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 */
66 
67     /* desc rings */
68     DescRing **rings;
69 
70     /* switch worlds */
71     World *worlds[ROCKER_WORLD_TYPE_MAX];
72     World *world_dflt;
73 
74     QLIST_ENTRY(rocker) next;
75 };
76 
77 static QLIST_HEAD(, rocker) rockers;
78 
rocker_find(const char * name)79 Rocker *rocker_find(const char *name)
80 {
81     Rocker *r;
82 
83     QLIST_FOREACH(r, &rockers, next)
84         if (strcmp(r->name, name) == 0) {
85             return r;
86         }
87 
88     return NULL;
89 }
90 
rocker_get_world(Rocker * r,enum rocker_world_type type)91 World *rocker_get_world(Rocker *r, enum rocker_world_type type)
92 {
93     if (type < ROCKER_WORLD_TYPE_MAX) {
94         return r->worlds[type];
95     }
96     return NULL;
97 }
98 
qmp_query_rocker(const char * name,Error ** errp)99 RockerSwitch *qmp_query_rocker(const char *name, Error **errp)
100 {
101     RockerSwitch *rocker;
102     Rocker *r;
103 
104     r = rocker_find(name);
105     if (!r) {
106         error_setg(errp, "rocker %s not found", name);
107         return NULL;
108     }
109 
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;
114 
115     return rocker;
116 }
117 
qmp_query_rocker_ports(const char * name,Error ** errp)118 RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp)
119 {
120     RockerPortList *list = NULL;
121     Rocker *r;
122     int i;
123 
124     r = rocker_find(name);
125     if (!r) {
126         error_setg(errp, "rocker %s not found", name);
127         return NULL;
128     }
129 
130     for (i = r->fp_ports - 1; i >= 0; i--) {
131         QAPI_LIST_PREPEND(list, fp_port_get_info(r->fp_port[i]));
132     }
133 
134     return list;
135 }
136 
rocker_fp_ports(Rocker * r)137 uint32_t rocker_fp_ports(Rocker *r)
138 {
139     return r->fp_ports;
140 }
141 
rocker_get_pport_by_tx_ring(Rocker * r,DescRing * ring)142 static uint32_t rocker_get_pport_by_tx_ring(Rocker *r,
143                                             DescRing *ring)
144 {
145     return (desc_ring_index(ring) - 2) / 2 + 1;
146 }
147 
tx_consume(Rocker * r,DescInfo * info)148 static int tx_consume(Rocker *r, DescInfo *info)
149 {
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;
165 
166     if (!buf) {
167         return -ROCKER_ENXIO;
168     }
169 
170     rocker_tlv_parse(tlvs, ROCKER_TLV_TX_MAX, buf, desc_tlv_size(info));
171 
172     if (!tlvs[ROCKER_TLV_TX_FRAGS]) {
173         return -ROCKER_EINVAL;
174     }
175 
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;
179     }
180 
181     if (tlvs[ROCKER_TLV_TX_OFFLOAD]) {
182         tx_offload = rocker_tlv_get_u8(tlvs[ROCKER_TLV_TX_OFFLOAD]);
183     }
184 
185     switch (tx_offload) {
186     case ROCKER_TX_OFFLOAD_L3_CSUM:
187         if (!tlvs[ROCKER_TLV_TX_L3_CSUM_OFF]) {
188             return -ROCKER_EINVAL;
189         }
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;
195         }
196         break;
197     }
198 
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);
204     }
205 
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);
210     }
211 
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);
217     }
218 
219     rocker_tlv_for_each_nested(tlv_frag, tlvs[ROCKER_TLV_TX_FRAGS], rem) {
220         hwaddr frag_addr;
221         uint16_t frag_len;
222 
223         if (rocker_tlv_type(tlv_frag) != ROCKER_TLV_TX_FRAG) {
224             err = -ROCKER_EINVAL;
225             goto err_bad_attr;
226         }
227 
228         rocker_tlv_parse_nested(tlvs, ROCKER_TLV_TX_FRAG_ATTR_MAX, tlv_frag);
229 
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;
234         }
235 
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]);
238 
239         if (iovcnt >= ROCKER_TX_FRAGS_MAX) {
240             goto err_too_many_frags;
241         }
242         iov[iovcnt].iov_len = frag_len;
243         iov[iovcnt].iov_base = g_malloc(frag_len);
244 
245         pci_dma_read(dev, frag_addr, iov[iovcnt].iov_base,
246                      iov[iovcnt].iov_len);
247 
248         iovcnt++;
249     }
250 
251     err = fp_port_eg(r->fp_port[port], iov, iovcnt);
252 
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);
257     }
258 
259     return err;
260 }
261 
cmd_get_port_settings(Rocker * r,DescInfo * info,char * buf,RockerTlv * cmd_info_tlv)262 static int cmd_get_port_settings(Rocker *r,
263                                  DescInfo *info, char *buf,
264                                  RockerTlv *cmd_info_tlv)
265 {
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;
281 
282     rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
283                             cmd_info_tlv);
284 
285     if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) {
286         return -ROCKER_EINVAL;
287     }
288 
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;
292     }
293     fp_port = r->fp_port[port];
294 
295     err = fp_port_get_settings(fp_port, &speed, &duplex, &autoneg);
296     if (err) {
297         return err;
298     }
299 
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);
304 
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));
314 
315     if (tlv_size > desc_buf_size(info)) {
316         return -ROCKER_EMSGSIZE;
317     }
318 
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);
333 
334     return desc_set_buf(info, tlv_size);
335 }
336 
cmd_set_port_settings(Rocker * r,RockerTlv * cmd_info_tlv)337 static int cmd_set_port_settings(Rocker *r,
338                                  RockerTlv *cmd_info_tlv)
339 {
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;
351 
352     rocker_tlv_parse_nested(tlvs, ROCKER_TLV_CMD_PORT_SETTINGS_MAX,
353                             cmd_info_tlv);
354 
355     if (!tlvs[ROCKER_TLV_CMD_PORT_SETTINGS_PPORT]) {
356         return -ROCKER_EINVAL;
357     }
358 
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;
362     }
363     fp_port = r->fp_port[port];
364 
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]) {
368 
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]);
372 
373         err = fp_port_set_settings(fp_port, speed, duplex, autoneg);
374         if (err) {
375             return err;
376         }
377     }
378 
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;
383         }
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);
388     }
389 
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;
394         }
395         /* We don't support world change. */
396         if (!fp_port_check_world(fp_port, r->worlds[mode])) {
397             return -ROCKER_EINVAL;
398         }
399     }
400 
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);
405     }
406 
407     return ROCKER_OK;
408 }
409 
cmd_consume(Rocker * r,DescInfo * info)410 static int cmd_consume(Rocker *r, DescInfo *info)
411 {
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;
418 
419     if (!buf) {
420         return -ROCKER_ENXIO;
421     }
422 
423     rocker_tlv_parse(tlvs, ROCKER_TLV_CMD_MAX, buf, desc_tlv_size(info));
424 
425     if (!tlvs[ROCKER_TLV_CMD_TYPE] || !tlvs[ROCKER_TLV_CMD_INFO]) {
426         return -ROCKER_EINVAL;
427     }
428 
429     cmd = rocker_tlv_get_le16(tlvs[ROCKER_TLV_CMD_TYPE]);
430     info_tlv = tlvs[ROCKER_TLV_CMD_INFO];
431 
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
438      */
439 
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;
461     }
462 
463     return err;
464 }
465 
rocker_msix_irq(Rocker * r,unsigned vector)466 static void rocker_msix_irq(Rocker *r, unsigned vector)
467 {
468     PCIDevice *dev = PCI_DEVICE(r);
469 
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;
474     }
475     msix_notify(dev, vector);
476 }
477 
rocker_event_link_changed(Rocker * r,uint32_t pport,bool link_up)478 int rocker_event_link_changed(Rocker *r, uint32_t pport, bool link_up)
479 {
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;
487 
488     if (!info) {
489         return -ROCKER_ENOBUFS;
490     }
491 
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 */
496 
497     if (tlv_size > desc_buf_size(info)) {
498         err = -ROCKER_EMSGSIZE;
499         goto err_too_big;
500     }
501 
502     buf = desc_get_buf(info, false);
503     if (!buf) {
504         err = -ROCKER_ENOMEM;
505         goto err_no_mem;
506     }
507 
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);
516 
517     err = desc_set_buf(info, tlv_size);
518 
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);
523     }
524 
525     return err;
526 }
527 
rocker_event_mac_vlan_seen(Rocker * r,uint32_t pport,uint8_t * addr,uint16_t vlan_id)528 int rocker_event_mac_vlan_seen(Rocker *r, uint32_t pport, uint8_t *addr,
529                                uint16_t vlan_id)
530 {
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;
540 
541     if (!fp_port_from_pport(pport, &port)) {
542         return -ROCKER_EINVAL;
543     }
544     fp_port = r->fp_port[port];
545     if (!fp_port_get_learning(fp_port)) {
546         return ROCKER_OK;
547     }
548 
549     info = desc_ring_fetch_desc(ring);
550     if (!info) {
551         return -ROCKER_ENOBUFS;
552     }
553 
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 */
559 
560     if (tlv_size > desc_buf_size(info)) {
561         err = -ROCKER_EMSGSIZE;
562         goto err_too_big;
563     }
564 
565     buf = desc_get_buf(info, false);
566     if (!buf) {
567         err = -ROCKER_ENOMEM;
568         goto err_no_mem;
569     }
570 
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);
579 
580     err = desc_set_buf(info, tlv_size);
581 
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);
586     }
587 
588     return err;
589 }
590 
rocker_get_rx_ring_by_pport(Rocker * r,uint32_t pport)591 static DescRing *rocker_get_rx_ring_by_pport(Rocker *r,
592                                                      uint32_t pport)
593 {
594     return r->rings[(pport - 1) * 2 + 3];
595 }
596 
rx_produce(World * world,uint32_t pport,const struct iovec * iov,int iovcnt,uint8_t copy_to_cpu)597 int rx_produce(World *world, uint32_t pport,
598                const struct iovec *iov, int iovcnt, uint8_t copy_to_cpu)
599 {
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;
615 
616     if (!info) {
617         return -ROCKER_ENOBUFS;
618     }
619 
620     buf = desc_get_buf(info, false);
621     if (!buf) {
622         err = -ROCKER_ENXIO;
623         goto out;
624     }
625     rocker_tlv_parse(tlvs, ROCKER_TLV_RX_MAX, buf, desc_tlv_size(info));
626 
627     if (!tlvs[ROCKER_TLV_RX_FRAG_ADDR] ||
628         !tlvs[ROCKER_TLV_RX_FRAG_MAX_LEN]) {
629         err = -ROCKER_EINVAL;
630         goto out;
631     }
632 
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]);
635 
636     if (data_size > frag_max_len) {
637         err = -ROCKER_EMSGSIZE;
638         goto out;
639     }
640 
641     if (copy_to_cpu) {
642         rx_flags |= ROCKER_RX_FLAGS_FWD_OFFLOAD;
643     }
644 
645     /* XXX calc rx flags/csum */
646 
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 */
652 
653     if (tlv_size > desc_buf_size(info)) {
654         err = -ROCKER_EMSGSIZE;
655         goto out;
656     }
657 
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.
662      */
663 
664     data = g_malloc(data_size);
665 
666     iov_to_buf(iov, iovcnt, 0, data, data_size);
667     pci_dma_write(dev, frag_addr, data, data_size);
668     g_free(data);
669 
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);
676 
677     err = desc_set_buf(info, tlv_size);
678 
679 out:
680     if (desc_ring_post_desc(ring, err)) {
681         rocker_msix_irq(r, ROCKER_MSIX_VEC_RX(pport - 1));
682     }
683 
684     return err;
685 }
686 
rocker_port_eg(Rocker * r,uint32_t pport,const struct iovec * iov,int iovcnt)687 int rocker_port_eg(Rocker *r, uint32_t pport,
688                    const struct iovec *iov, int iovcnt)
689 {
690     FpPort *fp_port;
691     uint32_t port;
692 
693     if (!fp_port_from_pport(pport, &port)) {
694         return -ROCKER_EINVAL;
695     }
696 
697     fp_port = r->fp_port[port];
698 
699     return fp_port_eg(fp_port, iov, iovcnt);
700 }
701 
rocker_test_dma_ctrl(Rocker * r,uint32_t val)702 static void rocker_test_dma_ctrl(Rocker *r, uint32_t val)
703 {
704     PCIDevice *dev = PCI_DEVICE(r);
705     char *buf;
706     int i;
707 
708     buf = g_malloc(r->test_dma_size);
709 
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];
721         }
722         break;
723     default:
724         DPRINTF("not test dma control val=0x%08x\n", val);
725         goto err_out;
726     }
727     pci_dma_write(dev, r->test_dma_addr, buf, r->test_dma_size);
728 
729     rocker_msix_irq(r, ROCKER_MSIX_VEC_TEST);
730 
731 err_out:
732     g_free(buf);
733 }
734 
735 static void rocker_reset(DeviceState *dev);
736 
rocker_control(Rocker * r,uint32_t val)737 static void rocker_control(Rocker *r, uint32_t val)
738 {
739     if (val & ROCKER_CONTROL_RESET) {
740         rocker_reset(DEVICE(r));
741     }
742 }
743 
rocker_pci_ring_count(Rocker * r)744 static int rocker_pci_ring_count(Rocker *r)
745 {
746     /* There are:
747      * - command ring
748      * - event ring
749      * - tx and rx ring per each port
750      */
751     return 2 + (2 * r->fp_ports);
752 }
753 
rocker_addr_is_desc_reg(Rocker * r,hwaddr addr)754 static bool rocker_addr_is_desc_reg(Rocker *r, hwaddr addr)
755 {
756     hwaddr start = ROCKER_DMA_DESC_BASE;
757     hwaddr end = start + (ROCKER_DMA_DESC_SIZE * rocker_pci_ring_count(r));
758 
759     return addr >= start && addr < end;
760 }
761 
rocker_port_phys_enable_write(Rocker * r,uint64_t new)762 static void rocker_port_phys_enable_write(Rocker *r, uint64_t new)
763 {
764     int i;
765     bool old_enabled;
766     bool new_enabled;
767     FpPort *fp_port;
768 
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;
775         }
776         if (new_enabled) {
777             fp_port_enable(r->fp_port[i]);
778         } else {
779             fp_port_disable(r->fp_port[i]);
780         }
781     }
782 }
783 
rocker_io_writel(void * opaque,hwaddr addr,uint32_t val)784 static void rocker_io_writel(void *opaque, hwaddr addr, uint32_t val)
785 {
786     Rocker *r = opaque;
787 
788     if (rocker_addr_is_desc_reg(r, addr)) {
789         unsigned index = ROCKER_RING_INDEX(addr);
790         unsigned offset = addr & ROCKER_DMA_DESC_MASK;
791 
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]));
807             }
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]));
815             }
816             break;
817         default:
818             DPRINTF("not implemented dma reg write(l) addr=0x" HWADDR_FMT_plx
819                     " val=0x%08x (ring %d, addr=0x%02x)\n",
820                     addr, val, index, offset);
821             break;
822         }
823         return;
824     }
825 
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" HWADDR_FMT_plx
861                 " val=0x%08x\n", addr, val);
862         break;
863     }
864 }
865 
rocker_io_writeq(void * opaque,hwaddr addr,uint64_t val)866 static void rocker_io_writeq(void *opaque, hwaddr addr, uint64_t val)
867 {
868     Rocker *r = opaque;
869 
870     if (rocker_addr_is_desc_reg(r, addr)) {
871         unsigned index = ROCKER_RING_INDEX(addr);
872         unsigned offset = addr & ROCKER_DMA_DESC_MASK;
873 
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" HWADDR_FMT_plx
880                     " val=0x" HWADDR_FMT_plx " (ring %d, offset=0x%02x)\n",
881                     addr, val, index, offset);
882             break;
883         }
884         return;
885     }
886 
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" HWADDR_FMT_plx
899                 " val=0x" HWADDR_FMT_plx "\n", addr, val);
900         break;
901     }
902 }
903 
904 #ifdef DEBUG_ROCKER
905 #define regname(reg) case (reg): return #reg
rocker_reg_name(void * opaque,hwaddr addr)906 static const char *rocker_reg_name(void *opaque, hwaddr addr)
907 {
908     Rocker *r = opaque;
909 
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];
915 
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);
926         }
927 
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;
953         }
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);
976         }
977     }
978     return "???";
979 }
980 #else
rocker_reg_name(void * opaque,hwaddr addr)981 static const char *rocker_reg_name(void *opaque, hwaddr addr)
982 {
983     return NULL;
984 }
985 #endif
986 
rocker_mmio_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)987 static void rocker_mmio_write(void *opaque, hwaddr addr, uint64_t val,
988                               unsigned size)
989 {
990     DPRINTF("Write %s addr " HWADDR_FMT_plx
991             ", size %u, val " HWADDR_FMT_plx "\n",
992             rocker_reg_name(opaque, addr), addr, size, val);
993 
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;
1001     }
1002 }
1003 
rocker_port_phys_link_status(Rocker * r)1004 static uint64_t rocker_port_phys_link_status(Rocker *r)
1005 {
1006     int i;
1007     uint64_t status = 0;
1008 
1009     for (i = 0; i < r->fp_ports; i++) {
1010         FpPort *port = r->fp_port[i];
1011 
1012         if (fp_port_get_link_up(port)) {
1013             status |= 1ULL << (i + 1);
1014         }
1015     }
1016     return status;
1017 }
1018 
rocker_port_phys_enable_read(Rocker * r)1019 static uint64_t rocker_port_phys_enable_read(Rocker *r)
1020 {
1021     int i;
1022     uint64_t ret = 0;
1023 
1024     for (i = 0; i < r->fp_ports; i++) {
1025         FpPort *port = r->fp_port[i];
1026 
1027         if (fp_port_enabled(port)) {
1028             ret |= 1ULL << (i + 1);
1029         }
1030     }
1031     return ret;
1032 }
1033 
rocker_io_readl(void * opaque,hwaddr addr)1034 static uint32_t rocker_io_readl(void *opaque, hwaddr addr)
1035 {
1036     Rocker *r = opaque;
1037     uint32_t ret;
1038 
1039     if (rocker_addr_is_desc_reg(r, addr)) {
1040         unsigned index = ROCKER_RING_INDEX(addr);
1041         unsigned offset = addr & ROCKER_DMA_DESC_MASK;
1042 
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" HWADDR_FMT_plx
1064                     " (ring %d, addr=0x%02x)\n", addr, index, offset);
1065             ret = 0;
1066             break;
1067         }
1068         return ret;
1069     }
1070 
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" HWADDR_FMT_plx "\n", addr);
1119         ret = 0;
1120         break;
1121     }
1122     return ret;
1123 }
1124 
rocker_io_readq(void * opaque,hwaddr addr)1125 static uint64_t rocker_io_readq(void *opaque, hwaddr addr)
1126 {
1127     Rocker *r = opaque;
1128     uint64_t ret;
1129 
1130     if (rocker_addr_is_desc_reg(r, addr)) {
1131         unsigned index = ROCKER_RING_INDEX(addr);
1132         unsigned offset = addr & ROCKER_DMA_DESC_MASK;
1133 
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" HWADDR_FMT_plx
1140                     " (ring %d, addr=0x%02x)\n", addr, index, offset);
1141             ret = 0;
1142             break;
1143         }
1144         return ret;
1145     }
1146 
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" HWADDR_FMT_plx "\n", addr);
1169         ret = 0;
1170         break;
1171     }
1172     return ret;
1173 }
1174 
rocker_mmio_read(void * opaque,hwaddr addr,unsigned size)1175 static uint64_t rocker_mmio_read(void *opaque, hwaddr addr, unsigned size)
1176 {
1177     DPRINTF("Read %s addr " HWADDR_FMT_plx ", size %u\n",
1178             rocker_reg_name(opaque, addr), addr, size);
1179 
1180     switch (size) {
1181     case 4:
1182         return rocker_io_readl(opaque, addr);
1183     case 8:
1184         return rocker_io_readq(opaque, addr);
1185     }
1186 
1187     return -1;
1188 }
1189 
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,
1197     },
1198     .impl = {
1199         .min_access_size = 4,
1200         .max_access_size = 8,
1201     },
1202 };
1203 
rocker_msix_vectors_unuse(Rocker * r,unsigned int num_vectors)1204 static void rocker_msix_vectors_unuse(Rocker *r,
1205                                       unsigned int num_vectors)
1206 {
1207     PCIDevice *dev = PCI_DEVICE(r);
1208     int i;
1209 
1210     for (i = 0; i < num_vectors; i++) {
1211         msix_vector_unuse(dev, i);
1212     }
1213 }
1214 
rocker_msix_vectors_use(Rocker * r,unsigned int num_vectors)1215 static void rocker_msix_vectors_use(Rocker *r, unsigned int num_vectors)
1216 {
1217     PCIDevice *dev = PCI_DEVICE(r);
1218     int i;
1219 
1220     for (i = 0; i < num_vectors; i++) {
1221         msix_vector_use(dev, i);
1222     }
1223 }
1224 
rocker_msix_init(Rocker * r,Error ** errp)1225 static int rocker_msix_init(Rocker *r, Error **errp)
1226 {
1227     PCIDevice *dev = PCI_DEVICE(r);
1228     int err;
1229 
1230     err = msix_init(dev, ROCKER_MSIX_VEC_COUNT(r->fp_ports),
1231                     &r->msix_bar,
1232                     ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_TABLE_OFFSET,
1233                     &r->msix_bar,
1234                     ROCKER_PCI_MSIX_BAR_IDX, ROCKER_PCI_MSIX_PBA_OFFSET,
1235                     0, errp);
1236     if (err) {
1237         return err;
1238     }
1239 
1240     rocker_msix_vectors_use(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
1241 
1242     return 0;
1243 }
1244 
rocker_msix_uninit(Rocker * r)1245 static void rocker_msix_uninit(Rocker *r)
1246 {
1247     PCIDevice *dev = PCI_DEVICE(r);
1248 
1249     msix_uninit(dev, &r->msix_bar, &r->msix_bar);
1250     rocker_msix_vectors_unuse(r, ROCKER_MSIX_VEC_COUNT(r->fp_ports));
1251 }
1252 
rocker_world_type_by_name(Rocker * r,const char * name)1253 static World *rocker_world_type_by_name(Rocker *r, const char *name)
1254 {
1255     int i;
1256 
1257     for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1258         if (strcmp(name, world_name(r->worlds[i])) == 0) {
1259             return r->worlds[i];
1260         }
1261     }
1262     return NULL;
1263 }
1264 
pci_rocker_realize(PCIDevice * dev,Error ** errp)1265 static void pci_rocker_realize(PCIDevice *dev, Error **errp)
1266 {
1267     Rocker *r = ROCKER(dev);
1268     const MACAddr zero = { .a = { 0, 0, 0, 0, 0, 0 } };
1269     const MACAddr dflt = { .a = { 0x52, 0x54, 0x00, 0x12, 0x35, 0x01 } };
1270     static int sw_index;
1271     int i, err = 0;
1272 
1273     /* allocate worlds */
1274 
1275     r->worlds[ROCKER_WORLD_TYPE_OF_DPA] = of_dpa_world_alloc(r);
1276 
1277     if (!r->world_name) {
1278         r->world_name = g_strdup(world_name(r->worlds[ROCKER_WORLD_TYPE_OF_DPA]));
1279     }
1280 
1281     r->world_dflt = rocker_world_type_by_name(r, r->world_name);
1282     if (!r->world_dflt) {
1283         error_setg(errp,
1284                 "invalid argument requested world %s does not exist",
1285                 r->world_name);
1286         goto err_world_type_by_name;
1287     }
1288 
1289     /* set up memory-mapped region at BAR0 */
1290 
1291     memory_region_init_io(&r->mmio, OBJECT(r), &rocker_mmio_ops, r,
1292                           "rocker-mmio", ROCKER_PCI_BAR0_SIZE);
1293     pci_register_bar(dev, ROCKER_PCI_BAR0_IDX,
1294                      PCI_BASE_ADDRESS_SPACE_MEMORY, &r->mmio);
1295 
1296     /* set up memory-mapped region for MSI-X */
1297 
1298     memory_region_init(&r->msix_bar, OBJECT(r), "rocker-msix-bar",
1299                        ROCKER_PCI_MSIX_BAR_SIZE);
1300     pci_register_bar(dev, ROCKER_PCI_MSIX_BAR_IDX,
1301                      PCI_BASE_ADDRESS_SPACE_MEMORY, &r->msix_bar);
1302 
1303     /* MSI-X init */
1304 
1305     err = rocker_msix_init(r, errp);
1306     if (err) {
1307         goto err_msix_init;
1308     }
1309 
1310     /* validate switch properties */
1311 
1312     if (!r->name) {
1313         r->name = g_strdup(TYPE_ROCKER);
1314     }
1315 
1316     if (rocker_find(r->name)) {
1317         error_setg(errp, "%s already exists", r->name);
1318         goto err_duplicate;
1319     }
1320 
1321     /* Rocker name is passed in port name requests to OS with the intention
1322      * that the name is used in interface names. Limit the length of the
1323      * rocker name to avoid naming problems in the OS. Also, adding the
1324      * port number as p# and unganged breakout b#, where # is at most 2
1325      * digits, so leave room for it too (-1 for string terminator, -3 for
1326      * p# and -3 for b#)
1327      */
1328 #define ROCKER_IFNAMSIZ 16
1329 #define MAX_ROCKER_NAME_LEN  (ROCKER_IFNAMSIZ - 1 - 3 - 3)
1330     if (strlen(r->name) > MAX_ROCKER_NAME_LEN) {
1331         error_setg(errp,
1332                 "name too long; please shorten to at most %d chars",
1333                 MAX_ROCKER_NAME_LEN);
1334         goto err_name_too_long;
1335     }
1336 
1337     if (memcmp(&r->fp_start_macaddr, &zero, sizeof(zero)) == 0) {
1338         memcpy(&r->fp_start_macaddr, &dflt, sizeof(dflt));
1339         r->fp_start_macaddr.a[4] += (sw_index++);
1340     }
1341 
1342     if (!r->switch_id) {
1343         memcpy(&r->switch_id, &r->fp_start_macaddr,
1344                sizeof(r->fp_start_macaddr));
1345     }
1346 
1347     if (r->fp_ports > ROCKER_FP_PORTS_MAX) {
1348         r->fp_ports = ROCKER_FP_PORTS_MAX;
1349     }
1350 
1351     r->rings = g_new(DescRing *, rocker_pci_ring_count(r));
1352 
1353     /* Rings are ordered like this:
1354      * - command ring
1355      * - event ring
1356      * - port0 tx ring
1357      * - port0 rx ring
1358      * - port1 tx ring
1359      * - port1 rx ring
1360      * .....
1361      */
1362 
1363     for (i = 0; i < rocker_pci_ring_count(r); i++) {
1364         DescRing *ring = desc_ring_alloc(r, i);
1365 
1366         if (i == ROCKER_RING_CMD) {
1367             desc_ring_set_consume(ring, cmd_consume, ROCKER_MSIX_VEC_CMD);
1368         } else if (i == ROCKER_RING_EVENT) {
1369             desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_EVENT);
1370         } else if (i % 2 == 0) {
1371             desc_ring_set_consume(ring, tx_consume,
1372                                   ROCKER_MSIX_VEC_TX((i - 2) / 2));
1373         } else if (i % 2 == 1) {
1374             desc_ring_set_consume(ring, NULL, ROCKER_MSIX_VEC_RX((i - 3) / 2));
1375         }
1376 
1377         r->rings[i] = ring;
1378     }
1379 
1380     for (i = 0; i < r->fp_ports; i++) {
1381         FpPort *port =
1382             fp_port_alloc(r, r->name, &r->fp_start_macaddr,
1383                           i, &r->fp_ports_peers[i]);
1384 
1385         r->fp_port[i] = port;
1386         fp_port_set_world(port, r->world_dflt);
1387     }
1388 
1389     QLIST_INSERT_HEAD(&rockers, r, next);
1390 
1391     return;
1392 
1393 err_name_too_long:
1394 err_duplicate:
1395     rocker_msix_uninit(r);
1396 err_msix_init:
1397     object_unparent(OBJECT(&r->msix_bar));
1398     object_unparent(OBJECT(&r->mmio));
1399 err_world_type_by_name:
1400     for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1401         if (r->worlds[i]) {
1402             world_free(r->worlds[i]);
1403         }
1404     }
1405 }
1406 
pci_rocker_uninit(PCIDevice * dev)1407 static void pci_rocker_uninit(PCIDevice *dev)
1408 {
1409     Rocker *r = ROCKER(dev);
1410     int i;
1411 
1412     QLIST_REMOVE(r, next);
1413 
1414     for (i = 0; i < r->fp_ports; i++) {
1415         FpPort *port = r->fp_port[i];
1416 
1417         fp_port_free(port);
1418         r->fp_port[i] = NULL;
1419     }
1420 
1421     for (i = 0; i < rocker_pci_ring_count(r); i++) {
1422         if (r->rings[i]) {
1423             desc_ring_free(r->rings[i]);
1424         }
1425     }
1426     g_free(r->rings);
1427 
1428     rocker_msix_uninit(r);
1429     object_unparent(OBJECT(&r->msix_bar));
1430     object_unparent(OBJECT(&r->mmio));
1431 
1432     for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1433         if (r->worlds[i]) {
1434             world_free(r->worlds[i]);
1435         }
1436     }
1437     g_free(r->fp_ports_peers);
1438 }
1439 
rocker_reset(DeviceState * dev)1440 static void rocker_reset(DeviceState *dev)
1441 {
1442     Rocker *r = ROCKER(dev);
1443     int i;
1444 
1445     for (i = 0; i < ROCKER_WORLD_TYPE_MAX; i++) {
1446         if (r->worlds[i]) {
1447             world_reset(r->worlds[i]);
1448         }
1449     }
1450     for (i = 0; i < r->fp_ports; i++) {
1451         fp_port_reset(r->fp_port[i]);
1452         fp_port_set_world(r->fp_port[i], r->world_dflt);
1453     }
1454 
1455     r->test_reg = 0;
1456     r->test_reg64 = 0;
1457     r->test_dma_addr = 0;
1458     r->test_dma_size = 0;
1459 
1460     for (i = 0; i < rocker_pci_ring_count(r); i++) {
1461         desc_ring_reset(r->rings[i]);
1462     }
1463 
1464     DPRINTF("Reset done\n");
1465 }
1466 
1467 static Property rocker_properties[] = {
1468     DEFINE_PROP_STRING("name", Rocker, name),
1469     DEFINE_PROP_STRING("world", Rocker, world_name),
1470     DEFINE_PROP_MACADDR("fp_start_macaddr", Rocker,
1471                         fp_start_macaddr),
1472     DEFINE_PROP_UINT64("switch_id", Rocker,
1473                        switch_id, 0),
1474     DEFINE_PROP_ARRAY("ports", Rocker, fp_ports,
1475                       fp_ports_peers, qdev_prop_netdev, NICPeers),
1476     DEFINE_PROP_END_OF_LIST(),
1477 };
1478 
1479 static const VMStateDescription rocker_vmsd = {
1480     .name = TYPE_ROCKER,
1481     .unmigratable = 1,
1482 };
1483 
rocker_class_init(ObjectClass * klass,void * data)1484 static void rocker_class_init(ObjectClass *klass, void *data)
1485 {
1486     DeviceClass *dc = DEVICE_CLASS(klass);
1487     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1488 
1489     k->realize = pci_rocker_realize;
1490     k->exit = pci_rocker_uninit;
1491     k->vendor_id = PCI_VENDOR_ID_REDHAT;
1492     k->device_id = PCI_DEVICE_ID_REDHAT_ROCKER;
1493     k->revision = ROCKER_PCI_REVISION;
1494     k->class_id = PCI_CLASS_NETWORK_OTHER;
1495     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1496     dc->desc = "Rocker Switch";
1497     dc->reset = rocker_reset;
1498     device_class_set_props(dc, rocker_properties);
1499     dc->vmsd = &rocker_vmsd;
1500 }
1501 
1502 static const TypeInfo rocker_info = {
1503     .name          = TYPE_ROCKER,
1504     .parent        = TYPE_PCI_DEVICE,
1505     .instance_size = sizeof(Rocker),
1506     .class_init    = rocker_class_init,
1507     .interfaces = (InterfaceInfo[]) {
1508         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
1509         { },
1510     },
1511 };
1512 
rocker_register_types(void)1513 static void rocker_register_types(void)
1514 {
1515     type_register_static(&rocker_info);
1516 }
1517 
1518 type_init(rocker_register_types)
1519