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