📄 realtekr1000.cpp
字号:
if (!tx_descMd || tx_descMd->prepare() != kIOReturnSuccess) { DLog("Couldn't allocate physical memory for tx_desc\n"); return false; } txdesc_space = tx_descMd->getBytesNoCopy(); txdesc_phy_dma_addr = tx_descMd->getPhysicalSegment(0, &len); sizeof_rxdesc_space = NUM_RX_DESC * sizeof(RxDesc) + 256; rx_descMd = IOBufferMemoryDescriptor::withOptions(kIOMemoryPhysicallyContiguous, sizeof_rxdesc_space, PAGE_SIZE); if (!rx_descMd || rx_descMd->prepare() != kIOReturnSuccess) { DLog("Couldn't allocate physical memory for rx_desc\n"); return false; } rxdesc_space = rx_descMd->getBytesNoCopy(); rxdesc_phy_dma_addr = rx_descMd->getPhysicalSegment(0, &len); TxDescArray = reinterpret_cast<TxDesc *>(txdesc_space); RxDescArray = reinterpret_cast<RxDesc *>(rxdesc_space); for(int i = 0; i < NUM_RX_DESC; i++) { Rx_dbuff[i] = 0; Rx_skbuff_Md[i] = IOBufferMemoryDescriptor::withOptions(kIOMemoryPhysicallyContiguous, MAX_RX_SKBDATA_SIZE, PAGE_SIZE); if (!Rx_skbuff_Md[i] || Rx_skbuff_Md[i]->prepare() != kIOReturnSuccess) { DLog("Couldn't allocate physical memory for Rx_dbuff, step %d\n", i); return false; } Rx_dbuff[i] = static_cast<uchar *>(Rx_skbuff_Md[i]->getBytesNoCopy()); if (!Rx_dbuff[i]) { DLog("Pointer in NULL, step %d\n", i); return false; } IOByteCount len; Rx_skbuff_Dma[i] = Rx_skbuff_Md[i]->getPhysicalSegment(0, &len); RxDescArray[i].status = 0; RxDescArray[i].vlan_tag = 0; /*Rx_skbuff[i] = NULL;//allocatePacket(MAX_RX_SKBDATA_SIZE); Rx_skbuff_Dma[i] = static_cast<IOPhysicalAddress>(mbuf_data_to_physical(mbuf_data(Rx_skbuff[i])));*/ } //Ring initialization for(int i = 0; i < NUM_TX_DESC; i++) { /*Tx_skbuff[i] = NULL; TxDescArray[i].status = 0;*/ //Tx_skbuff_Md[i] = NULL; Tx_dbuff[i] = NULL; Tx_skbuff_Md[i] = IOBufferMemoryDescriptor::withOptions(kIOMemoryPhysicallyContiguous, MAX_TX_SKBDATA_SIZE, PAGE_SIZE); if (!Tx_skbuff_Md[i] || Tx_skbuff_Md[i]->prepare() != kIOReturnSuccess) { DLog("Couldn't allocate physical memory for Tx_dbuff, step %d\n", i); return false; } Tx_dbuff[i] = static_cast<uchar *>(Tx_skbuff_Md[i]->getBytesNoCopy()); if (!Tx_dbuff[i]) { DLog("Pointer in NULL, step %d\n", i); return false; } IOByteCount len; Tx_skbuff_Dma[i] = static_cast<IOPhysicalAddress>(Tx_skbuff_Md[i]->getPhysicalSegment(0, &len)); TxDescArray[i].status = 0; TxDescArray[i].vlan_tag = 0; TxDescArray[i].buf_addr = OSSwapHostToLittleInt32(Tx_skbuff_Dma[i]); TxDescArray[i].buf_Haddr = 0; } for(int i = 0; i < NUM_RX_DESC; i++) { if (i == (NUM_RX_DESC - 1)) { RxDescArray[i].status = OSSwapHostToLittleInt32((OWNbit | EORbit) | static_cast<unsigned long>(hw_rx_pkt_len)); } else { RxDescArray[i].status = OSSwapHostToLittleInt32(OWNbit | static_cast<unsigned long>(hw_rx_pkt_len)); } RxDescArray[i].buf_addr = OSSwapHostToLittleInt32(Rx_skbuff_Dma[i]); RxDescArray[i].buf_Haddr = 0; } return true;}void RealtekR1000::FreeDescriptorsMemory(){ R1000TxClear(); if (tx_descMd) { tx_descMd->complete(); tx_descMd->release(); tx_descMd = NULL; } if (rx_descMd) { rx_descMd->complete(); rx_descMd->release(); rx_descMd = NULL; } for(int i = 0; i < NUM_RX_DESC; i++) { if (Rx_skbuff_Md[i]) { Rx_skbuff_Md[i]->complete(); Rx_skbuff_Md[i]->release(); Rx_skbuff_Md[i] = NULL; } } for(int i = 0; i < NUM_TX_DESC; i++) { if (Tx_skbuff_Md[i]) { Tx_skbuff_Md[i]->complete(); Tx_skbuff_Md[i]->release(); Tx_skbuff_Md[i] = NULL; } } } bool RealtekR1000::R1000InitEventSources(IOService *provider){ DLog("RealtekR1000::R1000InitEventSources()\n"); IOWorkLoop *loop = getWorkLoop(); //Needed, cause may be called before WorkLoop creation //Sanity check if (!loop) { DLog("::R1000InitEventSources: Could not getWorkLoop.\n"); return false; } transmitQueue = getOutputQueue(); if (!transmitQueue) { DLog("::R1000InitEventSources: Could not getOutputQueue.\n"); return false; } // we need to see what else is listening on this interrupt to allow multiple devices to function // or else we break other things, like other NIC's and what not /* int msi_index = -1; int intr_index = 0, intr_type = 0; IOReturn intr_ret; while (true) { intr_ret = provider->getInterruptType(intr_index, &intr_type); if (intr_ret != kIOReturnSuccess) break; if (intr_type & kIOInterruptTypePCIMessaged) msi_index = intr_index; intr_index++; } DLog("RTL1000: Got interrupt index of '%d'.\n", msi_index); // set to zero just in case we didnt find anything if(!msi_index) { msi_index = 0; } DLog("RTL1000: Got interrupt index of '%d'.\n", msi_index); intSource = IOInterruptEventSource::interruptEventSource(this, OSMemberFunctionCast(IOInterruptEventSource::Action, this, &RealtekR1000::R1000Interrupt), pciDev, msi_index); // check for some type of fuckup with msi_index = 0 */ intSource = IOInterruptEventSource::interruptEventSource(this, OSMemberFunctionCast(IOInterruptEventSource::Action, this, &RealtekR1000::R1000Interrupt), pciDev); //Adding interrupt to our workloop event sources if (!intSource || loop->addEventSource(intSource) != kIOReturnSuccess) { DLog("::R1000InitEventSources: Could not get InterruptEventSource and/or addEventSource.\n"); return false; } intSource->enable(); //Registering watchdog (i.e. if timeout exceeds) timerSource = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &RealtekR1000::R1000TxTimeout)); if (!timerSource || loop->addEventSource(timerSource) != kIOReturnSuccess) { DLog("::R1000InitEventSources: Could not get timerEventSource and/or addEventSource.\n"); return false; } return true;}bool RealtekR1000::R1000OpenAdapter(){ DLog("bool RealtekR1000::R1000OpenAdapter()\n"); R1000HwStart(); return true;}void RealtekR1000::R1000CloseAdapter(){ /* Stop the chip's Tx and Rx processes. */ WriteMMIO8(ChipCmd, 0x00); /* Disable interrupts by clearing the interrupt mask. */ WriteMMIO16(IntrMask, 0x0000); /* Update the error counts. */ //TO-DO: FIX-ME, Realy need? //priv->stats.rx_missed_errors += ReadMMIO32(RxMissed); WriteMMIO32(RxMissed, 0);}void RealtekR1000::R1000TxClear(){ cur_tx = 0; dirty_tx = 0; for(int i = 0; i < NUM_TX_DESC; i++) { TxDescArray[i].status = 0; if (Tx_skbuff[i] != NULL) { freePacket(Tx_skbuff[i]); Tx_skbuff[i] = NULL; } }}//Interrupt handlervoid RealtekR1000::R1000Interrupt(OSObject * client, IOInterruptEventSource * src, int count){ // dont process interrupts until we're ready if(!this->isInitialized) { //DLog("Ignoring interrupt, card not initilized yet.\n"); return; } // dont process interrupts until we're enabled if(!this->enabled) { //DLog("Ignoring interrupt, card not enabled?\n"); return; } //DLog("RealtekR1000::R1000Interrupt(OSObject * client, IOInterruptEventSource * src, int count)\n"); int boguscnt = max_interrupt_work; unsigned int status = 0; unsigned int phy_status = 0; WriteMMIO16(IntrMask, 0x0000); do { // get status from card status = ReadMMIO16(IntrStatus); // from realtek linux driver // ** hotplug/major error/no more work/shared irq if (status == 0xFFFF) break; // from realtek linux driver // ** write clean mask ? here? unknown, same status WriteMMIO16(IntrStatus, status); // if the link status has changed if(status&LinkChg) { DLog("Interrupt :: Link changed?\n"); // read physical status phy_status = ReadMMIO8(PHYstatus); // if we have link and physical status if(phy_status&LinkStatus) { // in original R1000 driver? what does this do? never ran except in few conditions and when @ 100mbit WriteGMII32(0x1f, 0x0001); WriteGMII32(0x10, 0xf01b); WriteGMII32(0x1f, 0x0000); DLog("Interrupt :: Link up?\n"); // report to OSX that link is up this->setLinkStatus( kIONetworkLinkValid | kIONetworkLinkActive ); } // link must be down else { // in original R1000 driver? what does this do? never ran except in few conditions and when @ 100mbit WriteGMII32(0x1f, 0x0001); WriteGMII32(0x10, 0xf41b); WriteGMII32(0x1f, 0x0000); DLog("Interrupt :: Link down?\n"); // report to OSX that link is down this->setLinkStatus( kIONetworkLinkValid ); } } // if no work to be done...exit if ((status & r1000_intr_mask) == 0) break; if ((status & TxOK) && (status & TxDescUnavail)) { // set polling bit WriteMMIO8(TxPoll, 0x40); // write status? per realtek linux WriteMMIO16(IntrStatus, TxDescUnavail); } // handle RX if (status & (RxOK | RxDescUnavail | RxFIFOOver)) { R1000RxInterrupt(); } // handle TX if (status & (TxOK | TxErr)) { R1000TxInterrupt(); } boguscnt--; } while (boguscnt > 0); if (boguscnt <= 0) { //DLog("Too much work at interrupt!\n"); // Clear all interrupt sources WriteMMIO16(IntrStatus, 0xffff); } // write clean mask WriteMMIO16 ( IntrMask, r1000_intr_mask);}void RealtekR1000::R1000RxInterrupt(){ int lcur_rx; int pkt_size = 0 ; int rxdesc_cnt = 0; struct __mbuf *rx_skb = NULL; struct RxDesc *rxdesc; lcur_rx = cur_rx; rxdesc = &RxDescArray[lcur_rx]; while (((OSSwapLittleToHostInt32(rxdesc->status) & OWNbit) == 0) && (rxdesc_cnt < max_interrupt_work)) { rxdesc_cnt++; if(OSSwapLittleToHostInt32(rxdesc->status) & RxRES) { DLog("RX_RING_IS_FULL stalling\n"); //TO-DO: Add error counters if (OSSwapLittleToHostInt32(rxdesc->status) & (RxRWT|RxRUNT)) ;//priv->stats.rx_length_errors++; if (OSSwapLittleToHostInt32(rxdesc->status) & RxCRC) ;//priv->stats.rx_crc_errors++; } else { pkt_size=static_cast<int>(OSSwapLittleToHostInt32(rxdesc->status) & 0x00001FFF) - 4; if (pkt_size > rx_pkt_len ) { DLog("Error -- Rx packet size() > mtu()+14\n"); pkt_size = rx_pkt_len; } //rx_skb = Rx_skbuff[lcur_rx]; rx_skb = allocatePacket(MAX_RX_SKBDATA_SIZE); if (!rx_skb) continue; bcopy(Rx_dbuff[lcur_rx], mbuf_data(rx_skb), pkt_size); if (rx_skb != NULL) { mbuf_setlen(rx_skb, pkt_size); //TO-DO: Add network stack notification //DLog("Receive: packet len %d, mised packets %d\n", pkt_size, ReadMMIO32(RxMissed)); netif->inputPacket(rx_skb, pkt_size, IONetworkInterface::kInputOptionQueuePacket); netif->flushInputQueue(); } else { DLog("Allocate n_skb failed!\n"); } // Update rx descriptor if (lcur_rx == (NUM_RX_DESC - 1)) { RxDescArray[lcur_rx].status = OSSwapHostToLittleInt32((OWNbit | EORbit) | static_cast<unsigned long>(hw_rx_pkt_len)); } else { RxDescArray[lcur_rx].status = OSSwapHostToLittleInt32(OWNbit | static_cast<unsigned long>(hw_rx_pkt_len)); } } lcur_rx = (lcur_rx +1) % NUM_RX_DESC; rxdesc = &RxDescArray[lcur_rx]; } if (rxdesc_cnt >= max_interrupt_work) { DLog(" Too much work at Rx interrupt.\n"); } cur_rx = lcur_rx;}void RealtekR1000::R1000TxInterrupt(){ unsigned long ldirty_tx, tx_left=0; int entry = cur_tx % NUM_TX_DESC; int txloop_cnt = 0; ldirty_tx = dirty_tx; tx_left = cur_tx - ldirty_tx; //DLog("R1000TxInterrupt cur_tx %d, dirty_tx %d, tx_left %d\n", cur_tx, dirty_tx, tx_left); while ((tx_left > 0) && (txloop_cnt < max_interrupt_work)) { if ((OSSwapLittleToHostInt32(TxDescArray[entry].status) & OWNbit) == 0) { if (Tx_skbuff[ldirty_tx % NUM_TX_DESC] != NULL) { //DLog("Send: R1000TxInterrupt, packet sended to the network, packet size %d, phys addr %x\n", mbuf_len(Tx_skbuff[ldirty_tx % NUM_TX_DESC]), OSSwapLittleToHostInt32(RxDescArray[ldirty_tx % NUM_TX_DESC].buf_addr)); {#ifdef DEBUG /*uchar *data = Tx_dbuff[ldirty_tx % NUM_TX_DESC]; for(int i = 0; i < mbuf_len(Tx_skbuff[ldirty_tx % NUM_TX_DESC]); i++) DLog("%02x ", data[i]); DLog("\n");*/#endif } freePacket(Tx_skbuff[ldirty_tx % NUM_TX_DESC]); Tx_skbuff[ldirty_tx % NUM_TX_DESC] = NULL; } else { DLog("Tx_skbuff[ldirty_tx % NUM_TX_DESC] is NULL!\n"); } /*Tx_skbuff_Md[ldirty_tx % NUM_TX_DESC]->complete(); Tx_skbuff_Md[ldirty_tx % NUM_TX_DESC]->release(); Tx_skbuff_Md[ldirty_tx % NUM_TX_DESC] = NULL;*/ ldirty_tx++; tx_left--; entry++; } txloop_cnt++; } if (dirty_tx != ldirty_tx) { dirty_tx = ldirty_tx; transmitQueue->start(); }}void RealtekR1000::R1000TxTimeout(OSObject *owner, IOTimerEventSource * timer){ DLog("RealtekR1000::R1000TxTimeout(OSObject *owner, IOTimerEventSource * timer)\n"); uchar tmp8; /* disable Tx, if not already */ tmp8 = ReadMMIO8( ChipCmd ); if (tmp8 & CmdTxEnb) { WriteMMIO8 (ChipCmd, tmp8 & ~CmdTxEnb); } /* Disable interrupts by clearing the interrupt mask. */ WriteMMIO16(IntrMask, 0x0000); R1000TxClear(); R1000HwStart(); transmitQueue->start();}/* This is completely open software */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -