?? pcnet.c
字號(hào):
uint32_t rdra, tdra;#ifdef PCNET_DEBUG printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s)));#endif if (BCR_SSIZE32(s)) { s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), (uint8_t *)&initblk, sizeof(initblk), 0); mode = le16_to_cpu(initblk.mode); rlen = initblk.rlen >> 4; tlen = initblk.tlen >> 4; ladrf[0] = le16_to_cpu(initblk.ladrf[0]); ladrf[1] = le16_to_cpu(initblk.ladrf[1]); ladrf[2] = le16_to_cpu(initblk.ladrf[2]); ladrf[3] = le16_to_cpu(initblk.ladrf[3]); padr[0] = le16_to_cpu(initblk.padr[0]); padr[1] = le16_to_cpu(initblk.padr[1]); padr[2] = le16_to_cpu(initblk.padr[2]); rdra = le32_to_cpu(initblk.rdra); tdra = le32_to_cpu(initblk.tdra); } else { struct pcnet_initblk16 initblk; s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), (uint8_t *)&initblk, sizeof(initblk), 0); mode = le16_to_cpu(initblk.mode); ladrf[0] = le16_to_cpu(initblk.ladrf[0]); ladrf[1] = le16_to_cpu(initblk.ladrf[1]); ladrf[2] = le16_to_cpu(initblk.ladrf[2]); ladrf[3] = le16_to_cpu(initblk.ladrf[3]); padr[0] = le16_to_cpu(initblk.padr[0]); padr[1] = le16_to_cpu(initblk.padr[1]); padr[2] = le16_to_cpu(initblk.padr[2]); rdra = le32_to_cpu(initblk.rdra); tdra = le32_to_cpu(initblk.tdra); rlen = rdra >> 29; tlen = tdra >> 29; rdra &= 0x00ffffff; tdra &= 0x00ffffff; }#if defined(PCNET_DEBUG) printf("rlen=%d tlen=%d\n", rlen, tlen);#endif CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512; CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512; s->csr[ 6] = (tlen << 12) | (rlen << 8); s->csr[15] = mode; s->csr[ 8] = ladrf[0]; s->csr[ 9] = ladrf[1]; s->csr[10] = ladrf[2]; s->csr[11] = ladrf[3]; s->csr[12] = padr[0]; s->csr[13] = padr[1]; s->csr[14] = padr[2]; s->rdra = PHYSADDR(s, rdra); s->tdra = PHYSADDR(s, tdra); CSR_RCVRC(s) = CSR_RCVRL(s); CSR_XMTRC(s) = CSR_XMTRL(s);#ifdef PCNET_DEBUG printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", BCR_SSIZE32(s), s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));#endif s->csr[0] |= 0x0101; s->csr[0] &= ~0x0004; /* clear STOP bit */}static void pcnet_start(PCNetState *s){#ifdef PCNET_DEBUG printf("pcnet_start\n");#endif if (!CSR_DTX(s)) s->csr[0] |= 0x0010; /* set TXON */ if (!CSR_DRX(s)) s->csr[0] |= 0x0020; /* set RXON */ s->csr[0] &= ~0x0004; /* clear STOP bit */ s->csr[0] |= 0x0002;}static void pcnet_stop(PCNetState *s){#ifdef PCNET_DEBUG printf("pcnet_stop\n");#endif s->csr[0] &= ~0x7feb; s->csr[0] |= 0x0014; s->csr[4] &= ~0x02c2; s->csr[5] &= ~0x0011; pcnet_poll_timer(s);}static void pcnet_rdte_poll(PCNetState *s){ s->csr[28] = s->csr[29] = 0; if (s->rdra) { int bad = 0;#if 1 target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));#else target_phys_addr_t crda = s->rdra + (CSR_RCVRL(s) - CSR_RCVRC(s)) * (BCR_SWSTYLE(s) ? 16 : 8 ); int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1; target_phys_addr_t nrda = s->rdra + (CSR_RCVRL(s) - nrdc) * (BCR_SWSTYLE(s) ? 16 : 8 ); int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1; target_phys_addr_t nnrd = s->rdra + (CSR_RCVRL(s) - nnrc) * (BCR_SWSTYLE(s) ? 16 : 8 );#endif CHECK_RMD(PHYSADDR(s,crda), bad); if (!bad) { CHECK_RMD(PHYSADDR(s,nrda), bad); if (bad || (nrda == crda)) nrda = 0; CHECK_RMD(PHYSADDR(s,nnrd), bad); if (bad || (nnrd == crda)) nnrd = 0; s->csr[28] = crda & 0xffff; s->csr[29] = crda >> 16; s->csr[26] = nrda & 0xffff; s->csr[27] = nrda >> 16; s->csr[36] = nnrd & 0xffff; s->csr[37] = nnrd >> 16;#ifdef PCNET_DEBUG if (bad) { printf("pcnet: BAD RMD RECORDS AFTER 0x%08x\n", PHYSADDR(s,crda)); } } else { printf("pcnet: BAD RMD RDA=0x%08x\n", PHYSADDR(s,crda));#endif } } if (CSR_CRDA(s)) { struct pcnet_RMD rmd; RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s))); CSR_CRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT); CSR_CRST(s) = rmd.status;#ifdef PCNET_DEBUG_RMD_X printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMDL=0x%04x RMDS=0x%04x RMDM=0x%08x\n", PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s), rmd.buf_length, rmd.status, rmd.msg_length); PRINT_RMD(&rmd);#endif } else { CSR_CRBC(s) = CSR_CRST(s) = 0; } if (CSR_NRDA(s)) { struct pcnet_RMD rmd; RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s))); CSR_NRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT); CSR_NRST(s) = rmd.status; } else { CSR_NRBC(s) = CSR_NRST(s) = 0; }}static int pcnet_tdte_poll(PCNetState *s){ s->csr[34] = s->csr[35] = 0; if (s->tdra) { target_phys_addr_t cxda = s->tdra + (CSR_XMTRL(s) - CSR_XMTRC(s)) * (BCR_SWSTYLE(s) ? 16 : 8); int bad = 0; CHECK_TMD(PHYSADDR(s, cxda),bad); if (!bad) { if (CSR_CXDA(s) != cxda) { s->csr[60] = s->csr[34]; s->csr[61] = s->csr[35]; s->csr[62] = CSR_CXBC(s); s->csr[63] = CSR_CXST(s); } s->csr[34] = cxda & 0xffff; s->csr[35] = cxda >> 16;#ifdef PCNET_DEBUG_X printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda));#endif } } if (CSR_CXDA(s)) { struct pcnet_TMD tmd; TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT); CSR_CXST(s) = tmd.status; } else { CSR_CXBC(s) = CSR_CXST(s) = 0; } return !!(CSR_CXST(s) & 0x8000);}static int pcnet_can_receive(void *opaque){ PCNetState *s = opaque; if (CSR_STOP(s) || CSR_SPND(s)) return 0; if (s->recv_pos > 0) return 0; return sizeof(s->buffer)-16;}#define MIN_BUF_SIZE 60static void pcnet_receive(void *opaque, const uint8_t *buf, int size){ PCNetState *s = opaque; int is_padr = 0, is_bcast = 0, is_ladr = 0; uint8_t buf1[60]; if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) return;#ifdef PCNET_DEBUG printf("pcnet_receive size=%d\n", size);#endif /* if too small buffer, then expand it */ if (size < MIN_BUF_SIZE) { memcpy(buf1, buf, size); memset(buf1 + size, 0, MIN_BUF_SIZE - size); buf = buf1; size = MIN_BUF_SIZE; } if (CSR_PROM(s) || (is_padr=padr_match(s, buf, size)) || (is_bcast=padr_bcast(s, buf, size)) || (is_ladr=ladr_match(s, buf, size))) { pcnet_rdte_poll(s); if (!(CSR_CRST(s) & 0x8000) && s->rdra) { struct pcnet_RMD rmd; int rcvrc = CSR_RCVRC(s)-1,i; target_phys_addr_t nrda; for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) { if (rcvrc <= 1) rcvrc = CSR_RCVRL(s); nrda = s->rdra + (CSR_RCVRL(s) - rcvrc) * (BCR_SWSTYLE(s) ? 16 : 8 ); RMDLOAD(&rmd, PHYSADDR(s,nrda)); if (GET_FIELD(rmd.status, RMDS, OWN)) {#ifdef PCNET_DEBUG_RMD printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", rcvrc, CSR_RCVRC(s));#endif CSR_RCVRC(s) = rcvrc; pcnet_rdte_poll(s); break; } } } if (!(CSR_CRST(s) & 0x8000)) {#ifdef PCNET_DEBUG_RMD printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));#endif s->csr[0] |= 0x1000; /* Set MISS flag */ CSR_MISSC(s)++; } else { uint8_t *src = &s->buffer[8]; target_phys_addr_t crda = CSR_CRDA(s); struct pcnet_RMD rmd; int pktcount = 0; memcpy(src, buf, size);#if 1 /* no need to compute the CRC */ src[size] = 0; src[size + 1] = 0; src[size + 2] = 0; src[size + 3] = 0; size += 4;#else /* XXX: avoid CRC generation */ if (!CSR_ASTRP_RCV(s)) { uint32_t fcs = ~0; uint8_t *p = src; while (size < 46) { src[size++] = 0; } while (p != &src[size]) { CRC(fcs, *p++); } ((uint32_t *)&src[size])[0] = htonl(fcs); size += 4; /* FCS at end of packet */ } else size += 4;#endif#ifdef PCNET_DEBUG_MATCH PRINT_PKTHDR(buf);#endif RMDLOAD(&rmd, PHYSADDR(s,crda)); /*if (!CSR_LAPPEN(s))*/ SET_FIELD(&rmd.status, RMDS, STP, 1);#define PCNET_RECV_STORE() do { \ int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),size); \ target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr); \ s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \ src += count; size -= count; \ SET_FIELD(&rmd.msg_length, RMDM, MCNT, count); \ SET_FIELD(&rmd.status, RMDS, OWN, 0); \ RMDSTORE(&rmd, PHYSADDR(s,crda)); \ pktcount++; \} while (0) PCNET_RECV_STORE(); if ((size > 0) && CSR_NRDA(s)) { target_phys_addr_t nrda = CSR_NRDA(s); RMDLOAD(&rmd, PHYSADDR(s,nrda)); if (GET_FIELD(rmd.status, RMDS, OWN)) { crda = nrda; PCNET_RECV_STORE(); if ((size > 0) && (nrda=CSR_NNRD(s))) { RMDLOAD(&rmd, PHYSADDR(s,nrda)); if (GET_FIELD(rmd.status, RMDS, OWN)) { crda = nrda; PCNET_RECV_STORE(); } } } }#undef PCNET_RECV_STORE RMDLOAD(&rmd, PHYSADDR(s,crda)); if (size == 0) { SET_FIELD(&rmd.status, RMDS, ENP, 1); SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr); SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr); SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast); } else { SET_FIELD(&rmd.status, RMDS, OFLO, 1); SET_FIELD(&rmd.status, RMDS, BUFF, 1); SET_FIELD(&rmd.status, RMDS, ERR, 1); } RMDSTORE(&rmd, PHYSADDR(s,crda)); s->csr[0] |= 0x0400;#ifdef PCNET_DEBUG printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);#endif#ifdef PCNET_DEBUG_RMD PRINT_RMD(&rmd);#endif while (pktcount--) { if (CSR_RCVRC(s) <= 1) CSR_RCVRC(s) = CSR_RCVRL(s); else CSR_RCVRC(s)--; } pcnet_rdte_poll(s); } } pcnet_poll(s); pcnet_update_irq(s);}static void pcnet_transmit(PCNetState *s){ target_phys_addr_t xmit_cxda = 0; int count = CSR_XMTRL(s)-1; s->xmit_pos = -1; if (!CSR_TXON(s)) { s->csr[0] &= ~0x0008; return; } s->tx_busy = 1; txagain: if (pcnet_tdte_poll(s)) { struct pcnet_TMD tmd; TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));#ifdef PCNET_DEBUG_TMD printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s))); PRINT_TMD(&tmd);#endif if (GET_FIELD(tmd.status, TMDS, STP)) { s->xmit_pos = 0;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -