/*--------------------------------------------------------------------------- * * connect the device (drive) interrupt to our workloop * * ---------------------------------------------------------------------------*/ bool AppleKiwiATA::createDeviceInterrupt(void) { // create a device interrupt source and attach it to the work loop DLOG("AppleKiwiATA createDeviceInterrupt started\n"); _devIntSrc = IOInterruptEventSource::interruptEventSource( (OSObject *)this, (IOInterruptEventSource::Action) &AppleKiwiATA::sDeviceInterruptOccurred, getProvider(), 0); DLOG("AppleKiwiATA createdDeviceInterruptsource = %x\n", _devIntSrc); DLOG("_workLoop = %x\n", _workLoop); if( !_devIntSrc || getWorkLoop()->addEventSource(_devIntSrc) ) { DLOG("AppleKiwiATA failed create dev intrpt source\n"); return false; } // enable interrupt to PCI bus UInt32 intMaskLE = (busChildNumber == 0)? 0x00000200 : 0x00000400; *globalControlReg &= ~intMaskLE; OSSynchronizeIO(); _devIntSrc->enable(); DLOG("AppleKiwiATA createDeviceInterrupt done\n"); return true; }
void AppleKiwiATA::selectIOTiming( ataUnitID unit ) { // this chip snoops the SetFeatures command and we don't need to do anything // unless it is running with the PLL at 133mhz in the case of the 271. In // that event, we have to override the snoop mode because the chip's internals // don't set the correct mode unless the pll is running at 100 mhz. if(mode6Capable) { UInt32 bTiming = kPartBTiming33LE; switch(bitSigToNumeric(busTimings[unit].ataUltraDMASpeedMode) ) { case 2: bTiming = kPartBTiming33LE; break; case 4: bTiming = kPartBTiming66LE; break; case 5: bTiming = kPartBTiming100LE; break; case 6: bTiming = kPartBTiming133LE; break; default: IOLog("AppleKiwiATA: error setting timing registers\n"); break; } //set the registers if( unit == 0) { *timingAReg0 = kPartATimingLE; *timingBReg0 = bTiming; } else { *timingAReg1 = kPartATimingLE; *timingBReg1 = bTiming; } OSSynchronizeIO(); } return; }
/*--------------------------------------------------------------------------- * ---------------------------------------------------------------------------*/ IOReturn OHareATA::handleDeviceInterrupt(void) { if( _dmaIntExpected != true ) { volatile UInt8 status = *_tfStatusCmdReg; OSSynchronizeIO(); status++; // prevent compiler removal of unused variable. } return super::handleDeviceInterrupt(); }
/*--------------------------------------------------------------------------- * * If there's a timeout, read the drive's status reg to clear any pending * interrupt, then clear the interrupt bit and enable inta# propogation in the * controller. * ---------------------------------------------------------------------------*/ void AppleKiwiATA::handleTimeout( void ) { if( isBusOnline == false) { return; } getLock(true); stopDMA(); volatile UInt8 statusByte = *_tfStatusCmdReg; OSSynchronizeIO(); statusByte++; // make sure the compiler doesn't drop this. super::handleTimeout(); getLock( false); }
IOReturn AppleKiwiATA::message (UInt32 type, IOService* provider, void* argument) { switch( type ) { case kATARemovedEvent: DLOG( "AppleKiwiATA got remove event.\n"); // mark the bus as dead. if(isBusOnline == true) { isBusOnline = false; // lock the queue, don't dispatch immediates or anything else. _queueState = IOATAController::kQueueLocked; // disable the interrupt source(s) and timers _devIntSrc->disable(); stopTimer(); _workLoop->removeEventSource(_devIntSrc); _workLoop->removeEventSource(_timer); getLock(true); stopDMA(); // disable the controller pins *globalControlReg |= 0x00000800; // LE format OSSynchronizeIO(); // flush any commands in the queue handleQueueFlush(); // if there's a command active then call through the command gate // and clean it up from inside the workloop. // if( _currentCommand != 0) { DLOG( "AppleKiwiATA Calling cleanup bus.\n"); _cmdGate->runAction( (IOCommandGate::Action) &AppleKiwiATA::cleanUpAction, 0, // arg 0 0, // arg 1 0, 0); // arg2 arg 3 } _workLoop->removeEventSource(_cmdGate); getLock(false); DLOG( "AppleKiwiATA notify the clients.\n"); terminate( ); getProvider()->message( 'ofln', 0 ); } break; default: DLOG( "AppleKiwiATA got some other event = %d\n", (int) type); return super::message(type, provider, argument); break; } return kATANoErr; }
/*--------------------------------------------------------------------------- * * Intercept the setup for the control register pointers so we can set the * timing register in the cell to some safe value prior to scanning for devices * start. * * ---------------------------------------------------------------------------*/ bool AppleKiwiATA::configureTFPointers(void) { DLOG("AppleKiwiATA config TF Pointers \n"); OSString* locationCompare = OSString::withCString( "1" ); if( locationCompare->isEqualTo( getProvider()->getLocation() )) { busChildNumber = 1; } locationCompare->release(); locationCompare = NULL; DLOG("AppleKiwiATA busChildNumber = %d, string = %1s \n", busChildNumber, getProvider()->getLocation()); ioBaseAddrMap[0] = getProvider()->mapDeviceMemoryWithIndex( busChildNumber == 0 ? 0 : 2 ); if ( ioBaseAddrMap[0] == NULL ) { return false; } volatile UInt8* baseAddress = (volatile UInt8*)ioBaseAddrMap[0]->getVirtualAddress(); _tfDataReg = (volatile UInt16*) (baseAddress + 0x00); _tfFeatureReg = baseAddress + 0x01; _tfSCountReg = baseAddress + 0x02; _tfSectorNReg = baseAddress + 0x03; _tfCylLoReg = baseAddress + 0x04; _tfCylHiReg = baseAddress + 0x05; _tfSDHReg = baseAddress + 0x06; _tfStatusCmdReg = baseAddress + 0x07; DLOG("AppleKiwiATA base address 0 = %lX \n", baseAddress); // get the address of the alt-status register from the second base address. ioBaseAddrMap[1] = getProvider()->mapDeviceMemoryWithIndex( busChildNumber == 0 ? 1 : 3 ); if ( ioBaseAddrMap[1] == NULL ) { return false; } baseAddress = (volatile UInt8 *)ioBaseAddrMap[1]->getVirtualAddress(); _tfAltSDevCReg = baseAddress + 2; DLOG("AppleKiwiATA base address 1 = %lX altStatus at %lx \n", baseAddress, _tfAltSDevCReg); // get the address of the BusMaster/DMA control registers from last base address. ioBaseAddrMap[2] = getProvider()->mapDeviceMemoryWithIndex( 4 ); if ( ioBaseAddrMap[2] == NULL ) { return false; } volatile UInt8* bmAddress = (volatile UInt8*)ioBaseAddrMap[2]->getVirtualAddress(); if( busChildNumber == 1) { bmAddress += 0x08; // secondary bus } DLOG("AppleKiwiATA base address 2 = %lX \n", bmAddress); _bmCommandReg = bmAddress; _bmStatusReg = bmAddress + 2; _bmPRDAddresReg = (volatile UInt32*) (bmAddress + 4); // get the address of the mmio control registers from base address 5. ioBaseAddrMap[3] = getProvider()->mapDeviceMemoryWithIndex( 5 ); if ( ioBaseAddrMap[3] == NULL ) { return false; } volatile UInt8* bar5Address = (volatile UInt8*)ioBaseAddrMap[3]->getVirtualAddress(); DLOG("AppleKiwiATA base address 5 = %lx \n", bar5Address); if( busChildNumber == 1) { globalControlReg = (volatile UInt32*) (bar5Address + 0x1208); // secondary bus timingAReg0 =(volatile UInt32*) (bar5Address + 0x120c); timingBReg0 =(volatile UInt32*) (bar5Address + 0x1210); timingAReg1 =(volatile UInt32*) (bar5Address + 0x1214); timingBReg1 =(volatile UInt32*) (bar5Address + 0x1218); } else { globalControlReg =(volatile UInt32*) (bar5Address + 0x1108); // primary bus timingAReg0 =(volatile UInt32*) (bar5Address + 0x110c); timingBReg0 =(volatile UInt32*) (bar5Address + 0x1110); timingAReg1 =(volatile UInt32*) (bar5Address + 0x1114); timingBReg1 =(volatile UInt32*) (bar5Address + 0x1118); } // enable the controller pins *globalControlReg &= (~ 0x00000800); // already LE OSSynchronizeIO(); busTimings[0].ataUltraDMASpeedMode = 32; busTimings[1].ataUltraDMASpeedMode = 32; DLOG("AppleKiwiATA GCR = %lx \n", *globalControlReg); IOSleep(50); DLOG("AppleKiwiATA configTFPointers done\n"); return true; }
/*--------------------------------------------------------------------------- * * handleDeviceInterrupt - overriden here so we can make sure that the DMA has * processed in the event first. * ---------------------------------------------------------------------------*/ IOReturn AppleKiwiATA::handleDeviceInterrupt(void) { if( isBusOnline == false) { return kIOReturnOffline; } if( _currentCommand == 0) { return 0; } UInt32 intMaskLE = (busChildNumber == 0)? 0x00000200 : 0x00000400; // grab a lock getLock(true); UInt32 gcrStatus = *globalControlReg; UInt8 bmStatus = *_bmStatusReg; OSSynchronizeIO(); if( ! (gcrStatus & 0x00000020 )/*bmStatus & 0x04*/ ) // check that the interrupt was asserted since we aren't filtering at interrupt level anymore. { getLock( false ); return 0; } // if this is a DMA command, make sure that the data is fully flushed into system memory // before proceeding. The bmStatus register will set the 0x04 flag bit indicating fifo is flushed. if( (_currentCommand->getFlags() & mATAFlagUseDMA ) == mATAFlagUseDMA ) { while( !(bmStatus & 0x04) ) { bmStatus = *_bmStatusReg; OSSynchronizeIO(); } } // disable interrupt to PCI bus *globalControlReg |= intMaskLE; OSSynchronizeIO(); // clear the edge-trigger bit *_bmStatusReg = 0x04; OSSynchronizeIO(); // super class clears the interrupt request by reading the status reg IOReturn result = super::handleDeviceInterrupt(); // enable interrupt to PCI bus *globalControlReg &= ~intMaskLE; OSSynchronizeIO(); getLock( false ); return result; }
UInt32 AtherosL1Ethernet::outputPacket(mbuf_t m, void *prm) { u32 buf_len; at_adapter *adapter=&adapter_; u16 next_to_use; u16 tpd_req = 1; TpdDescr *pTpd ; struct at_buffer *buffer_info; if(tpd_avail(&adapter->tpd_ring) < tpd_req) { // no enough descriptor DbgPrint("no enough resource!!\n"); freePacket(m); return kIOReturnOutputDropped; } // init tpd flags struct at_tpd_ring* tpd_ring = &adapter->tpd_ring; pTpd = AT_TPD_DESC(tpd_ring, ((u16)atomic_read(&tpd_ring->next_to_use))); //memset(pTpd, 0, sizeof(TpdDescr)); memset(((u8*)pTpd + sizeof(pTpd->addr)), 0, (sizeof(TpdDescr) - sizeof(pTpd->addr))); //addr don't clear next_to_use = (u16)atomic_read(&tpd_ring->next_to_use); buffer_info = tpd_ring->buffer_info+next_to_use; if (!buffer_info->memDesc) { DbgPrint("Tx buffer is null!!\n"); freePacket(m); return kIOReturnOutputDropped; } if (mbuf_pkthdr_len(m) <= AT_TX_BUF_LEN) buf_len = mbuf_pkthdr_len(m); else { DbgPrint("Tx Packet size is too big, droping\n"); freePacket(m); return kIOReturnOutputDropped; } DbgPrint("outputPacket() length %d next_to_use=%d\n", buf_len, next_to_use); UInt8 *data_ptr = (UInt8 *)buffer_info->memDesc->getBytesNoCopy(); UInt32 pkt_snd_len = 0; mbuf_t cur_buf = m; do { if (mbuf_data(cur_buf)) bcopy(mbuf_data(cur_buf), data_ptr, mbuf_len(cur_buf)); data_ptr += mbuf_len(cur_buf); pkt_snd_len += mbuf_len(cur_buf); } while(((cur_buf = mbuf_next(cur_buf)) != NULL) && ((pkt_snd_len + mbuf_len(cur_buf)) <= buf_len)); buf_len = pkt_snd_len; buffer_info->length = (UInt16)buf_len; pTpd->buf_len= OSSwapHostToLittleInt16((UInt16)buf_len); pTpd->eop = 1; if(++next_to_use == tpd_ring->count) next_to_use = 0; atomic_set(&tpd_ring->next_to_use, next_to_use); // update mailbox at_update_mailbox(adapter); OSSynchronizeIO(); freePacket(m); return kIOReturnOutputSuccess; }
UInt32 AttansicL2Ethernet::outputPacket(mbuf_t m, void *prm) { at_adapter *adapter=&adapter_; tx_pkt_header_t* txph; u32 offset, copy_len; int txs_unused; int txbuf_unused; u32 buf_len; if (mbuf_pkthdr_len(m) <= MAX_TX_BUF_LEN) buf_len = mbuf_pkthdr_len(m); else { DbgPrint("Tx Packet size is too big, droping\n"); freePacket(m); return kIOReturnOutputDropped; } txs_unused = TxsFreeUnit(adapter); txbuf_unused = TxdFreeBytes(adapter); if (txs_unused < 1 || buf_len > txbuf_unused) { // no enough resource DbgPrint("no enough resource!!\n"); freePacket(m); return kIOReturnOutputDropped; } offset = adapter->txd_write_ptr; DbgPrint("outputPacket() begin, txd_write_ptr %d txs_next_clear %d length %d \n" , adapter->txd_write_ptr,adapter->txs_next_clear,buf_len); txph = (tx_pkt_header_t*) (((u8*)adapter->txd_ring)+offset); offset += 4; if (offset >= adapter->txd_ring_size) offset -= adapter->txd_ring_size; u32 pkt_snd_len = 0; mbuf_t cur_buf = m; do { if (mbuf_data(cur_buf)){ copy_len = adapter->txd_ring_size - offset; if (copy_len >=mbuf_len(cur_buf)) { memcpy((u8*)adapter->txd_ring+offset, mbuf_data(cur_buf), mbuf_len(cur_buf)); } else { memcpy((u8*)adapter->txd_ring+offset, mbuf_data(cur_buf), copy_len); memcpy((u8*)adapter->txd_ring, ((u8*)mbuf_data(cur_buf))+copy_len, mbuf_len(cur_buf)-copy_len); } offset += mbuf_len(cur_buf); if (offset >= adapter->txd_ring_size) offset -= adapter->txd_ring_size; pkt_snd_len += mbuf_len(cur_buf); } } while(((cur_buf = mbuf_next(cur_buf)) != NULL) && ((pkt_snd_len + mbuf_len(cur_buf)) <= buf_len)); buf_len = pkt_snd_len; *(u32*)txph = 0; txph->pkt_size = buf_len; offset = ((offset+3)&~3); if (offset >= adapter->txd_ring_size) offset -= adapter->txd_ring_size; adapter->txd_write_ptr = offset; // clear txs before send adapter->txs_ring[adapter->txs_next_clear].update = 0; if (++adapter->txs_next_clear == adapter->txs_ring_size) adapter->txs_next_clear = 0; AT_WRITE_REGW( &adapter->hw, REG_MB_TXD_WR_IDX, (adapter->txd_write_ptr>>2)); OSSynchronizeIO(); freePacket(m); return kIOReturnOutputSuccess; }