|
|
1.1 ! root 1: /* ! 2: * QEMU model of the Xilinx Ethernet Lite MAC. ! 3: * ! 4: * Copyright (c) 2009 Edgar E. Iglesias. ! 5: * ! 6: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 7: * of this software and associated documentation files (the "Software"), to deal ! 8: * in the Software without restriction, including without limitation the rights ! 9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 10: * copies of the Software, and to permit persons to whom the Software is ! 11: * furnished to do so, subject to the following conditions: ! 12: * ! 13: * The above copyright notice and this permission notice shall be included in ! 14: * all copies or substantial portions of the Software. ! 15: * ! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 22: * THE SOFTWARE. ! 23: */ ! 24: ! 25: #include "sysbus.h" ! 26: #include "hw.h" ! 27: #include "net.h" ! 28: ! 29: #define D(x) ! 30: #define R_TX_BUF0 0 ! 31: #define R_TX_LEN0 (0x07f4 / 4) ! 32: #define R_TX_GIE0 (0x07f8 / 4) ! 33: #define R_TX_CTRL0 (0x07fc / 4) ! 34: #define R_TX_BUF1 (0x0800 / 4) ! 35: #define R_TX_LEN1 (0x0ff4 / 4) ! 36: #define R_TX_CTRL1 (0x0ffc / 4) ! 37: ! 38: #define R_RX_BUF0 (0x1000 / 4) ! 39: #define R_RX_CTRL0 (0x17fc / 4) ! 40: #define R_RX_BUF1 (0x1800 / 4) ! 41: #define R_RX_CTRL1 (0x1ffc / 4) ! 42: #define R_MAX (0x2000 / 4) ! 43: ! 44: #define GIE_GIE 0x80000000 ! 45: ! 46: #define CTRL_I 0x8 ! 47: #define CTRL_P 0x2 ! 48: #define CTRL_S 0x1 ! 49: ! 50: struct xlx_ethlite ! 51: { ! 52: SysBusDevice busdev; ! 53: qemu_irq irq; ! 54: VLANClientState *vc; ! 55: ! 56: uint32_t c_tx_pingpong; ! 57: uint32_t c_rx_pingpong; ! 58: unsigned int txbuf; ! 59: unsigned int rxbuf; ! 60: ! 61: uint8_t macaddr[6]; ! 62: uint32_t regs[R_MAX]; ! 63: }; ! 64: ! 65: static inline void eth_pulse_irq(struct xlx_ethlite *s) ! 66: { ! 67: /* Only the first gie reg is active. */ ! 68: if (s->regs[R_TX_GIE0] & GIE_GIE) { ! 69: qemu_irq_pulse(s->irq); ! 70: } ! 71: } ! 72: ! 73: static uint32_t eth_readl (void *opaque, target_phys_addr_t addr) ! 74: { ! 75: struct xlx_ethlite *s = opaque; ! 76: uint32_t r = 0; ! 77: ! 78: addr >>= 2; ! 79: ! 80: switch (addr) ! 81: { ! 82: case R_TX_GIE0: ! 83: case R_TX_LEN0: ! 84: case R_TX_LEN1: ! 85: case R_TX_CTRL1: ! 86: case R_TX_CTRL0: ! 87: case R_RX_CTRL1: ! 88: case R_RX_CTRL0: ! 89: r = s->regs[addr]; ! 90: D(qemu_log("%s %x=%x\n", __func__, addr * 4, r)); ! 91: break; ! 92: ! 93: /* Rx packet data is endian fixed at the way into the rx rams. This ! 94: * speeds things up because the ethlite MAC does not have a len ! 95: * register. That means the CPU will issue MMIO reads for the entire ! 96: * 2k rx buffer even for small packets. ! 97: */ ! 98: default: ! 99: r = s->regs[addr]; ! 100: break; ! 101: } ! 102: return r; ! 103: } ! 104: ! 105: static void ! 106: eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) ! 107: { ! 108: struct xlx_ethlite *s = opaque; ! 109: unsigned int base = 0; ! 110: ! 111: addr >>= 2; ! 112: switch (addr) ! 113: { ! 114: case R_TX_CTRL0: ! 115: case R_TX_CTRL1: ! 116: if (addr == R_TX_CTRL1) ! 117: base = 0x800 / 4; ! 118: ! 119: D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); ! 120: if ((value & (CTRL_P | CTRL_S)) == CTRL_S) { ! 121: qemu_send_packet(s->vc, ! 122: (void *) &s->regs[base], ! 123: s->regs[base + R_TX_LEN0]); ! 124: D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0])); ! 125: if (s->regs[base + R_TX_CTRL0] & CTRL_I) ! 126: eth_pulse_irq(s); ! 127: } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) { ! 128: memcpy(&s->macaddr[0], &s->regs[base], 6); ! 129: if (s->regs[base + R_TX_CTRL0] & CTRL_I) ! 130: eth_pulse_irq(s); ! 131: } ! 132: ! 133: /* We are fast and get ready pretty much immediately so ! 134: we actually never flip the S nor P bits to one. */ ! 135: s->regs[addr] = value & ~(CTRL_P | CTRL_S); ! 136: break; ! 137: ! 138: /* Keep these native. */ ! 139: case R_TX_LEN0: ! 140: case R_TX_LEN1: ! 141: case R_TX_GIE0: ! 142: case R_RX_CTRL0: ! 143: case R_RX_CTRL1: ! 144: D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); ! 145: s->regs[addr] = value; ! 146: break; ! 147: ! 148: /* Packet data, make sure it stays BE. */ ! 149: default: ! 150: s->regs[addr] = cpu_to_be32(value); ! 151: break; ! 152: } ! 153: } ! 154: ! 155: static CPUReadMemoryFunc *eth_read[] = { ! 156: NULL, NULL, ð_readl, ! 157: }; ! 158: ! 159: static CPUWriteMemoryFunc *eth_write[] = { ! 160: NULL, NULL, ð_writel, ! 161: }; ! 162: ! 163: static int eth_can_rx(VLANClientState *vc) ! 164: { ! 165: struct xlx_ethlite *s = vc->opaque; ! 166: int r; ! 167: r = !(s->regs[R_RX_CTRL0] & CTRL_S); ! 168: return r; ! 169: } ! 170: ! 171: static ssize_t eth_rx(VLANClientState *vc, const uint8_t *buf, size_t size) ! 172: { ! 173: struct xlx_ethlite *s = vc->opaque; ! 174: unsigned int rxbase = s->rxbuf * (0x800 / 4); ! 175: int i; ! 176: ! 177: /* DA filter. */ ! 178: if (!(buf[0] & 0x80) && memcmp(&s->macaddr[0], buf, 6)) ! 179: return size; ! 180: ! 181: if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) { ! 182: D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0])); ! 183: return -1; ! 184: } ! 185: ! 186: D(qemu_log("%s %d rxbase=%x\n", __func__, size, rxbase)); ! 187: memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size); ! 188: ! 189: /* Bring it into host endianess. */ ! 190: for (i = 0; i < ((size + 3) / 4); i++) { ! 191: uint32_t d = s->regs[rxbase + R_RX_BUF0 + i]; ! 192: s->regs[rxbase + R_RX_BUF0 + i] = be32_to_cpu(d); ! 193: } ! 194: ! 195: s->regs[rxbase + R_RX_CTRL0] |= CTRL_S; ! 196: if (s->regs[rxbase + R_RX_CTRL0] & CTRL_I) ! 197: eth_pulse_irq(s); ! 198: ! 199: /* If c_rx_pingpong was set flip buffers. */ ! 200: s->rxbuf ^= s->c_rx_pingpong; ! 201: return size; ! 202: } ! 203: ! 204: static void eth_cleanup(VLANClientState *vc) ! 205: { ! 206: struct xlx_ethlite *s = vc->opaque; ! 207: qemu_free(s); ! 208: } ! 209: ! 210: static void xilinx_ethlite_init(SysBusDevice *dev) ! 211: { ! 212: struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev); ! 213: int regs; ! 214: ! 215: sysbus_init_irq(dev, &s->irq); ! 216: s->rxbuf = 0; ! 217: ! 218: regs = cpu_register_io_memory(eth_read, eth_write, s); ! 219: sysbus_init_mmio(dev, R_MAX * 4, regs); ! 220: ! 221: qdev_get_macaddr(&dev->qdev, s->macaddr); ! 222: s->vc = qdev_get_vlan_client(&dev->qdev, ! 223: eth_can_rx, eth_rx, NULL, eth_cleanup, s); ! 224: } ! 225: ! 226: static SysBusDeviceInfo xilinx_ethlite_info = { ! 227: .init = xilinx_ethlite_init, ! 228: .qdev.name = "xilinx,ethlite", ! 229: .qdev.size = sizeof(struct xlx_ethlite), ! 230: .qdev.props = (Property[]) { ! 231: { ! 232: .name = "txpingpong", ! 233: .info = &qdev_prop_uint32, ! 234: .offset = offsetof(struct xlx_ethlite, c_tx_pingpong), ! 235: .defval = (uint32_t[]) { 1 }, ! 236: },{ ! 237: .name = "rxpingpong", ! 238: .info = &qdev_prop_uint32, ! 239: .offset = offsetof(struct xlx_ethlite, c_rx_pingpong), ! 240: .defval = (uint32_t[]) { 1 }, ! 241: }, ! 242: {/* end of list */} ! 243: } ! 244: }; ! 245: ! 246: static void xilinx_ethlite_register(void) ! 247: { ! 248: sysbus_register_withprop(&xilinx_ethlite_info); ! 249: } ! 250: ! 251: device_init(xilinx_ethlite_register)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.