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 ð_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 ð_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