AppleUltra66ATA.cpp [plain text]
#include "AppleUltra66ATA.h"
#undef super
#define super IOATAStandardDriver
extern pmap_t kernel_pmap;
OSDefineMetaClassAndStructors( AppleUltra66ATA, IOATAStandardDriver )
static inline int rnddiv( int x, int y )
{
if ( x < 0 )
return 0;
else
return ( (x / y) + (( x % y ) ? 1 : 0) );
}
bool AppleUltra66ATA::configure( IOService *forProvider, ATAControllerInfo *controllerInfo )
{
provider = forProvider;
if ( identifyController() == false )
{
return false;
}
ioMapATA = provider->mapDeviceMemoryWithIndex(0);
if ( ioMapATA == NULL ) return false;
ioBaseATA = (volatile UInt32 *)ioMapATA->getVirtualAddress();
ioMapDMA = provider->mapDeviceMemoryWithIndex(1);
if ( ioMapDMA == NULL ) return false;
ioBaseDMA = (volatile IODBDMAChannelRegisters *)ioMapDMA->getVirtualAddress();
dmaDescriptors = (IODBDMADescriptor *)kalloc(page_size);
if ( dmaDescriptors == 0 )
{
return false;
}
dmaDescriptorsPhys = (UInt32) pmap_extract(kernel_pmap, (vm_offset_t) dmaDescriptors);
if ( (UInt32)dmaDescriptors & (page_size - 1) )
{
IOLog("AppleUltra66ATA::%s() - DMA Descriptor memory not page aligned!!", __FUNCTION__);
return false;
}
bzero( dmaDescriptors, page_size );
numDescriptors = page_size/sizeof(IODBDMADescriptor);
dmaMemoryCursor = IOBigMemoryCursor::withSpecification( 64*1024-2, 0xffffffff );
if ( dmaMemoryCursor == NULL )
{
return false;
}
bitBucketAddr = IOMalloc(32);
if ( bitBucketAddr == 0 )
{
return false;
}
bitBucketAddrPhys = (UInt32) pmap_extract(kernel_pmap, (vm_offset_t) (((UInt32)bitBucketAddr + 0xf) & ~0x0f));
interruptEventSource = IOInterruptEventSource::interruptEventSource( (OSObject *) this,
(IOInterruptEventAction) &AppleUltra66ATA::interruptOccurred,
(IOService *) provider,
(int) 0 );
if ( interruptEventSource == NULL )
{
return false;
}
disableControllerInterrupts();
getWorkLoop()->addEventSource( interruptEventSource );
controllerInfo->maxDevicesSupported = 2;
controllerInfo->devicePrivateDataSize = 0;
controllerInfo->commandPrivateDataSize = 0;
controllerInfo->disableCancelCommands = false;
return true;
}
bool AppleUltra66ATA::identifyController()
{
OSData *compatibleEntry, *modelEntry;
do
{
controllerType = kControllerTypeDBDMAVersion1;
compatibleEntry = OSDynamicCast( OSData, provider->getProperty( "compatible" ) );
if ( compatibleEntry == 0 ) break;
if ( compatibleEntry->isEqualTo( "keylargo-ata", sizeof("keylargo-ata")-1 ) == true )
{
controllerType = kControllerTypeDBDMAVersion2;
modelEntry = OSDynamicCast( OSData, provider->getProperty("model") );
if ( modelEntry == 0 ) break;
if ( modelEntry->isEqualTo( "ata-4", sizeof("ata-4")-1 ) == true )
{
controllerType = kControllerTypeUltra66DBDMA;
}
}
} while ( 0 );
return true;
}
bool AppleUltra66ATA::calculateTiming( UInt32 deviceNum, ATATiming *pTiming )
{
bool rc = false;
switch ( controllerType )
{
case kControllerTypeDBDMAVersion1:
case kControllerTypeDBDMAVersion2:
switch ( pTiming->timingProtocol )
{
case kATATimingPIO:
rc = calculatePIOTiming( deviceNum, pTiming );
break;
case kATATimingDMA:
rc = calculateDMATiming( deviceNum, pTiming );
break;
default:
;
}
break;
case kControllerTypeUltra66DBDMA:
switch ( pTiming->timingProtocol )
{
case kATATimingPIO:
rc = calculateUltra66PIOTiming( deviceNum, pTiming );
break;
case kATATimingDMA:
rc = calculateUltra66DMATiming( deviceNum, pTiming );
break;
case kATATimingUltraDMA66:
rc = calculateUltra66UDMATiming( deviceNum, pTiming );
break;
default:
;
}
break;
default:
;
}
return rc;
}
bool AppleUltra66ATA::calculatePIOTiming( UInt32 unitNum, ATATiming *pTiming )
{
int accessTime;
int accessTicks;
int recTime;
int recTicks;
int cycleTime;
accessTicks = rnddiv(pTiming->minDataAccess, kATASysClkNS);
accessTicks -= kATAPioAccessBase;
if (accessTicks < kATAPioAccessMin )
{
accessTicks = kATAPioAccessMin;
}
accessTime = (accessTicks + kATAPioAccessBase) * kATASysClkNS;
recTime = pTiming->minDataCycle - accessTime;
recTicks = rnddiv( recTime, kATASysClkNS );
recTicks -= kATAPioRecoveryBase;
if ( recTicks < kATAPioRecoveryMin )
{
recTicks = kATAPioRecoveryMin;
}
cycleTime = (recTicks + kATAPioRecoveryBase + accessTicks + kATAPioAccessBase) * kATASysClkNS;
ideTimingWord[unitNum] &= ~0x7ff;
ideTimingWord[unitNum] |= accessTicks | (recTicks << 5);
#if 0
IOLog("AppleUltra66ATA::%s() Unit %1d PIO Requested Timings: Access: %3dns Cycle: %3dns \n\r",
__FUNCTION__, (int)unitNum, (int)pTiming->minDataAccess, (int)pTiming->minDataCycle);
IOLog("AppleUltra66ATA::%s() PIO Actual Timings: Access: %3dns Cycle: %3dns\n\r",
__FUNCTION__, accessTime, cycleTime );
#endif
return true;
}
bool AppleUltra66ATA::calculateDMATiming( UInt32 unitNum, ATATiming *pTiming )
{
int accessTime;
int accessTicks;
int recTime;
int recTicks;
int cycleTime;
int cycleTimeOrig;
int halfTick = 0;
cycleTimeOrig = pTiming->minDataCycle;
#if 0
if ( IsPowerStar() )
{
if ( cycleTimeOrig < 150 ) pTiming->minDataCycle = 150;
}
#endif
accessTicks = rnddiv(pTiming->minDataAccess, kATASysClkNS);
accessTicks -= kATADmaAccessBase;
if ( accessTicks < kATADmaAccessMin )
{
accessTicks = kATADmaAccessMin;
}
accessTime = (accessTicks + kATADmaAccessBase) * kATASysClkNS;
recTime = pTiming->minDataCycle - accessTime;
recTicks = rnddiv( recTime, kATASysClkNS );
recTicks -= kATADmaRecoveryBase;
if ( recTicks < kATADmaRecoveryMin )
{
recTicks = kATADmaRecoveryMin;
}
cycleTime = (recTicks + kATADmaRecoveryBase + accessTicks + kATADmaAccessBase) * kATASysClkNS;
if ( controllerType == kControllerTypeDBDMAVersion1 )
{
if ( (accessTicks > kATADmaAccessMin) && ((UInt32)(accessTime - kATASysClkNS/2) >= pTiming->minDataAccess) )
{
if ( (UInt32)(cycleTime - kATASysClkNS) >= pTiming->minDataCycle )
{
halfTick = 1;
accessTicks--;
accessTime -= kATASysClkNS/2;
cycleTime -= kATASysClkNS;
}
}
}
ideTimingWord[unitNum] &= ~0xffff800;
ideTimingWord[unitNum] |= (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11;
#if 0
IOLog("AppleUltra66ATA::%s() Unit %1d DMA Requested Timings: Access: %3dns Cycle: %3dns \n\r",
__FUNCTION__, (int)unitNum, (int)pTiming->minDataAccess, (int)cycleTimeOrig);
IOLog("AppleUltra66ATA::%s() DMA Actual Timings: Access: %3dns Cycle: %3dns\n\r",
__FUNCTION__, accessTime, cycleTime );
IOLog("AppleUltra66ATA::%s() Ide DMA Timings = %08lx\n\r", __FUNCTION__, ideTimingWord[unitNum] );
#endif
return true;
}
bool AppleUltra66ATA::calculateUltra66PIOTiming( UInt32 unitNum, ATATiming *pTiming )
{
int accessTime;
int accessTicks;
int recTime;
int recTicks;
int cycleTime;
accessTicks = rnddiv(pTiming->minDataAccess * 1000, kATAUltra66ClockPS );
accessTime = accessTicks * kATAUltra66ClockPS;
recTime = pTiming->minDataCycle * 1000 - accessTime;
recTicks = rnddiv( recTime, kATAUltra66ClockPS );
cycleTime = (recTicks + accessTicks ) * kATAUltra66ClockPS;
ideTimingWord[unitNum] &= ~0xe00003ff;
ideTimingWord[unitNum] |= accessTicks | (recTicks << 5);
#if 0
IOLog("AppleUltra66ATA::%s() Unit %1d PIO Requested Timings: Access: %3dns Cycle: %3dns \n\r",
__FUNCTION__, (int)unitNum, (int)pTiming->minDataAccess, (int)pTiming->minDataCycle);
IOLog("AppleUltra66ATA::%s() PIO Actual Timings: Access: %3dns Cycle: %3dns\n\r",
__FUNCTION__, accessTime / 1000, cycleTime / 1000 );
IOLog("AppleUltra66ATA::%s() Ide PIO Timings = %08lx\n\r", __FUNCTION__, ideTimingWord[unitNum] );
#endif
return true;
}
bool AppleUltra66ATA::calculateUltra66DMATiming( UInt32 unitNum, ATATiming *pTiming )
{
int accessTime;
int accessTicks;
int recTime;
int recTicks;
int cycleTime;
accessTicks = rnddiv(pTiming->minDataAccess * 1000, kATAUltra66ClockPS);
accessTime = accessTicks * kATAUltra66ClockPS;
recTime = pTiming->minDataCycle * 1000 - accessTime;
recTicks = rnddiv( recTime, kATAUltra66ClockPS );
cycleTime = (recTicks + accessTicks) * kATAUltra66ClockPS;
ideTimingWord[unitNum] &= ~0x001ffc00;
ideTimingWord[unitNum] |= (accessTicks | (recTicks << 5)) << 10;
#if 0
IOLog("AppleUltra66ATA::%s() Unit %1d DMA Requested Timings: Access: %3dns Cycle: %3dns \n\r",
__FUNCTION__, (int)unitNum, (int)pTiming->minDataAccess, (int)pTiming->minDataCycle);
IOLog("AppleUltra66ATA::%s() DMA Actual Timings: Access: %3dns Cycle: %3dns\n\r",
__FUNCTION__, accessTime / 1000, cycleTime / 1000 );
IOLog("AppleUltra66ATA::%s() Ide DMA Timings = %08lx\n\r", __FUNCTION__, ideTimingWord[unitNum] );
#endif
return true;
}
bool AppleUltra66ATA::calculateUltra66UDMATiming( UInt32 unitNum, ATATiming *pTiming )
{
int rdyToPauseTicks;
int rdyToPauseTime;
int cycleTime;
int cycleTicks;
rdyToPauseTicks = rnddiv(pTiming->minDataAccess * 1000, kATAUltra66ClockPS);
rdyToPauseTime = rdyToPauseTicks * kATAUltra66ClockPS;
cycleTicks = rnddiv(pTiming->minDataCycle * 1000, kATAUltra66ClockPS);
cycleTime = cycleTicks * kATAUltra66ClockPS;
ideTimingWord[unitNum] &= ~0x1ff00000;
ideTimingWord[unitNum] |= ((rdyToPauseTicks << 5) | (cycleTicks << 1) | 1) << 20;
#if 0
IOLog("AppleUltra66ATA::%s() Unit %1d UDMA66 Requested Timings: ReadyToPause: %3dns Cycle: %3dns \n\r",
__FUNCTION__, (int)unitNum, (int)pTiming->minDataAccess, (int)pTiming->minDataCycle);
IOLog("AppleUltra66ATA::%s() UDMA66 Actual Timings: ReadyToPause: %3dns Cycle: %3dns\n\r",
__FUNCTION__, rdyToPauseTime / 1000, cycleTime / 1000 );
IOLog("AppleUltra66ATA::%s() Ide DMA Timings = %08lx\n\r", __FUNCTION__, ideTimingWord[unitNum] );
#endif
return true;
}
void AppleUltra66ATA::newDeviceSelected( IOATAStandardDevice *newDevice )
{
OSWriteSwapInt32( ioBaseATA, 0x200, ideTimingWord[newDevice->getUnit()] );
eieio();
}
bool AppleUltra66ATA::selectTiming( UInt32 unitNum, ATATimingProtocol timingProtocol )
{
if ( controllerType == kControllerTypeUltra66DBDMA )
{
switch ( timingProtocol )
{
case kATATimingUltraDMA66:
ideTimingWord[unitNum] |= 0x00100000;
break;
case kATATimingDMA:
ideTimingWord[unitNum] &= ~0x00100000;
break;
default:
;
}
}
return true;
}
bool AppleUltra66ATA::programDma( IOATAStandardCommand *cmd )
{
IOMemoryDescriptor *memoryDesc;
IODBDMADescriptor *dmaDesc;
UInt32 dmaCmd;
bool isWrite;
IOPhysicalSegment physSeg;
IOByteCount offset;
UInt32 i;
IODBDMAReset( ioBaseDMA );
cmd->getPointers( &memoryDesc, &dmaReqLength, &isWrite );
if ( dmaReqLength == 0 )
{
return true;
}
offset = 0;
dmaCmd = (isWrite == true) ? kdbdmaOutputMore : kdbdmaInputMore;
dmaDesc = dmaDescriptors;
for ( i = 0; i < numDescriptors; i++, dmaDesc++ )
{
if ( dmaMemoryCursor->getPhysicalSegments( memoryDesc, offset, &physSeg, 1 ) != 1 )
{
break;
}
IOMakeDBDMADescriptor( dmaDesc,
dmaCmd,
kdbdmaKeyStream0,
kdbdmaIntNever,
kdbdmaBranchNever,
kdbdmaWaitNever,
physSeg.length,
physSeg.location );
offset += physSeg.length;
}
if ( i == numDescriptors )
{
return false;
}
if ( dmaReqLength & 1 )
{
i++;
IOMakeDBDMADescriptor( dmaDesc++,
dmaCmd,
kdbdmaKeyStream0,
kdbdmaIntNever,
kdbdmaBranchNever,
kdbdmaWaitNever,
1,
bitBucketAddrPhys );
}
if ( i == numDescriptors )
{
return false;
}
IOMakeDBDMADescriptor( dmaDesc,
kdbdmaStop,
kdbdmaKeyStream0,
kdbdmaIntNever,
kdbdmaBranchNever,
kdbdmaWaitNever,
0,
0 );
IOSetDBDMACommandPtr( ioBaseDMA, dmaDescriptorsPhys );
return true;
}
bool AppleUltra66ATA::startDma( IOATAStandardCommand * )
{
if ( dmaReqLength != 0 )
{
IODBDMAContinue( ioBaseDMA );
}
return true;
}
bool AppleUltra66ATA::stopDma( IOATAStandardCommand *, UInt32 *transferCount )
{
UInt32 i;
UInt32 ccResult;
UInt32 byteCount = 0;
*transferCount = 0;
if ( dmaReqLength == 0 )
{
return true;
}
IODBDMAStop( ioBaseDMA );
for ( i=0; i < numDescriptors; i++ )
{
ccResult = IOGetCCResult( &dmaDescriptors[i] );
if ( (ccResult & (kdbdmaStatusActive | kdbdmaStatusDead)) == 0 )
{
break;
}
byteCount += (IOGetCCOperation( &dmaDescriptors[i] ) & kdbdmaReqCountMask) - (ccResult & kdbdmaResCountMask);
}
*transferCount = byteCount;
return true;
}
bool AppleUltra66ATA::resetDma()
{
IODBDMAReset( ioBaseDMA );
return true;
}
bool AppleUltra66ATA::checkDmaActive()
{
return ((IOGetDBDMAChannelStatus( ioBaseDMA ) & kdbdmaActive) != 0);
}
void AppleUltra66ATA::disableControllerInterrupts()
{
interruptEventSource->disable();
}
void AppleUltra66ATA::enableControllerInterrupts()
{
interruptEventSource->enable();
}
void AppleUltra66ATA::free()
{
if ( interruptEventSource != 0 )
{
interruptEventSource->disable();
interruptEventSource->release();
}
if ( ioMapATA != 0 )
{
ioMapATA->release();
}
if ( ioMapDMA != 0 )
{
ioMapDMA->release();
}
if ( bitBucketAddr != 0 )
{
IOFree( bitBucketAddr, 32 );
}
if ( dmaDescriptors != 0 )
{
kfree( (vm_offset_t)dmaDescriptors, page_size );
}
}
void AppleUltra66ATA::writeATAReg( UInt32 regIndex, UInt32 regValue )
{
regIndex += (regIndex >= kATARegDeviceControl ) ? (kATACS3RegBase - kATARegDeviceControl + 6) : 0;
if ( regIndex )
{
*((volatile UInt8 *)ioBaseATA + (regIndex<<4)) = regValue;
}
else
{
*(volatile UInt16 *)ioBaseATA = regValue;
}
eieio();
}
UInt32 AppleUltra66ATA::readATAReg( UInt32 regIndex )
{
regIndex += (regIndex >= kATARegAltStatus ) ? (kATACS3RegBase - kATARegAltStatus + 6) : 0;
if ( regIndex )
{
return *((volatile UInt8 *)ioBaseATA + (regIndex<<4));
}
else
{
return *(volatile UInt16 *)ioBaseATA;
}
}