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 mmio; 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 mdio; 98 XlnxXpsEthLitePort port[2]; 99 }; 100 101 static inline void eth_pulse_irq(XlnxXpsEthLite *s) 102 { 103 /* Only the first gie reg is active. */ 104 if (s->port[0].reg.tx_gie & GIE_GIE) { 105 qemu_irq_pulse(s->irq); 106 } 107 } 108 109 static unsigned addr_to_port_index(hwaddr addr) 110 { 111 return extract64(addr, 11, 1); 112 } 113 114 static void *txbuf_ptr(XlnxXpsEthLite *s, unsigned port_index) 115 { 116 return memory_region_get_ram_ptr(&s->port[port_index].txbuf); 117 } 118 119 static void *rxbuf_ptr(XlnxXpsEthLite *s, unsigned port_index) 120 { 121 return memory_region_get_ram_ptr(&s->port[port_index].rxbuf); 122 } 123 124 static uint64_t port_tx_read(void *opaque, hwaddr addr, unsigned int size) 125 { 126 XlnxXpsEthLite *s = opaque; 127 unsigned port_index = addr_to_port_index(addr); 128 uint32_t r = 0; 129 130 switch (addr >> 2) { 131 case TX_LEN: 132 r = s->port[port_index].reg.tx_len; 133 break; 134 case TX_GIE: 135 r = s->port[port_index].reg.tx_gie; 136 break; 137 case TX_CTRL: 138 r = s->port[port_index].reg.tx_ctrl; 139 break; 140 default: 141 g_assert_not_reached(); 142 } 143 144 return r; 145 } 146 147 static void port_tx_write(void *opaque, hwaddr addr, uint64_t value, 148 unsigned int size) 149 { 150 XlnxXpsEthLite *s = opaque; 151 unsigned port_index = addr_to_port_index(addr); 152 153 switch (addr >> 2) { 154 case TX_LEN: 155 s->port[port_index].reg.tx_len = value; 156 break; 157 case TX_GIE: 158 s->port[port_index].reg.tx_gie = value; 159 break; 160 case TX_CTRL: 161 if ((value & (CTRL_P | CTRL_S)) == CTRL_S) { 162 qemu_send_packet(qemu_get_queue(s->nic), 163 txbuf_ptr(s, port_index), 164 s->port[port_index].reg.tx_len); 165 if (s->port[port_index].reg.tx_ctrl & CTRL_I) { 166 eth_pulse_irq(s); 167 } 168 } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) { 169 memcpy(&s->conf.macaddr.a[0], txbuf_ptr(s, port_index), 6); 170 if (s->port[port_index].reg.tx_ctrl & CTRL_I) { 171 eth_pulse_irq(s); 172 } 173 } 174 /* 175 * We are fast and get ready pretty much immediately 176 * so we actually never flip the S nor P bits to one. 177 */ 178 s->port[port_index].reg.tx_ctrl = value & ~(CTRL_P | CTRL_S); 179 break; 180 default: 181 g_assert_not_reached(); 182 } 183 } 184 185 static const MemoryRegionOps eth_porttx_ops = { 186 .read = port_tx_read, 187 .write = port_tx_write, 188 .endianness = DEVICE_NATIVE_ENDIAN, 189 .impl = { 190 .min_access_size = 4, 191 .max_access_size = 4, 192 }, 193 .valid = { 194 .min_access_size = 4, 195 .max_access_size = 4, 196 }, 197 }; 198 199 static uint64_t port_rx_read(void *opaque, hwaddr addr, unsigned int size) 200 { 201 XlnxXpsEthLite *s = opaque; 202 unsigned port_index = addr_to_port_index(addr); 203 uint32_t r = 0; 204 205 switch (addr >> 2) { 206 case RX_CTRL: 207 r = s->port[port_index].reg.rx_ctrl; 208 break; 209 default: 210 g_assert_not_reached(); 211 } 212 213 return r; 214 } 215 216 static void port_rx_write(void *opaque, hwaddr addr, uint64_t value, 217 unsigned int size) 218 { 219 XlnxXpsEthLite *s = opaque; 220 unsigned port_index = addr_to_port_index(addr); 221 222 switch (addr >> 2) { 223 case RX_CTRL: 224 if (!(value & CTRL_S)) { 225 qemu_flush_queued_packets(qemu_get_queue(s->nic)); 226 } 227 s->port[port_index].reg.rx_ctrl = value; 228 break; 229 default: 230 g_assert_not_reached(); 231 } 232 } 233 234 static const MemoryRegionOps eth_portrx_ops = { 235 .read = port_rx_read, 236 .write = port_rx_write, 237 .endianness = DEVICE_NATIVE_ENDIAN, 238 .impl = { 239 .min_access_size = 4, 240 .max_access_size = 4, 241 }, 242 .valid = { 243 .min_access_size = 4, 244 .max_access_size = 4, 245 }, 246 }; 247 248 static bool eth_can_rx(NetClientState *nc) 249 { 250 XlnxXpsEthLite *s = qemu_get_nic_opaque(nc); 251 252 return !(s->port[s->port_index].reg.rx_ctrl & CTRL_S); 253 } 254 255 static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) 256 { 257 XlnxXpsEthLite *s = qemu_get_nic_opaque(nc); 258 unsigned int port_index = s->port_index; 259 260 /* DA filter. */ 261 if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6)) 262 return size; 263 264 if (s->port[port_index].reg.rx_ctrl & CTRL_S) { 265 trace_ethlite_pkt_lost(s->port[port_index].reg.rx_ctrl); 266 return -1; 267 } 268 269 if (size >= BUFSZ_MAX) { 270 trace_ethlite_pkt_size_too_big(size); 271 return -1; 272 } 273 memcpy(rxbuf_ptr(s, port_index), buf, size); 274 275 s->port[port_index].reg.rx_ctrl |= CTRL_S; 276 if (s->port[port_index].reg.rx_ctrl & CTRL_I) { 277 eth_pulse_irq(s); 278 } 279 280 /* If c_rx_pingpong was set flip buffers. */ 281 s->port_index ^= s->c_rx_pingpong; 282 return size; 283 } 284 285 static void xilinx_ethlite_reset(DeviceState *dev) 286 { 287 XlnxXpsEthLite *s = XILINX_ETHLITE(dev); 288 289 s->port_index = 0; 290 } 291 292 static NetClientInfo net_xilinx_ethlite_info = { 293 .type = NET_CLIENT_DRIVER_NIC, 294 .size = sizeof(NICState), 295 .can_receive = eth_can_rx, 296 .receive = eth_rx, 297 }; 298 299 static void xilinx_ethlite_realize(DeviceState *dev, Error **errp) 300 { 301 XlnxXpsEthLite *s = XILINX_ETHLITE(dev); 302 303 memory_region_init(&s->mmio, OBJECT(dev), 304 "xlnx.xps-ethernetlite", 0x2000); 305 306 object_initialize_child(OBJECT(dev), "ethlite.mdio", &s->mdio, 307 TYPE_UNIMPLEMENTED_DEVICE); 308 qdev_prop_set_string(DEVICE(&s->mdio), "name", "ethlite.mdio"); 309 qdev_prop_set_uint64(DEVICE(&s->mdio), "size", 4 * 4); 310 sysbus_realize(SYS_BUS_DEVICE(&s->mdio), &error_fatal); 311 memory_region_add_subregion(&s->mmio, A_MDIO_BASE, 312 sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mdio), 0)); 313 314 for (unsigned i = 0; i < 2; i++) { 315 memory_region_init_ram(&s->port[i].txbuf, OBJECT(dev), 316 i ? "ethlite.tx[1]buf" : "ethlite.tx[0]buf", 317 BUFSZ_MAX, &error_abort); 318 memory_region_add_subregion(&s->mmio, 0x0800 * i, &s->port[i].txbuf); 319 memory_region_init_io(&s->port[i].txio, OBJECT(dev), 320 ð_porttx_ops, s, 321 i ? "ethlite.tx[1]io" : "ethlite.tx[0]io", 322 4 * TX_MAX); 323 memory_region_add_subregion(&s->mmio, i ? A_TX_BASE1 : A_TX_BASE0, 324 &s->port[i].txio); 325 326 memory_region_init_ram(&s->port[i].rxbuf, OBJECT(dev), 327 i ? "ethlite.rx[1]buf" : "ethlite.rx[0]buf", 328 BUFSZ_MAX, &error_abort); 329 memory_region_add_subregion(&s->mmio, 0x1000 + 0x0800 * i, 330 &s->port[i].rxbuf); 331 memory_region_init_io(&s->port[i].rxio, OBJECT(dev), 332 ð_portrx_ops, s, 333 i ? "ethlite.rx[1]io" : "ethlite.rx[0]io", 334 4 * RX_MAX); 335 memory_region_add_subregion(&s->mmio, i ? A_RX_BASE1 : A_RX_BASE0, 336 &s->port[i].rxio); 337 } 338 339 qemu_macaddr_default_if_unset(&s->conf.macaddr); 340 s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf, 341 object_get_typename(OBJECT(dev)), dev->id, 342 &dev->mem_reentrancy_guard, s); 343 qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a); 344 } 345 346 static void xilinx_ethlite_init(Object *obj) 347 { 348 XlnxXpsEthLite *s = XILINX_ETHLITE(obj); 349 350 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 351 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 352 } 353 354 static const Property xilinx_ethlite_properties[] = { 355 DEFINE_PROP_UINT32("tx-ping-pong", XlnxXpsEthLite, c_tx_pingpong, 1), 356 DEFINE_PROP_UINT32("rx-ping-pong", XlnxXpsEthLite, c_rx_pingpong, 1), 357 DEFINE_NIC_PROPERTIES(XlnxXpsEthLite, conf), 358 }; 359 360 static void xilinx_ethlite_class_init(ObjectClass *klass, void *data) 361 { 362 DeviceClass *dc = DEVICE_CLASS(klass); 363 364 dc->realize = xilinx_ethlite_realize; 365 device_class_set_legacy_reset(dc, xilinx_ethlite_reset); 366 device_class_set_props(dc, xilinx_ethlite_properties); 367 } 368 369 static const TypeInfo xilinx_ethlite_types[] = { 370 { 371 .name = TYPE_XILINX_ETHLITE, 372 .parent = TYPE_SYS_BUS_DEVICE, 373 .instance_size = sizeof(XlnxXpsEthLite), 374 .instance_init = xilinx_ethlite_init, 375 .class_init = xilinx_ethlite_class_init, 376 }, 377 }; 378 379 DEFINE_TYPES(xilinx_ethlite_types) 380