xref: /openbmc/qemu/hw/net/xilinx_ethlite.c (revision a34606dbb3c7094b6e9fde5e1463a306b6921255)
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_BUF1     (0x0800 / 4)
46 #define A_TX_BASE1     0x0ff4
47 
48 #define R_RX_BUF0     (0x1000 / 4)
49 #define A_RX_BASE0     0x17fc
50 #define R_RX_BUF1     (0x1800 / 4)
51 #define A_RX_BASE1     0x1ffc
52 #define R_MAX         (0x2000 / 4)
53 
54 enum {
55     TX_LEN =  0,
56     TX_GIE =  1,
57     TX_CTRL = 2,
58     TX_MAX
59 };
60 
61 enum {
62     RX_CTRL = 0,
63     RX_MAX
64 };
65 
66 #define GIE_GIE    0x80000000
67 
68 #define CTRL_I     0x8
69 #define CTRL_P     0x2
70 #define CTRL_S     0x1
71 
72 typedef struct XlnxXpsEthLitePort {
73     MemoryRegion txio;
74     MemoryRegion rxio;
75 
76     struct {
77         uint32_t tx_len;
78         uint32_t tx_gie;
79         uint32_t tx_ctrl;
80 
81         uint32_t rx_ctrl;
82     } reg;
83 } XlnxXpsEthLitePort;
84 
85 #define TYPE_XILINX_ETHLITE "xlnx.xps-ethernetlite"
86 OBJECT_DECLARE_SIMPLE_TYPE(XlnxXpsEthLite, XILINX_ETHLITE)
87 
88 struct XlnxXpsEthLite
89 {
90     SysBusDevice parent_obj;
91 
92     MemoryRegion mmio;
93     qemu_irq irq;
94     NICState *nic;
95     NICConf conf;
96 
97     uint32_t c_tx_pingpong;
98     uint32_t c_rx_pingpong;
99     unsigned int port_index; /* dual port RAM index */
100 
101     UnimplementedDeviceState mdio;
102     XlnxXpsEthLitePort port[2];
103     uint32_t regs[R_MAX];
104 };
105 
106 static inline void eth_pulse_irq(XlnxXpsEthLite *s)
107 {
108     /* Only the first gie reg is active.  */
109     if (s->port[0].reg.tx_gie & GIE_GIE) {
110         qemu_irq_pulse(s->irq);
111     }
112 }
113 
114 static unsigned addr_to_port_index(hwaddr addr)
115 {
116     return extract64(addr, 11, 1);
117 }
118 
119 static void *txbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
120 {
121     unsigned int rxbase = port_index * (0x800 / 4);
122 
123     return &s->regs[rxbase + R_TX_BUF0];
124 }
125 
126 static void *rxbuf_ptr(XlnxXpsEthLite *s, unsigned port_index)
127 {
128     unsigned int rxbase = port_index * (0x800 / 4);
129 
130     return &s->regs[rxbase + R_RX_BUF0];
131 }
132 
133 static uint64_t port_tx_read(void *opaque, hwaddr addr, unsigned int size)
134 {
135     XlnxXpsEthLite *s = opaque;
136     unsigned port_index = addr_to_port_index(addr);
137     uint32_t r = 0;
138 
139     switch (addr >> 2) {
140     case TX_LEN:
141         r = s->port[port_index].reg.tx_len;
142         break;
143     case TX_GIE:
144         r = s->port[port_index].reg.tx_gie;
145         break;
146     case TX_CTRL:
147         r = s->port[port_index].reg.tx_ctrl;
148         break;
149     default:
150         g_assert_not_reached();
151     }
152 
153     return r;
154 }
155 
156 static void port_tx_write(void *opaque, hwaddr addr, uint64_t value,
157                           unsigned int size)
158 {
159     XlnxXpsEthLite *s = opaque;
160     unsigned port_index = addr_to_port_index(addr);
161 
162     switch (addr >> 2) {
163     case TX_LEN:
164         s->port[port_index].reg.tx_len = value;
165         break;
166     case TX_GIE:
167         s->port[port_index].reg.tx_gie = value;
168         break;
169     case TX_CTRL:
170         if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
171             qemu_send_packet(qemu_get_queue(s->nic),
172                              txbuf_ptr(s, port_index),
173                              s->port[port_index].reg.tx_len);
174             if (s->port[port_index].reg.tx_ctrl & CTRL_I) {
175                 eth_pulse_irq(s);
176             }
177         } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
178             memcpy(&s->conf.macaddr.a[0], txbuf_ptr(s, port_index), 6);
179             if (s->port[port_index].reg.tx_ctrl & CTRL_I) {
180                 eth_pulse_irq(s);
181             }
182         }
183         /*
184          * We are fast and get ready pretty much immediately
185          * so we actually never flip the S nor P bits to one.
186          */
187         s->port[port_index].reg.tx_ctrl = value & ~(CTRL_P | CTRL_S);
188         break;
189     default:
190         g_assert_not_reached();
191     }
192 }
193 
194 static const MemoryRegionOps eth_porttx_ops = {
195         .read = port_tx_read,
196         .write = port_tx_write,
197         .endianness = DEVICE_NATIVE_ENDIAN,
198         .impl = {
199             .min_access_size = 4,
200             .max_access_size = 4,
201         },
202         .valid = {
203             .min_access_size = 4,
204             .max_access_size = 4,
205         },
206 };
207 
208 static uint64_t port_rx_read(void *opaque, hwaddr addr, unsigned int size)
209 {
210     XlnxXpsEthLite *s = opaque;
211     unsigned port_index = addr_to_port_index(addr);
212     uint32_t r = 0;
213 
214     switch (addr >> 2) {
215     case RX_CTRL:
216         r = s->port[port_index].reg.rx_ctrl;
217         break;
218     default:
219         g_assert_not_reached();
220     }
221 
222     return r;
223 }
224 
225 static void port_rx_write(void *opaque, hwaddr addr, uint64_t value,
226                           unsigned int size)
227 {
228     XlnxXpsEthLite *s = opaque;
229     unsigned port_index = addr_to_port_index(addr);
230 
231     switch (addr >> 2) {
232     case RX_CTRL:
233         if (!(value & CTRL_S)) {
234             qemu_flush_queued_packets(qemu_get_queue(s->nic));
235         }
236         s->port[port_index].reg.rx_ctrl = value;
237         break;
238     default:
239         g_assert_not_reached();
240     }
241 }
242 
243 static const MemoryRegionOps eth_portrx_ops = {
244         .read = port_rx_read,
245         .write = port_rx_write,
246         .endianness = DEVICE_NATIVE_ENDIAN,
247         .impl = {
248             .min_access_size = 4,
249             .max_access_size = 4,
250         },
251         .valid = {
252             .min_access_size = 4,
253             .max_access_size = 4,
254         },
255 };
256 
257 static uint64_t
258 eth_read(void *opaque, hwaddr addr, unsigned int size)
259 {
260     XlnxXpsEthLite *s = opaque;
261     uint32_t r = 0;
262 
263     addr >>= 2;
264 
265     switch (addr)
266     {
267         default:
268             r = tswap32(s->regs[addr]);
269             break;
270     }
271     return r;
272 }
273 
274 static void
275 eth_write(void *opaque, hwaddr addr,
276           uint64_t val64, unsigned int size)
277 {
278     XlnxXpsEthLite *s = opaque;
279     uint32_t value = val64;
280 
281     addr >>= 2;
282     switch (addr)
283     {
284         default:
285             s->regs[addr] = tswap32(value);
286             break;
287     }
288 }
289 
290 static const MemoryRegionOps eth_ops = {
291     .read = eth_read,
292     .write = eth_write,
293     .endianness = DEVICE_NATIVE_ENDIAN,
294     .impl = {
295         .min_access_size = 4,
296         .max_access_size = 4,
297     },
298     .valid = {
299         .min_access_size = 4,
300         .max_access_size = 4
301     }
302 };
303 
304 static bool eth_can_rx(NetClientState *nc)
305 {
306     XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
307 
308     return !(s->port[s->port_index].reg.rx_ctrl & CTRL_S);
309 }
310 
311 static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
312 {
313     XlnxXpsEthLite *s = qemu_get_nic_opaque(nc);
314     unsigned int port_index = s->port_index;
315 
316     /* DA filter.  */
317     if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
318         return size;
319 
320     if (s->port[port_index].reg.rx_ctrl & CTRL_S) {
321         trace_ethlite_pkt_lost(s->port[port_index].reg.rx_ctrl);
322         return -1;
323     }
324 
325     if (size >= BUFSZ_MAX) {
326         trace_ethlite_pkt_size_too_big(size);
327         return -1;
328     }
329     memcpy(rxbuf_ptr(s, port_index), buf, size);
330 
331     s->port[port_index].reg.rx_ctrl |= CTRL_S;
332     if (s->port[port_index].reg.rx_ctrl & CTRL_I) {
333         eth_pulse_irq(s);
334     }
335 
336     /* If c_rx_pingpong was set flip buffers.  */
337     s->port_index ^= s->c_rx_pingpong;
338     return size;
339 }
340 
341 static void xilinx_ethlite_reset(DeviceState *dev)
342 {
343     XlnxXpsEthLite *s = XILINX_ETHLITE(dev);
344 
345     s->port_index = 0;
346 }
347 
348 static NetClientInfo net_xilinx_ethlite_info = {
349     .type = NET_CLIENT_DRIVER_NIC,
350     .size = sizeof(NICState),
351     .can_receive = eth_can_rx,
352     .receive = eth_rx,
353 };
354 
355 static void xilinx_ethlite_realize(DeviceState *dev, Error **errp)
356 {
357     XlnxXpsEthLite *s = XILINX_ETHLITE(dev);
358 
359     object_initialize_child(OBJECT(dev), "ethlite.mdio", &s->mdio,
360                             TYPE_UNIMPLEMENTED_DEVICE);
361     qdev_prop_set_string(DEVICE(&s->mdio), "name", "ethlite.mdio");
362     qdev_prop_set_uint64(DEVICE(&s->mdio), "size", 4 * 4);
363     sysbus_realize(SYS_BUS_DEVICE(&s->mdio), &error_fatal);
364     memory_region_add_subregion(&s->mmio, A_MDIO_BASE,
365                            sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mdio), 0));
366 
367     for (unsigned i = 0; i < 2; i++) {
368         memory_region_init_io(&s->port[i].txio, OBJECT(dev),
369                               &eth_porttx_ops, s,
370                               i ? "ethlite.tx[1]io" : "ethlite.tx[0]io",
371                               4 * TX_MAX);
372         memory_region_add_subregion(&s->mmio, i ? A_TX_BASE1 : A_TX_BASE0,
373                                     &s->port[i].txio);
374 
375         memory_region_init_io(&s->port[i].rxio, OBJECT(dev),
376                               &eth_portrx_ops, s,
377                               i ? "ethlite.rx[1]io" : "ethlite.rx[0]io",
378                               4 * RX_MAX);
379         memory_region_add_subregion(&s->mmio, i ? A_RX_BASE1 : A_RX_BASE0,
380                                     &s->port[i].rxio);
381     }
382 
383     qemu_macaddr_default_if_unset(&s->conf.macaddr);
384     s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
385                           object_get_typename(OBJECT(dev)), dev->id,
386                           &dev->mem_reentrancy_guard, s);
387     qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
388 }
389 
390 static void xilinx_ethlite_init(Object *obj)
391 {
392     XlnxXpsEthLite *s = XILINX_ETHLITE(obj);
393 
394     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
395 
396     memory_region_init_io(&s->mmio, obj, &eth_ops, s,
397                           "xlnx.xps-ethernetlite", R_MAX * 4);
398     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
399 }
400 
401 static const Property xilinx_ethlite_properties[] = {
402     DEFINE_PROP_UINT32("tx-ping-pong", XlnxXpsEthLite, c_tx_pingpong, 1),
403     DEFINE_PROP_UINT32("rx-ping-pong", XlnxXpsEthLite, c_rx_pingpong, 1),
404     DEFINE_NIC_PROPERTIES(XlnxXpsEthLite, conf),
405 };
406 
407 static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
408 {
409     DeviceClass *dc = DEVICE_CLASS(klass);
410 
411     dc->realize = xilinx_ethlite_realize;
412     device_class_set_legacy_reset(dc, xilinx_ethlite_reset);
413     device_class_set_props(dc, xilinx_ethlite_properties);
414 }
415 
416 static const TypeInfo xilinx_ethlite_types[] = {
417     {
418         .name          = TYPE_XILINX_ETHLITE,
419         .parent        = TYPE_SYS_BUS_DEVICE,
420         .instance_size = sizeof(XlnxXpsEthLite),
421         .instance_init = xilinx_ethlite_init,
422         .class_init    = xilinx_ethlite_class_init,
423     },
424 };
425 
426 DEFINE_TYPES(xilinx_ethlite_types)
427