mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 01:29:20 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
384 lines
11 KiB
C
384 lines
11 KiB
C
/*
|
|
File: HALc96AMIC.c
|
|
|
|
Contains: routines that setup/teardown DMA buffers for AMIC
|
|
|
|
Notes:
|
|
|
|
Entry points:
|
|
|
|
Written by: Paul Wolf
|
|
|
|
Copyright: © 1992-1993 by Apple Computer, Inc., all rights reserved.
|
|
|
|
Change History (most recent first):
|
|
|
|
<SM8> 11/22/93 pdw Rolling in from <MCxx>.
|
|
<SM7> 11/10/93 chp Fix a DebugStr string.
|
|
<SM6> 10/15/93 pdw Fixing "Cold Fusion EVT2/VM" bug by always calling LockMemory on
|
|
our permanent copy buffer.
|
|
<SM5> 10/14/93 pdw Added support for Synchronous data transfers, rewrote State
|
|
Machine, message handling etc.
|
|
<SM4> 9/13/93 pdw Changed the risky slash pattern.
|
|
<SM3> 9/9/93 pdw Lots of little changes. Name changes, temporary cache_bug
|
|
stuff.
|
|
<SM2> 8/13/93 pdw TEMPORARY: Reverted to 200 as MIN_DMA_SIZE and now I always call
|
|
LockMemory - not just when VM is on.
|
|
<1> 7/17/93 pdw first checked in
|
|
|
|
*/
|
|
|
|
// NOTE: The following five symbols are mutually exclusive
|
|
// - only set one of them to 1 at a time
|
|
#define COPYBACK 0
|
|
#define NONCACHEABLE 1
|
|
#define WRITE_THROUGH 0
|
|
// these two must be tied in with dbl-buffering also (push/flush must happen before DMA)
|
|
#define COPYBACK_PUSH 0
|
|
#define COPYBACK_FLUSH 0
|
|
|
|
|
|
#include <Types.h>
|
|
#include <Traps.h>
|
|
#include <TrapsPrivate.h>
|
|
#include <Memory.h>
|
|
#include <Errors.h>
|
|
#include <SCSI.h>
|
|
#include <SCSIStandard.h>
|
|
|
|
#include "SCSIDebug.h"
|
|
#include "Recorder.h"
|
|
#include "ACAM.h"
|
|
#include "SIMCore.h"
|
|
#include "HALc96.h"
|
|
#include "SIMCorePriv.h"
|
|
#include "SCSIGlue.h"
|
|
|
|
#define MAX(a,b) ((a)>=(b)?(a):(b))
|
|
|
|
|
|
/****** Function Prototypes For Inside only *******/
|
|
|
|
|
|
/****** Transfer Constants (Check HALc96PSC.a as well!) *******/
|
|
#define MIN_AMIC_DMA_SIZE 0x200 // 20
|
|
|
|
|
|
/*********************************************************************************
|
|
InitAMIC - Initialize DMA Hardware
|
|
*********************************************************************************/
|
|
|
|
// external
|
|
OSErr
|
|
InitHW_AMIC( HALc96Globals *HALg)
|
|
{
|
|
#pragma unused (HALg)
|
|
|
|
return (noErr);
|
|
}
|
|
|
|
/*********************************************************************************
|
|
InitSW_AMIC - Initialize Software stuff required for DMA support
|
|
*********************************************************************************/
|
|
|
|
// external
|
|
OSErr
|
|
InitSW_AMIC( HALc96Globals *HALg)
|
|
{
|
|
long err;
|
|
ulong numBlocks, pageSize, bufferSize;
|
|
void *memStart, *pageStart;
|
|
MemoryBlock lockedBlock;
|
|
LogicalToPhysicalTable l2pTable;
|
|
|
|
|
|
//*** WARNING: The following code is Page Size Dependent !!! ***
|
|
|
|
//*** WARNING: Don't change these unless you change HALc96DMA.a as well
|
|
pageSize = 4*1024;
|
|
//*** WARNING: Don't change this unless you change HALc96DMA.a as well
|
|
bufferSize = 1*pageSize; // must be a multiple of pageSize
|
|
|
|
memStart = NewPtrSys( bufferSize+pageSize);
|
|
if (memStart==0)
|
|
return (memFullErr);
|
|
|
|
pageStart = (void *)((((long)memStart-1) & ~(pageSize-1)) + pageSize);
|
|
|
|
SetPtrSize( memStart, (long)pageStart + MAX(bufferSize,pageSize) - (long)memStart);
|
|
|
|
err = LockMemory(pageStart, bufferSize);
|
|
if (err!=noErr)
|
|
return (err);
|
|
|
|
lockedBlock.address = pageStart;
|
|
lockedBlock.count = bufferSize;
|
|
|
|
l2pTable.logical = lockedBlock;
|
|
numBlocks = 1;
|
|
|
|
GetPhysical( &l2pTable, &numBlocks);
|
|
|
|
HALg->physicalCopyBuffer = l2pTable.physical[0].address;
|
|
HALg->logicalCopyBuffer = pageStart;
|
|
HALg->minDMAsize = MIN_AMIC_DMA_SIZE;
|
|
|
|
return (noErr);
|
|
}
|
|
|
|
|
|
/*********************************************************************************
|
|
SetupIOAMIC - LockMemory on user buffers as necessary
|
|
*********************************************************************************/
|
|
|
|
void
|
|
SetupIOAMIC( SIM_IO *ioPtr)
|
|
{
|
|
int i;
|
|
SGRecord *sgList;
|
|
Ptr firstAddr = nil;
|
|
ulong firstLen = 0;
|
|
ulong cnt = 1;
|
|
Ptr pageStart;
|
|
long err;
|
|
Ptr addr;
|
|
ulong count;
|
|
|
|
|
|
|
|
// Have we already done it ? If so, return
|
|
// (this could happen if we started it then got a reselect and then retried this one again)
|
|
|
|
if( ioPtr->SIMprivFlags & (1 << kbSetupComplete) )
|
|
return;
|
|
|
|
IfRecordEvent( (long)ioPtr, (long)'suIO');
|
|
|
|
// Note that we don't do TIB's because we would have to pre-interpret them nor do we do
|
|
// anything with scsiDataPhysical ranges because they should be taken care of by client
|
|
// (at least they're supposed to). We won't get here with a TIB since old-API transactions
|
|
// are handled by DoSelect not DoInitiate (which is where the call to SetupIO happens).
|
|
|
|
if ( ioPtr->scsiFlags & scsiDataPhysical )
|
|
return;
|
|
|
|
//ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ Scatter/Gather List ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ
|
|
|
|
if ( ioPtr->scsiDataType == scsiDataSG )
|
|
{
|
|
sgList = (SGRecord *) ioPtr->scsiDataPtr;
|
|
|
|
for( i = 0; i < ioPtr->scsiSGListCount; i+=1 )
|
|
{
|
|
/* No sense fooling with small transfers due to lock memory overhead
|
|
The data xfer routine will know that the buffer is not locked down and
|
|
will use the old routine instead of direct DMA. (DMA to known locked buffer
|
|
and then BlockMove)
|
|
*/
|
|
if( (count = sgList[i].SGCount) <= MIN_AMIC_DMA_SIZE )
|
|
continue; /* Don't bother */
|
|
|
|
if( (ulong)(addr = (Ptr)(sgList[i].SGAddr)) >= 0x40000000 ) { // Up in ROM or NuBus Land
|
|
ioPtr->SIMprivFlags |= (1 << kbUseDblBuffer);
|
|
break;
|
|
}
|
|
|
|
if (VMRunning())
|
|
{ // <SM2> pdw
|
|
if( noErr != LockMemory( addr, count) ) {
|
|
ioPtr->SIMprivFlags |= (1 << kbUseDblBuffer);
|
|
break;
|
|
}
|
|
else {
|
|
ioPtr->SIMprivFlags |= (1 << kbSetupComplete);
|
|
if( !firstAddr ) {
|
|
firstAddr = addr;
|
|
firstLen = count;
|
|
}
|
|
}
|
|
}
|
|
else // VM not running
|
|
{
|
|
#if WRITE_THROUGH
|
|
pageStart = (Ptr)( (ulong)addr & (0xFFFFF000));
|
|
do {
|
|
err = nkMakePageWriteThrough( (Ptr)((long)pageStart>>12));
|
|
if (err<0)
|
|
DebugStr("\p nkMakePageWriteThrough failed");
|
|
pageStart += 0x1000;
|
|
} while ( pageStart < addr+count);
|
|
|
|
ioPtr->SIMprivFlags |= (1 << kbSetupComplete);
|
|
#elif NONCACHEABLE
|
|
pageStart = (Ptr)( (ulong)addr & (0xFFFFF000));
|
|
do {
|
|
err = nkMakePageNonCacheable( (Ptr)((long)pageStart>>12));
|
|
if (err<0)
|
|
DebugStr("\p nkMakePageNonCacheable failed");
|
|
pageStart += 0x1000;
|
|
} while ( pageStart < addr+count);
|
|
|
|
ioPtr->SIMprivFlags |= (1 << kbSetupComplete);
|
|
#elif COPYBACK_PUSH
|
|
err = nkPushCacheRange(addr, count);
|
|
if (err<0)
|
|
DebugStr("\p nkPushCacheRange failed");
|
|
#elif COPYBACK_FLUSH
|
|
err = nkFlushCacheRange(addr, count);
|
|
if (err<0)
|
|
DebugStr("\p nkFlushCacheRange failed");
|
|
#endif
|
|
firstAddr = addr;
|
|
firstLen = count;
|
|
}
|
|
}
|
|
}
|
|
|
|
//ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ else Address/Count ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ
|
|
|
|
else {
|
|
/* Don't bother with small buffers */
|
|
if( (firstLen = ioPtr->scsiDataLength) <= MIN_AMIC_DMA_SIZE )
|
|
return;
|
|
|
|
if( (ulong)(firstAddr = ioPtr->scsiDataPtr) >= 0x40000000 ) { // Up in ROM or NuBus Land
|
|
ioPtr->SIMprivFlags |= (1 << kbUseDblBuffer);
|
|
}
|
|
else {
|
|
if (VMRunning()) { // <SM2> pdw
|
|
IfRecordEvent( (long)firstAddr, (long)'LkMm');
|
|
if( err = LockMemory( firstAddr, firstLen) != noErr )
|
|
ioPtr->SIMprivFlags |= (1 << kbUseDblBuffer);
|
|
else {
|
|
ioPtr->SIMprivFlags |= (1 << kbSetupComplete);
|
|
IfRecordEvent( (long)firstLen, (long)err);
|
|
}
|
|
}
|
|
else // VM not running
|
|
{
|
|
#if WRITE_THROUGH
|
|
pageStart = (Ptr)( (ulong)firstAddr & (0xFFFFF000));
|
|
do {
|
|
err = nkMakePageWriteThrough( (Ptr)((long)pageStart>>12));
|
|
if (err<0)
|
|
DebugStr("\p nkMakePageWriteThrough failed");
|
|
pageStart += 0x1000;
|
|
} while ( pageStart < firstAddr+firstLen);
|
|
|
|
ioPtr->SIMprivFlags |= (1 << kbSetupComplete);
|
|
#elif NONCACHEABLE
|
|
pageStart = (Ptr)( (ulong)firstAddr & (0xFFFFF000));
|
|
do {
|
|
err = nkMakePageNonCacheable( (Ptr)((long)pageStart>>12));
|
|
if (err<0)
|
|
DebugStr("\p nkMakePageWriteThrough failed");
|
|
pageStart += 0x1000;
|
|
} while ( pageStart < firstAddr+firstLen);
|
|
|
|
ioPtr->SIMprivFlags |= (1 << kbSetupComplete);
|
|
#elif COPYBACK_PUSH
|
|
err = nkPushCacheRange(firstAddr, firstLen);
|
|
if (err<0)
|
|
DebugStr("\p nkPushCacheRange failed");
|
|
#elif COPYBACK_FLUSH
|
|
err = nkFlushCacheRange(firstAddr, firstLen);
|
|
if (err<0)
|
|
DebugStr("\p nkFlushCacheRange failed");
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
//ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ Do an initial GetPhysical ÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉ
|
|
|
|
if( (ioPtr->SIMprivFlags & (1 << kbUseDblBuffer)) == 0 && firstAddr && firstLen ) {
|
|
ioPtr->logical.address = firstAddr;
|
|
ioPtr->logical.count = firstLen;
|
|
if( GetPhysical( (LogicalToPhysicalTable *)&ioPtr->logical, &cnt) )
|
|
ioPtr->SIMprivFlags |= (1 << kbUseDblBuffer);
|
|
else
|
|
{
|
|
// Check to see if the bug in GetPhysical caught us.
|
|
// If it did we need to setup logical.address and logical.count
|
|
// the way they are supposed to be.
|
|
if( ioPtr->logical.address == firstAddr ) {
|
|
(char *)ioPtr->logical.address += ioPtr->physical.count;
|
|
ioPtr->logical.count -= ioPtr->physical.count;
|
|
}
|
|
ioPtr->transLogEnd = firstAddr + ioPtr->physical.count;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************
|
|
TeardownIOAMIC - UnlockMemory user buffers as necessary
|
|
*********************************************************************************/
|
|
|
|
void
|
|
TeardownIOAMIC( SIM_IO * ioPtr, HALc96Globals * HALg)
|
|
{
|
|
#pragma unused(HALg)
|
|
|
|
Ptr pageStart;
|
|
int i;
|
|
SGRecord * sgList;
|
|
Ptr addr;
|
|
ulong count;
|
|
long err;
|
|
|
|
// We don't need to check whether we should be here or not because the flag
|
|
// kbSetupComplete (in ioPtr->SIMprivFlags) will be set only if LockMemory or other
|
|
// undo-required things were done in SetupIO, and that flag is checked
|
|
// before this routine is called (optimization).
|
|
|
|
/* Scatter/Gather List */
|
|
|
|
if ( ioPtr->scsiDataType == scsiDataSG )
|
|
{
|
|
sgList = (SGRecord *) ioPtr->scsiDataPtr;
|
|
|
|
for( i = 0; i < ioPtr->scsiSGListCount; i+=1 )
|
|
{
|
|
/* Don't bother with small buffers */
|
|
if( (count = sgList[i].SGCount) <= MIN_AMIC_DMA_SIZE )
|
|
continue;
|
|
|
|
if( (ulong)(addr = (Ptr)(sgList[i].SGAddr)) >= 0x40000000 ) // Up in ROM or NuBus Land
|
|
break;
|
|
|
|
IfRecordEvent( (long)addr, (long)'UnLk');
|
|
err = UnlockMemory( addr, count); // Can't do anything about errors
|
|
IfRecordEvent( (long)count, (long)err);
|
|
|
|
}
|
|
}
|
|
|
|
/* Address/Count */
|
|
|
|
else
|
|
{
|
|
if (VMRunning())
|
|
{
|
|
IfRecordEvent( (long)ioPtr->scsiDataPtr, (long)'UnLk');
|
|
err = UnlockMemory(ioPtr->scsiDataPtr, ioPtr->scsiDataLength);
|
|
IfRecordEvent( (long)ioPtr->scsiDataLength, (long)err);
|
|
}
|
|
else
|
|
{ // VM not running
|
|
#if WRITE_THROUGH | NONCACHEABLE
|
|
pageStart = (Ptr)( (ulong)(addr=ioPtr->scsiDataPtr) & (0xFFFFF000));
|
|
do {
|
|
IfRecordEvent( (long)pageStart, (long)'MPgC');
|
|
err = nkMakePageCacheable( (Ptr)((long)pageStart>>12));
|
|
if (err<0)
|
|
DebugStr("\p nkMakePageCacheable failed");
|
|
pageStart += 0x1000;
|
|
} while ( pageStart < addr+ioPtr->scsiDataLength);
|
|
#else
|
|
IfRecordEvent( (long)ioPtr->scsiDataPtr, (long)'UnL2');
|
|
err = UnlockMemory( ioPtr->scsiDataPtr, ioPtr->scsiDataLength);
|
|
IfRecordEvent( (long)ioPtr->scsiDataLength, (long)err);
|
|
#endif
|
|
}
|
|
}
|
|
} |