xref: /qemu/hw/net/xilinx_ethlite.c (revision 30ee88622edfa962154222b4a674361488ed823b)
1  /*
2   * QEMU model of the Xilinx Ethernet Lite MAC.
3   *
4   * Copyright (c) 2009 Edgar E. Iglesias.
5   * Copyright (c) 2024 Linaro, Ltd
6   *
7   * DS580: https://docs.amd.com/v/u/en-US/xps_ethernetlite
8   * LogiCORE IP XPS Ethernet Lite Media Access Controller
9   *
10   * Permission is hereby granted, free of charge, to any person obtaining a copy
11   * of this software and associated documentation files (the "Software"), to deal
12   * in the Software without restriction, including without limitation the rights
13   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14   * copies of the Software, and to permit persons to whom the Software is
15   * furnished to do so, subject to the following conditions:
16   *
17   * The above copyright notice and this permission notice shall be included in
18   * all copies or substantial portions of the Software.
19   *
20   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26   * THE SOFTWARE.
27   */
28  
29  #include "qemu/osdep.h"
30  #include "qemu/module.h"
31  #include "qemu/bitops.h"
32  #include "qom/object.h"
33  #include "qapi/error.h"
34  #include "hw/sysbus.h"
35  #include "hw/irq.h"
36  #include "hw/qdev-properties.h"
37  #include "hw/misc/unimp.h"
38  #include "net/net.h"
39  #include "trace.h"
40  
41  #define BUFSZ_MAX      0x07e4
42  #define A_MDIO_BASE    0x07e4
43  #define A_TX_BASE0     0x07f4
44  #define A_TX_BASE1     0x0ff4
45  #define A_RX_BASE0     0x17fc
46  #define A_RX_BASE1     0x1ffc
47  
48  enum {
49      TX_LEN =  0,
50      TX_GIE =  1,
51      TX_CTRL = 2,
52      TX_MAX
53  };
54  
55  enum {
56      RX_CTRL = 0,
57      RX_MAX
58  };
59  
60  #define GIE_GIE    0x80000000
61  
62  #define CTRL_I     0x8
63  #define CTRL_P     0x2
64  #define CTRL_S     0x1
65  
66  typedef struct XlnxXpsEthLitePort {
67      MemoryRegion txio;
68      MemoryRegion rxio;
69      MemoryRegion txbuf;
70      MemoryRegion rxbuf;
71  
72      struct {
73          uint32_t tx_len;
74          uint32_t tx_gie;
75          uint32_t tx_ctrl;
76  
77          uint32_t rx_ctrl;
78      } reg;
79  } XlnxXpsEthLitePort;
80  
81  #define TYPE_XILINX_ETHLITE "xlnx.xps-ethernetlite"
82  OBJECT_DECLARE_SIMPLE_TYPE(XlnxXpsEthLite, XILINX_ETHLITE)
83  
84  struct XlnxXpsEthLite
85  {
86      SysBusDevice parent_obj;
87  
88      MemoryRegion container;
89      qemu_irq irq;
90      NICState *nic;
91      NICConf conf;
92  
93      uint32_t c_tx_pingpong;
94      uint32_t c_rx_pingpong;
95      unsigned int port_index; /* dual port RAM index */
96  
97      UnimplementedDeviceState rsvd;
98      UnimplementedDeviceState mdio;
99      XlnxXpsEthLitePort port[2];
100  };
101  
102  static inline void eth_pulse_irq(XlnxXpsEthLite *s)
103  {
104      /* Only the first gie reg is active.  */
105      if (s->port[0].reg.tx_gie & GIE_GIE) {
106          qemu_irq_pulse(s->irq);
107      }
108  }
109  
110  static unsigned addr_to_port_index(hwaddr addr)
111  {
112      return extract64(addr, 11, 1);
113  }
114  
115  static void *txbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
116  {
117      return memory_region_get_ram_ptr(&s->port[port_index].txbuf);
118  }
119  
120  static void *rxbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
121  {
122      return memory_region_get_ram_ptr(&s->port[port_index].rxbuf);
123  }
124  
125  static uint64_t port_tx_read(void *opaque, hwaddr addr, unsigned int size)
126  {
127      XlnxXpsEthLite *s = opaque;
128      unsigned port_index = addr_to_port_index(addr);
129      uint32_t r = 0;
130  
131      switch (addr >> 2) {
132      case TX_LEN:
133          r = s->port[port_index].reg.tx_len;
134          break;
135      case TX_GIE:
136          r = s->port[port_index].reg.tx_gie;
137          break;
138      case TX_CTRL:
139          r = s->port[port_index].reg.tx_ctrl;
140          break;
141      default:
142          g_assert_not_reached();
143      }
144  
145      return r;
146  }
147  
148  static void port_tx_write(void *opaque, hwaddr addr, uint64_t value,
149                            unsigned int size)
150  {
151      XlnxXpsEthLite *s = opaque;
152      unsigned port_index = addr_to_port_index(addr);
153  
154      switch (addr >> 2) {
155      case TX_LEN:
156          s->port[port_index].reg.tx_len = value;
157          break;
158      case TX_GIE:
159          s->port[port_index].reg.tx_gie = value;
160          break;
161      case TX_CTRL:
162          if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
163              qemu_send_packet(qemu_get_queue(s->nic),
164                               txbuf_ptr(s, port_index),
165                               s->port[port_index].reg.tx_len);
166              if (s->port[port_index].reg.tx_ctrl & CTRL_I) {
167                  eth_pulse_irq(s);
168              }
169          } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
170              memcpy(&s->conf.macaddr.a[0], txbuf_ptr(s, port_index), 6);
171              if (s->port[port_index].reg.tx_ctrl & CTRL_I) {
172                  eth_pulse_irq(s);
173              }
174          }
175          /*
176           * We are fast and get ready pretty much immediately
177           * so we actually never flip the S nor P bits to one.
178           */
179          s->port[port_index].reg.tx_ctrl = value & ~(CTRL_P | CTRL_S);
180          break;
181      default:
182          g_assert_not_reached();
183      }
184  }
185  
186  static const MemoryRegionOps eth_porttx_ops = {
187          .read = port_tx_read,
188          .write = port_tx_write,
189          .endianness = DEVICE_NATIVE_ENDIAN,
190          .impl = {
191              .min_access_size = 4,
192              .max_access_size = 4,
193          },
194          .valid = {
195              .min_access_size = 4,
196              .max_access_size = 4,
197          },
198  };
199  
200  static uint64_t port_rx_read(void *opaque, hwaddr addr, unsigned int size)
201  {
202      XlnxXpsEthLite *s = opaque;
203      unsigned port_index = addr_to_port_index(addr);
204      uint32_t r = 0;
205  
206      switch (addr >> 2) {
207      case RX_CTRL:
208          r = s->port[port_index].reg.rx_ctrl;
209          break;
210      default:
211          g_assert_not_reached();
212      }
213  
214      return r;
215  }
216  
217  static void port_rx_write(void *opaque, hwaddr addr, uint64_t value,
218                            unsigned int size)
219  {
220      XlnxXpsEthLite *s = opaque;
221      unsigned port_index = addr_to_port_index(addr);
222  
223      switch (addr >> 2) {
224      case RX_CTRL:
225          if (!(value & CTRL_S)) {
226              qemu_flush_queued_packets(qemu_get_queue(s->nic));
227          }
228          s->port[port_index].reg.rx_ctrl = value;
229          break;
230      default:
231          g_assert_not_reached();
232      }
233  }
234  
235  static const MemoryRegionOps eth_portrx_ops = {
236          .read = port_rx_read,
237          .write = port_rx_write,
238          .endianness = DEVICE_NATIVE_ENDIAN,
239          .impl = {
240              .min_access_size = 4,
241              .max_access_size = 4,
242          },
243          .valid = {
244              .min_access_size = 4,
245              .max_access_size = 4,
246          },
247  };
248  
249  static bool eth_can_rx(NetClientState *nc)
250  {
251      XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
252  
253      return !(s->port[s->port_index].reg.rx_ctrl & CTRL_S);
254  }
255  
256  static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
257  {
258      XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
259      unsigned int port_index = s->port_index;
260  
261      /* DA filter.  */
262      if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
263          return size;
264  
265      if (s->port[port_index].reg.rx_ctrl & CTRL_S) {
266          trace_ethlite_pkt_lost(s->port[port_index].reg.rx_ctrl);
267          return -1;
268      }
269  
270      if (size >= BUFSZ_MAX) {
271          trace_ethlite_pkt_size_too_big(size);
272          return -1;
273      }
274      memcpy(rxbuf_ptr(s, port_index), buf, size);
275  
276      s->port[port_index].reg.rx_ctrl |= CTRL_S;
277      if (s->port[port_index].reg.rx_ctrl & CTRL_I) {
278          eth_pulse_irq(s);
279      }
280  
281      /* If c_rx_pingpong was set flip buffers.  */
282      s->port_index ^= s->c_rx_pingpong;
283      return size;
284  }
285  
286  static void xilinx_ethlite_reset(DeviceState *dev)
287  {
288      XlnxXpsEthLite *s = XILINX_ETHLITE(dev);
289  
290      s->port_index = 0;
291  }
292  
293  static NetClientInfo net_xilinx_ethlite_info = {
294      .type = NET_CLIENT_DRIVER_NIC,
295      .size = sizeof(NICState),
296      .can_receive = eth_can_rx,
297      .receive = eth_rx,
298  };
299  
300  static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
301  {
302      XlnxXpsEthLite *s = XILINX_ETHLITE(dev);
303  
304      memory_region_init(&s->container, OBJECT(dev),
305                         "xlnx.xps-ethernetlite", 0x2000);
306  
307      object_initialize_child(OBJECT(dev), "ethlite.reserved", &s->rsvd,
308                              TYPE_UNIMPLEMENTED_DEVICE);
309      qdev_prop_set_string(DEVICE(&s->rsvd), "name", "ethlite.reserved");
310      qdev_prop_set_uint64(DEVICE(&s->rsvd), "size",
311                           memory_region_size(&s->container));
312      sysbus_realize(SYS_BUS_DEVICE(&s->rsvd), &error_fatal);
313      memory_region_add_subregion_overlap(&s->container, 0,
314                             sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->rsvd), 0),
315                             -1);
316  
317      object_initialize_child(OBJECT(dev), "ethlite.mdio", &s->mdio,
318                              TYPE_UNIMPLEMENTED_DEVICE);
319      qdev_prop_set_string(DEVICE(&s->mdio), "name", "ethlite.mdio");
320      qdev_prop_set_uint64(DEVICE(&s->mdio), "size", 4 * 4);
321      sysbus_realize(SYS_BUS_DEVICE(&s->mdio), &error_fatal);
322      memory_region_add_subregion(&s->container, A_MDIO_BASE,
323                             sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mdio), 0));
324  
325      for (unsigned i = 0; i < 2; i++) {
326          memory_region_init_ram(&s->port[i].txbuf, OBJECT(dev),
327                                 i ? "ethlite.tx[1]buf" : "ethlite.tx[0]buf",
328                                 BUFSZ_MAX, &error_abort);
329          memory_region_add_subregion(&s->container, 0x0800 * i, &s->port[i].txbuf);
330          memory_region_init_io(&s->port[i].txio, OBJECT(dev),
331                                &eth_porttx_ops, s,
332                                i ? "ethlite.tx[1]io" : "ethlite.tx[0]io",
333                                4 * TX_MAX);
334          memory_region_add_subregion(&s->container, i ? A_TX_BASE1 : A_TX_BASE0,
335                                      &s->port[i].txio);
336  
337          memory_region_init_ram(&s->port[i].rxbuf, OBJECT(dev),
338                                 i ? "ethlite.rx[1]buf" : "ethlite.rx[0]buf",
339                                 BUFSZ_MAX, &error_abort);
340          memory_region_add_subregion(&s->container, 0x1000 + 0x0800 * i,
341                                      &s->port[i].rxbuf);
342          memory_region_init_io(&s->port[i].rxio, OBJECT(dev),
343                                &eth_portrx_ops, s,
344                                i ? "ethlite.rx[1]io" : "ethlite.rx[0]io",
345                                4 * RX_MAX);
346          memory_region_add_subregion(&s->container, i ? A_RX_BASE1 : A_RX_BASE0,
347                                      &s->port[i].rxio);
348      }
349  
350      qemu_macaddr_default_if_unset(&s->conf.macaddr);
351      s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
352                            object_get_typename(OBJECT(dev)), dev->id,
353                            &dev->mem_reentrancy_guard, s);
354      qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
355  }
356  
357  static void xilinx_ethlite_init(Object *obj)
358  {
359      XlnxXpsEthLite *s = XILINX_ETHLITE(obj);
360  
361      sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
362      sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->container);
363  }
364  
365  static const Property xilinx_ethlite_properties[] = {
366      DEFINE_PROP_UINT32("tx-ping-pong", XlnxXpsEthLite, c_tx_pingpong, 1),
367      DEFINE_PROP_UINT32("rx-ping-pong", XlnxXpsEthLite, c_rx_pingpong, 1),
368      DEFINE_NIC_PROPERTIES(XlnxXpsEthLite, conf),
369  };
370  
371  static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
372  {
373      DeviceClass *dc = DEVICE_CLASS(klass);
374  
375      dc->realize = xilinx_ethlite_realize;
376      device_class_set_legacy_reset(dc, xilinx_ethlite_reset);
377      device_class_set_props(dc, xilinx_ethlite_properties);
378  }
379  
380  static const TypeInfo xilinx_ethlite_types[] = {
381      {
382          .name          = TYPE_XILINX_ETHLITE,
383          .parent        = TYPE_SYS_BUS_DEVICE,
384          .instance_size = sizeof(XlnxXpsEthLite),
385          .instance_init = xilinx_ethlite_init,
386          .class_init    = xilinx_ethlite_class_init,
387      },
388  };
389  
390  DEFINE_TYPES(xilinx_ethlite_types)
391