supermario/base/SuperMarioProj.1994-02-09/OS/StartMgr/UnivTestEnv/SONIC_Loopback.c
2019-06-29 23:17:50 +08:00

698 lines
24 KiB
C

/*
File: SONIC_Loopback.c
Contains: This is the source file for the SONIC Loopback subtest.
This test performs a loopback test of the SONIC in a variety
of modes, as determined by the test modifier. This test can
operate in either a polled or interrupt driven mode, as determined
by the subtest modifier.
Written by: Joe Smyth
Copyright: © 1990, 1992 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<SM2> 5/2/92 kc Roll in Horror. Comments follow:
<H2> 3/6/92 AL Upgraded to CTE v2.1 (copied over from XXTest project).
*/
//
// SONIC_Loopback.c
//
//
// 4/16/91 SW Changed the last byte of the DATACONFIG register from a C to a 9 per the instructions of
// Jano Banks and Sean Findley -- Sean
//
#include <SupportFunctions.h>
#include <SONIC_Loopback.h>
#include <SONIC_Common.h>
SubtestErr SONIC_Loopback( CTEInfo *info,
SONIC_Loopback_Params *params,
SONIC_Loopback_Results *results)
{
#pragma unused (debugstring)
SONIC_Loopback_Err err = SONIC_Loopback_Err_Unexpected ;
UWORD temp_register ;
UWORD NumOfCollisions ;
UWORD *handy_pointer ;
ULONG temp_data_address_scalar ;
int i;
ExceptionInfo exceptionInfo ;
ExceptionArg exceptionArg ;
int originalInterruptLevel ;
char debugstring[100] ;
#if defined (useMacsBug)
if (params->debug_mode)
{
sprintf ( debugstring , "Now at start of Loopback Subtest") ;
DebugStr( c2pstr(debugstring) ) ;
}
sprintf ( debugstring , "Now at start of Bitwalk Subtest") ;
DebugStr( c2pstr(debugstring) ) ;
#endif
//
// Return the Silicon Revision to the Results block
//
results->Silicon_Rev = *(params->Sonic->regsArray[S_VERSION]);
//
// Put Sonic into software reset and disable reception
//
*(params->Sonic->regsArray[S_COMMAND]) = 0x0094 ;
if(*(params->Sonic->regsArray[S_COMMAND]) != 0x0094) // Check that we are in reset
{
err = SONIC_Loopback_Err_on_Reset;
goto ErrorExit ;
}
// Set up new configuration register for revs greater than 3
// I changed the last byte of the S_DATACONFIG register from C to 9 according to instrutions from
// HW guys -- Sean
if (results->Silicon_Rev > 3)
{
*(params->Sonic->regsArray[S_DATACONFIG2]) = 0x0000 ;
if (params->align_flag)
*(params->Sonic->regsArray[S_DATACONFIG]) = 0x8329 ;
else
*(params->Sonic->regsArray[S_DATACONFIG]) = 0x8309 ;
}
else
{
if (params->align_flag)
*(params->Sonic->regsArray[S_DATACONFIG]) = 0x0329 ;
else
*(params->Sonic->regsArray[S_DATACONFIG]) = 0x0309 ;
}
//
// Clear interrupt status register and disable the interrupts
//
*(params->Sonic->regsArray[S_INTMASK]) = 0x0000 ; // Disable all interrupts
if(0 != *(params->Sonic->regsArray[S_INTMASK]))
{
err = SONIC_Loopback_Err_disabling_interrupts;
goto ErrorExit ;
}
*(params->Sonic->regsArray[S_INTSTATUS]) = 0x7FFF ;
if(0 != *(params->Sonic->regsArray[S_INTSTATUS]))
{
err = SONIC_Loopback_Err_clearing_Interrupt_Status ;
goto ErrorExit ;
}
//
// If we want to install interrupts then do it here
//
if (params->interrupt_mode)
{
exceptionArg.params = params ;
exceptionArg.results = results ;
originalInterruptLevel = SUP_SetInterruptLevel(info,7) ;
params->interrupt_install_function(info, &exceptionInfo, &exceptionArg) ; // Install the interrupt handler.
SUP_SetInterruptLevel(info, params->interrupt_level - 1) ; // set interrupt mask to SONIC level -1. Interrupts will be
// serviced now if generated.
*(params->Sonic->regsArray[S_INTMASK]) = 0x7FFF ; // Enable all SONIC interrupts
*(params->Sonic->regsArray[S_TXCONTROL]) &= 0x7FFF ; // Clear the PINT bit
*(params->Sonic->regsArray[S_TXCONTROL]) |= 0x8000 ; // Set the PINT bit thus generating a programmable interrupt
}
//
// Clear reset
//
temp_register = *(params->Sonic->regsArray[S_COMMAND]) ;
*(params->Sonic->regsArray[S_COMMAND]) = (temp_register & 0xFF7F) ; // Clear reset
//
// Initialise the End of buffer word count register to maximum packet size: 760 words
//
*(params->Sonic->regsArray[S_EOBC]) = 0x02F8 ;
//
// Initialise the first Receive Descriptor Area and the Upper Receive Descriptor Address
//
temp_data_address_scalar = (ULONG)params->RDA1_physical_ptr ;
*(params->Sonic->regsArray[S_URDA]) = (UWORD)((temp_data_address_scalar & 0xFFFF0000)>>bitshift16) ;
results->URDA_value = *(params->Sonic->regsArray[S_URDA]) ;
temp_data_address_scalar = (ULONG)params->RDA1_physical_ptr ;
*(params->Sonic->regsArray[S_CRDA]) = (UWORD)(temp_data_address_scalar & 0x0000FFFF) ;
results->CRDA_value = *(params->Sonic->regsArray[S_CRDA]) ;
temp_data_address_scalar = (ULONG)params->RDA2_physical_ptr ;
params->RDA1_logical_ptr->RXpkt_link = (temp_data_address_scalar & 0x0000FFFE) ; // initialise RXpkt.link/EOL EOL = 0, there is another RDA
params->RDA1_logical_ptr->RXpkt_in_use = 0xFFFF ; // avail the RDA to Sonic: RXpkt_in_use -> non-zero
params->RDA1_logical_ptr->RXpkt_status = 0 ; // The rest of the RDA is initialised to zero as it will be filled in by SONIC
params->RDA1_logical_ptr->RXpkt_byte_count = 0 ; // as it receives a packet
params->RDA1_logical_ptr->RXpkt_ptr0 = 0 ;
params->RDA1_logical_ptr->RXpkt_ptr1 = 0 ;
params->RDA1_logical_ptr->RXpkt_seq_no = 0 ;
//
// Initialise the second Receive Descriptor Area
//
temp_data_address_scalar = (ULONG)params->RDA3_physical_ptr ;
params->RDA2_logical_ptr->RXpkt_link = ((temp_data_address_scalar & 0x0000FFFF) | 0x00000001); // initialise RXpkt.link/EOL EOL = 1, this is the last RDA until we get the RDE
// interrupt at which time we will allow SONIC to reuse RDA1.
params->RDA2_logical_ptr->RXpkt_in_use = 0xFFFF ; // avail the RDA to Sonic: RXpkt_in_use -> non-zero
params->RDA2_logical_ptr->RXpkt_status = 0 ; // The rest of the RDA is initialised to zero as it will be filled in by SONIC
params->RDA2_logical_ptr->RXpkt_byte_count = 0 ; // as it receives a packet
params->RDA2_logical_ptr->RXpkt_ptr0 = 0 ;
params->RDA2_logical_ptr->RXpkt_ptr1 = 0 ;
params->RDA2_logical_ptr->RXpkt_seq_no = 0 ;
//
// Initialise the third Receive Descriptor Area
//
temp_data_address_scalar = (ULONG)params->RDA1_physical_ptr ;
params->RDA3_logical_ptr->RXpkt_link = ((temp_data_address_scalar & 0x0000FFFF) | 0x00000001); // initialise RXpkt.link/EOL EOL = 1, this is the last RDA
params->RDA3_logical_ptr->RXpkt_in_use = 0xFFFF ; // avail the RDA to Sonic: RXpkt_in_use -> non-zero
params->RDA3_logical_ptr->RXpkt_status = 0 ; // The rest of the RDA is initialised to zero as it will be filled in by SONIC
params->RDA3_logical_ptr->RXpkt_byte_count = 0 ; // as it receives a packet
params->RDA3_logical_ptr->RXpkt_ptr0 = 0 ;
params->RDA3_logical_ptr->RXpkt_ptr1 = 0 ;
params->RDA3_logical_ptr->RXpkt_seq_no = 0 ;
//
// Initialise the Receive Resource Area
//
temp_data_address_scalar = (ULONG)params->RRA_physical_ptr ;
*(params->Sonic->regsArray[S_URRA]) = (UWORD)((temp_data_address_scalar & 0xFFFF0000)>>bitshift16) ; // load upper Receive Resource Address
temp_data_address_scalar = (ULONG)params->RRA_physical_ptr ;
*(params->Sonic->regsArray[S_RSA]) = (UWORD)(temp_data_address_scalar & 0x0000FFFF) ; // load Receive Resource Start Address
*(params->Sonic->regsArray[S_RRP]) = (UWORD)(temp_data_address_scalar & 0x0000FFFF) ; // load Receive Resource Read Pointer
temp_data_address_scalar = (ULONG)params->RRA_physical_ptr ;
*(params->Sonic->regsArray[S_REA]) = (UWORD)((temp_data_address_scalar + sizeof(Receive_Resource_Area)) & 0x0000FFFF) ; // load Receive Resource End Address
temp_data_address_scalar = (ULONG)(&((*params->RRA_physical_ptr)[2].RXrsc_ptr0)) ;
*(params->Sonic->regsArray[S_RWP]) = (UWORD)(temp_data_address_scalar & 0x0000FFFF) ; // load Resource Write Pointer
//
// Load the Receive Buffer information into the RRA
//
// First for the Receive Buffer Area 1
temp_data_address_scalar = (ULONG)params->RBA1_physical_ptr ;
(*params->RRA_logical_ptr)[0].RXrsc_ptr1 = ((temp_data_address_scalar & 0xFFFF0000)>>bitshift16) ; // Store the RXrsrc.buff_ptr1 for RBA1 in the RRA
temp_data_address_scalar = (ULONG)params->RBA1_physical_ptr ;
(*params->RRA_logical_ptr)[0].RXrsc_ptr0 = (temp_data_address_scalar & 0x0000FFFF) ; // Store the RXrsrc.buff_ptr0 for RBA1 in the RRA
(*params->RRA_logical_ptr)[0].RXrsc_wc0 = 800 ; // Our buffer size is 800 words
(*params->RRA_logical_ptr)[0].RXrsc_wc1 = 0 ;
// And for Receive Buffer Area 2
temp_data_address_scalar = (ULONG)params->RBA2_physical_ptr ;
(*params->RRA_logical_ptr)[1].RXrsc_ptr1 = ((temp_data_address_scalar & 0xFFFF0000)>>bitshift16) ; // Store the RXrsrc.buff_ptr1 for RBA2 in the RRA
temp_data_address_scalar = (ULONG)params->RBA2_physical_ptr ;
(*params->RRA_logical_ptr)[1].RXrsc_ptr0 = (temp_data_address_scalar & 0x0000FFFF) ; // Store the RXrsrc.buff_ptr0 for RBA2 in the RRA
(*params->RRA_logical_ptr)[1].RXrsc_wc0 = 800 ; // Our buffer size is 800 words
(*params->RRA_logical_ptr)[1].RXrsc_wc1 = 0 ;
// And finally for Receive Buffer Area 3
temp_data_address_scalar = (ULONG)params->RBA3_physical_ptr ;
(*params->RRA_logical_ptr)[2].RXrsc_ptr1 = ((temp_data_address_scalar & 0xFFFF0000)>>bitshift16) ; // Store the RXrsrc.buff_ptr1 for RBA3 in the RRA
temp_data_address_scalar = (ULONG)params->RBA3_physical_ptr ;
(*params->RRA_logical_ptr)[2].RXrsc_ptr0 = (temp_data_address_scalar & 0x0000FFFF) ; // Store the RXrsrc.buff_ptr0 for RBA3 in the RRA
(*params->RRA_logical_ptr)[2].RXrsc_wc0 = 800 ; // Our buffer size is 800 words.
(*params->RRA_logical_ptr)[2].RXrsc_wc1 = 0 ;
//
// Load the first block of RRA data into the Sonic Registers by invoking the Read RRA command
// This is subsequently done automatically by SONIC as receive buffers are exhausted, until the RRA is
// empty.
// Note :This is the first DMA of the loopback DTM.
//
temp_register = *(params->Sonic->regsArray[S_COMMAND]) ;
*(params->Sonic->regsArray[S_COMMAND]) = (temp_register & 0xFF7F) ; // Clear the Sonic Software reset
temp_register = *(params->Sonic->regsArray[S_COMMAND]) ;
*(params->Sonic->regsArray[S_COMMAND]) = (temp_register | 0x0100) ; // Invoke Read RRA
results->CRBA0_value = *(params->Sonic->regsArray[S_CRBA0]) ; // Report what we actually loaded
results->CRBA1_value = *(params->Sonic->regsArray[S_CRBA1]) ;
results->RBWC0_value = *(params->Sonic->regsArray[S_RBWC0]) ;
results->RBWC1_value = *(params->Sonic->regsArray[S_RBWC1]) ;
//
// Initialise the receive buffers
//
for ( i = 0; i < sizeof(bufferArea); i++)
{
(*params->RBA1_logical_ptr)[i] = InitialData1;
(*params->RBA2_logical_ptr)[i] = InitialData2;
}
//
// Initialise the Transmit Descriptor Areas
//
// First pkt1TDA
temp_data_address_scalar = (ULONG)params->TDA_physical_ptr ;
*(params->Sonic->regsArray[S_UTDA]) = (UWORD)((temp_data_address_scalar & 0xFFFF0000)>>bitshift16) ;
temp_data_address_scalar = (ULONG)params->TDA_physical_ptr ;
*(params->Sonic->regsArray[S_CTDA]) = (UWORD)(temp_data_address_scalar & 0x0000FFFF) ;
params->TDA_logical_ptr->pkt1TDA.TXpkt_status = 0 ;
params->TDA_logical_ptr->pkt1TDA.TXpkt_config = 0x0000 ; // configure the SONIC Transmitter with Programmable Interrupt, CRC on
// and "Out of Window Collision Timer" begins at first bit of Preamble
params->TDA_logical_ptr->pkt1TDA.TXpkt_size = 1500 ;
params->TDA_logical_ptr->pkt1TDA.TXpkt_frag_count = 1 ;
temp_data_address_scalar = (ULONG)params->TBA1_physical_ptr ;
params->TDA_logical_ptr->pkt1TDA.TXpkt_frag_ptr0 = (temp_data_address_scalar & 0x0000FFFF) ;
temp_data_address_scalar = (ULONG)params->TBA1_physical_ptr ;
params->TDA_logical_ptr->pkt1TDA.TXpkt_frag_ptr1 = ((temp_data_address_scalar & 0xFFFF0000)>>bitshift16) ;
params->TDA_logical_ptr->pkt1TDA.TXpkt_frag_size = 1500 ;
temp_data_address_scalar = (ULONG)(&(params->TDA_physical_ptr->pkt2TDA.TXpkt_status)) ;
if (params->loopback_mode == MACMode)
temp_data_address_scalar = (temp_data_address_scalar | 0x00000001) ; // If its MAC loopback mode only transmit 1 packet ie make this the last TDA
else
temp_data_address_scalar = (temp_data_address_scalar & 0x0000FFFE) ; // Otherwise tell SONIC there's another to follow. This is because MAC loopback
// is too fast for the receive cct to keep up with multiple packets.
params->TDA_logical_ptr->pkt1TDA.TXpkt_link = (UWORD)(temp_data_address_scalar & 0x0000FFFF) ;
// and now pkt2TDA
params->TDA_logical_ptr->pkt2TDA.TXpkt_status = 0 ;
params->TDA_logical_ptr->pkt2TDA.TXpkt_config = 0x0000 ; // configure the SONIC Transmitter with Programmable Interrupt, CRC on
// and "Out of Window Collision Timer" begins at first bit of Preamble
params->TDA_logical_ptr->pkt2TDA.TXpkt_size = 1500 ;
params->TDA_logical_ptr->pkt2TDA.TXpkt_frag_count = 2 ;
temp_data_address_scalar = (ULONG)params->TBA2_physical_ptr ;
params->TDA_logical_ptr->pkt2TDA.TXpkt_frag1_ptr0 = (temp_data_address_scalar & 0x0000FFFF) ;
temp_data_address_scalar = (ULONG)params->TBA2_physical_ptr ;
params->TDA_logical_ptr->pkt2TDA.TXpkt_frag1_ptr1 = ((temp_data_address_scalar & 0xFFFF0000)>>bitshift16) ;
params->TDA_logical_ptr->pkt2TDA.TXpkt_frag1_size = 750 ;
temp_data_address_scalar = (ULONG)(&((*params->TBA2_physical_ptr)[800])) ;
params->TDA_logical_ptr->pkt2TDA.TXpkt_frag2_ptr0 = (temp_data_address_scalar & 0x0000FFFF) ;
temp_data_address_scalar = (ULONG)(&((*params->TBA2_physical_ptr)[800])) ;
params->TDA_logical_ptr->pkt2TDA.TXpkt_frag2_ptr1 = ((temp_data_address_scalar & 0xFFFF0000)>>bitshift16) ;
params->TDA_logical_ptr->pkt2TDA.TXpkt_frag2_size = 750 ;
temp_data_address_scalar = (ULONG)(&(params->TDA_physical_ptr->pkt1TDA.TXpkt_status)) ;
params->TDA_logical_ptr->pkt2TDA.TXpkt_link = ((temp_data_address_scalar & 0x0000FFFF) | 0x00000001) ; // This is the last TDA, so EOL = 1
//
// Initialise the transmit buffer data, but only the used fragments
//
for ( i = 0; i < 1500; i++)
(*params->TBA1_logical_ptr)[i] = ExpectedData1 ;
for ( i = 1500; i < 1600; i++)
(*params->TBA1_logical_ptr)[i] = 0 ;
for ( i = 0; i < 750; i++)
(*params->TBA2_logical_ptr)[i] = ExpectedData2 ;
for ( i = 750; i < 800; i++)
(*params->TBA2_logical_ptr)[i] = 0 ;
for ( i = 800; i < 1550; i++)
(*params->TBA2_logical_ptr)[i] = ExpectedData3 ;
for ( i = 1550; i < 1600; i++)
(*params->TBA2_logical_ptr)[i] = 0 ;
//
// Prepare Sonic pointers for Load CAM instruction
//
*(params->Sonic->regsArray[S_CAMDC]) = (UWORD)params->CAM_Data_logical_ptr->number_of_CAM_entries ;
temp_data_address_scalar = (ULONG)params->CAM_Data_physical_ptr->CAM_data;
*(params->Sonic->regsArray[S_URRA]) = (UWORD)((temp_data_address_scalar & 0xFFFF0000)>>bitshift16) ;
temp_data_address_scalar = (ULONG)params->CAM_Data_physical_ptr->CAM_data;
*(params->Sonic->regsArray[S_CAMDP]) = (UWORD)(temp_data_address_scalar & 0x0000FFFF) ;
//
// Issue load CAM command
//
temp_register = *(params->Sonic->regsArray[S_COMMAND]) ;
*(params->Sonic->regsArray[S_COMMAND]) = (temp_register & 0xFF7F) ; // Clear reset
temp_register = *(params->Sonic->regsArray[S_COMMAND]) ;
*(params->Sonic->regsArray[S_COMMAND]) = (temp_register | 0x0200) ; // Invoke load CAM
// Call the test specified Timeout Function.
if (params->interrupt_mode ? handy_pointer = &results->interrupts_serviced : handy_pointer = params->Sonic->regsArray[S_INTSTATUS]) ;
if (err = params->timeoutMethod(info,handy_pointer, 0x1000,params->timeout_factor ))
{
err = SONIC_Loopback_Err_LCAM_timeout ;
results->interrupt_status = *(params->Sonic->regsArray[S_INTSTATUS]);
goto ErrorExit ;
}
results->interrupt_status = *(params->Sonic->regsArray[S_INTSTATUS]);
if (results->interrupt_error)
{
err = SONIC_Loopback_Err_Interrupt ;
goto ErrorExit ;
}
//
// Configure the receive control register
//
switch( params->loopback_mode )
{
case MACMode:
*(params->Sonic->regsArray[S_RXCONTROL]) = 0xFA00 ;
break;
case ENDECMode:
*(params->Sonic->regsArray[S_RXCONTROL]) = 0xFC00 ;
break;
case TransceiverMode:
*(params->Sonic->regsArray[S_RXCONTROL]) = 0xFE00 ;
break;
default:
err = SONIC_Loopback_Err_no_loopback_mode_specified ;
goto ErrorExit;
break;
}
//
// Enable receiver
//
*(params->Sonic->regsArray[S_COMMAND]) = 0x0008 ;
//
// Start transmission
//
*(params->Sonic->regsArray[S_COMMAND]) = 0x000A ;
//
// Call the test specified Timeout Function for the 1st packet.
//
results->CRBA0_value = *(params->Sonic->regsArray[S_CRBA0]) ; // Report what receive buffer is been used
results->CRBA1_value = *(params->Sonic->regsArray[S_CRBA1]) ;
results->RBWC0_value = *(params->Sonic->regsArray[S_RBWC0]) ;
results->RBWC1_value = *(params->Sonic->regsArray[S_RBWC1]) ;
results->pkt_number = 1 ;
handy_pointer = (UWORD *)(&(params->RDA1_logical_ptr->RXpkt_status)) ;
if (err = params->timeoutMethod(info,handy_pointer, 0x0002, params->timeout_factor )) // The mask 2 is the LBK (loopback packet received)
{ // bit of the RDA status register.
err = SONIC_Loopback_Err_timeout_receiving_1st_pkt ;
results->Pkt1_Receive_Status = (UWORD)(params->RDA1_logical_ptr->RXpkt_status) ;
results->Pkt1_Transmit_Status = (UWORD)(params->TDA_logical_ptr->pkt1TDA.TXpkt_status) ;
goto ErrorExit ;
}
results->Pkt1_Receive_Status = (UWORD)(params->RDA1_logical_ptr->RXpkt_status) ; // Only lower word is valid
//
// Check for other errors
//
results->Pkt1_Transmit_Status = (UWORD)(params->TDA_logical_ptr->pkt1TDA.TXpkt_status) ; // Only lower word is valid
if (results->Pkt1_Transmit_Status & 0x044E) // Check only error bits
{
err = SONIC_Loopback_Err_transmitting_1st_pkt ;
goto ErrorExit ;
}
if (results->Pkt1_Receive_Status & 0x000C) // Check only error bits
{
err = SONIC_Loopback_Err_receiving_1st_pkt ;
goto ErrorExit ;
}
//
// Compare received data with transmitted data for the first packet
//
for (i = 0; i < 1500; i++)
{
results->transmitted_data = (*params->TBA1_logical_ptr)[i] ;
results->received_data = (*params->RBA1_logical_ptr)[i];
results->offset_of_byte_in_err = i ;
if ((results->received_data != results->transmitted_data) || (results->received_data == 0) || (results->transmitted_data == 0)) // Sanity check, make sure we`re not transmitting and receiving zero`s
{
err = SONIC_Loopback_Err_in_1st_pkt_data ;
goto ErrorExit ;
}
}
//
// If we are doing a MAC loopback then end here
//
if (params->loopback_mode == MACMode)
goto MAC_Loopback_Exit ;
//
// Call the test specified Timeout Function for 2nd packet.
//
results->CRBA0_value = *(params->Sonic->regsArray[S_CRBA0]) ; // Report what receive buffer is been used
results->CRBA1_value = *(params->Sonic->regsArray[S_CRBA1]) ;
results->RBWC0_value = *(params->Sonic->regsArray[S_RBWC0]) ;
results->RBWC1_value = *(params->Sonic->regsArray[S_RBWC1]) ;
results->pkt_number = 2 ;
results->offset_of_byte_in_err = 0 ; // reset values for second packet
results->transmitted_data = 0 ;
results->received_data = 0 ;
handy_pointer = (UWORD *)(&(params->RDA2_logical_ptr->RXpkt_status)) ;
if (err = params->timeoutMethod(info,handy_pointer, 0x0002, params->timeout_factor )) // The mask 2 is the LBK (loopback packet received)
{ // bit of the TDA status register.
err = SONIC_Loopback_Err_timeout_receiving_2nd_pkt ;
results->Pkt2_Receive_Status = (UWORD)(params->RDA2_logical_ptr->RXpkt_status) ;
results->Pkt2_Transmit_Status = (UWORD)(params->TDA_logical_ptr->pkt2TDA.TXpkt_status) ;
goto ErrorExit ;
}
//
// Check for other errors in 2nd pkt
//
results->Pkt2_Receive_Status = (UWORD)(params->RDA2_logical_ptr->RXpkt_status) ;
results->Pkt2_Transmit_Status = (UWORD)(params->TDA_logical_ptr->pkt2TDA.TXpkt_status) ;
if (results->Pkt2_Transmit_Status & 0x044E)
{
err = SONIC_Loopback_Err_transmitting_2nd_pkt ;
goto ErrorExit ;
}
if (results->Pkt2_Receive_Status & 0x000C)
{
err = SONIC_Loopback_Err_receiving_2nd_pkt ;
goto ErrorExit ;
}
//
// Compare received data with transmitted data for the second packet
//
for (i = 0; i < 750; i++)
{
results->transmitted_data = (*params->TBA2_logical_ptr)[i] ;
results->received_data = (*params->RBA2_logical_ptr)[i] ;
results->offset_of_byte_in_err = i ;
if ((results->received_data != results->transmitted_data) || (results->received_data == 0) || (results->transmitted_data == 0))
{
err = SONIC_Loopback_Err_in_2nd_pkt_1st_fragment_data ;
goto ErrorExit ;
}
}
for (i = 750; i < 1500; i++)
{
results->transmitted_data = (*params->TBA2_logical_ptr)[i + 50] ; // Fragment 2 begins at location 800 in the TBA, thus the offset of 50
results->received_data = (*params->RBA2_logical_ptr)[i] ;
results->offset_of_byte_in_err = i ;
if ((results->received_data != results->transmitted_data) || (results->received_data == 0) || (results->transmitted_data == 0))
{
err = SONIC_Loopback_Err_in_2nd_pkt_2nd_fragment_data ;
goto ErrorExit ;
}
}
//
// Prepare the first TDA for another transmission so we can generate an RBA Exceeded interrupt
// then link TDA2 back to it by setting the EOL bit of the link field to 0.
// TDA2 link already points to TDA1 from the initial set up.
//
if ((params->interrupt_mode) & (params->loopback_mode != MACMode))
{
params->TDA_logical_ptr->pkt1TDA.TXpkt_status = 0 ;
params->TDA_logical_ptr->pkt1TDA.TXpkt_link |= 0x0001 ; // Make the TDA1 the last one in the list
params->TDA_logical_ptr->pkt2TDA.TXpkt_link &= 0xFFFE ; // enable TDA2 to link back to TDA1
*(params->Sonic->regsArray[S_COMMAND]) = 0x000A ; // Start Transmission
results->CRBA0_value = *(params->Sonic->regsArray[S_CRBA0]) ; // Report what receive buffer is been used
results->CRBA1_value = *(params->Sonic->regsArray[S_CRBA1]) ;
results->RBWC0_value = *(params->Sonic->regsArray[S_RBWC0]) ;
results->RBWC1_value = *(params->Sonic->regsArray[S_RBWC1]) ;
}
//
// If we get to here then all is OK, so return no error.
//
MAC_Loopback_Exit :
err = SONIC_Loopback_Err_Ok;
//
// Do a final check that there were no interrupt errors and that we got all the interrupts we expected
//
if (params->interrupt_mode)
{
SUP_SetInterruptLevel(info,7) ; // Disable external interrupts.
*(params->Sonic->regsArray[S_INTMASK]) = 0x0000 ; // Disable all SONIC interrupts
params->interrupt_remove_function(info, &exceptionInfo, &exceptionArg) ;
SUP_SetInterruptLevel(info,originalInterruptLevel) ; // Enable external interrupts.
if (results->interrupt_error)
{
err = SONIC_Loopback_Err_Interrupt ;
goto ErrorExit ;
}
switch( params->loopback_mode )
{
case MACMode:
temp_register = results->interrupts_serviced ;
if (!(temp_register &= 0x1E00)) // Only check for what we really are sure of.
{
err = SONIC_Loopback_Err_Expected_Interrupt_not_received ;
goto ErrorExit ;
}
break;
case ENDECMode:
case TransceiverMode:
temp_register = results->interrupts_serviced ;
if (!(temp_register &= 0x1E60)) // Only check for what we really are sure of.
{
err = SONIC_Loopback_Err_Expected_Interrupt_not_received ;
goto ErrorExit ;
}
break;
default:
err = SONIC_Loopback_Err_no_loopback_mode_specified ;
goto ErrorExit;
break;
}
}
ErrorExit :
// Fill the Collision Count into the NumOfCollisionsDetected result field
NumOfCollisions = (results->Pkt1_Transmit_Status & 0xF800) ;
results->NumOfCollisionsDetected = (NumOfCollisions >> 11) ; // Only bits 11 thru 15 are valid
NumOfCollisions = (results->Pkt2_Transmit_Status & 0xF800) ;
results->NumOfCollisionsDetected += (NumOfCollisions >> 11) ; // Only bits 11 thru 15 are valid
// If we installed an interrupt handler earlier, now would be a good time to remove it.
if ((err) && (params->interrupt_mode)) // if there is no error then it is already removed
{
SUP_SetInterruptLevel(info,7) ; // Disable external interrupts.
*(params->Sonic->regsArray[S_INTMASK]) = 0x0000 ; // Disable all SONIC interrupts
params->interrupt_remove_function(info, &exceptionInfo, &exceptionArg) ;
SUP_SetInterruptLevel(info,originalInterruptLevel) ; // Enable external interrupts.
}
return(err);
}