|
|
1.1 ! root 1: /* ! 2: * ColdFire Fast Ethernet Controller emulation. ! 3: * ! 4: * Copyright (c) 2007 CodeSourcery. ! 5: * ! 6: * This code is licenced under the GPL ! 7: */ ! 8: #include "hw.h" ! 9: #include "net.h" ! 10: #include "mcf.h" ! 11: /* For crc32 */ ! 12: #include <zlib.h> ! 13: ! 14: //#define DEBUG_FEC 1 ! 15: ! 16: #ifdef DEBUG_FEC ! 17: #define DPRINTF(fmt, args...) \ ! 18: do { printf("mcf_fec: " fmt , ##args); } while (0) ! 19: #else ! 20: #define DPRINTF(fmt, args...) do {} while(0) ! 21: #endif ! 22: ! 23: #define FEC_MAX_FRAME_SIZE 2032 ! 24: ! 25: typedef struct { ! 26: qemu_irq *irq; ! 27: VLANClientState *vc; ! 28: uint32_t irq_state; ! 29: uint32_t eir; ! 30: uint32_t eimr; ! 31: int rx_enabled; ! 32: uint32_t rx_descriptor; ! 33: uint32_t tx_descriptor; ! 34: uint32_t ecr; ! 35: uint32_t mmfr; ! 36: uint32_t mscr; ! 37: uint32_t rcr; ! 38: uint32_t tcr; ! 39: uint32_t tfwr; ! 40: uint32_t rfsr; ! 41: uint32_t erdsr; ! 42: uint32_t etdsr; ! 43: uint32_t emrbr; ! 44: uint8_t macaddr[6]; ! 45: } mcf_fec_state; ! 46: ! 47: #define FEC_INT_HB 0x80000000 ! 48: #define FEC_INT_BABR 0x40000000 ! 49: #define FEC_INT_BABT 0x20000000 ! 50: #define FEC_INT_GRA 0x10000000 ! 51: #define FEC_INT_TXF 0x08000000 ! 52: #define FEC_INT_TXB 0x04000000 ! 53: #define FEC_INT_RXF 0x02000000 ! 54: #define FEC_INT_RXB 0x01000000 ! 55: #define FEC_INT_MII 0x00800000 ! 56: #define FEC_INT_EB 0x00400000 ! 57: #define FEC_INT_LC 0x00200000 ! 58: #define FEC_INT_RL 0x00100000 ! 59: #define FEC_INT_UN 0x00080000 ! 60: ! 61: #define FEC_EN 2 ! 62: #define FEC_RESET 1 ! 63: ! 64: /* Map interrupt flags onto IRQ lines. */ ! 65: #define FEC_NUM_IRQ 13 ! 66: static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = { ! 67: FEC_INT_TXF, ! 68: FEC_INT_TXB, ! 69: FEC_INT_UN, ! 70: FEC_INT_RL, ! 71: FEC_INT_RXF, ! 72: FEC_INT_RXB, ! 73: FEC_INT_MII, ! 74: FEC_INT_LC, ! 75: FEC_INT_HB, ! 76: FEC_INT_GRA, ! 77: FEC_INT_EB, ! 78: FEC_INT_BABT, ! 79: FEC_INT_BABR ! 80: }; ! 81: ! 82: /* Buffer Descriptor. */ ! 83: typedef struct { ! 84: uint16_t flags; ! 85: uint16_t length; ! 86: uint32_t data; ! 87: } mcf_fec_bd; ! 88: ! 89: #define FEC_BD_R 0x8000 ! 90: #define FEC_BD_E 0x8000 ! 91: #define FEC_BD_O1 0x4000 ! 92: #define FEC_BD_W 0x2000 ! 93: #define FEC_BD_O2 0x1000 ! 94: #define FEC_BD_L 0x0800 ! 95: #define FEC_BD_TC 0x0400 ! 96: #define FEC_BD_ABC 0x0200 ! 97: #define FEC_BD_M 0x0100 ! 98: #define FEC_BD_BC 0x0080 ! 99: #define FEC_BD_MC 0x0040 ! 100: #define FEC_BD_LG 0x0020 ! 101: #define FEC_BD_NO 0x0010 ! 102: #define FEC_BD_CR 0x0004 ! 103: #define FEC_BD_OV 0x0002 ! 104: #define FEC_BD_TR 0x0001 ! 105: ! 106: static void mcf_fec_read_bd(mcf_fec_bd *bd, uint32_t addr) ! 107: { ! 108: cpu_physical_memory_read(addr, (uint8_t *)bd, sizeof(*bd)); ! 109: be16_to_cpus(&bd->flags); ! 110: be16_to_cpus(&bd->length); ! 111: be32_to_cpus(&bd->data); ! 112: } ! 113: ! 114: static void mcf_fec_write_bd(mcf_fec_bd *bd, uint32_t addr) ! 115: { ! 116: mcf_fec_bd tmp; ! 117: tmp.flags = cpu_to_be16(bd->flags); ! 118: tmp.length = cpu_to_be16(bd->length); ! 119: tmp.data = cpu_to_be32(bd->data); ! 120: cpu_physical_memory_write(addr, (uint8_t *)&tmp, sizeof(tmp)); ! 121: } ! 122: ! 123: static void mcf_fec_update(mcf_fec_state *s) ! 124: { ! 125: uint32_t active; ! 126: uint32_t changed; ! 127: uint32_t mask; ! 128: int i; ! 129: ! 130: active = s->eir & s->eimr; ! 131: changed = active ^s->irq_state; ! 132: for (i = 0; i < FEC_NUM_IRQ; i++) { ! 133: mask = mcf_fec_irq_map[i]; ! 134: if (changed & mask) { ! 135: DPRINTF("IRQ %d = %d\n", i, (active & mask) != 0); ! 136: qemu_set_irq(s->irq[i], (active & mask) != 0); ! 137: } ! 138: } ! 139: s->irq_state = active; ! 140: } ! 141: ! 142: static void mcf_fec_do_tx(mcf_fec_state *s) ! 143: { ! 144: uint32_t addr; ! 145: mcf_fec_bd bd; ! 146: int frame_size; ! 147: int len; ! 148: uint8_t frame[FEC_MAX_FRAME_SIZE]; ! 149: uint8_t *ptr; ! 150: ! 151: DPRINTF("do_tx\n"); ! 152: ptr = frame; ! 153: frame_size = 0; ! 154: addr = s->tx_descriptor; ! 155: while (1) { ! 156: mcf_fec_read_bd(&bd, addr); ! 157: DPRINTF("tx_bd %x flags %04x len %d data %08x\n", ! 158: addr, bd.flags, bd.length, bd.data); ! 159: if ((bd.flags & FEC_BD_R) == 0) { ! 160: /* Run out of descriptors to transmit. */ ! 161: break; ! 162: } ! 163: len = bd.length; ! 164: if (frame_size + len > FEC_MAX_FRAME_SIZE) { ! 165: len = FEC_MAX_FRAME_SIZE - frame_size; ! 166: s->eir |= FEC_INT_BABT; ! 167: } ! 168: cpu_physical_memory_read(bd.data, ptr, len); ! 169: ptr += len; ! 170: frame_size += len; ! 171: if (bd.flags & FEC_BD_L) { ! 172: /* Last buffer in frame. */ ! 173: DPRINTF("Sending packet\n"); ! 174: qemu_send_packet(s->vc, frame, len); ! 175: ptr = frame; ! 176: frame_size = 0; ! 177: s->eir |= FEC_INT_TXF; ! 178: } ! 179: s->eir |= FEC_INT_TXB; ! 180: bd.flags &= ~FEC_BD_R; ! 181: /* Write back the modified descriptor. */ ! 182: mcf_fec_write_bd(&bd, addr); ! 183: /* Advance to the next descriptor. */ ! 184: if ((bd.flags & FEC_BD_W) != 0) { ! 185: addr = s->etdsr; ! 186: } else { ! 187: addr += 8; ! 188: } ! 189: } ! 190: s->tx_descriptor = addr; ! 191: } ! 192: ! 193: static void mcf_fec_enable_rx(mcf_fec_state *s) ! 194: { ! 195: mcf_fec_bd bd; ! 196: ! 197: mcf_fec_read_bd(&bd, s->rx_descriptor); ! 198: s->rx_enabled = ((bd.flags & FEC_BD_E) != 0); ! 199: if (!s->rx_enabled) ! 200: DPRINTF("RX buffer full\n"); ! 201: } ! 202: ! 203: static void mcf_fec_reset(mcf_fec_state *s) ! 204: { ! 205: s->eir = 0; ! 206: s->eimr = 0; ! 207: s->rx_enabled = 0; ! 208: s->ecr = 0; ! 209: s->mscr = 0; ! 210: s->rcr = 0x05ee0001; ! 211: s->tcr = 0; ! 212: s->tfwr = 0; ! 213: s->rfsr = 0x500; ! 214: } ! 215: ! 216: static uint32_t mcf_fec_read(void *opaque, target_phys_addr_t addr) ! 217: { ! 218: mcf_fec_state *s = (mcf_fec_state *)opaque; ! 219: switch (addr & 0x3ff) { ! 220: case 0x004: return s->eir; ! 221: case 0x008: return s->eimr; ! 222: case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */ ! 223: case 0x014: return 0; /* TDAR */ ! 224: case 0x024: return s->ecr; ! 225: case 0x040: return s->mmfr; ! 226: case 0x044: return s->mscr; ! 227: case 0x064: return 0; /* MIBC */ ! 228: case 0x084: return s->rcr; ! 229: case 0x0c4: return s->tcr; ! 230: case 0x0e4: /* PALR */ ! 231: return (s->macaddr[0] << 24) | (s->macaddr[1] << 16) ! 232: | (s->macaddr[2] << 8) | s->macaddr[3]; ! 233: break; ! 234: case 0x0e8: /* PAUR */ ! 235: return (s->macaddr[4] << 24) | (s->macaddr[5] << 16) | 0x8808; ! 236: case 0x0ec: return 0x10000; /* OPD */ ! 237: case 0x118: return 0; ! 238: case 0x11c: return 0; ! 239: case 0x120: return 0; ! 240: case 0x124: return 0; ! 241: case 0x144: return s->tfwr; ! 242: case 0x14c: return 0x600; ! 243: case 0x150: return s->rfsr; ! 244: case 0x180: return s->erdsr; ! 245: case 0x184: return s->etdsr; ! 246: case 0x188: return s->emrbr; ! 247: default: ! 248: cpu_abort(cpu_single_env, "mcf_fec_read: Bad address 0x%x\n", ! 249: (int)addr); ! 250: return 0; ! 251: } ! 252: } ! 253: ! 254: static void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value) ! 255: { ! 256: mcf_fec_state *s = (mcf_fec_state *)opaque; ! 257: switch (addr & 0x3ff) { ! 258: case 0x004: ! 259: s->eir &= ~value; ! 260: break; ! 261: case 0x008: ! 262: s->eimr = value; ! 263: break; ! 264: case 0x010: /* RDAR */ ! 265: if ((s->ecr & FEC_EN) && !s->rx_enabled) { ! 266: DPRINTF("RX enable\n"); ! 267: mcf_fec_enable_rx(s); ! 268: } ! 269: break; ! 270: case 0x014: /* TDAR */ ! 271: if (s->ecr & FEC_EN) { ! 272: mcf_fec_do_tx(s); ! 273: } ! 274: break; ! 275: case 0x024: ! 276: s->ecr = value; ! 277: if (value & FEC_RESET) { ! 278: DPRINTF("Reset\n"); ! 279: mcf_fec_reset(s); ! 280: } ! 281: if ((s->ecr & FEC_EN) == 0) { ! 282: s->rx_enabled = 0; ! 283: } ! 284: break; ! 285: case 0x040: ! 286: /* TODO: Implement MII. */ ! 287: s->mmfr = value; ! 288: break; ! 289: case 0x044: ! 290: s->mscr = value & 0xfe; ! 291: break; ! 292: case 0x064: ! 293: /* TODO: Implement MIB. */ ! 294: break; ! 295: case 0x084: ! 296: s->rcr = value & 0x07ff003f; ! 297: /* TODO: Implement LOOP mode. */ ! 298: break; ! 299: case 0x0c4: /* TCR */ ! 300: /* We transmit immediately, so raise GRA immediately. */ ! 301: s->tcr = value; ! 302: if (value & 1) ! 303: s->eir |= FEC_INT_GRA; ! 304: break; ! 305: case 0x0e4: /* PALR */ ! 306: s->macaddr[0] = value >> 24; ! 307: s->macaddr[1] = value >> 16; ! 308: s->macaddr[2] = value >> 8; ! 309: s->macaddr[3] = value; ! 310: break; ! 311: case 0x0e8: /* PAUR */ ! 312: s->macaddr[4] = value >> 24; ! 313: s->macaddr[5] = value >> 16; ! 314: break; ! 315: case 0x0ec: ! 316: /* OPD */ ! 317: break; ! 318: case 0x118: ! 319: case 0x11c: ! 320: case 0x120: ! 321: case 0x124: ! 322: /* TODO: implement MAC hash filtering. */ ! 323: break; ! 324: case 0x144: ! 325: s->tfwr = value & 3; ! 326: break; ! 327: case 0x14c: ! 328: /* FRBR writes ignored. */ ! 329: break; ! 330: case 0x150: ! 331: s->rfsr = (value & 0x3fc) | 0x400; ! 332: break; ! 333: case 0x180: ! 334: s->erdsr = value & ~3; ! 335: s->rx_descriptor = s->erdsr; ! 336: break; ! 337: case 0x184: ! 338: s->etdsr = value & ~3; ! 339: s->tx_descriptor = s->etdsr; ! 340: break; ! 341: case 0x188: ! 342: s->emrbr = value & 0x7f0; ! 343: break; ! 344: default: ! 345: cpu_abort(cpu_single_env, "mcf_fec_write Bad address 0x%x\n", ! 346: (int)addr); ! 347: } ! 348: mcf_fec_update(s); ! 349: } ! 350: ! 351: static int mcf_fec_can_receive(void *opaque) ! 352: { ! 353: mcf_fec_state *s = (mcf_fec_state *)opaque; ! 354: return s->rx_enabled; ! 355: } ! 356: ! 357: static void mcf_fec_receive(void *opaque, const uint8_t *buf, int size) ! 358: { ! 359: mcf_fec_state *s = (mcf_fec_state *)opaque; ! 360: mcf_fec_bd bd; ! 361: uint32_t flags = 0; ! 362: uint32_t addr; ! 363: uint32_t crc; ! 364: uint32_t buf_addr; ! 365: uint8_t *crc_ptr; ! 366: unsigned int buf_len; ! 367: ! 368: DPRINTF("do_rx len %d\n", size); ! 369: if (!s->rx_enabled) { ! 370: fprintf(stderr, "mcf_fec_receive: Unexpected packet\n"); ! 371: } ! 372: /* 4 bytes for the CRC. */ ! 373: size += 4; ! 374: crc = cpu_to_be32(crc32(~0, buf, size)); ! 375: crc_ptr = (uint8_t *)&crc; ! 376: /* Huge frames are truncted. */ ! 377: if (size > FEC_MAX_FRAME_SIZE) { ! 378: size = FEC_MAX_FRAME_SIZE; ! 379: flags |= FEC_BD_TR | FEC_BD_LG; ! 380: } ! 381: /* Frames larger than the user limit just set error flags. */ ! 382: if (size > (s->rcr >> 16)) { ! 383: flags |= FEC_BD_LG; ! 384: } ! 385: addr = s->rx_descriptor; ! 386: while (size > 0) { ! 387: mcf_fec_read_bd(&bd, addr); ! 388: if ((bd.flags & FEC_BD_E) == 0) { ! 389: /* No descriptors available. Bail out. */ ! 390: /* FIXME: This is wrong. We should probably either save the ! 391: remainder for when more RX buffers are available, or ! 392: flag an error. */ ! 393: fprintf(stderr, "mcf_fec: Lost end of frame\n"); ! 394: break; ! 395: } ! 396: buf_len = (size <= s->emrbr) ? size: s->emrbr; ! 397: bd.length = buf_len; ! 398: size -= buf_len; ! 399: DPRINTF("rx_bd %x length %d\n", addr, bd.length); ! 400: /* The last 4 bytes are the CRC. */ ! 401: if (size < 4) ! 402: buf_len += size - 4; ! 403: buf_addr = bd.data; ! 404: cpu_physical_memory_write(buf_addr, buf, buf_len); ! 405: buf += buf_len; ! 406: if (size < 4) { ! 407: cpu_physical_memory_write(buf_addr + buf_len, crc_ptr, 4 - size); ! 408: crc_ptr += 4 - size; ! 409: } ! 410: bd.flags &= ~FEC_BD_E; ! 411: if (size == 0) { ! 412: /* Last buffer in frame. */ ! 413: bd.flags |= flags | FEC_BD_L; ! 414: DPRINTF("rx frame flags %04x\n", bd.flags); ! 415: s->eir |= FEC_INT_RXF; ! 416: } else { ! 417: s->eir |= FEC_INT_RXB; ! 418: } ! 419: mcf_fec_write_bd(&bd, addr); ! 420: /* Advance to the next descriptor. */ ! 421: if ((bd.flags & FEC_BD_W) != 0) { ! 422: addr = s->erdsr; ! 423: } else { ! 424: addr += 8; ! 425: } ! 426: } ! 427: s->rx_descriptor = addr; ! 428: mcf_fec_enable_rx(s); ! 429: mcf_fec_update(s); ! 430: } ! 431: ! 432: static CPUReadMemoryFunc *mcf_fec_readfn[] = { ! 433: mcf_fec_read, ! 434: mcf_fec_read, ! 435: mcf_fec_read ! 436: }; ! 437: ! 438: static CPUWriteMemoryFunc *mcf_fec_writefn[] = { ! 439: mcf_fec_write, ! 440: mcf_fec_write, ! 441: mcf_fec_write ! 442: }; ! 443: ! 444: void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) ! 445: { ! 446: mcf_fec_state *s; ! 447: int iomemtype; ! 448: ! 449: s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state)); ! 450: s->irq = irq; ! 451: iomemtype = cpu_register_io_memory(0, mcf_fec_readfn, ! 452: mcf_fec_writefn, s); ! 453: cpu_register_physical_memory(base, 0x400, iomemtype); ! 454: ! 455: s->vc = qemu_new_vlan_client(nd->vlan, mcf_fec_receive, ! 456: mcf_fec_can_receive, s); ! 457: memcpy(s->macaddr, nd->macaddr, 6); ! 458: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.