|
|
1.1 ! root 1: /* ! 2: * QEMU NS SONIC DP8393x netcard ! 3: * ! 4: * Copyright (c) 2008-2009 Herve Poussineau ! 5: * ! 6: * This program is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU General Public License as ! 8: * published by the Free Software Foundation; either version 2 of ! 9: * the License, or (at your option) any later version. ! 10: * ! 11: * This program is distributed in the hope that it will be useful, ! 12: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: * GNU General Public License for more details. ! 15: * ! 16: * You should have received a copy of the GNU General Public License along ! 17: * with this program; if not, see <http://www.gnu.org/licenses/>. ! 18: */ ! 19: ! 20: #include "hw.h" ! 21: #include "qemu-timer.h" ! 22: #include "net.h" ! 23: #include "mips.h" ! 24: ! 25: //#define DEBUG_SONIC ! 26: ! 27: /* Calculate CRCs properly on Rx packets */ ! 28: #define SONIC_CALCULATE_RXCRC ! 29: ! 30: #if defined(SONIC_CALCULATE_RXCRC) ! 31: /* For crc32 */ ! 32: #include <zlib.h> ! 33: #endif ! 34: ! 35: #ifdef DEBUG_SONIC ! 36: #define DPRINTF(fmt, ...) \ ! 37: do { printf("sonic: " fmt , ## __VA_ARGS__); } while (0) ! 38: static const char* reg_names[] = { ! 39: "CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA", ! 40: "TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0", ! 41: "CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP", ! 42: "RWP", "TRBA0", "TRBA1", "0x1b", "0x1c", "0x1d", "0x1e", "LLFA", ! 43: "TTDA", "CEP", "CAP2", "CAP1", "CAP0", "CE", "CDP", "CDC", ! 44: "SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT", ! 45: "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37", ! 46: "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "DCR2" }; ! 47: #else ! 48: #define DPRINTF(fmt, ...) do {} while (0) ! 49: #endif ! 50: ! 51: #define SONIC_ERROR(fmt, ...) \ ! 52: do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0) ! 53: ! 54: #define SONIC_CR 0x00 ! 55: #define SONIC_DCR 0x01 ! 56: #define SONIC_RCR 0x02 ! 57: #define SONIC_TCR 0x03 ! 58: #define SONIC_IMR 0x04 ! 59: #define SONIC_ISR 0x05 ! 60: #define SONIC_UTDA 0x06 ! 61: #define SONIC_CTDA 0x07 ! 62: #define SONIC_TPS 0x08 ! 63: #define SONIC_TFC 0x09 ! 64: #define SONIC_TSA0 0x0a ! 65: #define SONIC_TSA1 0x0b ! 66: #define SONIC_TFS 0x0c ! 67: #define SONIC_URDA 0x0d ! 68: #define SONIC_CRDA 0x0e ! 69: #define SONIC_CRBA0 0x0f ! 70: #define SONIC_CRBA1 0x10 ! 71: #define SONIC_RBWC0 0x11 ! 72: #define SONIC_RBWC1 0x12 ! 73: #define SONIC_EOBC 0x13 ! 74: #define SONIC_URRA 0x14 ! 75: #define SONIC_RSA 0x15 ! 76: #define SONIC_REA 0x16 ! 77: #define SONIC_RRP 0x17 ! 78: #define SONIC_RWP 0x18 ! 79: #define SONIC_TRBA0 0x19 ! 80: #define SONIC_TRBA1 0x1a ! 81: #define SONIC_LLFA 0x1f ! 82: #define SONIC_TTDA 0x20 ! 83: #define SONIC_CEP 0x21 ! 84: #define SONIC_CAP2 0x22 ! 85: #define SONIC_CAP1 0x23 ! 86: #define SONIC_CAP0 0x24 ! 87: #define SONIC_CE 0x25 ! 88: #define SONIC_CDP 0x26 ! 89: #define SONIC_CDC 0x27 ! 90: #define SONIC_SR 0x28 ! 91: #define SONIC_WT0 0x29 ! 92: #define SONIC_WT1 0x2a ! 93: #define SONIC_RSC 0x2b ! 94: #define SONIC_CRCT 0x2c ! 95: #define SONIC_FAET 0x2d ! 96: #define SONIC_MPT 0x2e ! 97: #define SONIC_MDT 0x2f ! 98: #define SONIC_DCR2 0x3f ! 99: ! 100: #define SONIC_CR_HTX 0x0001 ! 101: #define SONIC_CR_TXP 0x0002 ! 102: #define SONIC_CR_RXDIS 0x0004 ! 103: #define SONIC_CR_RXEN 0x0008 ! 104: #define SONIC_CR_STP 0x0010 ! 105: #define SONIC_CR_ST 0x0020 ! 106: #define SONIC_CR_RST 0x0080 ! 107: #define SONIC_CR_RRRA 0x0100 ! 108: #define SONIC_CR_LCAM 0x0200 ! 109: #define SONIC_CR_MASK 0x03bf ! 110: ! 111: #define SONIC_DCR_DW 0x0020 ! 112: #define SONIC_DCR_LBR 0x2000 ! 113: #define SONIC_DCR_EXBUS 0x8000 ! 114: ! 115: #define SONIC_RCR_PRX 0x0001 ! 116: #define SONIC_RCR_LBK 0x0002 ! 117: #define SONIC_RCR_FAER 0x0004 ! 118: #define SONIC_RCR_CRCR 0x0008 ! 119: #define SONIC_RCR_CRS 0x0020 ! 120: #define SONIC_RCR_LPKT 0x0040 ! 121: #define SONIC_RCR_BC 0x0080 ! 122: #define SONIC_RCR_MC 0x0100 ! 123: #define SONIC_RCR_LB0 0x0200 ! 124: #define SONIC_RCR_LB1 0x0400 ! 125: #define SONIC_RCR_AMC 0x0800 ! 126: #define SONIC_RCR_PRO 0x1000 ! 127: #define SONIC_RCR_BRD 0x2000 ! 128: #define SONIC_RCR_RNT 0x4000 ! 129: ! 130: #define SONIC_TCR_PTX 0x0001 ! 131: #define SONIC_TCR_BCM 0x0002 ! 132: #define SONIC_TCR_FU 0x0004 ! 133: #define SONIC_TCR_EXC 0x0040 ! 134: #define SONIC_TCR_CRSL 0x0080 ! 135: #define SONIC_TCR_NCRS 0x0100 ! 136: #define SONIC_TCR_EXD 0x0400 ! 137: #define SONIC_TCR_CRCI 0x2000 ! 138: #define SONIC_TCR_PINT 0x8000 ! 139: ! 140: #define SONIC_ISR_RBE 0x0020 ! 141: #define SONIC_ISR_RDE 0x0040 ! 142: #define SONIC_ISR_TC 0x0080 ! 143: #define SONIC_ISR_TXDN 0x0200 ! 144: #define SONIC_ISR_PKTRX 0x0400 ! 145: #define SONIC_ISR_PINT 0x0800 ! 146: #define SONIC_ISR_LCD 0x1000 ! 147: ! 148: typedef struct dp8393xState { ! 149: /* Hardware */ ! 150: int it_shift; ! 151: qemu_irq irq; ! 152: #ifdef DEBUG_SONIC ! 153: int irq_level; ! 154: #endif ! 155: QEMUTimer *watchdog; ! 156: int64_t wt_last_update; ! 157: VLANClientState *vc; ! 158: int mmio_index; ! 159: ! 160: /* Registers */ ! 161: uint8_t cam[16][6]; ! 162: uint16_t regs[0x40]; ! 163: ! 164: /* Temporaries */ ! 165: uint8_t tx_buffer[0x10000]; ! 166: int loopback_packet; ! 167: ! 168: /* Memory access */ ! 169: void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write); ! 170: void* mem_opaque; ! 171: } dp8393xState; ! 172: ! 173: static void dp8393x_update_irq(dp8393xState *s) ! 174: { ! 175: int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0; ! 176: ! 177: #ifdef DEBUG_SONIC ! 178: if (level != s->irq_level) { ! 179: s->irq_level = level; ! 180: if (level) { ! 181: DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]); ! 182: } else { ! 183: DPRINTF("lower irq\n"); ! 184: } ! 185: } ! 186: #endif ! 187: ! 188: qemu_set_irq(s->irq, level); ! 189: } ! 190: ! 191: static void do_load_cam(dp8393xState *s) ! 192: { ! 193: uint16_t data[8]; ! 194: int width, size; ! 195: uint16_t index = 0; ! 196: ! 197: width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; ! 198: size = sizeof(uint16_t) * 4 * width; ! 199: ! 200: while (s->regs[SONIC_CDC] & 0x1f) { ! 201: /* Fill current entry */ ! 202: s->memory_rw(s->mem_opaque, ! 203: (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], ! 204: (uint8_t *)data, size, 0); ! 205: s->cam[index][0] = data[1 * width] & 0xff; ! 206: s->cam[index][1] = data[1 * width] >> 8; ! 207: s->cam[index][2] = data[2 * width] & 0xff; ! 208: s->cam[index][3] = data[2 * width] >> 8; ! 209: s->cam[index][4] = data[3 * width] & 0xff; ! 210: s->cam[index][5] = data[3 * width] >> 8; ! 211: DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index, ! 212: s->cam[index][0], s->cam[index][1], s->cam[index][2], ! 213: s->cam[index][3], s->cam[index][4], s->cam[index][5]); ! 214: /* Move to next entry */ ! 215: s->regs[SONIC_CDC]--; ! 216: s->regs[SONIC_CDP] += size; ! 217: index++; ! 218: } ! 219: ! 220: /* Read CAM enable */ ! 221: s->memory_rw(s->mem_opaque, ! 222: (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], ! 223: (uint8_t *)data, size, 0); ! 224: s->regs[SONIC_CE] = data[0 * width]; ! 225: DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]); ! 226: ! 227: /* Done */ ! 228: s->regs[SONIC_CR] &= ~SONIC_CR_LCAM; ! 229: s->regs[SONIC_ISR] |= SONIC_ISR_LCD; ! 230: dp8393x_update_irq(s); ! 231: } ! 232: ! 233: static void do_read_rra(dp8393xState *s) ! 234: { ! 235: uint16_t data[8]; ! 236: int width, size; ! 237: ! 238: /* Read memory */ ! 239: width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; ! 240: size = sizeof(uint16_t) * 4 * width; ! 241: s->memory_rw(s->mem_opaque, ! 242: (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP], ! 243: (uint8_t *)data, size, 0); ! 244: ! 245: /* Update SONIC registers */ ! 246: s->regs[SONIC_CRBA0] = data[0 * width]; ! 247: s->regs[SONIC_CRBA1] = data[1 * width]; ! 248: s->regs[SONIC_RBWC0] = data[2 * width]; ! 249: s->regs[SONIC_RBWC1] = data[3 * width]; ! 250: DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n", ! 251: s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1], ! 252: s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]); ! 253: ! 254: /* Go to next entry */ ! 255: s->regs[SONIC_RRP] += size; ! 256: ! 257: /* Handle wrap */ ! 258: if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) { ! 259: s->regs[SONIC_RRP] = s->regs[SONIC_RSA]; ! 260: } ! 261: ! 262: /* Check resource exhaustion */ ! 263: if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP]) ! 264: { ! 265: s->regs[SONIC_ISR] |= SONIC_ISR_RBE; ! 266: dp8393x_update_irq(s); ! 267: } ! 268: ! 269: /* Done */ ! 270: s->regs[SONIC_CR] &= ~SONIC_CR_RRRA; ! 271: } ! 272: ! 273: static void do_software_reset(dp8393xState *s) ! 274: { ! 275: qemu_del_timer(s->watchdog); ! 276: ! 277: s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX); ! 278: s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS; ! 279: } ! 280: ! 281: static void set_next_tick(dp8393xState *s) ! 282: { ! 283: uint32_t ticks; ! 284: int64_t delay; ! 285: ! 286: if (s->regs[SONIC_CR] & SONIC_CR_STP) { ! 287: qemu_del_timer(s->watchdog); ! 288: return; ! 289: } ! 290: ! 291: ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0]; ! 292: s->wt_last_update = qemu_get_clock(vm_clock); ! 293: delay = ticks_per_sec * ticks / 5000000; ! 294: qemu_mod_timer(s->watchdog, s->wt_last_update + delay); ! 295: } ! 296: ! 297: static void update_wt_regs(dp8393xState *s) ! 298: { ! 299: int64_t elapsed; ! 300: uint32_t val; ! 301: ! 302: if (s->regs[SONIC_CR] & SONIC_CR_STP) { ! 303: qemu_del_timer(s->watchdog); ! 304: return; ! 305: } ! 306: ! 307: elapsed = s->wt_last_update - qemu_get_clock(vm_clock); ! 308: val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0]; ! 309: val -= elapsed / 5000000; ! 310: s->regs[SONIC_WT1] = (val >> 16) & 0xffff; ! 311: s->regs[SONIC_WT0] = (val >> 0) & 0xffff; ! 312: set_next_tick(s); ! 313: ! 314: } ! 315: ! 316: static void do_start_timer(dp8393xState *s) ! 317: { ! 318: s->regs[SONIC_CR] &= ~SONIC_CR_STP; ! 319: set_next_tick(s); ! 320: } ! 321: ! 322: static void do_stop_timer(dp8393xState *s) ! 323: { ! 324: s->regs[SONIC_CR] &= ~SONIC_CR_ST; ! 325: update_wt_regs(s); ! 326: } ! 327: ! 328: static void do_receiver_enable(dp8393xState *s) ! 329: { ! 330: s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS; ! 331: } ! 332: ! 333: static void do_receiver_disable(dp8393xState *s) ! 334: { ! 335: s->regs[SONIC_CR] &= ~SONIC_CR_RXEN; ! 336: } ! 337: ! 338: static void do_transmit_packets(dp8393xState *s) ! 339: { ! 340: uint16_t data[12]; ! 341: int width, size; ! 342: int tx_len, len; ! 343: uint16_t i; ! 344: ! 345: width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; ! 346: ! 347: while (1) { ! 348: /* Read memory */ ! 349: DPRINTF("Transmit packet at %08x\n", ! 350: (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]); ! 351: size = sizeof(uint16_t) * 6 * width; ! 352: s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA]; ! 353: s->memory_rw(s->mem_opaque, ! 354: ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width, ! 355: (uint8_t *)data, size, 0); ! 356: tx_len = 0; ! 357: ! 358: /* Update registers */ ! 359: s->regs[SONIC_TCR] = data[0 * width] & 0xf000; ! 360: s->regs[SONIC_TPS] = data[1 * width]; ! 361: s->regs[SONIC_TFC] = data[2 * width]; ! 362: s->regs[SONIC_TSA0] = data[3 * width]; ! 363: s->regs[SONIC_TSA1] = data[4 * width]; ! 364: s->regs[SONIC_TFS] = data[5 * width]; ! 365: ! 366: /* Handle programmable interrupt */ ! 367: if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) { ! 368: s->regs[SONIC_ISR] |= SONIC_ISR_PINT; ! 369: } else { ! 370: s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT; ! 371: } ! 372: ! 373: for (i = 0; i < s->regs[SONIC_TFC]; ) { ! 374: /* Append fragment */ ! 375: len = s->regs[SONIC_TFS]; ! 376: if (tx_len + len > sizeof(s->tx_buffer)) { ! 377: len = sizeof(s->tx_buffer) - tx_len; ! 378: } ! 379: s->memory_rw(s->mem_opaque, ! 380: (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0], ! 381: &s->tx_buffer[tx_len], len, 0); ! 382: tx_len += len; ! 383: ! 384: i++; ! 385: if (i != s->regs[SONIC_TFC]) { ! 386: /* Read next fragment details */ ! 387: size = sizeof(uint16_t) * 3 * width; ! 388: s->memory_rw(s->mem_opaque, ! 389: ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width, ! 390: (uint8_t *)data, size, 0); ! 391: s->regs[SONIC_TSA0] = data[0 * width]; ! 392: s->regs[SONIC_TSA1] = data[1 * width]; ! 393: s->regs[SONIC_TFS] = data[2 * width]; ! 394: } ! 395: } ! 396: ! 397: /* Handle Ethernet checksum */ ! 398: if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) { ! 399: /* Don't append FCS there, to look like slirp packets ! 400: * which don't have one */ ! 401: } else { ! 402: /* Remove existing FCS */ ! 403: tx_len -= 4; ! 404: } ! 405: ! 406: if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) { ! 407: /* Loopback */ ! 408: s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; ! 409: if (s->vc->can_receive(s->vc)) { ! 410: s->loopback_packet = 1; ! 411: s->vc->receive(s->vc, s->tx_buffer, tx_len); ! 412: } ! 413: } else { ! 414: /* Transmit packet */ ! 415: qemu_send_packet(s->vc, s->tx_buffer, tx_len); ! 416: } ! 417: s->regs[SONIC_TCR] |= SONIC_TCR_PTX; ! 418: ! 419: /* Write status */ ! 420: data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */ ! 421: size = sizeof(uint16_t) * width; ! 422: s->memory_rw(s->mem_opaque, ! 423: (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA], ! 424: (uint8_t *)data, size, 1); ! 425: ! 426: if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) { ! 427: /* Read footer of packet */ ! 428: size = sizeof(uint16_t) * width; ! 429: s->memory_rw(s->mem_opaque, ! 430: ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width, ! 431: (uint8_t *)data, size, 0); ! 432: s->regs[SONIC_CTDA] = data[0 * width] & ~0x1; ! 433: if (data[0 * width] & 0x1) { ! 434: /* EOL detected */ ! 435: break; ! 436: } ! 437: } ! 438: } ! 439: ! 440: /* Done */ ! 441: s->regs[SONIC_CR] &= ~SONIC_CR_TXP; ! 442: s->regs[SONIC_ISR] |= SONIC_ISR_TXDN; ! 443: dp8393x_update_irq(s); ! 444: } ! 445: ! 446: static void do_halt_transmission(dp8393xState *s) ! 447: { ! 448: /* Nothing to do */ ! 449: } ! 450: ! 451: static void do_command(dp8393xState *s, uint16_t command) ! 452: { ! 453: if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) { ! 454: s->regs[SONIC_CR] &= ~SONIC_CR_RST; ! 455: return; ! 456: } ! 457: ! 458: s->regs[SONIC_CR] |= (command & SONIC_CR_MASK); ! 459: ! 460: if (command & SONIC_CR_HTX) ! 461: do_halt_transmission(s); ! 462: if (command & SONIC_CR_TXP) ! 463: do_transmit_packets(s); ! 464: if (command & SONIC_CR_RXDIS) ! 465: do_receiver_disable(s); ! 466: if (command & SONIC_CR_RXEN) ! 467: do_receiver_enable(s); ! 468: if (command & SONIC_CR_STP) ! 469: do_stop_timer(s); ! 470: if (command & SONIC_CR_ST) ! 471: do_start_timer(s); ! 472: if (command & SONIC_CR_RST) ! 473: do_software_reset(s); ! 474: if (command & SONIC_CR_RRRA) ! 475: do_read_rra(s); ! 476: if (command & SONIC_CR_LCAM) ! 477: do_load_cam(s); ! 478: } ! 479: ! 480: static uint16_t read_register(dp8393xState *s, int reg) ! 481: { ! 482: uint16_t val = 0; ! 483: ! 484: switch (reg) { ! 485: /* Update data before reading it */ ! 486: case SONIC_WT0: ! 487: case SONIC_WT1: ! 488: update_wt_regs(s); ! 489: val = s->regs[reg]; ! 490: break; ! 491: /* Accept read to some registers only when in reset mode */ ! 492: case SONIC_CAP2: ! 493: case SONIC_CAP1: ! 494: case SONIC_CAP0: ! 495: if (s->regs[SONIC_CR] & SONIC_CR_RST) { ! 496: val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8; ! 497: val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)]; ! 498: } ! 499: break; ! 500: /* All other registers have no special contrainst */ ! 501: default: ! 502: val = s->regs[reg]; ! 503: } ! 504: ! 505: DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]); ! 506: ! 507: return val; ! 508: } ! 509: ! 510: static void write_register(dp8393xState *s, int reg, uint16_t val) ! 511: { ! 512: DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]); ! 513: ! 514: switch (reg) { ! 515: /* Command register */ ! 516: case SONIC_CR: ! 517: do_command(s, val);; ! 518: break; ! 519: /* Prevent write to read-only registers */ ! 520: case SONIC_CAP2: ! 521: case SONIC_CAP1: ! 522: case SONIC_CAP0: ! 523: case SONIC_SR: ! 524: case SONIC_MDT: ! 525: DPRINTF("writing to reg %d invalid\n", reg); ! 526: break; ! 527: /* Accept write to some registers only when in reset mode */ ! 528: case SONIC_DCR: ! 529: if (s->regs[SONIC_CR] & SONIC_CR_RST) { ! 530: s->regs[reg] = val & 0xbfff; ! 531: } else { ! 532: DPRINTF("writing to DCR invalid\n"); ! 533: } ! 534: break; ! 535: case SONIC_DCR2: ! 536: if (s->regs[SONIC_CR] & SONIC_CR_RST) { ! 537: s->regs[reg] = val & 0xf017; ! 538: } else { ! 539: DPRINTF("writing to DCR2 invalid\n"); ! 540: } ! 541: break; ! 542: /* 12 lower bytes are Read Only */ ! 543: case SONIC_TCR: ! 544: s->regs[reg] = val & 0xf000; ! 545: break; ! 546: /* 9 lower bytes are Read Only */ ! 547: case SONIC_RCR: ! 548: s->regs[reg] = val & 0xffe0; ! 549: break; ! 550: /* Ignore most significant bit */ ! 551: case SONIC_IMR: ! 552: s->regs[reg] = val & 0x7fff; ! 553: dp8393x_update_irq(s); ! 554: break; ! 555: /* Clear bits by writing 1 to them */ ! 556: case SONIC_ISR: ! 557: val &= s->regs[reg]; ! 558: s->regs[reg] &= ~val; ! 559: if (val & SONIC_ISR_RBE) { ! 560: do_read_rra(s); ! 561: } ! 562: dp8393x_update_irq(s); ! 563: break; ! 564: /* Ignore least significant bit */ ! 565: case SONIC_RSA: ! 566: case SONIC_REA: ! 567: case SONIC_RRP: ! 568: case SONIC_RWP: ! 569: s->regs[reg] = val & 0xfffe; ! 570: break; ! 571: /* Invert written value for some registers */ ! 572: case SONIC_CRCT: ! 573: case SONIC_FAET: ! 574: case SONIC_MPT: ! 575: s->regs[reg] = val ^ 0xffff; ! 576: break; ! 577: /* All other registers have no special contrainst */ ! 578: default: ! 579: s->regs[reg] = val; ! 580: } ! 581: ! 582: if (reg == SONIC_WT0 || reg == SONIC_WT1) { ! 583: set_next_tick(s); ! 584: } ! 585: } ! 586: ! 587: static void dp8393x_watchdog(void *opaque) ! 588: { ! 589: dp8393xState *s = opaque; ! 590: ! 591: if (s->regs[SONIC_CR] & SONIC_CR_STP) { ! 592: return; ! 593: } ! 594: ! 595: s->regs[SONIC_WT1] = 0xffff; ! 596: s->regs[SONIC_WT0] = 0xffff; ! 597: set_next_tick(s); ! 598: ! 599: /* Signal underflow */ ! 600: s->regs[SONIC_ISR] |= SONIC_ISR_TC; ! 601: dp8393x_update_irq(s); ! 602: } ! 603: ! 604: static uint32_t dp8393x_readw(void *opaque, target_phys_addr_t addr) ! 605: { ! 606: dp8393xState *s = opaque; ! 607: int reg; ! 608: ! 609: if ((addr & ((1 << s->it_shift) - 1)) != 0) { ! 610: return 0; ! 611: } ! 612: ! 613: reg = addr >> s->it_shift; ! 614: return read_register(s, reg); ! 615: } ! 616: ! 617: static uint32_t dp8393x_readb(void *opaque, target_phys_addr_t addr) ! 618: { ! 619: uint16_t v = dp8393x_readw(opaque, addr & ~0x1); ! 620: return (v >> (8 * (addr & 0x1))) & 0xff; ! 621: } ! 622: ! 623: static uint32_t dp8393x_readl(void *opaque, target_phys_addr_t addr) ! 624: { ! 625: uint32_t v; ! 626: v = dp8393x_readw(opaque, addr); ! 627: v |= dp8393x_readw(opaque, addr + 2) << 16; ! 628: return v; ! 629: } ! 630: ! 631: static void dp8393x_writew(void *opaque, target_phys_addr_t addr, uint32_t val) ! 632: { ! 633: dp8393xState *s = opaque; ! 634: int reg; ! 635: ! 636: if ((addr & ((1 << s->it_shift) - 1)) != 0) { ! 637: return; ! 638: } ! 639: ! 640: reg = addr >> s->it_shift; ! 641: ! 642: write_register(s, reg, (uint16_t)val); ! 643: } ! 644: ! 645: static void dp8393x_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) ! 646: { ! 647: uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1); ! 648: ! 649: switch (addr & 3) { ! 650: case 0: ! 651: val = val | (old_val & 0xff00); ! 652: break; ! 653: case 1: ! 654: val = (val << 8) | (old_val & 0x00ff); ! 655: break; ! 656: } ! 657: dp8393x_writew(opaque, addr & ~0x1, val); ! 658: } ! 659: ! 660: static void dp8393x_writel(void *opaque, target_phys_addr_t addr, uint32_t val) ! 661: { ! 662: dp8393x_writew(opaque, addr, val & 0xffff); ! 663: dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff); ! 664: } ! 665: ! 666: static CPUReadMemoryFunc *dp8393x_read[3] = { ! 667: dp8393x_readb, ! 668: dp8393x_readw, ! 669: dp8393x_readl, ! 670: }; ! 671: ! 672: static CPUWriteMemoryFunc *dp8393x_write[3] = { ! 673: dp8393x_writeb, ! 674: dp8393x_writew, ! 675: dp8393x_writel, ! 676: }; ! 677: ! 678: static int nic_can_receive(VLANClientState *vc) ! 679: { ! 680: dp8393xState *s = vc->opaque; ! 681: ! 682: if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN)) ! 683: return 0; ! 684: if (s->regs[SONIC_ISR] & SONIC_ISR_RBE) ! 685: return 0; ! 686: return 1; ! 687: } ! 688: ! 689: static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) ! 690: { ! 691: static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; ! 692: int i; ! 693: ! 694: /* Check for runt packet (remember that checksum is not there) */ ! 695: if (size < 64 - 4) { ! 696: return (s->regs[SONIC_RCR] & SONIC_RCR_RNT) ? 0 : -1; ! 697: } ! 698: ! 699: /* Check promiscuous mode */ ! 700: if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) { ! 701: return 0; ! 702: } ! 703: ! 704: /* Check multicast packets */ ! 705: if ((s->regs[SONIC_RCR] & SONIC_RCR_AMC) && (buf[0] & 1) == 1) { ! 706: return SONIC_RCR_MC; ! 707: } ! 708: ! 709: /* Check broadcast */ ! 710: if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) { ! 711: return SONIC_RCR_BC; ! 712: } ! 713: ! 714: /* Check CAM */ ! 715: for (i = 0; i < 16; i++) { ! 716: if (s->regs[SONIC_CE] & (1 << i)) { ! 717: /* Entry enabled */ ! 718: if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) { ! 719: return 0; ! 720: } ! 721: } ! 722: } ! 723: ! 724: return -1; ! 725: } ! 726: ! 727: static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size) ! 728: { ! 729: uint16_t data[10]; ! 730: dp8393xState *s = vc->opaque; ! 731: int packet_type; ! 732: uint32_t available, address; ! 733: int width, rx_len = size; ! 734: uint32_t checksum; ! 735: ! 736: width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; ! 737: ! 738: s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER | ! 739: SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC); ! 740: ! 741: packet_type = receive_filter(s, buf, size); ! 742: if (packet_type < 0) { ! 743: DPRINTF("packet not for netcard\n"); ! 744: return -1; ! 745: } ! 746: ! 747: /* XXX: Check byte ordering */ ! 748: ! 749: /* Check for EOL */ ! 750: if (s->regs[SONIC_LLFA] & 0x1) { ! 751: /* Are we still in resource exhaustion? */ ! 752: size = sizeof(uint16_t) * 1 * width; ! 753: address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width; ! 754: s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0); ! 755: if (data[0 * width] & 0x1) { ! 756: /* Still EOL ; stop reception */ ! 757: return -1; ! 758: } else { ! 759: s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; ! 760: } ! 761: } ! 762: ! 763: /* Save current position */ ! 764: s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1]; ! 765: s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0]; ! 766: ! 767: /* Calculate the ethernet checksum */ ! 768: #ifdef SONIC_CALCULATE_RXCRC ! 769: checksum = cpu_to_le32(crc32(0, buf, rx_len)); ! 770: #else ! 771: checksum = 0; ! 772: #endif ! 773: ! 774: /* Put packet into RBA */ ! 775: DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]); ! 776: address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]; ! 777: s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1); ! 778: address += rx_len; ! 779: s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1); ! 780: rx_len += 4; ! 781: s->regs[SONIC_CRBA1] = address >> 16; ! 782: s->regs[SONIC_CRBA0] = address & 0xffff; ! 783: available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]; ! 784: available -= rx_len / 2; ! 785: s->regs[SONIC_RBWC1] = available >> 16; ! 786: s->regs[SONIC_RBWC0] = available & 0xffff; ! 787: ! 788: /* Update status */ ! 789: if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) { ! 790: s->regs[SONIC_RCR] |= SONIC_RCR_LPKT; ! 791: } ! 792: s->regs[SONIC_RCR] |= packet_type; ! 793: s->regs[SONIC_RCR] |= SONIC_RCR_PRX; ! 794: if (s->loopback_packet) { ! 795: s->regs[SONIC_RCR] |= SONIC_RCR_LBK; ! 796: s->loopback_packet = 0; ! 797: } ! 798: ! 799: /* Write status to memory */ ! 800: DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]); ! 801: data[0 * width] = s->regs[SONIC_RCR]; /* status */ ! 802: data[1 * width] = rx_len; /* byte count */ ! 803: data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */ ! 804: data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */ ! 805: data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */ ! 806: size = sizeof(uint16_t) * 5 * width; ! 807: s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1); ! 808: ! 809: /* Move to next descriptor */ ! 810: size = sizeof(uint16_t) * width; ! 811: s->memory_rw(s->mem_opaque, ! 812: ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width, ! 813: (uint8_t *)data, size, 0); ! 814: s->regs[SONIC_LLFA] = data[0 * width]; ! 815: if (s->regs[SONIC_LLFA] & 0x1) { ! 816: /* EOL detected */ ! 817: s->regs[SONIC_ISR] |= SONIC_ISR_RDE; ! 818: } else { ! 819: data[0 * width] = 0; /* in_use */ ! 820: s->memory_rw(s->mem_opaque, ! 821: ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width, ! 822: (uint8_t *)data, size, 1); ! 823: s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; ! 824: s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX; ! 825: s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff); ! 826: ! 827: if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) { ! 828: /* Read next RRA */ ! 829: do_read_rra(s); ! 830: } ! 831: } ! 832: ! 833: /* Done */ ! 834: dp8393x_update_irq(s); ! 835: ! 836: return size; ! 837: } ! 838: ! 839: static void nic_reset(void *opaque) ! 840: { ! 841: dp8393xState *s = opaque; ! 842: qemu_del_timer(s->watchdog); ! 843: ! 844: s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS; ! 845: s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR); ! 846: s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT); ! 847: s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX; ! 848: s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM; ! 849: s->regs[SONIC_IMR] = 0; ! 850: s->regs[SONIC_ISR] = 0; ! 851: s->regs[SONIC_DCR2] = 0; ! 852: s->regs[SONIC_EOBC] = 0x02F8; ! 853: s->regs[SONIC_RSC] = 0; ! 854: s->regs[SONIC_CE] = 0; ! 855: s->regs[SONIC_RSC] = 0; ! 856: ! 857: /* Network cable is connected */ ! 858: s->regs[SONIC_RCR] |= SONIC_RCR_CRS; ! 859: ! 860: dp8393x_update_irq(s); ! 861: } ! 862: ! 863: static void nic_cleanup(VLANClientState *vc) ! 864: { ! 865: dp8393xState *s = vc->opaque; ! 866: ! 867: cpu_unregister_io_memory(s->mmio_index); ! 868: ! 869: qemu_del_timer(s->watchdog); ! 870: qemu_free_timer(s->watchdog); ! 871: ! 872: qemu_free(s); ! 873: } ! 874: ! 875: void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, ! 876: qemu_irq irq, void* mem_opaque, ! 877: void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write)) ! 878: { ! 879: dp8393xState *s; ! 880: ! 881: qemu_check_nic_model(nd, "dp83932"); ! 882: ! 883: s = qemu_mallocz(sizeof(dp8393xState)); ! 884: ! 885: s->mem_opaque = mem_opaque; ! 886: s->memory_rw = memory_rw; ! 887: s->it_shift = it_shift; ! 888: s->irq = irq; ! 889: s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s); ! 890: s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ ! 891: ! 892: s->vc = nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, ! 893: nic_can_receive, nic_receive, NULL, ! 894: nic_cleanup, s); ! 895: ! 896: qemu_format_nic_info_str(s->vc, nd->macaddr); ! 897: qemu_register_reset(nic_reset, s); ! 898: nic_reset(s); ! 899: ! 900: s->mmio_index = cpu_register_io_memory(dp8393x_read, dp8393x_write, s); ! 901: cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index); ! 902: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.