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