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