|
|
1.1 ! root 1: /* ! 2: * QEMU AMD PC-Net II (Am79C970A) emulation ! 3: * ! 4: * Copyright (c) 2004 Antony T Curtis ! 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: /* This software was written to be compatible with the specification: ! 26: * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet ! 27: * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 ! 28: */ ! 29: ! 30: #include "vl.h" ! 31: ! 32: //#define PCNET_DEBUG ! 33: //#define PCNET_DEBUG_IO ! 34: //#define PCNET_DEBUG_BCR ! 35: //#define PCNET_DEBUG_CSR ! 36: //#define PCNET_DEBUG_RMD ! 37: //#define PCNET_DEBUG_TMD ! 38: //#define PCNET_DEBUG_MATCH ! 39: ! 40: ! 41: #define PCNET_IOPORT_SIZE 0x20 ! 42: #define PCNET_PNPMMIO_SIZE 0x20 ! 43: ! 44: ! 45: typedef struct PCNetState_st PCNetState; ! 46: ! 47: struct PCNetState_st { ! 48: PCIDevice dev; ! 49: VLANClientState *vc; ! 50: NICInfo *nd; ! 51: QEMUTimer *poll_timer; ! 52: int mmio_io_addr, rap, isr, lnkst; ! 53: target_phys_addr_t rdra, tdra; ! 54: uint8_t prom[16]; ! 55: uint16_t csr[128]; ! 56: uint16_t bcr[32]; ! 57: uint64_t timer; ! 58: int xmit_pos, recv_pos; ! 59: uint8_t buffer[4096]; ! 60: int tx_busy; ! 61: }; ! 62: ! 63: /* XXX: using bitfields for target memory structures is almost surely ! 64: not portable, so it should be suppressed ASAP */ ! 65: #ifdef __GNUC__ ! 66: #define PACKED_FIELD(A) A __attribute__ ((packed)) ! 67: #else ! 68: #error FixMe ! 69: #endif ! 70: ! 71: struct qemu_ether_header { ! 72: uint8_t ether_dhost[6]; ! 73: uint8_t ether_shost[6]; ! 74: uint16_t ether_type; ! 75: }; ! 76: ! 77: /* BUS CONFIGURATION REGISTERS */ ! 78: #define BCR_MSRDA 0 ! 79: #define BCR_MSWRA 1 ! 80: #define BCR_MC 2 ! 81: #define BCR_LNKST 4 ! 82: #define BCR_LED1 5 ! 83: #define BCR_LED2 6 ! 84: #define BCR_LED3 7 ! 85: #define BCR_FDC 9 ! 86: #define BCR_BSBC 18 ! 87: #define BCR_EECAS 19 ! 88: #define BCR_SWS 20 ! 89: #define BCR_PLAT 22 ! 90: ! 91: #define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080) ! 92: #define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100) ! 93: #define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF) ! 94: ! 95: #define CSR_INIT(S) !!(((S)->csr[0])&0x0001) ! 96: #define CSR_STRT(S) !!(((S)->csr[0])&0x0002) ! 97: #define CSR_STOP(S) !!(((S)->csr[0])&0x0004) ! 98: #define CSR_TDMD(S) !!(((S)->csr[0])&0x0008) ! 99: #define CSR_TXON(S) !!(((S)->csr[0])&0x0010) ! 100: #define CSR_RXON(S) !!(((S)->csr[0])&0x0020) ! 101: #define CSR_INEA(S) !!(((S)->csr[0])&0x0040) ! 102: #define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020) ! 103: #define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040) ! 104: #define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800) ! 105: #define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000) ! 106: #define CSR_SPND(S) !!(((S)->csr[5])&0x0001) ! 107: #define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000) ! 108: #define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000) ! 109: #define CSR_DRX(S) !!(((S)->csr[15])&0x0001) ! 110: #define CSR_DTX(S) !!(((S)->csr[15])&0x0002) ! 111: #define CSR_LOOP(S) !!(((S)->csr[15])&0x0004) ! 112: #define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000) ! 113: #define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000) ! 114: #define CSR_PROM(S) !!(((S)->csr[15])&0x8000) ! 115: ! 116: #define CSR_CRBC(S) ((S)->csr[40]) ! 117: #define CSR_CRST(S) ((S)->csr[41]) ! 118: #define CSR_CXBC(S) ((S)->csr[42]) ! 119: #define CSR_CXST(S) ((S)->csr[43]) ! 120: #define CSR_NRBC(S) ((S)->csr[44]) ! 121: #define CSR_NRST(S) ((S)->csr[45]) ! 122: #define CSR_POLL(S) ((S)->csr[46]) ! 123: #define CSR_PINT(S) ((S)->csr[47]) ! 124: #define CSR_RCVRC(S) ((S)->csr[72]) ! 125: #define CSR_XMTRC(S) ((S)->csr[74]) ! 126: #define CSR_RCVRL(S) ((S)->csr[76]) ! 127: #define CSR_XMTRL(S) ((S)->csr[78]) ! 128: #define CSR_MISSC(S) ((S)->csr[112]) ! 129: ! 130: #define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16)) ! 131: #define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16)) ! 132: #define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16)) ! 133: #define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16)) ! 134: #define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16)) ! 135: #define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16)) ! 136: #define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16)) ! 137: #define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16)) ! 138: #define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16)) ! 139: #define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16)) ! 140: #define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16)) ! 141: #define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16)) ! 142: #define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16)) ! 143: #define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16)) ! 144: ! 145: #define PHYSADDR(S,A) \ ! 146: (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16)) ! 147: ! 148: struct pcnet_initblk16 { ! 149: uint16_t mode; ! 150: uint16_t padr1; ! 151: uint16_t padr2; ! 152: uint16_t padr3; ! 153: uint16_t ladrf1; ! 154: uint16_t ladrf2; ! 155: uint16_t ladrf3; ! 156: uint16_t ladrf4; ! 157: unsigned PACKED_FIELD(rdra:24); ! 158: unsigned PACKED_FIELD(res1:5); ! 159: unsigned PACKED_FIELD(rlen:3); ! 160: unsigned PACKED_FIELD(tdra:24); ! 161: unsigned PACKED_FIELD(res2:5); ! 162: unsigned PACKED_FIELD(tlen:3); ! 163: }; ! 164: ! 165: struct pcnet_initblk32 { ! 166: uint16_t mode; ! 167: unsigned PACKED_FIELD(res1:4); ! 168: unsigned PACKED_FIELD(rlen:4); ! 169: unsigned PACKED_FIELD(res2:4); ! 170: unsigned PACKED_FIELD(tlen:4); ! 171: uint16_t padr1; ! 172: uint16_t padr2; ! 173: uint16_t padr3; ! 174: uint16_t _res; ! 175: uint16_t ladrf1; ! 176: uint16_t ladrf2; ! 177: uint16_t ladrf3; ! 178: uint16_t ladrf4; ! 179: uint32_t rdra; ! 180: uint32_t tdra; ! 181: }; ! 182: ! 183: struct pcnet_TMD { ! 184: struct { ! 185: unsigned tbadr:32; ! 186: } tmd0; ! 187: struct { ! 188: unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:7), PACKED_FIELD(bpe:1); ! 189: unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(def:1), PACKED_FIELD(one:1); ! 190: unsigned PACKED_FIELD(ltint:1), PACKED_FIELD(nofcs:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); ! 191: } tmd1; ! 192: struct { ! 193: unsigned PACKED_FIELD(trc:4), PACKED_FIELD(res:12); ! 194: unsigned PACKED_FIELD(tdr:10), PACKED_FIELD(rtry:1), PACKED_FIELD(lcar:1); ! 195: unsigned PACKED_FIELD(lcol:1), PACKED_FIELD(exdef:1), PACKED_FIELD(uflo:1), PACKED_FIELD(buff:1); ! 196: } tmd2; ! 197: struct { ! 198: unsigned res:32; ! 199: } tmd3; ! 200: }; ! 201: ! 202: struct pcnet_RMD { ! 203: struct { ! 204: unsigned rbadr:32; ! 205: } rmd0; ! 206: struct { ! 207: unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:4); ! 208: unsigned PACKED_FIELD(bam:1), PACKED_FIELD(lafm:1), PACKED_FIELD(pam:1), PACKED_FIELD(bpe:1); ! 209: unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(buff:1), PACKED_FIELD(crc:1); ! 210: unsigned PACKED_FIELD(oflo:1), PACKED_FIELD(fram:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); ! 211: } rmd1; ! 212: struct { ! 213: unsigned PACKED_FIELD(mcnt:12), PACKED_FIELD(zeros:4); ! 214: unsigned PACKED_FIELD(rpc:8), PACKED_FIELD(rcc:8); ! 215: } rmd2; ! 216: struct { ! 217: unsigned res:32; ! 218: } rmd3; ! 219: }; ! 220: ! 221: ! 222: #define PRINT_TMD(T) printf( \ ! 223: "TMD0 : TBADR=0x%08x\n" \ ! 224: "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \ ! 225: "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \ ! 226: " BPE=%d, BCNT=%d\n" \ ! 227: "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \ ! 228: "LCA=%d, RTR=%d,\n" \ ! 229: " TDR=%d, TRC=%d\n", \ ! 230: (T)->tmd0.tbadr, \ ! 231: (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \ ! 232: (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \ ! 233: (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \ ! 234: 4096-(T)->tmd1.bcnt, \ ! 235: (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\ ! 236: (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \ ! 237: (T)->tmd2.tdr, (T)->tmd2.trc) ! 238: ! 239: #define PRINT_RMD(R) printf( \ ! 240: "RMD0 : RBADR=0x%08x\n" \ ! 241: "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \ ! 242: "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \ ! 243: "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \ ! 244: "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \ ! 245: (R)->rmd0.rbadr, \ ! 246: (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \ ! 247: (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \ ! 248: (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \ ! 249: (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \ ! 250: (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \ ! 251: (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \ ! 252: (R)->rmd2.zeros) ! 253: ! 254: static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) ! 255: { ! 256: if (!BCR_SWSTYLE(s)) { ! 257: uint16_t xda[4]; ! 258: cpu_physical_memory_read(addr, ! 259: (void *)&xda[0], sizeof(xda)); ! 260: ((uint32_t *)tmd)[0] = (xda[0]&0xffff) | ! 261: ((xda[1]&0x00ff) << 16); ! 262: ((uint32_t *)tmd)[1] = (xda[2]&0xffff)| ! 263: ((xda[1] & 0xff00) << 16); ! 264: ((uint32_t *)tmd)[2] = ! 265: (xda[3] & 0xffff) << 16; ! 266: ((uint32_t *)tmd)[3] = 0; ! 267: } ! 268: else ! 269: if (BCR_SWSTYLE(s) != 3) ! 270: cpu_physical_memory_read(addr, (void *)tmd, 16); ! 271: else { ! 272: uint32_t xda[4]; ! 273: cpu_physical_memory_read(addr, ! 274: (void *)&xda[0], sizeof(xda)); ! 275: ((uint32_t *)tmd)[0] = xda[2]; ! 276: ((uint32_t *)tmd)[1] = xda[1]; ! 277: ((uint32_t *)tmd)[2] = xda[0]; ! 278: ((uint32_t *)tmd)[3] = xda[3]; ! 279: } ! 280: } ! 281: ! 282: static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) ! 283: { ! 284: if (!BCR_SWSTYLE(s)) { ! 285: uint16_t xda[4]; ! 286: xda[0] = ((uint32_t *)tmd)[0] & 0xffff; ! 287: xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) | ! 288: ((((uint32_t *)tmd)[1]>>16)&0xff00); ! 289: xda[2] = ((uint32_t *)tmd)[1] & 0xffff; ! 290: xda[3] = ((uint32_t *)tmd)[2] >> 16; ! 291: cpu_physical_memory_write(addr, ! 292: (void *)&xda[0], sizeof(xda)); ! 293: } ! 294: else { ! 295: if (BCR_SWSTYLE(s) != 3) ! 296: cpu_physical_memory_write(addr, (void *)tmd, 16); ! 297: else { ! 298: uint32_t xda[4]; ! 299: xda[0] = ((uint32_t *)tmd)[2]; ! 300: xda[1] = ((uint32_t *)tmd)[1]; ! 301: xda[2] = ((uint32_t *)tmd)[0]; ! 302: xda[3] = ((uint32_t *)tmd)[3]; ! 303: cpu_physical_memory_write(addr, ! 304: (void *)&xda[0], sizeof(xda)); ! 305: } ! 306: } ! 307: } ! 308: ! 309: static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) ! 310: { ! 311: if (!BCR_SWSTYLE(s)) { ! 312: uint16_t rda[4]; ! 313: cpu_physical_memory_read(addr, ! 314: (void *)&rda[0], sizeof(rda)); ! 315: ((uint32_t *)rmd)[0] = (rda[0]&0xffff)| ! 316: ((rda[1] & 0x00ff) << 16); ! 317: ((uint32_t *)rmd)[1] = (rda[2]&0xffff)| ! 318: ((rda[1] & 0xff00) << 16); ! 319: ((uint32_t *)rmd)[2] = rda[3] & 0xffff; ! 320: ((uint32_t *)rmd)[3] = 0; ! 321: } ! 322: else ! 323: if (BCR_SWSTYLE(s) != 3) ! 324: cpu_physical_memory_read(addr, (void *)rmd, 16); ! 325: else { ! 326: uint32_t rda[4]; ! 327: cpu_physical_memory_read(addr, ! 328: (void *)&rda[0], sizeof(rda)); ! 329: ((uint32_t *)rmd)[0] = rda[2]; ! 330: ((uint32_t *)rmd)[1] = rda[1]; ! 331: ((uint32_t *)rmd)[2] = rda[0]; ! 332: ((uint32_t *)rmd)[3] = rda[3]; ! 333: } ! 334: } ! 335: ! 336: static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) ! 337: { ! 338: if (!BCR_SWSTYLE(s)) { ! 339: uint16_t rda[4]; \ ! 340: rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \ ! 341: rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)|\ ! 342: ((((uint32_t *)rmd)[1]>>16)&0xff00);\ ! 343: rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \ ! 344: rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \ ! 345: cpu_physical_memory_write(addr, \ ! 346: (void *)&rda[0], sizeof(rda)); \ ! 347: } ! 348: else { ! 349: if (BCR_SWSTYLE(s) != 3) ! 350: cpu_physical_memory_write(addr, (void *)rmd, 16); ! 351: else { ! 352: uint32_t rda[4]; ! 353: rda[0] = ((uint32_t *)rmd)[2]; ! 354: rda[1] = ((uint32_t *)rmd)[1]; ! 355: rda[2] = ((uint32_t *)rmd)[0]; ! 356: rda[3] = ((uint32_t *)rmd)[3]; ! 357: cpu_physical_memory_write(addr, ! 358: (void *)&rda[0], sizeof(rda)); ! 359: } ! 360: } ! 361: } ! 362: ! 363: ! 364: #define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR) ! 365: ! 366: #define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR) ! 367: ! 368: #define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR) ! 369: ! 370: #define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR) ! 371: ! 372: #if 1 ! 373: ! 374: #define CHECK_RMD(ADDR,RES) do { \ ! 375: struct pcnet_RMD rmd; \ ! 376: RMDLOAD(&rmd,(ADDR)); \ ! 377: (RES) |= (rmd.rmd1.ones != 15) \ ! 378: || (rmd.rmd2.zeros != 0); \ ! 379: } while (0) ! 380: ! 381: #define CHECK_TMD(ADDR,RES) do { \ ! 382: struct pcnet_TMD tmd; \ ! 383: TMDLOAD(&tmd,(ADDR)); \ ! 384: (RES) |= (tmd.tmd1.ones != 15); \ ! 385: } while (0) ! 386: ! 387: #else ! 388: ! 389: #define CHECK_RMD(ADDR,RES) do { \ ! 390: switch (BCR_SWSTYLE(s)) { \ ! 391: case 0x00: \ ! 392: do { \ ! 393: uint16_t rda[4]; \ ! 394: cpu_physical_memory_read((ADDR), \ ! 395: (void *)&rda[0], sizeof(rda)); \ ! 396: (RES) |= (rda[2] & 0xf000)!=0xf000; \ ! 397: (RES) |= (rda[3] & 0xf000)!=0x0000; \ ! 398: } while (0); \ ! 399: break; \ ! 400: case 0x01: \ ! 401: case 0x02: \ ! 402: do { \ ! 403: uint32_t rda[4]; \ ! 404: cpu_physical_memory_read((ADDR), \ ! 405: (void *)&rda[0], sizeof(rda)); \ ! 406: (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ ! 407: (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ ! 408: } while (0); \ ! 409: break; \ ! 410: case 0x03: \ ! 411: do { \ ! 412: uint32_t rda[4]; \ ! 413: cpu_physical_memory_read((ADDR), \ ! 414: (void *)&rda[0], sizeof(rda)); \ ! 415: (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ ! 416: (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ ! 417: } while (0); \ ! 418: break; \ ! 419: } \ ! 420: } while (0) ! 421: ! 422: #define CHECK_TMD(ADDR,RES) do { \ ! 423: switch (BCR_SWSTYLE(s)) { \ ! 424: case 0x00: \ ! 425: do { \ ! 426: uint16_t xda[4]; \ ! 427: cpu_physical_memory_read((ADDR), \ ! 428: (void *)&xda[0], sizeof(xda)); \ ! 429: (RES) |= (xda[2] & 0xf000)!=0xf000;\ ! 430: } while (0); \ ! 431: break; \ ! 432: case 0x01: \ ! 433: case 0x02: \ ! 434: case 0x03: \ ! 435: do { \ ! 436: uint32_t xda[4]; \ ! 437: cpu_physical_memory_read((ADDR), \ ! 438: (void *)&xda[0], sizeof(xda)); \ ! 439: (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ ! 440: } while (0); \ ! 441: break; \ ! 442: } \ ! 443: } while (0) ! 444: ! 445: #endif ! 446: ! 447: #define PRINT_PKTHDR(BUF) do { \ ! 448: struct qemu_ether_header *hdr = (void *)(BUF); \ ! 449: printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \ ! 450: "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \ ! 451: "type=0x%04x (bcast=%d)\n", \ ! 452: hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \ ! 453: hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \ ! 454: hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \ ! 455: hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \ ! 456: be16_to_cpu(hdr->ether_type), \ ! 457: !!ETHER_IS_MULTICAST(hdr->ether_dhost)); \ ! 458: } while (0) ! 459: ! 460: #define MULTICAST_FILTER_LEN 8 ! 461: ! 462: static inline uint32_t lnc_mchash(const uint8_t *ether_addr) ! 463: { ! 464: #define LNC_POLYNOMIAL 0xEDB88320UL ! 465: uint32_t crc = 0xFFFFFFFF; ! 466: int idx, bit; ! 467: uint8_t data; ! 468: ! 469: for (idx = 0; idx < 6; idx++) { ! 470: for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) { ! 471: crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0); ! 472: data >>= 1; ! 473: } ! 474: } ! 475: return crc; ! 476: #undef LNC_POLYNOMIAL ! 477: } ! 478: ! 479: #define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) ! 480: ! 481: /* generated using the AUTODIN II polynomial ! 482: * x^32 + x^26 + x^23 + x^22 + x^16 + ! 483: * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 ! 484: */ ! 485: static const uint32_t crctab[256] = { ! 486: 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, ! 487: 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, ! 488: 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, ! 489: 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, ! 490: 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, ! 491: 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, ! 492: 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, ! 493: 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, ! 494: 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, ! 495: 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, ! 496: 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, ! 497: 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, ! 498: 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, ! 499: 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, ! 500: 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, ! 501: 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, ! 502: 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, ! 503: 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, ! 504: 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, ! 505: 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, ! 506: 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, ! 507: 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, ! 508: 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, ! 509: 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, ! 510: 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, ! 511: 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, ! 512: 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, ! 513: 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, ! 514: 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, ! 515: 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, ! 516: 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, ! 517: 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, ! 518: 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, ! 519: 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, ! 520: 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, ! 521: 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, ! 522: 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, ! 523: 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, ! 524: 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, ! 525: 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, ! 526: 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, ! 527: 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, ! 528: 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, ! 529: 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, ! 530: 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, ! 531: 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, ! 532: 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, ! 533: 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, ! 534: 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, ! 535: 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, ! 536: 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, ! 537: 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, ! 538: 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, ! 539: 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, ! 540: 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, ! 541: 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, ! 542: 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, ! 543: 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, ! 544: 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, ! 545: 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, ! 546: 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, ! 547: 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, ! 548: 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, ! 549: 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, ! 550: }; ! 551: ! 552: static inline int padr_match(PCNetState *s, const uint8_t *buf, int size) ! 553: { ! 554: struct qemu_ether_header *hdr = (void *)buf; ! 555: uint8_t padr[6] = { ! 556: s->csr[12] & 0xff, s->csr[12] >> 8, ! 557: s->csr[13] & 0xff, s->csr[13] >> 8, ! 558: s->csr[14] & 0xff, s->csr[14] >> 8 ! 559: }; ! 560: int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6); ! 561: #ifdef PCNET_DEBUG_MATCH ! 562: printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " ! 563: "padr=%02x:%02x:%02x:%02x:%02x:%02x\n", ! 564: hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], ! 565: hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], ! 566: padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]); ! 567: printf("padr_match result=%d\n", result); ! 568: #endif ! 569: return result; ! 570: } ! 571: ! 572: static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size) ! 573: { ! 574: static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ! 575: struct qemu_ether_header *hdr = (void *)buf; ! 576: int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6); ! 577: #ifdef PCNET_DEBUG_MATCH ! 578: printf("padr_bcast result=%d\n", result); ! 579: #endif ! 580: return result; ! 581: } ! 582: ! 583: static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) ! 584: { ! 585: struct qemu_ether_header *hdr = (void *)buf; ! 586: if ((*(hdr->ether_dhost)&0x01) && ! 587: ((uint64_t *)&s->csr[8])[0] != 0LL) { ! 588: uint8_t ladr[8] = { ! 589: s->csr[8] & 0xff, s->csr[8] >> 8, ! 590: s->csr[9] & 0xff, s->csr[9] >> 8, ! 591: s->csr[10] & 0xff, s->csr[10] >> 8, ! 592: s->csr[11] & 0xff, s->csr[11] >> 8 ! 593: }; ! 594: int index = lnc_mchash(hdr->ether_dhost) >> 26; ! 595: return !!(ladr[index >> 3] & (1 << (index & 7))); ! 596: } ! 597: return 0; ! 598: } ! 599: ! 600: static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx) ! 601: { ! 602: while (idx < 1) idx += CSR_RCVRL(s); ! 603: return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8)); ! 604: } ! 605: ! 606: static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time) ! 607: { ! 608: int64_t next_time = current_time + ! 609: muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)), ! 610: ticks_per_sec, 33000000L); ! 611: if (next_time <= current_time) ! 612: next_time = current_time + 1; ! 613: return next_time; ! 614: } ! 615: ! 616: static void pcnet_poll(PCNetState *s); ! 617: static void pcnet_poll_timer(void *opaque); ! 618: ! 619: static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap); ! 620: static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value); ! 621: static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val); ! 622: static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); ! 623: ! 624: static void pcnet_s_reset(PCNetState *s) ! 625: { ! 626: #ifdef PCNET_DEBUG ! 627: printf("pcnet_s_reset\n"); ! 628: #endif ! 629: ! 630: s->lnkst = 0x40; ! 631: s->rdra = 0; ! 632: s->tdra = 0; ! 633: s->rap = 0; ! 634: ! 635: s->bcr[BCR_BSBC] &= ~0x0080; ! 636: ! 637: s->csr[0] = 0x0004; ! 638: s->csr[3] = 0x0000; ! 639: s->csr[4] = 0x0115; ! 640: s->csr[5] = 0x0000; ! 641: s->csr[6] = 0x0000; ! 642: s->csr[8] = 0; ! 643: s->csr[9] = 0; ! 644: s->csr[10] = 0; ! 645: s->csr[11] = 0; ! 646: s->csr[12] = le16_to_cpu(((uint16_t *)&s->prom[0])[0]); ! 647: s->csr[13] = le16_to_cpu(((uint16_t *)&s->prom[0])[1]); ! 648: s->csr[14] = le16_to_cpu(((uint16_t *)&s->prom[0])[2]); ! 649: s->csr[15] &= 0x21c4; ! 650: s->csr[72] = 1; ! 651: s->csr[74] = 1; ! 652: s->csr[76] = 1; ! 653: s->csr[78] = 1; ! 654: s->csr[80] = 0x1410; ! 655: s->csr[88] = 0x1003; ! 656: s->csr[89] = 0x0262; ! 657: s->csr[94] = 0x0000; ! 658: s->csr[100] = 0x0200; ! 659: s->csr[103] = 0x0105; ! 660: s->csr[103] = 0x0105; ! 661: s->csr[112] = 0x0000; ! 662: s->csr[114] = 0x0000; ! 663: s->csr[122] = 0x0000; ! 664: s->csr[124] = 0x0000; ! 665: ! 666: s->tx_busy = 0; ! 667: } ! 668: ! 669: static void pcnet_update_irq(PCNetState *s) ! 670: { ! 671: int isr = 0; ! 672: s->csr[0] &= ~0x0080; ! 673: ! 674: #if 1 ! 675: if (((s->csr[0] & ~s->csr[3]) & 0x5f00) || ! 676: (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) || ! 677: (((s->csr[5]>>1) & s->csr[5]) & 0x0048)) ! 678: #else ! 679: if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ || ! 680: (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ || ! 681: (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ || ! 682: (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ || ! 683: (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ || ! 684: (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ || ! 685: (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ || ! 686: (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ || ! 687: (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ || ! 688: (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ || ! 689: (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ || ! 690: (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */) ! 691: #endif ! 692: { ! 693: ! 694: isr = CSR_INEA(s); ! 695: s->csr[0] |= 0x0080; ! 696: } ! 697: ! 698: if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */ ! 699: s->csr[4] &= ~0x0080; ! 700: s->csr[4] |= 0x0040; ! 701: s->csr[0] |= 0x0080; ! 702: isr = 1; ! 703: #ifdef PCNET_DEBUG ! 704: printf("pcnet user int\n"); ! 705: #endif ! 706: } ! 707: ! 708: #if 1 ! 709: if (((s->csr[5]>>1) & s->csr[5]) & 0x0500) ! 710: #else ! 711: if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ || ! 712: (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ ) ! 713: #endif ! 714: { ! 715: isr = 1; ! 716: s->csr[0] |= 0x0080; ! 717: } ! 718: ! 719: if (isr != s->isr) { ! 720: #ifdef PCNET_DEBUG ! 721: printf("pcnet: INTA=%d\n", isr); ! 722: #endif ! 723: } ! 724: pci_set_irq(&s->dev, 0, isr); ! 725: s->isr = isr; ! 726: } ! 727: ! 728: static void pcnet_init(PCNetState *s) ! 729: { ! 730: #ifdef PCNET_DEBUG ! 731: printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s))); ! 732: #endif ! 733: ! 734: #define PCNET_INIT() do { \ ! 735: cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)), \ ! 736: (uint8_t *)&initblk, sizeof(initblk)); \ ! 737: s->csr[15] = le16_to_cpu(initblk.mode); \ ! 738: CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \ ! 739: CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \ ! 740: s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \ ! 741: s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \ ! 742: s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \ ! 743: s->csr[10] = le16_to_cpu(initblk.ladrf3); \ ! 744: s->csr[11] = le16_to_cpu(initblk.ladrf4); \ ! 745: s->csr[12] = le16_to_cpu(initblk.padr1); \ ! 746: s->csr[13] = le16_to_cpu(initblk.padr2); \ ! 747: s->csr[14] = le16_to_cpu(initblk.padr3); \ ! 748: s->rdra = PHYSADDR(s,initblk.rdra); \ ! 749: s->tdra = PHYSADDR(s,initblk.tdra); \ ! 750: } while (0) ! 751: ! 752: if (BCR_SSIZE32(s)) { ! 753: struct pcnet_initblk32 initblk; ! 754: PCNET_INIT(); ! 755: #ifdef PCNET_DEBUG ! 756: printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", ! 757: initblk.rlen, initblk.tlen); ! 758: #endif ! 759: } else { ! 760: struct pcnet_initblk16 initblk; ! 761: PCNET_INIT(); ! 762: #ifdef PCNET_DEBUG ! 763: printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", ! 764: initblk.rlen, initblk.tlen); ! 765: #endif ! 766: } ! 767: ! 768: #undef PCNET_INIT ! 769: ! 770: CSR_RCVRC(s) = CSR_RCVRL(s); ! 771: CSR_XMTRC(s) = CSR_XMTRL(s); ! 772: ! 773: #ifdef PCNET_DEBUG ! 774: printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", ! 775: BCR_SSIZE32(s), ! 776: s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s)); ! 777: #endif ! 778: ! 779: s->csr[0] |= 0x0101; ! 780: s->csr[0] &= ~0x0004; /* clear STOP bit */ ! 781: } ! 782: ! 783: static void pcnet_start(PCNetState *s) ! 784: { ! 785: #ifdef PCNET_DEBUG ! 786: printf("pcnet_start\n"); ! 787: #endif ! 788: ! 789: if (!CSR_DTX(s)) ! 790: s->csr[0] |= 0x0010; /* set TXON */ ! 791: ! 792: if (!CSR_DRX(s)) ! 793: s->csr[0] |= 0x0020; /* set RXON */ ! 794: ! 795: s->csr[0] &= ~0x0004; /* clear STOP bit */ ! 796: s->csr[0] |= 0x0002; ! 797: } ! 798: ! 799: static void pcnet_stop(PCNetState *s) ! 800: { ! 801: #ifdef PCNET_DEBUG ! 802: printf("pcnet_stop\n"); ! 803: #endif ! 804: s->csr[0] &= ~0x7feb; ! 805: s->csr[0] |= 0x0014; ! 806: s->csr[4] &= ~0x02c2; ! 807: s->csr[5] &= ~0x0011; ! 808: pcnet_poll_timer(s); ! 809: } ! 810: ! 811: static void pcnet_rdte_poll(PCNetState *s) ! 812: { ! 813: s->csr[28] = s->csr[29] = 0; ! 814: if (s->rdra) { ! 815: int bad = 0; ! 816: #if 1 ! 817: target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); ! 818: target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); ! 819: target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s)); ! 820: #else ! 821: target_phys_addr_t crda = s->rdra + ! 822: (CSR_RCVRL(s) - CSR_RCVRC(s)) * ! 823: (BCR_SWSTYLE(s) ? 16 : 8 ); ! 824: int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1; ! 825: target_phys_addr_t nrda = s->rdra + ! 826: (CSR_RCVRL(s) - nrdc) * ! 827: (BCR_SWSTYLE(s) ? 16 : 8 ); ! 828: int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1; ! 829: target_phys_addr_t nnrd = s->rdra + ! 830: (CSR_RCVRL(s) - nnrc) * ! 831: (BCR_SWSTYLE(s) ? 16 : 8 ); ! 832: #endif ! 833: ! 834: CHECK_RMD(PHYSADDR(s,crda), bad); ! 835: if (!bad) { ! 836: CHECK_RMD(PHYSADDR(s,nrda), bad); ! 837: if (bad || (nrda == crda)) nrda = 0; ! 838: CHECK_RMD(PHYSADDR(s,nnrd), bad); ! 839: if (bad || (nnrd == crda)) nnrd = 0; ! 840: ! 841: s->csr[28] = crda & 0xffff; ! 842: s->csr[29] = crda >> 16; ! 843: s->csr[26] = nrda & 0xffff; ! 844: s->csr[27] = nrda >> 16; ! 845: s->csr[36] = nnrd & 0xffff; ! 846: s->csr[37] = nnrd >> 16; ! 847: #ifdef PCNET_DEBUG ! 848: if (bad) { ! 849: printf("pcnet: BAD RMD RECORDS AFTER 0x%08x\n", ! 850: PHYSADDR(s,crda)); ! 851: } ! 852: } else { ! 853: printf("pcnet: BAD RMD RDA=0x%08x\n", PHYSADDR(s,crda)); ! 854: #endif ! 855: } ! 856: } ! 857: ! 858: if (CSR_CRDA(s)) { ! 859: struct pcnet_RMD rmd; ! 860: RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s))); ! 861: CSR_CRBC(s) = rmd.rmd1.bcnt; ! 862: CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16; ! 863: #ifdef PCNET_DEBUG_RMD_X ! 864: printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n", ! 865: PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s), ! 866: ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]); ! 867: PRINT_RMD(&rmd); ! 868: #endif ! 869: } else { ! 870: CSR_CRBC(s) = CSR_CRST(s) = 0; ! 871: } ! 872: ! 873: if (CSR_NRDA(s)) { ! 874: struct pcnet_RMD rmd; ! 875: RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s))); ! 876: CSR_NRBC(s) = rmd.rmd1.bcnt; ! 877: CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16; ! 878: } else { ! 879: CSR_NRBC(s) = CSR_NRST(s) = 0; ! 880: } ! 881: ! 882: } ! 883: ! 884: static int pcnet_tdte_poll(PCNetState *s) ! 885: { ! 886: s->csr[34] = s->csr[35] = 0; ! 887: if (s->tdra) { ! 888: target_phys_addr_t cxda = s->tdra + ! 889: (CSR_XMTRL(s) - CSR_XMTRC(s)) * ! 890: (BCR_SWSTYLE(s) ? 16 : 8 ); ! 891: int bad = 0; ! 892: CHECK_TMD(PHYSADDR(s, cxda),bad); ! 893: if (!bad) { ! 894: if (CSR_CXDA(s) != cxda) { ! 895: s->csr[60] = s->csr[34]; ! 896: s->csr[61] = s->csr[35]; ! 897: s->csr[62] = CSR_CXBC(s); ! 898: s->csr[63] = CSR_CXST(s); ! 899: } ! 900: s->csr[34] = cxda & 0xffff; ! 901: s->csr[35] = cxda >> 16; ! 902: #ifdef PCNET_DEBUG ! 903: } else { ! 904: printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda)); ! 905: #endif ! 906: } ! 907: } ! 908: ! 909: if (CSR_CXDA(s)) { ! 910: struct pcnet_TMD tmd; ! 911: ! 912: TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); ! 913: ! 914: CSR_CXBC(s) = tmd.tmd1.bcnt; ! 915: CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16; ! 916: } else { ! 917: CSR_CXBC(s) = CSR_CXST(s) = 0; ! 918: } ! 919: ! 920: return !!(CSR_CXST(s) & 0x8000); ! 921: } ! 922: ! 923: static int pcnet_can_receive(void *opaque) ! 924: { ! 925: PCNetState *s = opaque; ! 926: if (CSR_STOP(s) || CSR_SPND(s)) ! 927: return 0; ! 928: ! 929: if (s->recv_pos > 0) ! 930: return 0; ! 931: ! 932: return sizeof(s->buffer)-16; ! 933: } ! 934: ! 935: #define MIN_BUF_SIZE 60 ! 936: ! 937: static void pcnet_receive(void *opaque, const uint8_t *buf, int size) ! 938: { ! 939: PCNetState *s = opaque; ! 940: int is_padr = 0, is_bcast = 0, is_ladr = 0; ! 941: uint8_t buf1[60]; ! 942: ! 943: if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) ! 944: return; ! 945: ! 946: #ifdef PCNET_DEBUG ! 947: printf("pcnet_receive size=%d\n", size); ! 948: #endif ! 949: ! 950: /* if too small buffer, then expand it */ ! 951: if (size < MIN_BUF_SIZE) { ! 952: memcpy(buf1, buf, size); ! 953: memset(buf1 + size, 0, MIN_BUF_SIZE - size); ! 954: buf = buf1; ! 955: size = MIN_BUF_SIZE; ! 956: } ! 957: ! 958: if (CSR_PROM(s) ! 959: || (is_padr=padr_match(s, buf, size)) ! 960: || (is_bcast=padr_bcast(s, buf, size)) ! 961: || (is_ladr=ladr_match(s, buf, size))) { ! 962: ! 963: pcnet_rdte_poll(s); ! 964: ! 965: if (!(CSR_CRST(s) & 0x8000) && s->rdra) { ! 966: struct pcnet_RMD rmd; ! 967: int rcvrc = CSR_RCVRC(s)-1,i; ! 968: target_phys_addr_t nrda; ! 969: for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) { ! 970: if (rcvrc <= 1) ! 971: rcvrc = CSR_RCVRL(s); ! 972: nrda = s->rdra + ! 973: (CSR_RCVRL(s) - rcvrc) * ! 974: (BCR_SWSTYLE(s) ? 16 : 8 ); ! 975: RMDLOAD(&rmd, PHYSADDR(s,nrda)); ! 976: if (rmd.rmd1.own) { ! 977: #ifdef PCNET_DEBUG_RMD ! 978: printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", ! 979: rcvrc, CSR_RCVRC(s)); ! 980: #endif ! 981: CSR_RCVRC(s) = rcvrc; ! 982: pcnet_rdte_poll(s); ! 983: break; ! 984: } ! 985: } ! 986: } ! 987: ! 988: if (!(CSR_CRST(s) & 0x8000)) { ! 989: #ifdef PCNET_DEBUG_RMD ! 990: printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s)); ! 991: #endif ! 992: s->csr[0] |= 0x1000; /* Set MISS flag */ ! 993: CSR_MISSC(s)++; ! 994: } else { ! 995: uint8_t *src = &s->buffer[8]; ! 996: target_phys_addr_t crda = CSR_CRDA(s); ! 997: struct pcnet_RMD rmd; ! 998: int pktcount = 0; ! 999: ! 1000: memcpy(src, buf, size); ! 1001: ! 1002: #if 1 ! 1003: /* no need to compute the CRC */ ! 1004: src[size] = 0; ! 1005: src[size + 1] = 0; ! 1006: src[size + 2] = 0; ! 1007: src[size + 3] = 0; ! 1008: size += 4; ! 1009: #else ! 1010: /* XXX: avoid CRC generation */ ! 1011: if (!CSR_ASTRP_RCV(s)) { ! 1012: uint32_t fcs = ~0; ! 1013: uint8_t *p = src; ! 1014: ! 1015: while (size < 46) { ! 1016: src[size++] = 0; ! 1017: } ! 1018: ! 1019: while (p != &src[size]) { ! 1020: CRC(fcs, *p++); ! 1021: } ! 1022: ((uint32_t *)&src[size])[0] = htonl(fcs); ! 1023: size += 4; /* FCS at end of packet */ ! 1024: } else size += 4; ! 1025: #endif ! 1026: ! 1027: #ifdef PCNET_DEBUG_MATCH ! 1028: PRINT_PKTHDR(buf); ! 1029: #endif ! 1030: ! 1031: RMDLOAD(&rmd, PHYSADDR(s,crda)); ! 1032: /*if (!CSR_LAPPEN(s))*/ ! 1033: rmd.rmd1.stp = 1; ! 1034: ! 1035: #define PCNET_RECV_STORE() do { \ ! 1036: int count = MIN(4096 - rmd.rmd1.bcnt,size); \ ! 1037: target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \ ! 1038: cpu_physical_memory_write(rbadr, src, count); \ ! 1039: src += count; size -= count; \ ! 1040: rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \ ! 1041: RMDSTORE(&rmd, PHYSADDR(s,crda)); \ ! 1042: pktcount++; \ ! 1043: } while (0) ! 1044: ! 1045: PCNET_RECV_STORE(); ! 1046: if ((size > 0) && CSR_NRDA(s)) { ! 1047: target_phys_addr_t nrda = CSR_NRDA(s); ! 1048: RMDLOAD(&rmd, PHYSADDR(s,nrda)); ! 1049: if (rmd.rmd1.own) { ! 1050: crda = nrda; ! 1051: PCNET_RECV_STORE(); ! 1052: if ((size > 0) && (nrda=CSR_NNRD(s))) { ! 1053: RMDLOAD(&rmd, PHYSADDR(s,nrda)); ! 1054: if (rmd.rmd1.own) { ! 1055: crda = nrda; ! 1056: PCNET_RECV_STORE(); ! 1057: } ! 1058: } ! 1059: } ! 1060: } ! 1061: ! 1062: #undef PCNET_RECV_STORE ! 1063: ! 1064: RMDLOAD(&rmd, PHYSADDR(s,crda)); ! 1065: if (size == 0) { ! 1066: rmd.rmd1.enp = 1; ! 1067: rmd.rmd1.pam = !CSR_PROM(s) && is_padr; ! 1068: rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr; ! 1069: rmd.rmd1.bam = !CSR_PROM(s) && is_bcast; ! 1070: } else { ! 1071: rmd.rmd1.oflo = 1; ! 1072: rmd.rmd1.buff = 1; ! 1073: rmd.rmd1.err = 1; ! 1074: } ! 1075: RMDSTORE(&rmd, PHYSADDR(s,crda)); ! 1076: s->csr[0] |= 0x0400; ! 1077: ! 1078: #ifdef PCNET_DEBUG ! 1079: printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", ! 1080: CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount); ! 1081: #endif ! 1082: #ifdef PCNET_DEBUG_RMD ! 1083: PRINT_RMD(&rmd); ! 1084: #endif ! 1085: ! 1086: while (pktcount--) { ! 1087: if (CSR_RCVRC(s) <= 1) ! 1088: CSR_RCVRC(s) = CSR_RCVRL(s); ! 1089: else ! 1090: CSR_RCVRC(s)--; ! 1091: } ! 1092: ! 1093: pcnet_rdte_poll(s); ! 1094: ! 1095: } ! 1096: } ! 1097: ! 1098: pcnet_poll(s); ! 1099: pcnet_update_irq(s); ! 1100: } ! 1101: ! 1102: static void pcnet_transmit(PCNetState *s) ! 1103: { ! 1104: target_phys_addr_t xmit_cxda = 0; ! 1105: int count = CSR_XMTRL(s)-1; ! 1106: s->xmit_pos = -1; ! 1107: ! 1108: if (!CSR_TXON(s)) { ! 1109: s->csr[0] &= ~0x0008; ! 1110: return; ! 1111: } ! 1112: ! 1113: s->tx_busy = 1; ! 1114: ! 1115: txagain: ! 1116: if (pcnet_tdte_poll(s)) { ! 1117: struct pcnet_TMD tmd; ! 1118: ! 1119: TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); ! 1120: ! 1121: #ifdef PCNET_DEBUG_TMD ! 1122: printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s))); ! 1123: PRINT_TMD(&tmd); ! 1124: #endif ! 1125: if (tmd.tmd1.stp) { ! 1126: s->xmit_pos = 0; ! 1127: if (!tmd.tmd1.enp) { ! 1128: cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), ! 1129: s->buffer, 4096 - tmd.tmd1.bcnt); ! 1130: s->xmit_pos += 4096 - tmd.tmd1.bcnt; ! 1131: } ! 1132: xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); ! 1133: } ! 1134: if (tmd.tmd1.enp && (s->xmit_pos >= 0)) { ! 1135: cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), ! 1136: s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt); ! 1137: s->xmit_pos += 4096 - tmd.tmd1.bcnt; ! 1138: #ifdef PCNET_DEBUG ! 1139: printf("pcnet_transmit size=%d\n", s->xmit_pos); ! 1140: #endif ! 1141: if (CSR_LOOP(s)) ! 1142: pcnet_receive(s, s->buffer, s->xmit_pos); ! 1143: else ! 1144: qemu_send_packet(s->vc, s->buffer, s->xmit_pos); ! 1145: ! 1146: s->csr[0] &= ~0x0008; /* clear TDMD */ ! 1147: s->csr[4] |= 0x0004; /* set TXSTRT */ ! 1148: s->xmit_pos = -1; ! 1149: } ! 1150: ! 1151: tmd.tmd1.own = 0; ! 1152: TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); ! 1153: if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint)) ! 1154: s->csr[0] |= 0x0200; /* set TINT */ ! 1155: ! 1156: if (CSR_XMTRC(s)<=1) ! 1157: CSR_XMTRC(s) = CSR_XMTRL(s); ! 1158: else ! 1159: CSR_XMTRC(s)--; ! 1160: if (count--) ! 1161: goto txagain; ! 1162: ! 1163: } else ! 1164: if (s->xmit_pos >= 0) { ! 1165: struct pcnet_TMD tmd; ! 1166: TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda)); ! 1167: tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1; ! 1168: tmd.tmd1.own = 0; ! 1169: TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda)); ! 1170: s->csr[0] |= 0x0200; /* set TINT */ ! 1171: if (!CSR_DXSUFLO(s)) { ! 1172: s->csr[0] &= ~0x0010; ! 1173: } else ! 1174: if (count--) ! 1175: goto txagain; ! 1176: } ! 1177: ! 1178: s->tx_busy = 0; ! 1179: } ! 1180: ! 1181: static void pcnet_poll(PCNetState *s) ! 1182: { ! 1183: if (CSR_RXON(s)) { ! 1184: pcnet_rdte_poll(s); ! 1185: } ! 1186: ! 1187: if (CSR_TDMD(s) || ! 1188: (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s))) ! 1189: { ! 1190: /* prevent recursion */ ! 1191: if (s->tx_busy) ! 1192: return; ! 1193: ! 1194: pcnet_transmit(s); ! 1195: } ! 1196: } ! 1197: ! 1198: static void pcnet_poll_timer(void *opaque) ! 1199: { ! 1200: PCNetState *s = opaque; ! 1201: ! 1202: qemu_del_timer(s->poll_timer); ! 1203: ! 1204: if (CSR_TDMD(s)) { ! 1205: pcnet_transmit(s); ! 1206: } ! 1207: ! 1208: pcnet_update_irq(s); ! 1209: ! 1210: if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) { ! 1211: uint64_t now = qemu_get_clock(vm_clock) * 33; ! 1212: if (!s->timer || !now) ! 1213: s->timer = now; ! 1214: else { ! 1215: uint64_t t = now - s->timer + CSR_POLL(s); ! 1216: if (t > 0xffffLL) { ! 1217: pcnet_poll(s); ! 1218: CSR_POLL(s) = CSR_PINT(s); ! 1219: } else ! 1220: CSR_POLL(s) = t; ! 1221: } ! 1222: qemu_mod_timer(s->poll_timer, ! 1223: pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock))); ! 1224: } ! 1225: } ! 1226: ! 1227: ! 1228: static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value) ! 1229: { ! 1230: uint16_t val = new_value; ! 1231: #ifdef PCNET_DEBUG_CSR ! 1232: printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val); ! 1233: #endif ! 1234: switch (rap) { ! 1235: case 0: ! 1236: s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */ ! 1237: ! 1238: s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048); ! 1239: ! 1240: val = (val & 0x007f) | (s->csr[0] & 0x7f00); ! 1241: ! 1242: /* IFF STOP, STRT and INIT are set, clear STRT and INIT */ ! 1243: if ((val&7) == 7) ! 1244: val &= ~3; ! 1245: ! 1246: if (!CSR_STOP(s) && (val & 4)) ! 1247: pcnet_stop(s); ! 1248: ! 1249: if (!CSR_INIT(s) && (val & 1)) ! 1250: pcnet_init(s); ! 1251: ! 1252: if (!CSR_STRT(s) && (val & 2)) ! 1253: pcnet_start(s); ! 1254: ! 1255: if (CSR_TDMD(s)) ! 1256: pcnet_transmit(s); ! 1257: ! 1258: return; ! 1259: case 1: ! 1260: case 2: ! 1261: case 8: ! 1262: case 9: ! 1263: case 10: ! 1264: case 11: ! 1265: case 12: ! 1266: case 13: ! 1267: case 14: ! 1268: case 15: ! 1269: case 18: /* CRBAL */ ! 1270: case 19: /* CRBAU */ ! 1271: case 20: /* CXBAL */ ! 1272: case 21: /* CXBAU */ ! 1273: case 22: /* NRBAU */ ! 1274: case 23: /* NRBAU */ ! 1275: case 24: ! 1276: case 25: ! 1277: case 26: ! 1278: case 27: ! 1279: case 28: ! 1280: case 29: ! 1281: case 30: ! 1282: case 31: ! 1283: case 32: ! 1284: case 33: ! 1285: case 34: ! 1286: case 35: ! 1287: case 36: ! 1288: case 37: ! 1289: case 38: ! 1290: case 39: ! 1291: case 40: /* CRBC */ ! 1292: case 41: ! 1293: case 42: /* CXBC */ ! 1294: case 43: ! 1295: case 44: ! 1296: case 45: ! 1297: case 46: /* POLL */ ! 1298: case 47: /* POLLINT */ ! 1299: case 72: ! 1300: case 74: ! 1301: case 76: /* RCVRL */ ! 1302: case 78: /* XMTRL */ ! 1303: case 112: ! 1304: if (CSR_STOP(s) || CSR_SPND(s)) ! 1305: break; ! 1306: return; ! 1307: case 3: ! 1308: break; ! 1309: case 4: ! 1310: s->csr[4] &= ~(val & 0x026a); ! 1311: val &= ~0x026a; val |= s->csr[4] & 0x026a; ! 1312: break; ! 1313: case 5: ! 1314: s->csr[5] &= ~(val & 0x0a90); ! 1315: val &= ~0x0a90; val |= s->csr[5] & 0x0a90; ! 1316: break; ! 1317: case 16: ! 1318: pcnet_csr_writew(s,1,val); ! 1319: return; ! 1320: case 17: ! 1321: pcnet_csr_writew(s,2,val); ! 1322: return; ! 1323: case 58: ! 1324: pcnet_bcr_writew(s,BCR_SWS,val); ! 1325: break; ! 1326: default: ! 1327: return; ! 1328: } ! 1329: s->csr[rap] = val; ! 1330: } ! 1331: ! 1332: static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap) ! 1333: { ! 1334: uint32_t val; ! 1335: switch (rap) { ! 1336: case 0: ! 1337: pcnet_update_irq(s); ! 1338: val = s->csr[0]; ! 1339: val |= (val & 0x7800) ? 0x8000 : 0; ! 1340: break; ! 1341: case 16: ! 1342: return pcnet_csr_readw(s,1); ! 1343: case 17: ! 1344: return pcnet_csr_readw(s,2); ! 1345: case 58: ! 1346: return pcnet_bcr_readw(s,BCR_SWS); ! 1347: case 88: ! 1348: val = s->csr[89]; ! 1349: val <<= 16; ! 1350: val |= s->csr[88]; ! 1351: break; ! 1352: default: ! 1353: val = s->csr[rap]; ! 1354: } ! 1355: #ifdef PCNET_DEBUG_CSR ! 1356: printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val); ! 1357: #endif ! 1358: return val; ! 1359: } ! 1360: ! 1361: static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val) ! 1362: { ! 1363: rap &= 127; ! 1364: #ifdef PCNET_DEBUG_BCR ! 1365: printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val); ! 1366: #endif ! 1367: switch (rap) { ! 1368: case BCR_SWS: ! 1369: if (!(CSR_STOP(s) || CSR_SPND(s))) ! 1370: return; ! 1371: val &= ~0x0300; ! 1372: switch (val & 0x00ff) { ! 1373: case 0: ! 1374: val |= 0x0200; ! 1375: break; ! 1376: case 1: ! 1377: val |= 0x0100; ! 1378: break; ! 1379: case 2: ! 1380: case 3: ! 1381: val |= 0x0300; ! 1382: break; ! 1383: default: ! 1384: printf("Bad SWSTYLE=0x%02x\n", val & 0xff); ! 1385: val = 0x0200; ! 1386: break; ! 1387: } ! 1388: #ifdef PCNET_DEBUG ! 1389: printf("BCR_SWS=0x%04x\n", val); ! 1390: #endif ! 1391: case BCR_LNKST: ! 1392: case BCR_LED1: ! 1393: case BCR_LED2: ! 1394: case BCR_LED3: ! 1395: case BCR_MC: ! 1396: case BCR_FDC: ! 1397: case BCR_BSBC: ! 1398: case BCR_EECAS: ! 1399: case BCR_PLAT: ! 1400: s->bcr[rap] = val; ! 1401: break; ! 1402: default: ! 1403: break; ! 1404: } ! 1405: } ! 1406: ! 1407: static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) ! 1408: { ! 1409: uint32_t val; ! 1410: rap &= 127; ! 1411: switch (rap) { ! 1412: case BCR_LNKST: ! 1413: case BCR_LED1: ! 1414: case BCR_LED2: ! 1415: case BCR_LED3: ! 1416: val = s->bcr[rap] & ~0x8000; ! 1417: val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0; ! 1418: break; ! 1419: default: ! 1420: val = rap < 32 ? s->bcr[rap] : 0; ! 1421: break; ! 1422: } ! 1423: #ifdef PCNET_DEBUG_BCR ! 1424: printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val); ! 1425: #endif ! 1426: return val; ! 1427: } ! 1428: ! 1429: static void pcnet_h_reset(PCNetState *s) ! 1430: { ! 1431: int i; ! 1432: uint16_t checksum; ! 1433: ! 1434: /* Initialize the PROM */ ! 1435: ! 1436: memcpy(s->prom, s->nd->macaddr, 6); ! 1437: s->prom[12] = s->prom[13] = 0x00; ! 1438: s->prom[14] = s->prom[15] = 0x57; ! 1439: ! 1440: for (i = 0,checksum = 0; i < 16; i++) ! 1441: checksum += s->prom[i]; ! 1442: *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum); ! 1443: ! 1444: ! 1445: s->bcr[BCR_MSRDA] = 0x0005; ! 1446: s->bcr[BCR_MSWRA] = 0x0005; ! 1447: s->bcr[BCR_MC ] = 0x0002; ! 1448: s->bcr[BCR_LNKST] = 0x00c0; ! 1449: s->bcr[BCR_LED1 ] = 0x0084; ! 1450: s->bcr[BCR_LED2 ] = 0x0088; ! 1451: s->bcr[BCR_LED3 ] = 0x0090; ! 1452: s->bcr[BCR_FDC ] = 0x0000; ! 1453: s->bcr[BCR_BSBC ] = 0x9001; ! 1454: s->bcr[BCR_EECAS] = 0x0002; ! 1455: s->bcr[BCR_SWS ] = 0x0200; ! 1456: s->bcr[BCR_PLAT ] = 0xff06; ! 1457: ! 1458: pcnet_s_reset(s); ! 1459: } ! 1460: ! 1461: static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) ! 1462: { ! 1463: PCNetState *s = opaque; ! 1464: #ifdef PCNET_DEBUG ! 1465: printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); ! 1466: #endif ! 1467: /* Check APROMWE bit to enable write access */ ! 1468: if (pcnet_bcr_readw(s,2) & 0x80) ! 1469: s->prom[addr & 15] = val; ! 1470: } ! 1471: ! 1472: static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) ! 1473: { ! 1474: PCNetState *s = opaque; ! 1475: uint32_t val = s->prom[addr &= 15]; ! 1476: #ifdef PCNET_DEBUG ! 1477: printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val); ! 1478: #endif ! 1479: return val; ! 1480: } ! 1481: ! 1482: static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val) ! 1483: { ! 1484: PCNetState *s = opaque; ! 1485: pcnet_poll_timer(s); ! 1486: #ifdef PCNET_DEBUG_IO ! 1487: printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val); ! 1488: #endif ! 1489: if (!BCR_DWIO(s)) { ! 1490: switch (addr & 0x0f) { ! 1491: case 0x00: /* RDP */ ! 1492: pcnet_csr_writew(s, s->rap, val); ! 1493: break; ! 1494: case 0x02: ! 1495: s->rap = val & 0x7f; ! 1496: break; ! 1497: case 0x06: ! 1498: pcnet_bcr_writew(s, s->rap, val); ! 1499: break; ! 1500: } ! 1501: } ! 1502: pcnet_update_irq(s); ! 1503: } ! 1504: ! 1505: static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr) ! 1506: { ! 1507: PCNetState *s = opaque; ! 1508: uint32_t val = -1; ! 1509: pcnet_poll_timer(s); ! 1510: if (!BCR_DWIO(s)) { ! 1511: switch (addr & 0x0f) { ! 1512: case 0x00: /* RDP */ ! 1513: val = pcnet_csr_readw(s, s->rap); ! 1514: break; ! 1515: case 0x02: ! 1516: val = s->rap; ! 1517: break; ! 1518: case 0x04: ! 1519: pcnet_s_reset(s); ! 1520: val = 0; ! 1521: break; ! 1522: case 0x06: ! 1523: val = pcnet_bcr_readw(s, s->rap); ! 1524: break; ! 1525: } ! 1526: } ! 1527: pcnet_update_irq(s); ! 1528: #ifdef PCNET_DEBUG_IO ! 1529: printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff); ! 1530: #endif ! 1531: return val; ! 1532: } ! 1533: ! 1534: static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) ! 1535: { ! 1536: PCNetState *s = opaque; ! 1537: pcnet_poll_timer(s); ! 1538: #ifdef PCNET_DEBUG_IO ! 1539: printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val); ! 1540: #endif ! 1541: if (BCR_DWIO(s)) { ! 1542: switch (addr & 0x0f) { ! 1543: case 0x00: /* RDP */ ! 1544: pcnet_csr_writew(s, s->rap, val & 0xffff); ! 1545: break; ! 1546: case 0x04: ! 1547: s->rap = val & 0x7f; ! 1548: break; ! 1549: case 0x0c: ! 1550: pcnet_bcr_writew(s, s->rap, val & 0xffff); ! 1551: break; ! 1552: } ! 1553: } else ! 1554: if ((addr & 0x0f) == 0) { ! 1555: /* switch device to dword i/o mode */ ! 1556: pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080); ! 1557: #ifdef PCNET_DEBUG_IO ! 1558: printf("device switched into dword i/o mode\n"); ! 1559: #endif ! 1560: } ! 1561: pcnet_update_irq(s); ! 1562: } ! 1563: ! 1564: static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) ! 1565: { ! 1566: PCNetState *s = opaque; ! 1567: uint32_t val = -1; ! 1568: pcnet_poll_timer(s); ! 1569: if (BCR_DWIO(s)) { ! 1570: switch (addr & 0x0f) { ! 1571: case 0x00: /* RDP */ ! 1572: val = pcnet_csr_readw(s, s->rap); ! 1573: break; ! 1574: case 0x04: ! 1575: val = s->rap; ! 1576: break; ! 1577: case 0x08: ! 1578: pcnet_s_reset(s); ! 1579: val = 0; ! 1580: break; ! 1581: case 0x0c: ! 1582: val = pcnet_bcr_readw(s, s->rap); ! 1583: break; ! 1584: } ! 1585: } ! 1586: pcnet_update_irq(s); ! 1587: #ifdef PCNET_DEBUG_IO ! 1588: printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val); ! 1589: #endif ! 1590: return val; ! 1591: } ! 1592: ! 1593: static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, ! 1594: uint32_t addr, uint32_t size, int type) ! 1595: { ! 1596: PCNetState *d = (PCNetState *)pci_dev; ! 1597: ! 1598: #ifdef PCNET_DEBUG_IO ! 1599: printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size); ! 1600: #endif ! 1601: ! 1602: register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); ! 1603: register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); ! 1604: ! 1605: register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); ! 1606: register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); ! 1607: register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); ! 1608: register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d); ! 1609: } ! 1610: ! 1611: static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) ! 1612: { ! 1613: PCNetState *d = opaque; ! 1614: #ifdef PCNET_DEBUG_IO ! 1615: printf("pcnet_mmio_writeb addr=0x%08x val=0x%02x\n", addr, val); ! 1616: #endif ! 1617: if (!(addr & 0x10)) ! 1618: pcnet_aprom_writeb(d, addr & 0x0f, val); ! 1619: } ! 1620: ! 1621: static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) ! 1622: { ! 1623: PCNetState *d = opaque; ! 1624: uint32_t val = -1; ! 1625: if (!(addr & 0x10)) ! 1626: val = pcnet_aprom_readb(d, addr & 0x0f); ! 1627: #ifdef PCNET_DEBUG_IO ! 1628: printf("pcnet_mmio_readb addr=0x%08x val=0x%02x\n", addr, val & 0xff); ! 1629: #endif ! 1630: return val; ! 1631: } ! 1632: ! 1633: static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) ! 1634: { ! 1635: PCNetState *d = opaque; ! 1636: #ifdef PCNET_DEBUG_IO ! 1637: printf("pcnet_mmio_writew addr=0x%08x val=0x%04x\n", addr, val); ! 1638: #endif ! 1639: if (addr & 0x10) ! 1640: pcnet_ioport_writew(d, addr & 0x0f, val); ! 1641: else { ! 1642: addr &= 0x0f; ! 1643: pcnet_aprom_writeb(d, addr, val & 0xff); ! 1644: pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); ! 1645: } ! 1646: } ! 1647: ! 1648: static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) ! 1649: { ! 1650: PCNetState *d = opaque; ! 1651: uint32_t val = -1; ! 1652: if (addr & 0x10) ! 1653: val = pcnet_ioport_readw(d, addr & 0x0f); ! 1654: else { ! 1655: addr &= 0x0f; ! 1656: val = pcnet_aprom_readb(d, addr+1); ! 1657: val <<= 8; ! 1658: val |= pcnet_aprom_readb(d, addr); ! 1659: } ! 1660: #ifdef PCNET_DEBUG_IO ! 1661: printf("pcnet_mmio_readw addr=0x%08x val = 0x%04x\n", addr, val & 0xffff); ! 1662: #endif ! 1663: return val; ! 1664: } ! 1665: ! 1666: static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) ! 1667: { ! 1668: PCNetState *d = opaque; ! 1669: #ifdef PCNET_DEBUG_IO ! 1670: printf("pcnet_mmio_writel addr=0x%08x val=0x%08x\n", addr, val); ! 1671: #endif ! 1672: if (addr & 0x10) ! 1673: pcnet_ioport_writel(d, addr & 0x0f, val); ! 1674: else { ! 1675: addr &= 0x0f; ! 1676: pcnet_aprom_writeb(d, addr, val & 0xff); ! 1677: pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); ! 1678: pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); ! 1679: pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); ! 1680: } ! 1681: } ! 1682: ! 1683: static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) ! 1684: { ! 1685: PCNetState *d = opaque; ! 1686: uint32_t val; ! 1687: if (addr & 0x10) ! 1688: val = pcnet_ioport_readl(d, addr & 0x0f); ! 1689: else { ! 1690: addr &= 0x0f; ! 1691: val = pcnet_aprom_readb(d, addr+3); ! 1692: val <<= 8; ! 1693: val |= pcnet_aprom_readb(d, addr+2); ! 1694: val <<= 8; ! 1695: val |= pcnet_aprom_readb(d, addr+1); ! 1696: val <<= 8; ! 1697: val |= pcnet_aprom_readb(d, addr); ! 1698: } ! 1699: #ifdef PCNET_DEBUG_IO ! 1700: printf("pcnet_mmio_readl addr=0x%08x val=0x%08x\n", addr, val); ! 1701: #endif ! 1702: return val; ! 1703: } ! 1704: ! 1705: ! 1706: static CPUWriteMemoryFunc *pcnet_mmio_write[] = { ! 1707: (CPUWriteMemoryFunc *)&pcnet_mmio_writeb, ! 1708: (CPUWriteMemoryFunc *)&pcnet_mmio_writew, ! 1709: (CPUWriteMemoryFunc *)&pcnet_mmio_writel ! 1710: }; ! 1711: ! 1712: static CPUReadMemoryFunc *pcnet_mmio_read[] = { ! 1713: (CPUReadMemoryFunc *)&pcnet_mmio_readb, ! 1714: (CPUReadMemoryFunc *)&pcnet_mmio_readw, ! 1715: (CPUReadMemoryFunc *)&pcnet_mmio_readl ! 1716: }; ! 1717: ! 1718: static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, ! 1719: uint32_t addr, uint32_t size, int type) ! 1720: { ! 1721: PCNetState *d = (PCNetState *)pci_dev; ! 1722: ! 1723: #ifdef PCNET_DEBUG_IO ! 1724: printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size); ! 1725: #endif ! 1726: ! 1727: cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr); ! 1728: } ! 1729: ! 1730: void pci_pcnet_init(PCIBus *bus, NICInfo *nd) ! 1731: { ! 1732: PCNetState *d; ! 1733: uint8_t *pci_conf; ! 1734: ! 1735: #if 0 ! 1736: printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", ! 1737: sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD)); ! 1738: #endif ! 1739: ! 1740: d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), ! 1741: -1, NULL, NULL); ! 1742: ! 1743: pci_conf = d->dev.config; ! 1744: ! 1745: *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022); ! 1746: *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000); ! 1747: *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007); ! 1748: *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280); ! 1749: pci_conf[0x08] = 0x10; ! 1750: pci_conf[0x09] = 0x00; ! 1751: pci_conf[0x0a] = 0x00; // ethernet network controller ! 1752: pci_conf[0x0b] = 0x02; ! 1753: pci_conf[0x0e] = 0x00; // header_type ! 1754: ! 1755: *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001); ! 1756: *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000); ! 1757: ! 1758: pci_conf[0x3d] = 1; // interrupt pin 0 ! 1759: pci_conf[0x3e] = 0x06; ! 1760: pci_conf[0x3f] = 0xff; ! 1761: ! 1762: /* Handler for memory-mapped I/O */ ! 1763: d->mmio_io_addr = ! 1764: cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d); ! 1765: ! 1766: pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, ! 1767: PCI_ADDRESS_SPACE_IO, pcnet_ioport_map); ! 1768: ! 1769: pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, ! 1770: PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); ! 1771: ! 1772: d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); ! 1773: ! 1774: d->nd = nd; ! 1775: ! 1776: d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, ! 1777: pcnet_can_receive, d); ! 1778: ! 1779: snprintf(d->vc->info_str, sizeof(d->vc->info_str), ! 1780: "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", ! 1781: d->nd->macaddr[0], ! 1782: d->nd->macaddr[1], ! 1783: d->nd->macaddr[2], ! 1784: d->nd->macaddr[3], ! 1785: d->nd->macaddr[4], ! 1786: d->nd->macaddr[5]); ! 1787: ! 1788: pcnet_h_reset(d); ! 1789: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.