📄 ns_gige.cc
字号:
if (reg & TX_CFG_BRST_DIS) ;#endif#if 0 /* we handle our own DMA, ignore the kernel's exhortations */ if (reg & TX_CFG_MXDMA) ;#endif // also, we currently don't care about fill/drain // thresholds though this may change in the future with // more realistic networks or a driver which changes it // according to feedback break; case GPIOR: // Only write writable bits regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); /* these just control general purpose i/o pins, don't matter */ break; case RXDP: regs.rxdp = reg; CRDD = false; break; case RXDP_HI: regs.rxdp_hi = reg; break; case RX_CFG: regs.rxcfg = reg;#if 0 if (reg & RX_CFG_AEP) ; if (reg & RX_CFG_ARP) ; if (reg & RX_CFG_STRIPCRC) ; if (reg & RX_CFG_RX_RD) ; if (reg & RX_CFG_ALP) ; if (reg & RX_CFG_AIRL) ; /* we handle our own DMA, ignore what kernel says about it */ if (reg & RX_CFG_MXDMA) ; //also, we currently don't care about fill/drain thresholds //though this may change in the future with more realistic //networks or a driver which changes it according to feedback if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;#endif break; case PQCR: /* there is no priority queueing used in the linux 2.6 driver */ regs.pqcr = reg; break; case WCSR: /* not going to implement wake on LAN */ regs.wcsr = reg; break; case PCR: /* not going to implement pause control */ regs.pcr = reg; break; case RFCR: regs.rfcr = reg; rxFilterEnable = (reg & RFCR_RFEN) ? true : false; acceptBroadcast = (reg & RFCR_AAB) ? true : false; acceptMulticast = (reg & RFCR_AAM) ? true : false; acceptUnicast = (reg & RFCR_AAU) ? true : false; acceptPerfect = (reg & RFCR_APM) ? true : false; acceptArp = (reg & RFCR_AARP) ? true : false; multicastHashEnable = (reg & RFCR_MHEN) ? true : false;#if 0 if (reg & RFCR_APAT) panic("RFCR_APAT not implemented!\n");#endif if (reg & RFCR_UHEN) panic("Unicast hash filtering not used by drivers!\n"); if (reg & RFCR_ULM) panic("RFCR_ULM not implemented!\n"); break; case RFDR: rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); switch (rfaddr) { case 0x000: rom.perfectMatch[0] = (uint8_t)reg; rom.perfectMatch[1] = (uint8_t)(reg >> 8); break; case 0x002: rom.perfectMatch[2] = (uint8_t)reg; rom.perfectMatch[3] = (uint8_t)(reg >> 8); break; case 0x004: rom.perfectMatch[4] = (uint8_t)reg; rom.perfectMatch[5] = (uint8_t)(reg >> 8); break; default: if (rfaddr >= FHASH_ADDR && rfaddr < FHASH_ADDR + FHASH_SIZE) { // Only word-aligned writes supported if (rfaddr % 2) panic("unaligned write to filter hash table!"); rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; rom.filterHash[rfaddr - FHASH_ADDR + 1] = (uint8_t)(reg >> 8); break; } panic("writing RFDR for something other than pattern matching\ or hashing! %#x\n", rfaddr); } case BRAR: regs.brar = reg; break; case BRDR: panic("the driver never uses BRDR, something is wrong!\n"); case SRR: panic("SRR is read only register!\n"); case MIBC: panic("the driver never uses MIBC, something is wrong!\n"); case VRCR: regs.vrcr = reg; break; case VTCR: regs.vtcr = reg; break; case VDR: panic("the driver never uses VDR, something is wrong!\n"); case CCSR: /* not going to implement clockrun stuff */ regs.ccsr = reg; break; case TBICR: regs.tbicr = reg; if (reg & TBICR_MR_LOOPBACK) panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); if (reg & TBICR_MR_AN_ENABLE) { regs.tanlpar = regs.tanar; regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); }#if 0 if (reg & TBICR_MR_RESTART_AN) ;#endif break; case TBISR: panic("TBISR is read only register!\n"); case TANAR: // Only write the writable bits regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); // Pause capability unimplemented#if 0 if (reg & TANAR_PS2) ; if (reg & TANAR_PS1) ;#endif break; case TANLPAR: panic("this should only be written to by the fake phy!\n"); case TANER: panic("TANER is read only register!\n"); case TESR: regs.tesr = reg; break; default: panic("invalid register access daddr=%#x", daddr); } } else { panic("Invalid Request Size"); } pkt->makeAtomicResponse(); return pioDelay;}voidNSGigE::devIntrPost(uint32_t interrupts){ if (interrupts & ISR_RESERVE) panic("Cannot set a reserved interrupt"); if (interrupts & ISR_NOIMPL) warn("interrupt not implemented %#x\n", interrupts); interrupts &= ISR_IMPL; regs.isr |= interrupts; if (interrupts & regs.imr) { if (interrupts & ISR_SWI) { totalSwi++; } if (interrupts & ISR_RXIDLE) { totalRxIdle++; } if (interrupts & ISR_RXOK) { totalRxOk++; } if (interrupts & ISR_RXDESC) { totalRxDesc++; } if (interrupts & ISR_TXOK) { totalTxOk++; } if (interrupts & ISR_TXIDLE) { totalTxIdle++; } if (interrupts & ISR_TXDESC) { totalTxDesc++; } if (interrupts & ISR_RXORN) { totalRxOrn++; } } DPRINTF(EthernetIntr, "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", interrupts, regs.isr, regs.imr); if ((regs.isr & regs.imr)) { Tick when = curTick; if ((regs.isr & regs.imr & ISR_NODELAY) == 0) when += intrDelay; cpuIntrPost(when); }}/* writing this interrupt counting stats inside this means that this function is now limited to being used to clear all interrupts upon the kernel reading isr and servicing. just telling you in case you were thinking of expanding use.*/voidNSGigE::devIntrClear(uint32_t interrupts){ if (interrupts & ISR_RESERVE) panic("Cannot clear a reserved interrupt"); if (regs.isr & regs.imr & ISR_SWI) { postedSwi++; } if (regs.isr & regs.imr & ISR_RXIDLE) { postedRxIdle++; } if (regs.isr & regs.imr & ISR_RXOK) { postedRxOk++; } if (regs.isr & regs.imr & ISR_RXDESC) { postedRxDesc++; } if (regs.isr & regs.imr & ISR_TXOK) { postedTxOk++; } if (regs.isr & regs.imr & ISR_TXIDLE) { postedTxIdle++; } if (regs.isr & regs.imr & ISR_TXDESC) { postedTxDesc++; } if (regs.isr & regs.imr & ISR_RXORN) { postedRxOrn++; } if (regs.isr & regs.imr & ISR_IMPL) postedInterrupts++; interrupts &= ~ISR_NOIMPL; regs.isr &= ~interrupts; DPRINTF(EthernetIntr, "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", interrupts, regs.isr, regs.imr); if (!(regs.isr & regs.imr)) cpuIntrClear();}voidNSGigE::devIntrChangeMask(){ DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", regs.isr, regs.imr, regs.isr & regs.imr); if (regs.isr & regs.imr) cpuIntrPost(curTick); else cpuIntrClear();}voidNSGigE::cpuIntrPost(Tick when){ // If the interrupt you want to post is later than an interrupt // already scheduled, just let it post in the coming one and don't // schedule another. // HOWEVER, must be sure that the scheduled intrTick is in the // future (this was formerly the source of a bug) /** * @todo this warning should be removed and the intrTick code should * be fixed. */ assert(when >= curTick); assert(intrTick >= curTick || intrTick == 0); if (when > intrTick && intrTick != 0) { DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", intrTick); return; } intrTick = when; if (intrTick < curTick) { debug_break(); intrTick = curTick; } DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", intrTick); if (intrEvent) intrEvent->squash(); intrEvent = new IntrEvent(this, intrTick, true);}voidNSGigE::cpuInterrupt(){ assert(intrTick == curTick); // Whether or not there's a pending interrupt, we don't care about // it anymore intrEvent = 0; intrTick = 0; // Don't send an interrupt if there's already one if (cpuPendingIntr) { DPRINTF(EthernetIntr, "would send an interrupt now, but there's already pending\n"); } else { // Send interrupt cpuPendingIntr = true; DPRINTF(EthernetIntr, "posting interrupt\n"); intrPost(); }}voidNSGigE::cpuIntrClear(){ if (!cpuPendingIntr) return; if (intrEvent) { intrEvent->squash(); intrEvent = 0; } intrTick = 0; cpuPendingIntr = false; DPRINTF(EthernetIntr, "clearing interrupt\n"); intrClear();}boolNSGigE::cpuIntrPending() const{ return cpuPendingIntr; }voidNSGigE::txReset(){ DPRINTF(Ethernet, "transmit reset\n"); CTDD = false; txEnable = false;; txFragPtr = 0; assert(txDescCnt == 0); txFifo.clear(); txState = txIdle; assert(txDmaState == dmaIdle);}voidNSGigE::rxReset(){ DPRINTF(Ethernet, "receive reset\n"); CRDD = false; assert(rxPktBytes == 0); rxEnable = false; rxFragPtr = 0; assert(rxDescCnt == 0); assert(rxDmaState == dmaIdle); rxFifo.clear(); rxState = rxIdle;}voidNSGigE::regsReset(){ memset(®s, 0, sizeof(regs)); regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); regs.mear = 0x12; regs.txcfg = 0x120; // set drain threshold to 1024 bytes and // fill threshold to 32 bytes regs.rxcfg = 0x4; // set drain threshold to 16 bytes regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 regs.mibc = MIBC_FRZ; regs.vdr = 0x81; // set the vlan tag type to 802.1q regs.tesr = 0xc000; // TBI capable of both full and half duplex regs.brar = 0xffffffff; extstsEnable = false; acceptBroadcast = false; acceptMulticast = false; acceptUnicast = false; acceptPerfect = false; acceptArp = false;}boolNSGigE::doRxDmaRead(){ assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); rxDmaState = dmaReading; if (dmaPending() || getState() != Running) rxDmaState = dmaReadWaiting; else dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); return true;}voidNSGigE::rxDmaReadDone(){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -