📄 pcnet.c
字号:
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 (rmd.rmd1.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))*/ rmd.rmd1.stp = 1;#define PCNET_RECV_STORE() do { \ int count = MIN(4096 - rmd.rmd1.bcnt,size); \ target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \ s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \ src += count; size -= count; \ rmd.rmd2.mcnt = count; rmd.rmd1.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 (rmd.rmd1.own) { crda = nrda; PCNET_RECV_STORE(); if ((size > 0) && (nrda=CSR_NNRD(s))) { RMDLOAD(&rmd, PHYSADDR(s,nrda)); if (rmd.rmd1.own) { crda = nrda; PCNET_RECV_STORE(); } } } }#undef PCNET_RECV_STORE RMDLOAD(&rmd, PHYSADDR(s,crda)); if (size == 0) { rmd.rmd1.enp = 1; rmd.rmd1.pam = !CSR_PROM(s) && is_padr; rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr; rmd.rmd1.bam = !CSR_PROM(s) && is_bcast; } else { rmd.rmd1.oflo = 1; rmd.rmd1.buff = 1; rmd.rmd1.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 (tmd.tmd1.stp) { s->xmit_pos = 0; if (!tmd.tmd1.enp) { s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr), s->buffer, 4096 - tmd.tmd1.bcnt, CSR_BSWP(s)); s->xmit_pos += 4096 - tmd.tmd1.bcnt; } xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); } if (tmd.tmd1.enp && (s->xmit_pos >= 0)) { s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr), s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt, CSR_BSWP(s)); s->xmit_pos += 4096 - tmd.tmd1.bcnt;#ifdef PCNET_DEBUG printf("pcnet_transmit size=%d\n", s->xmit_pos);#endif if (CSR_LOOP(s)) pcnet_receive(s, s->buffer, s->xmit_pos); else qemu_send_packet(s->vc, s->buffer, s->xmit_pos); s->csr[0] &= ~0x0008; /* clear TDMD */ s->csr[4] |= 0x0004; /* set TXSTRT */ s->xmit_pos = -1; } tmd.tmd1.own = 0; TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint)) s->csr[0] |= 0x0200; /* set TINT */ if (CSR_XMTRC(s)<=1) CSR_XMTRC(s) = CSR_XMTRL(s); else CSR_XMTRC(s)--; if (count--) goto txagain; } else if (s->xmit_pos >= 0) { struct pcnet_TMD tmd; TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda)); tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1; tmd.tmd1.own = 0; TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda)); s->csr[0] |= 0x0200; /* set TINT */ if (!CSR_DXSUFLO(s)) { s->csr[0] &= ~0x0010; } else if (count--) goto txagain; } s->tx_busy = 0;}static void pcnet_poll(PCNetState *s){ if (CSR_RXON(s)) { pcnet_rdte_poll(s); } if (CSR_TDMD(s) || (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s))) { /* prevent recursion */ if (s->tx_busy) return; pcnet_transmit(s); }}static void pcnet_poll_timer(void *opaque){ PCNetState *s = opaque; qemu_del_timer(s->poll_timer); if (CSR_TDMD(s)) { pcnet_transmit(s); } pcnet_update_irq(s); if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) { uint64_t now = qemu_get_clock(vm_clock) * 33; if (!s->timer || !now) s->timer = now; else { uint64_t t = now - s->timer + CSR_POLL(s); if (t > 0xffffLL) { pcnet_poll(s); CSR_POLL(s) = CSR_PINT(s); } else CSR_POLL(s) = t; } qemu_mod_timer(s->poll_timer, pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock))); }}static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value){ uint16_t val = new_value;#ifdef PCNET_DEBUG_CSR printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);#endif switch (rap) { case 0: s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */ s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048); val = (val & 0x007f) | (s->csr[0] & 0x7f00); /* IFF STOP, STRT and INIT are set, clear STRT and INIT */ if ((val&7) == 7) val &= ~3; if (!CSR_STOP(s) && (val & 4)) pcnet_stop(s); if (!CSR_INIT(s) && (val & 1)) pcnet_init(s); if (!CSR_STRT(s) && (val & 2)) pcnet_start(s); if (CSR_TDMD(s)) pcnet_transmit(s); return; case 1: case 2: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 18: /* CRBAL */ case 19: /* CRBAU */ case 20: /* CXBAL */ case 21: /* CXBAU */ case 22: /* NRBAU */ case 23: /* NRBAU */ case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: /* CRBC */ case 41: case 42: /* CXBC */ case 43: case 44: case 45: case 46: /* POLL */ case 47: /* POLLINT */ case 72: case 74: case 76: /* RCVRL */ case 78: /* XMTRL */ case 112: if (CSR_STOP(s) || CSR_SPND(s)) break; return; case 3: break; case 4: s->csr[4] &= ~(val & 0x026a); val &= ~0x026a; val |= s->csr[4] & 0x026a; break; case 5: s->csr[5] &= ~(val & 0x0a90); val &= ~0x0a90; val |= s->csr[5] & 0x0a90; break; case 16: pcnet_csr_writew(s,1,val); return; case 17: pcnet_csr_writew(s,2,val); return; case 58: pcnet_bcr_writew(s,BCR_SWS,val); break; default: return; } s->csr[rap] = val;}static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap){ uint32_t val; switch (rap) { case 0: pcnet_update_irq(s); val = s->csr[0]; val |= (val & 0x7800) ? 0x8000 : 0; break; case 16: return pcnet_csr_readw(s,1); case 17: return pcnet_csr_readw(s,2); case 58: return pcnet_bcr_readw(s,BCR_SWS); case 88: val = s->csr[89]; val <<= 16; val |= s->csr[88]; break; default: val = s->csr[rap]; }#ifdef PCNET_DEBUG_CSR printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);#endif return val;}static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val){ rap &= 127;#ifdef PCNET_DEBUG_BCR printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);#endif switch (rap) { case BCR_SWS: if (!(CSR_STOP(s) || CSR_SPND(s))) return; val &= ~0x0300; switch (val & 0x00ff) { case 0: val |= 0x0200; break; case 1: val |= 0x0100; break; case 2: case 3: val |= 0x0300; break; default: printf("Bad SWSTYLE=0x%02x\n", val & 0xff); val = 0x0200; break; }#ifdef PCNET_DEBUG printf("BCR_SWS=0x%04x\n", val);#endif case BCR_LNKST: case BCR_LED1: case BCR_LED2: case BCR_LED3: case BCR_MC: case BCR_FDC: case BCR_BSBC: case BCR_EECAS: case BCR_PLAT: s->bcr[rap] = val; break; default: break; }}static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap){ uint32_t val; rap &= 127; switch (rap) { case BCR_LNKST: case BCR_LED1: case BCR_LED2: case BCR_LED3: val = s->bcr[rap] & ~0x8000; val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0; break; default: val = rap < 32 ? s->bcr[rap] : 0; break; }#ifdef PCNET_DEBUG_BCR printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);#endif return val;}void pcnet_h_reset(void *opaque){ PCNetState *s = opaque; int i; uint16_t checksum; /* Initialize the PROM */ memcpy(s->prom, s->nd->macaddr, 6); s->prom[12] = s->prom[13] = 0x00; s->prom[14] = s->prom[15] = 0x57;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -