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;
|
||
}
|