823 lines
23 KiB
C
823 lines
23 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
sonictst.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the SONIC ethernet test for the selftest.
|
|||
|
The test consist in transmiting packets in loopback mode.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Lluis Abello (lluis) 19-Feb-1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "fwp.h"
|
|||
|
#include "sonictst.h"
|
|||
|
#include "iodevice.h"
|
|||
|
#include "ioaccess.h"
|
|||
|
#include "fwstring.h"
|
|||
|
#ifdef DUO
|
|||
|
#include "duoint.h"
|
|||
|
#endif
|
|||
|
|
|||
|
extern volatile ULONG TimerTicks;
|
|||
|
extern UCHAR * TranslationTable;
|
|||
|
|
|||
|
VOID
|
|||
|
MapDma(
|
|||
|
ULONG VirtualAddress,
|
|||
|
ULONG LogicalAddress,
|
|||
|
ULONG Pages
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine description:
|
|||
|
|
|||
|
This routine performs the I/O address maping by setting the
|
|||
|
translation table.
|
|||
|
|
|||
|
Physical and Logical Addresses must be page aligned.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VirtualAddress - Specifies the R4000 VirtualAddress.
|
|||
|
|
|||
|
Logical Address will be mapped to the physical
|
|||
|
address that this Virtual Address Maps.
|
|||
|
|
|||
|
LogicalAdress - Address to map
|
|||
|
|
|||
|
Pages - Number of pages to map
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
None.
|
|||
|
--*/
|
|||
|
{
|
|||
|
PTRANSLATION_ENTRY TranslationTable;
|
|||
|
ULONG PageFrameNumber,LogicalPage,PhysicalAddress;
|
|||
|
ULONG i;
|
|||
|
PhysicalAddress=VirtualAddress&0x0FFFFFFF; // Extract Physical Address from KSEG0-1
|
|||
|
TranslationTable= (PTRANSLATION_ENTRY)((READ_REGISTER_ULONG(&DMA_CONTROL->TranslationBase.Long)) | 0xA0000000);
|
|||
|
|
|||
|
// Initialize pointer to base
|
|||
|
// of Table to write the new entries.
|
|||
|
// Make physical address virtual
|
|||
|
// Non cached because we want it
|
|||
|
// to be written to memory
|
|||
|
LogicalPage= LogicalAddress>>12;
|
|||
|
PageFrameNumber=PhysicalAddress&0x03FFF000;
|
|||
|
for (i=0;i < Pages;i++) {
|
|||
|
TranslationTable[LogicalPage+i].PageFrame=PageFrameNumber;
|
|||
|
PageFrameNumber+=0x1000; // next page starts after 4Kb more
|
|||
|
TranslationTable[LogicalPage+i].Fill=0;
|
|||
|
}
|
|||
|
WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationLimit.Long,(LogicalPage+i) << 3);
|
|||
|
}
|
|||
|
VOID
|
|||
|
AllocateReceiveDescriptors(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine allocates and initializes a chain of 3 Receive Descriptors.
|
|||
|
The Receive Descriptors are linked in a circular queue so that the
|
|||
|
pointers don't need to be changed any more. The last Receive descriptor
|
|||
|
points to the first but it has the EOL flag set so it's the last on the
|
|||
|
queue and therefore sonic will not use the following descriptor (first one)
|
|||
|
until we free it. Once we process a received packet, the EOL flag must be
|
|||
|
rotated to the next descriptor to make a new descriptor available.
|
|||
|
|
|||
|
In order to be able to use the link field from both physical (system soft)
|
|||
|
and logical (sonic) address spaces the receive descriptors must have
|
|||
|
the same alignment for both physical and logical addresses.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG Link,i;
|
|||
|
ULONG LogicalReceiveDscr;
|
|||
|
ReceiveDscrQueue.Base = (PRECEIVE_DESCRIPTOR) PHYS_RECEIVE_DSCR_ADDRESS;
|
|||
|
LogicalReceiveDscr = LOGICAL_RECEIVE_DSCR_ADDRESS;
|
|||
|
MapDma((ULONG)ReceiveDscrQueue.Base, // R4000 Address
|
|||
|
LogicalReceiveDscr, // Logical Address
|
|||
|
1 // 1 page
|
|||
|
);
|
|||
|
//get 16 lower bits of address or offset
|
|||
|
ReceiveDscrQueue.Current=Link=(ULONG)ReceiveDscrQueue.Base & 0xFFFF;
|
|||
|
//
|
|||
|
// Link first descriptor to the second one.
|
|||
|
//
|
|||
|
for (i=0;i<2;i++) {
|
|||
|
Link += sizeof(RECEIVE_DESCRIPTOR);
|
|||
|
(ReceiveDscrQueue.Base[i]).Link.Data=Link; // Link to next RD
|
|||
|
(ReceiveDscrQueue.Base[i]).InUse.Data=AVAILABLE; // Make it avilable
|
|||
|
}
|
|||
|
//
|
|||
|
// Link last descriptor to the first but mark it as EOL
|
|||
|
//
|
|||
|
(ReceiveDscrQueue.Base[2]).Link.Data=ReceiveDscrQueue.Current | EOL;
|
|||
|
//
|
|||
|
// Make it avilable
|
|||
|
//
|
|||
|
(ReceiveDscrQueue.Base[2]).InUse.Data=AVAILABLE;
|
|||
|
ReceiveDscrQueue.Last=Link; // Keep track of the last one.
|
|||
|
// we need only the upper bits to access a descriptor as Base | First
|
|||
|
ReceiveDscrQueue.Base = (PRECEIVE_DESCRIPTOR)((ULONG) ReceiveDscrQueue.Base & 0xFFFF0000);
|
|||
|
//
|
|||
|
// Initialize sonic Receive descriptor pointers with the logical address
|
|||
|
// of the descriptors.
|
|||
|
//
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->URDA.Reg,(USHORT) (LogicalReceiveDscr >> 16));
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->CRDA.Reg,ReceiveDscrQueue.Current);
|
|||
|
}
|
|||
|
VOID
|
|||
|
AllocateReceiveResources(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine allocates and initializes the Receive Resource area.
|
|||
|
Two resources are allocated.
|
|||
|
The pointer of each entry points to the Receive Buffers which are
|
|||
|
also allocated by this routine. And the size of each buffer is also
|
|||
|
set in the Recieve Resource word count entry.
|
|||
|
|
|||
|
Receive Buffers allocated are RBA_SIZE bytes long.
|
|||
|
|
|||
|
It also allocate room for the CAM descriptors. The CAM descriptor pointer
|
|||
|
is pointed by CamDescriptor and resides inside the URRA segment.
|
|||
|
|
|||
|
The mapping Logical <-> Physical spaces is also done.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
ULONG ReceivePhysBuffer; // Temporay pointer to a receive buffer area.
|
|||
|
ULONG ReceiveLogBuffer; // Temporary pointer to a logical address.
|
|||
|
//
|
|||
|
//Allocate memory for the receive descriptors + CAM Addresses + CAM enable.
|
|||
|
//
|
|||
|
ReceivePhysRsrc = (PRECEIVE_RESOURCE) RECEIVE_PHYS_RSRC_ADDRESS;
|
|||
|
ReceiveLogRsrc = (PRECEIVE_RESOURCE) RECEIVE_LOG_RSRC_ADDRESS;
|
|||
|
MapDma((ULONG)ReceivePhysRsrc,
|
|||
|
(ULONG)ReceiveLogRsrc,
|
|||
|
1
|
|||
|
);
|
|||
|
//
|
|||
|
// Allocate Receive buffers in physical and logical spaces and map them.
|
|||
|
//
|
|||
|
ReceivePhysBuffer= (ULONG) RECEIVE_PHYS_BUFFER_ADDRESS;
|
|||
|
ReceiveLogBuffer= (ULONG) RECEIVE_LOG_BUFFER_ADDRESS;
|
|||
|
MapDma(ReceivePhysBuffer,ReceiveLogBuffer,2);
|
|||
|
//
|
|||
|
// The Receive Buffers are contiguos in memory. Sonic will write
|
|||
|
// the logical address of the packets received. To translate this
|
|||
|
// logical address to a physical one what we do is to keep the
|
|||
|
// offset between these physical and logical addresses and then
|
|||
|
// we just need to add this offset to the logical address to
|
|||
|
// convert it to physical.
|
|||
|
//
|
|||
|
ReceiveBufferTranslationOffset =ReceivePhysBuffer-ReceiveLogBuffer;
|
|||
|
//
|
|||
|
// for each receive resource, Write the logical
|
|||
|
// address of the receive buffer in the physical Receive resource.
|
|||
|
//
|
|||
|
for (i=0; i < 3; i++) {
|
|||
|
ReceivePhysRsrc[i].BufferPtr0.Data=ReceiveLogBuffer & 0xFFFF; //16 lower bits
|
|||
|
ReceivePhysRsrc[i].BufferPtr1.Data=ReceiveLogBuffer >> 16; //16 upper bits
|
|||
|
ReceivePhysRsrc[i].WordCount0.Data=((RBA_SIZE >>1) & 0xFFFF); //16 lower bits
|
|||
|
ReceivePhysRsrc[i].WordCount1.Data=(RBA_SIZE >> 17); //16 upper bits
|
|||
|
ReceiveLogBuffer += RBA_SIZE;
|
|||
|
}
|
|||
|
//
|
|||
|
// Initialize the CamDescriptor to point to the end of the RRA
|
|||
|
//
|
|||
|
PhysCamDescriptor=(PCAM_DESCRIPTOR)(&ReceivePhysRsrc[3]);
|
|||
|
LogCamDescriptor=(PCAM_DESCRIPTOR)(&ReceiveLogRsrc[3]);
|
|||
|
//
|
|||
|
// Initialize sonic Resource Area pointers with the logical address mapped
|
|||
|
// to the physical Area.
|
|||
|
//
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->URRA.Reg,(USHORT) ((ULONG)ReceiveLogRsrc >> 16));
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->RSA.Reg,(ULONG)ReceiveLogRsrc & 0xFFFF);
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->REA.Reg,(ULONG)(&ReceiveLogRsrc[3]) & 0xFFFF);
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->RRP.Reg,(ULONG)ReceiveLogRsrc & 0xFFFF);
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->RWP.Reg,(ULONG)(&ReceiveLogRsrc[2]) & 0xFFFF);
|
|||
|
|
|||
|
//
|
|||
|
// Set the lower boundary of the RBA to the maximum packet size.
|
|||
|
//
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->EOBC.Reg,MAX_PACKET_SIZE >> 1);
|
|||
|
//
|
|||
|
// Set The receive control register.
|
|||
|
//
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->ReceiveControl.Reg,RCR_ENDEC | RCR_RNT);
|
|||
|
}
|
|||
|
VOID
|
|||
|
SetCamDescriptor(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine Initializes the CAM descriptor area allocated by
|
|||
|
"AllocateReceiveResources" and being pointed by PhysCamDescriptor.
|
|||
|
|
|||
|
The Address loaded in the CAM is the one fetched from the NVRAM.
|
|||
|
|
|||
|
It leaves everything ready to issue the Load CAM command.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
//
|
|||
|
// Initialize CAM descriptor area.
|
|||
|
//
|
|||
|
PhysCamDescriptor[0].EntryPointer.Data=0;
|
|||
|
PhysCamDescriptor[0].Port0.Data=(StationAddress[1] << 8) |
|
|||
|
(StationAddress[0]);
|
|||
|
PhysCamDescriptor[0].Port1.Data=(StationAddress[3] << 8) |
|
|||
|
(StationAddress[2]);
|
|||
|
PhysCamDescriptor[0].Port2.Data=(StationAddress[5] << 8) |
|
|||
|
(StationAddress[4]);
|
|||
|
// Set CAM Enable.
|
|||
|
PhysCamDescriptor[1].EntryPointer.Data=1; // enable entry zero.
|
|||
|
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->CamDscrCount.Reg,1); // only one entry.
|
|||
|
// Lower 16 bits offset from URRA
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->CamDscrPtr.Reg,(ULONG)LogCamDescriptor & 0xFFFF);
|
|||
|
}
|
|||
|
VOID
|
|||
|
AllocateTransmitDescriptors(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine allocates and initializes a pool of Transmit Descriptors.
|
|||
|
The Transmit Descriptors are set to be used one for each packet as they
|
|||
|
have only room for one fragment.
|
|||
|
|
|||
|
The Descriptor fragment pointers are initialized to point to the
|
|||
|
Transmit Buffer Area which is also allocated.
|
|||
|
There is enough room allocated for each buffer for the bigest
|
|||
|
ethernet packet.
|
|||
|
|
|||
|
To keep the physical addresses of the TBA we use the upper 16 bits
|
|||
|
of the SONIC_ENTRY this is the field called 'Fill'.
|
|||
|
This way we don't ahve any restriction in these pointers but we
|
|||
|
have to deal with both, physical and logical.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
ULONG PhysTbaPtr,LogTbaPtr; // Transmit Buffer Area pointers
|
|||
|
//
|
|||
|
// Allocate memory for transmit descriptors and map it
|
|||
|
//
|
|||
|
PhysTransmitDscr = (PTRANSMIT_DESCRIPTOR) PHYS_TRANSMIT_DSCR_ADDRESS;
|
|||
|
LogicalTransmitDscr = (PTRANSMIT_DESCRIPTOR) LOGICAL_TRANSMIT_DSCR_ADDRESS;
|
|||
|
MapDma((ULONG) PhysTransmitDscr,
|
|||
|
(ULONG) LogicalTransmitDscr,
|
|||
|
1
|
|||
|
);
|
|||
|
//
|
|||
|
// Allocate memory for Transmit Buffer are and map it.
|
|||
|
//
|
|||
|
PhysTbaPtr = PHYS_TBA_ADDRESS;
|
|||
|
LogTbaPtr = LOG_TBA_ADDRESS;
|
|||
|
MapDma(PhysTbaPtr,LogTbaPtr,1);
|
|||
|
|
|||
|
// Initialize fragment count to 1 (packets won't be scatered)
|
|||
|
|
|||
|
PhysTransmitDscr->FragCount.Data = 1;
|
|||
|
//
|
|||
|
// Initialize Logical pointers to TBA
|
|||
|
//
|
|||
|
PhysTransmitDscr->FragPtr0.Data = LogTbaPtr & 0xFFFF;// lower 16 bits
|
|||
|
PhysTransmitDscr->FragPtr1.Data = LogTbaPtr >> 16; // upper 16 bits
|
|||
|
//
|
|||
|
// Initialize Physical pointer to TBA
|
|||
|
//
|
|||
|
PhysTransmitDscr->FragPtr0.Fill = PhysTbaPtr & 0xFFFF;// lower 16 bits
|
|||
|
PhysTransmitDscr->FragPtr1.Fill = PhysTbaPtr >> 16; // upper 16 bits
|
|||
|
//
|
|||
|
// Unlink the packets, we will transmit one at a time.
|
|||
|
//
|
|||
|
PhysTransmitDscr->Link.Data = EOL;
|
|||
|
PhysTransmitDscr->Config.Data = TCR_POWC;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize UTDA register. This can be done here because the base address
|
|||
|
// of the Transmit Descriptor Area will not change.
|
|||
|
// CTDA must be set after a new packet is ready to be sent.
|
|||
|
//
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->UTDA.Reg,(USHORT)((ULONG)LogicalTransmitDscr>>16));
|
|||
|
}
|
|||
|
VOID
|
|||
|
ComposeMessage(
|
|||
|
ULONG Size,
|
|||
|
UCHAR FirstValue
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine composes a message of the specified size.
|
|||
|
It places the message in the buffer especified by the Transmit
|
|||
|
Descriptor, and initializes the descriptor.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Size - Size of the message in bytes, must be <= MAX_PACKET_SIZE
|
|||
|
FirstValue - value of first Data byte in the packet.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
register ULONG i,j=0;
|
|||
|
PUCHAR MsgPtr; // Temporary pointer to the message area.
|
|||
|
//
|
|||
|
// Load pointer to packet
|
|||
|
//
|
|||
|
MsgPtr= (PUCHAR) ((PhysTransmitDscr->FragPtr1.Fill << 16) | (PhysTransmitDscr->FragPtr0.Fill));
|
|||
|
|
|||
|
|
|||
|
for (i=0; i<6; i++) {
|
|||
|
MsgPtr[j]=StationAddress[i]; // copy Destination address to packet
|
|||
|
MsgPtr[j+6]=StationAddress[i]; // copy Source address to packet
|
|||
|
j++;
|
|||
|
}
|
|||
|
j+=6;
|
|||
|
//
|
|||
|
// Set size of message
|
|||
|
//
|
|||
|
MsgPtr[j++] = Size >> 8; // upper 8 bits
|
|||
|
MsgPtr[j++] = Size & 0xFF; // lower 8 bits
|
|||
|
//
|
|||
|
// Compose message
|
|||
|
//
|
|||
|
for (i=0; i < Size; i++) {
|
|||
|
MsgPtr[j++] = FirstValue++;
|
|||
|
}
|
|||
|
//
|
|||
|
// Initialize other Transmit descriptor fields.
|
|||
|
//
|
|||
|
PhysTransmitDscr->PktSize.Data = Size+6+6+2;
|
|||
|
PhysTransmitDscr->FragSize.Data = Size+6+6+2;
|
|||
|
//
|
|||
|
// Initialize TDA registers with logical address.
|
|||
|
//
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->CTDA.Reg,((ULONG) LogicalTransmitDscr) & 0xFFFF);
|
|||
|
}
|
|||
|
VOID
|
|||
|
SonicCheckError(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine checks and reports error conditions after an interrupt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG ErrorValue;
|
|||
|
SonicErrors++;
|
|||
|
if (SonicStatus.InterruptID & INT_BR) { // Bus Retry.
|
|||
|
ErrorValue= READ_REGISTER_ULONG(&DMA_CONTROL->Errortype.Long);
|
|||
|
//
|
|||
|
// Clear error by writing back the contents of the register.
|
|||
|
//
|
|||
|
WRITE_REGISTER_ULONG(&DMA_CONTROL->Errortype.Long,ErrorValue);
|
|||
|
//
|
|||
|
// Read error registers to clear them
|
|||
|
//
|
|||
|
ErrorValue= READ_REGISTER_ULONG(&DMA_CONTROL->MemoryFailedAddress.Long);
|
|||
|
ErrorValue= READ_REGISTER_ULONG(&DMA_CONTROL->RemoteFailedAddress.Long);
|
|||
|
#ifndef DUO
|
|||
|
ErrorValue= READ_REGISTER_ULONG(&DMA_CONTROL->ParityDiagnosticLow.Long);
|
|||
|
#else
|
|||
|
ErrorValue= READ_REGISTER_ULONG(&DMA_CONTROL->EccDiagnostic);
|
|||
|
#endif
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
BOOLEAN
|
|||
|
WaitForSonicInterrupt(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine waits for a sonic interrupt by polling the Semaphore
|
|||
|
It sets the TimerTicks variable to 20 and if it becomes zero
|
|||
|
(at least 20 millisecond has passed) it time-out.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FALSE if the interrupt ocurred.
|
|||
|
TRUE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
TimerTicks=20;
|
|||
|
while (TimerTicks) { // check for timeout
|
|||
|
if (SonicIntSemaphore==0) { // if interrupt has ocurred
|
|||
|
return FALSE; // return to process
|
|||
|
}
|
|||
|
}
|
|||
|
return TRUE; // return if timeout.
|
|||
|
}
|
|||
|
VOID
|
|||
|
InitSonic(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine initializes the SONIC chip.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
#ifdef DUO
|
|||
|
//
|
|||
|
// Enable sonic interrupts in altera
|
|||
|
//
|
|||
|
USHORT InterruptMask;
|
|||
|
|
|||
|
InterruptMask = READ_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable);
|
|||
|
WRITE_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable,InterruptMask | (1 << 3));
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Software Reset
|
|||
|
//
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->Command.Reg,CR_RST);
|
|||
|
// Set Hardware dependent configuration.
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->DataConfiguration.Reg,DATA_CONFIGURATION);
|
|||
|
// Clear Reset
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->Command.Reg,0);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize all these messy tables of descriptors...
|
|||
|
//
|
|||
|
AllocateReceiveDescriptors();
|
|||
|
AllocateReceiveResources();
|
|||
|
SetCamDescriptor();
|
|||
|
AllocateTransmitDescriptors();
|
|||
|
//
|
|||
|
// Set Interrupt Mask
|
|||
|
//
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->InterruptMask.Reg,( INT_BR |
|
|||
|
INT_LCD |
|
|||
|
INT_PKTRX |
|
|||
|
INT_TXDN |
|
|||
|
INT_TXER |
|
|||
|
INT_RDE |
|
|||
|
INT_RBE |
|
|||
|
INT_RBAE |
|
|||
|
INT_RFO));
|
|||
|
//
|
|||
|
//Issue Load CAM Command and wait for this interrupt.
|
|||
|
//
|
|||
|
SonicStatus.ExpectedInt = INT_LCD; // Expect an INT_LCD interrupt.
|
|||
|
SonicIntSemaphore=1;
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->Command.Reg,CR_LCAM);
|
|||
|
if (WaitForSonicInterrupt()) {
|
|||
|
FwPrint("Timeout waiting for sonic int\r\n");
|
|||
|
SonicErrors++;
|
|||
|
return;
|
|||
|
}
|
|||
|
if (SonicStatus.Status==DONE) {
|
|||
|
SonicStatus.ExpectedInt=0; // clear expected interrupts.
|
|||
|
} else {
|
|||
|
FwPrint("Sonic status not DONE\r\n");
|
|||
|
SonicErrors++;
|
|||
|
}
|
|||
|
//
|
|||
|
// Issue the RRA Read Command
|
|||
|
//
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->Command.Reg,CR_RRA);
|
|||
|
while (READ_REGISTER_USHORT(&SONIC->Command.Reg) & CR_RRA) { // Wait until the command is processed.
|
|||
|
}
|
|||
|
//
|
|||
|
// Enable Reception.
|
|||
|
//
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->Command.Reg,CR_RXEN);
|
|||
|
while (READ_REGISTER_USHORT(&SONIC->Command.Reg) & CR_RXDIS) { // wait until reception is enabled.
|
|||
|
}
|
|||
|
}
|
|||
|
VOID
|
|||
|
SonicInterrupt(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is the SONIC port service interrupt. It will be called from
|
|||
|
the Trap Handler when getting an interrupt from the SONIC.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
register USHORT InterruptStatus,NotCleared;
|
|||
|
//
|
|||
|
// Read Interrupt Status register
|
|||
|
//
|
|||
|
InterruptStatus= READ_REGISTER_USHORT(&SONIC->InterruptStatus.Reg);
|
|||
|
//
|
|||
|
// clear interrupt writing it back
|
|||
|
//
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->InterruptStatus.Reg,InterruptStatus);
|
|||
|
InterruptStatus= InterruptStatus & (~INT_HBL); // clear HBL bit.
|
|||
|
if (EXPECTED_INT && NO_OTHER_INT) {
|
|||
|
if (InterruptStatus & INT_TXDN) {
|
|||
|
//
|
|||
|
// Packet Transmited
|
|||
|
//
|
|||
|
SonicStatus.ExpectedInt &= ~INT_TXDN; // clear expected bit.
|
|||
|
// check if it was properly sent.
|
|||
|
SonicStatus.TransmitControl=READ_REGISTER_USHORT(&SONIC->TransmitControl.Reg);
|
|||
|
if (SonicStatus.TransmitControl & (TCR_BCM | TCR_EXC | TCR_FU | TCR_EXD)) {
|
|||
|
//Error Transmiting
|
|||
|
SonicStatus.Status=ERROR;
|
|||
|
SonicStatus.InterruptID = InterruptStatus;
|
|||
|
SonicIntSemaphore = 0; // signal that the interrupt occurred.
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
if (InterruptStatus & INT_PKTRX) { // packet received
|
|||
|
SonicStatus.ExpectedInt &= ~INT_PKTRX; // clear interrupt
|
|||
|
}
|
|||
|
if (InterruptStatus & INT_LCD) { // load cam interrupt
|
|||
|
SonicStatus.ExpectedInt &= ~INT_LCD; // clear interrupt
|
|||
|
}
|
|||
|
if (SonicStatus.ExpectedInt) { // we still want another interrupt
|
|||
|
return;
|
|||
|
} else {
|
|||
|
SonicStatus.Status=DONE;
|
|||
|
SonicIntSemaphore = 0; // signal that the interrupt occurred.
|
|||
|
return;
|
|||
|
}
|
|||
|
} else { // we got an interrupt not expected.
|
|||
|
SonicStatus.InterruptID=InterruptStatus;
|
|||
|
SonicStatus.TransmitControl=READ_REGISTER_USHORT(&SONIC->TransmitControl.Reg);
|
|||
|
SonicStatus.Status=ERROR;
|
|||
|
SonicIntSemaphore = 0; // signal that the interrupt ocurred.
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
ULONG
|
|||
|
SonicCheckReception(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine compares the sent packet with the received one.
|
|||
|
Makes the used Receive Descriptor available, and if the Receive Buffer
|
|||
|
is full it makes the used receive resurce available.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ERROR - If errors are found
|
|||
|
DONE - If no errors
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PUCHAR SentMsg,ReceivedMsg;
|
|||
|
USHORT ReceiveStatus,TransmitControl;
|
|||
|
ULONG PktSize,i;
|
|||
|
if(CURRENT_DESCRIPTOR->InUse.Data) {
|
|||
|
FwPrint("Descriptor in use\r\n");
|
|||
|
SonicErrors++;
|
|||
|
return ERROR;
|
|||
|
}
|
|||
|
ReceiveStatus=CURRENT_DESCRIPTOR->Status.Data;
|
|||
|
if (ReceiveStatus & (RCR_MC | RCR_BC | RCR_COL | RCR_CRCR | RCR_FAER)) {
|
|||
|
FwPrint("Receive status %lx \r\n",ReceiveStatus);
|
|||
|
SonicErrors++;
|
|||
|
return ERROR;
|
|||
|
}
|
|||
|
//
|
|||
|
// Get ptr to packet and add the offset between Logical and Physical
|
|||
|
// to obtain the physical ptr.
|
|||
|
//
|
|||
|
ReceivedMsg=(PUCHAR) (( (CURRENT_DESCRIPTOR->PktPtr1.Data << 16) |
|
|||
|
(CURRENT_DESCRIPTOR->PktPtr0.Data))
|
|||
|
+ ReceiveBufferTranslationOffset);
|
|||
|
|
|||
|
SentMsg=(PUCHAR) (
|
|||
|
(PhysTransmitDscr->FragPtr1.Fill << 16) |
|
|||
|
PhysTransmitDscr->FragPtr0.Fill
|
|||
|
);
|
|||
|
PktSize=CURRENT_DESCRIPTOR->ByteCount.Data;
|
|||
|
PktSize -=4; // don't check FCS field.
|
|||
|
for (i=0;i<PktSize;i++) {
|
|||
|
if (ReceivedMsg[i] != SentMsg[i]) {
|
|||
|
FwPrint("\r\n Data mismatch, expected %02lx received %02lx \r\n",SentMsg[i],ReceivedMsg[i]);
|
|||
|
SonicErrors++;
|
|||
|
return ERROR;
|
|||
|
}
|
|||
|
}
|
|||
|
//
|
|||
|
// If we get here is because the packet was successfully received.
|
|||
|
// Set the descriptor tables ready for the next packet.
|
|||
|
//
|
|||
|
if (ReceiveStatus & RCR_LPKT) { // last packet in RBA.
|
|||
|
//
|
|||
|
// Advance the RWP to free the used Rba again.
|
|||
|
//
|
|||
|
if (READ_REGISTER_USHORT(&SONIC->RWP.Reg)+sizeof(RECEIVE_RESOURCE) ==
|
|||
|
READ_REGISTER_USHORT(&SONIC->REA.Reg)) {//if it's the last one
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->RWP.Reg,READ_REGISTER_USHORT(&SONIC->RSA.Reg));
|
|||
|
// the new RWP points at the starting address.
|
|||
|
} else {
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->RWP.Reg,READ_REGISTER_USHORT(&SONIC->RWP.Reg)+sizeof(RECEIVE_RESOURCE));
|
|||
|
}
|
|||
|
}
|
|||
|
//
|
|||
|
// Free Used Receive Descripor
|
|||
|
//
|
|||
|
CURRENT_DESCRIPTOR->InUse.Data=AVAILABLE; // make used desc available
|
|||
|
ReceiveDscrQueue.Current=CURRENT_DESCRIPTOR->Link.Data; // First is the next
|
|||
|
LAST_DESCRIPTOR->Link.Data &= NOT_EOL; // Last is not EOL any more.
|
|||
|
ReceiveDscrQueue.Last=LAST_DESCRIPTOR->Link.Data; // Last is next one.
|
|||
|
LAST_DESCRIPTOR->InUse.Data |= EOL; // New Last is EOL.
|
|||
|
return DONE;
|
|||
|
}
|
|||
|
VOID
|
|||
|
RomXTOA(
|
|||
|
IN ULONG number,
|
|||
|
OUT PSZ string
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine converts an ULONG to ASCII.
|
|||
|
The conversion is done in HexaDecimal.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
number - Supplies the ULONG to convert.
|
|||
|
string - PSZ where the result is placed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
for (i=7;i >= 0; i--) {
|
|||
|
string[i]=TranslationTable[number&0xF];
|
|||
|
number = number >> 4;
|
|||
|
}
|
|||
|
string[8]='\0';
|
|||
|
}
|
|||
|
ULONG
|
|||
|
RomSonicLoopBackTest(
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine implements the SONIC loopback test for the selftest.
|
|||
|
The Ethernet Controller is tested using a Loopback in the MAC.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns 0 if no errors are found.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
//
|
|||
|
// Note Packets are set to be 32 byte long so that they fit in the fifo.
|
|||
|
// This is done because at this point interrupts are dispatched trough
|
|||
|
// the Bootstrap Vector, reads from PROM take so long that the SONIC
|
|||
|
// will get Bus retry Errors.
|
|||
|
//
|
|||
|
ULONG i,MsgLength=MIN_DATA_LENGTH-32;
|
|||
|
CHAR String[64];
|
|||
|
SonicErrors=0;
|
|||
|
InitSonic();
|
|||
|
if (SonicErrors) {
|
|||
|
return SonicErrors;
|
|||
|
}
|
|||
|
for (i=0;i<16;i++) {
|
|||
|
ComposeMessage(MsgLength,(UCHAR)i);
|
|||
|
SonicStatus.ExpectedInt=INT_TXDN | INT_PKTRX;
|
|||
|
// Issue the Transmit command.
|
|||
|
SonicIntSemaphore=1;
|
|||
|
WRITE_REGISTER_USHORT(&SONIC->Command.Reg,CR_TXP);
|
|||
|
if (WaitForSonicInterrupt()) {
|
|||
|
FwPrint("Timeout waiting for sonic int 2\r\n");
|
|||
|
SonicErrors++;
|
|||
|
return SonicErrors;
|
|||
|
}
|
|||
|
if (SonicStatus.Status==DONE) { // a packet has been sent and received.
|
|||
|
if (SonicCheckReception()==ERROR) {
|
|||
|
FwPrint(ST_RECEIVED_MSG);
|
|||
|
return SonicErrors;
|
|||
|
} else {
|
|||
|
FwPrint(".");
|
|||
|
}
|
|||
|
} else {
|
|||
|
SonicCheckError();
|
|||
|
FwPrint("\r\nInt:%x Tx:%x",SonicStatus.InterruptID,SonicStatus.TransmitControl);
|
|||
|
return SonicErrors;
|
|||
|
}
|
|||
|
}
|
|||
|
return SonicErrors;
|
|||
|
}
|