xilinx_ethlite.c 12 KB

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