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