📄 ns_gige.cc
字号:
/** * This is to write to the PCI general configuration registers */TickNSGigE::writeConfig(PacketPtr pkt){ int offset = pkt->getAddr() & PCI_CONFIG_SIZE; if (offset < PCI_DEVICE_SPECIFIC) PciDev::writeConfig(pkt); else panic("Device specific PCI config space not implemented!\n"); switch (offset) { // seems to work fine without all these PCI settings, but i // put in the IO to double check, an assertion will fail if we // need to properly implement it case PCI_COMMAND: if (config.data[offset] & PCI_CMD_IOSE) ioEnable = true; else ioEnable = false; break; } return configDelay;}EtherInt*NSGigE::getEthPort(const std::string &if_name, int idx){ if (if_name == "interface") { if (interface->getPeer()) panic("interface already connected to\n"); return interface; } return NULL;}/** * This reads the device registers, which are detailed in the NS83820 * spec sheet */TickNSGigE::read(PacketPtr pkt){ assert(ioEnable); pkt->allocate(); //The mask is to give you only the offset into the device register file Addr daddr = pkt->getAddr() & 0xfff; DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", daddr, pkt->getAddr(), pkt->getSize()); // there are some reserved registers, you can see ns_gige_reg.h and // the spec sheet for details if (daddr > LAST && daddr <= RESERVED) { panic("Accessing reserved register"); } else if (daddr > RESERVED && daddr <= 0x3FC) { return readConfig(pkt); } else if (daddr >= MIB_START && daddr <= MIB_END) { // don't implement all the MIB's. hopefully the kernel // doesn't actually DEPEND upon their values // MIB are just hardware stats keepers pkt->set<uint32_t>(0); pkt->makeAtomicResponse(); return pioDelay; } else if (daddr > 0x3FC) panic("Something is messed up!\n"); assert(pkt->getSize() == sizeof(uint32_t)); uint32_t ® = *pkt->getPtr<uint32_t>(); uint16_t rfaddr; switch (daddr) { case CR: reg = regs.command; //these are supposed to be cleared on a read reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); break; case CFGR: reg = regs.config; break; case MEAR: reg = regs.mear; break; case PTSCR: reg = regs.ptscr; break; case ISR: reg = regs.isr; devIntrClear(ISR_ALL); break; case IMR: reg = regs.imr; break; case IER: reg = regs.ier; break; case IHR: reg = regs.ihr; break; case TXDP: reg = regs.txdp; break; case TXDP_HI: reg = regs.txdp_hi; break; case TX_CFG: reg = regs.txcfg; break; case GPIOR: reg = regs.gpior; break; case RXDP: reg = regs.rxdp; break; case RXDP_HI: reg = regs.rxdp_hi; break; case RX_CFG: reg = regs.rxcfg; break; case PQCR: reg = regs.pqcr; break; case WCSR: reg = regs.wcsr; break; case PCR: reg = regs.pcr; break; // see the spec sheet for how RFCR and RFDR work // basically, you write to RFCR to tell the machine // what you want to do next, then you act upon RFDR, // and the device will be prepared b/c of what you // wrote to RFCR case RFCR: reg = regs.rfcr; break; case RFDR: rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); switch (rfaddr) { // Read from perfect match ROM octets case 0x000: reg = rom.perfectMatch[1]; reg = reg << 8; reg += rom.perfectMatch[0]; break; case 0x002: reg = rom.perfectMatch[3] << 8; reg += rom.perfectMatch[2]; break; case 0x004: reg = rom.perfectMatch[5] << 8; reg += rom.perfectMatch[4]; break; default: // Read filter hash table if (rfaddr >= FHASH_ADDR && rfaddr < FHASH_ADDR + FHASH_SIZE) { // Only word-aligned reads supported if (rfaddr % 2) panic("unaligned read from filter hash table!"); reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; reg += rom.filterHash[rfaddr - FHASH_ADDR]; break; } panic("reading RFDR for something other than pattern" " matching or hashing! %#x\n", rfaddr); } break; case SRR: reg = regs.srr; break; case MIBC: reg = regs.mibc; reg &= ~(MIBC_MIBS | MIBC_ACLR); break; case VRCR: reg = regs.vrcr; break; case VTCR: reg = regs.vtcr; break; case VDR: reg = regs.vdr; break; case CCSR: reg = regs.ccsr; break; case TBICR: reg = regs.tbicr; break; case TBISR: reg = regs.tbisr; break; case TANAR: reg = regs.tanar; break; case TANLPAR: reg = regs.tanlpar; break; case TANER: reg = regs.taner; break; case TESR: reg = regs.tesr; break; case M5REG: reg = 0; if (params()->rx_thread) reg |= M5REG_RX_THREAD; if (params()->tx_thread) reg |= M5REG_TX_THREAD; if (params()->rss) reg |= M5REG_RSS; break; default: panic("reading unimplemented register: addr=%#x", daddr); } DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", daddr, reg, reg); pkt->makeAtomicResponse(); return pioDelay;}TickNSGigE::write(PacketPtr pkt){ assert(ioEnable); Addr daddr = pkt->getAddr() & 0xfff; DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", daddr, pkt->getAddr(), pkt->getSize()); if (daddr > LAST && daddr <= RESERVED) { panic("Accessing reserved register"); } else if (daddr > RESERVED && daddr <= 0x3FC) { return writeConfig(pkt); } else if (daddr > 0x3FC) panic("Something is messed up!\n"); if (pkt->getSize() == sizeof(uint32_t)) { uint32_t reg = pkt->get<uint32_t>(); uint16_t rfaddr; DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); switch (daddr) { case CR: regs.command = reg; if (reg & CR_TXD) { txEnable = false; } else if (reg & CR_TXE) { txEnable = true; // the kernel is enabling the transmit machine if (txState == txIdle) txKick(); } if (reg & CR_RXD) { rxEnable = false; } else if (reg & CR_RXE) { rxEnable = true; if (rxState == rxIdle) rxKick(); } if (reg & CR_TXR) txReset(); if (reg & CR_RXR) rxReset(); if (reg & CR_SWI) devIntrPost(ISR_SWI); if (reg & CR_RST) { txReset(); rxReset(); regsReset(); } break; case CFGR: if (reg & CFGR_LNKSTS || reg & CFGR_SPDSTS || reg & CFGR_DUPSTS || reg & CFGR_RESERVED || reg & CFGR_T64ADDR || reg & CFGR_PCI64_DET) // First clear all writable bits regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | CFGR_RESERVED | CFGR_T64ADDR | CFGR_PCI64_DET; // Now set the appropriate writable bits regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | CFGR_RESERVED | CFGR_T64ADDR | CFGR_PCI64_DET);// all these #if 0's are because i don't THINK the kernel needs to// have these implemented. if there is a problem relating to one of// these, you may need to add functionality in. if (reg & CFGR_TBI_EN) ; if (reg & CFGR_MODE_1000) ; if (reg & CFGR_AUTO_1000) panic("CFGR_AUTO_1000 not implemented!\n"); if (reg & CFGR_PINT_DUPSTS || reg & CFGR_PINT_LNKSTS || reg & CFGR_PINT_SPDSTS) ; if (reg & CFGR_TMRTEST) ; if (reg & CFGR_MRM_DIS) ; if (reg & CFGR_MWI_DIS) ; if (reg & CFGR_T64ADDR) ; // panic("CFGR_T64ADDR is read only register!\n"); if (reg & CFGR_PCI64_DET) panic("CFGR_PCI64_DET is read only register!\n"); if (reg & CFGR_DATA64_EN) ; if (reg & CFGR_M64ADDR) ; if (reg & CFGR_PHY_RST) ; if (reg & CFGR_PHY_DIS) ; if (reg & CFGR_EXTSTS_EN) extstsEnable = true; else extstsEnable = false; if (reg & CFGR_REQALG) ; if (reg & CFGR_SB) ; if (reg & CFGR_POW) ; if (reg & CFGR_EXD) ; if (reg & CFGR_PESEL) ; if (reg & CFGR_BROM_DIS) ; if (reg & CFGR_EXT_125) ; if (reg & CFGR_BEM) ; break; case MEAR: // Clear writable bits regs.mear &= MEAR_EEDO; // Set appropriate writable bits regs.mear |= reg & ~MEAR_EEDO; // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) // even though it could get it through RFDR if (reg & MEAR_EESEL) { // Rising edge of clock if (reg & MEAR_EECLK && !eepromClk) eepromKick(); } else { eepromState = eepromStart; regs.mear &= ~MEAR_EEDI; } eepromClk = reg & MEAR_EECLK; // since phy is completely faked, MEAR_MD* don't matter if (reg & MEAR_MDIO) ; if (reg & MEAR_MDDIR) ; if (reg & MEAR_MDC) ; break; case PTSCR: regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); // these control BISTs for various parts of chip - we // don't care or do just fake that the BIST is done if (reg & PTSCR_RBIST_EN) regs.ptscr |= PTSCR_RBIST_DONE; if (reg & PTSCR_EEBIST_EN) regs.ptscr &= ~PTSCR_EEBIST_EN; if (reg & PTSCR_EELOAD_EN) regs.ptscr &= ~PTSCR_EELOAD_EN; break; case ISR: /* writing to the ISR has no effect */ panic("ISR is a read only register!\n"); case IMR: regs.imr = reg; devIntrChangeMask(); break; case IER: regs.ier = reg; break; case IHR: regs.ihr = reg; /* not going to implement real interrupt holdoff */ break; case TXDP: regs.txdp = (reg & 0xFFFFFFFC); assert(txState == txIdle); CTDD = false; break; case TXDP_HI: regs.txdp_hi = reg; break; case TX_CFG: regs.txcfg = reg;#if 0 if (reg & TX_CFG_CSI) ; if (reg & TX_CFG_HBI) ; if (reg & TX_CFG_MLB) ; if (reg & TX_CFG_ATP) ; if (reg & TX_CFG_ECRETRY) { /* * this could easily be implemented, but considering * the network is just a fake pipe, wouldn't make * sense to do this */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -