summaryrefslogtreecommitdiffstats
path: root/private/ntos/fw/mips/sonictst.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/fw/mips/sonictst.c')
-rw-r--r--private/ntos/fw/mips/sonictst.c822
1 files changed, 822 insertions, 0 deletions
diff --git a/private/ntos/fw/mips/sonictst.c b/private/ntos/fw/mips/sonictst.c
new file mode 100644
index 000000000..30741fc32
--- /dev/null
+++ b/private/ntos/fw/mips/sonictst.c
@@ -0,0 +1,822 @@
+/*++
+
+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;
+}