/**     tnpa_5651x_eth_tests.c
 **
 ** Author: Ted Schmitz
 ** Date of original creation March 26, 2009
 **
 **     This file contains all the tests to verify the Ethernet controllers,
 ** muxes, phys and Ethernet paths from the Octeon's point of view.
 **
 **
 **/
#include <common.h>

#include "ll_bist.h"
#include "ll_post.h"
#include "diag_mon/errhand.h"
#include "diag_mon/errcodes.h"
#include "tnpa_5651x_eth_tests.h"
#include "diag_mon/diag_mon.h"  /* def for "TRUE" & "FALSE" */
#include "io_drivers.h"

#include <net.h>

/* external prototypes */
extern void sfpLinkSetup(void);
extern uint16_t get_phy_mode(int interface);
extern void phyRegRead(uint8_t mdio_addr, uint16_t reg, uint16_t *val, 
                       uint8_t dev_type, int bus_id);
extern void phyRegWrite(uint8_t mdio_addr, uint16_t reg, uint16_t mask, 
                        uint16_t newVal, int wait, uint8_t dev_type, int bus_id);

/* module globals*/
static char ping_received;           /* did we get the PING request */
static uint16_t eth_mode;            /* mode of current eth chan under test */

/* local prototypes */
static int front_panel_internal_phy_test(void);
static void reconfigure_eth_back_to_normal(void);
static int front_panel_external_loopback_test(void);
static int qlm1_qlm3_mux_loopback_test(void);
static void set_phy_loopback_mode(int channel);
static void clear_phy_loopback_mode(int channel);

/* define the following symbol to enable Ethernet debug messages */
//#define ENABLE_ETH_DEBUG_MSGS

/****************************************************************************
 **                     Octeon Ethernet Test
 **
 **     This is the main function called to verify all the Ethernet logic in
 ** the TNPA-5651x AMC card.  Ethernet tests are divided into groups.  This
 ** function calls each group in logic order.
 **
 ****************************************************************************/
void octeon_eth_test(void)
{
  printf("\n"); /* new line let each test section introduce themselves */

  /* loop data internally through XAUI muxes */
  if (qlm1_qlm3_mux_loopback_test() == FAIL)
    return;

  /* If front panel ports are selected, loop data internally through PHYs */
  if (front_panel_internal_phy_test() == FAIL)
    return;

  /* If front panel ports are selected, loop data externally through SFPs */
  if (front_panel_external_loopback_test() == FAIL)
    return;

  /* put all Ethernet hardware, software flags, etc., back to normal */
  reconfigure_eth_back_to_normal();
}

/****************************************************************************
 **               QLM1 & QLM3 Mux Internal Loopback Test
 **
 **   This test verifies QLM1 & QLM 3 are correctly connected logically to
 ** the XAUI muxes. 
 **   So for this test all traffic is moved through the QLM1 & QLM3, through
 ** the XAUI muxes, and back to the Octeon again.  Since we are looping data 
 ** internally, no data actually leaves the AMC card.
 **
 **   Each mux is put into a loopback mode and then a Ping packet is 
 ** transmitted to the port's own ip address.  Although at the time this test 
 ** was written, the TPNA-5651x Uboot code was not equipped to respond to a 
 ** ping request, the logic still received the request thereby proving the path 
 ** was in working order.
 **
 ** NOTE:  You must use different logical ports for 1Gb vs 10Gb setup as 
 **        follows:
 **
 ** NEW NOTE:  This was the case until the code was fixed. See new table below.
 **               Front Panel  ethact  (Old code)
 **        Speed     Port      set to
 **        ----- -----------  ---------
 **         1Gb    Port 0      octeth0
 **         1Gb    Port 1      octeth4
 **         10Gb   Port 0      octeth0
 **         10Gb   Port 1      octeth1
 **
 **               Front Panel  ethact  (New code)
 **        Speed     Port      set to
 **        ----- -----------  ---------
 **         1Gb    Port 0      octeth0
 **         1Gb    Port 1      octeth1
 **         10Gb   Port 0      octeth0
 **         10Gb   Port 1      octeth1
 **
 ** ALSO NOTE:  This test must be executed after function "sfpLinkSetup()" has
 **             been called.
 ** 
 **  - - - An additional note about environmental variables - - -
 **
 ** When you "get" an environmental variable, you are retrieving a pointer
 ** to that variable.
 **
 ** However, the location of environmental variables actually moves around as 
 ** new variables are added, updated, or deleted.  Therfore, NEVER GET AN 
 ** ENVIRONMENTAL VARIABLE UNTIL JUST BEFORE YOU USE IT!!!!  Especially when 
 ** you are modifying variables then retrieving others in the same function.
 **
 ** INPUT - Nothing
 **
 ** RETURN - "PASS" is returned if all tests and verifications pass.  "FAIL"
 **          is returned if any anomalies are detected during the test.
 **
 ****************************************************************************/
static int qlm1_qlm3_mux_loopback_test(void)
{
  char * port_ip_addr;              /* temp var for IP address of this board */
  int result;                       /* results of various function calls */
  struct errhand_info eh;           /* err info structure */
  //int i;

  /* subtest sign on message */
  printf("                - Looping data through XAUI muxes...");

#if 0 /* DEBUG - enable to basically disable this test */
  printf("Passed\n");
  return;
#endif

  /**
   **    Test Port 0, with the XAUI mux configured for the internal 
   ** loopback mode.
   **/
  h8_config_xaui_mux(DIAG_BOARD_CONFIG_PORTS_LOOPQLMS);

  port_ip_addr = getenv("ipaddr"); /* get the ip address of our board */
  if (port_ip_addr == 0)
    { /* if no IP address is yet set, use a temporary IP address for now */
      //printf("\nNo IP address current set. Using default IP address...\n");
    setenv("ipaddr", DEFAULT_IP_ADRS); /* set system ip adrs */
    port_ip_addr = DEFAULT_IP_ADRS;
    }

  /* set up the IP adrs (our board) to be used in any network transactions */
  NetPingIP = string_to_ip(port_ip_addr); 

  /* WARNING!!!  "special_eth_test_mode" MUST BE SET TO "MFG_TEST_MODE" FOR
                 THIS TEST TO WORK!!!

    Parts of the logic do not execute if this variable is not set correctly.
  */
  special_eth_test_mode = MFG_TEST_MODE;  /* place Uboot in spec test mode */
  ping_received = FALSE;                  /* init BIST ping received flag */

  /* test works with this added here if it has not been executed already */
  //sfpLinkSetup(); 

#if 0 /* DEBUG */
  //active_eth_port = getenv("ethact");
  //printf ("\nCurrent active Ethernet port = %s\n",active_eth_port);

  printf ("\nTesting Front Panel Ethernet Port 0...");
#endif

  /* Select Port zero as the active port */
  setenv("ethact", QLM1_ETH_NAME); 

  result = NetLoop(PING);         /* call Uboot logic to send a Ping */
#if 0 /* DEBUG - Remove at a later time */
  printf ("\nTesting Front Panel Ethernet Port 0 for 2nd time...");
  result = NetLoop(PING);         /* call Uboot logic to send a Ping */
#endif

  /* Check the BIST flag to see if the Ping request was ever reveived
     by the uboot code.  If not, report an error */
  if (ping_received != TRUE)
    {
    eh.call_type = EH_FAIL_USR_MSG;
    eh.error_stop = ES2750;
    eh.sup_error_stop = SES0000;
    eh.severity = SLEVEL_FATAL;
    eh.data_exp[0] = (unsigned int) 0;
    eh.data_rec[0] = (unsigned int) 0;
    eh.fail_adrs = (unsigned int) 0;
    eh.disp_size = DISP_SIZE_1B;
    eh.void_ptr = "Port 0 was set to XAUI mux loopback mode when test "
                  "failed.";
    eh.fru_list[0] = mb;
    eh.fru_list[1] = 0xFF;

    /* report the error to the BIST system */
    error_handler(&eh);

    reconfigure_eth_back_to_normal(); /* put all eth hw back to nornal */
    return FAIL;
    }

  /**
   **    Test Port 1, with the XAUI mux configured for the internal 
   ** loopback mode.
   **/

#if 0 /* no need for this code any longer but left here in case we need
         to see how to tell the difference between 1BG & 10GB mode */
  eth_mode = get_phy_mode(ETH_PORT_1); /* see how eth port 1 is configured */
  if (eth_mode == ROUT_1G_FRONT)
    setenv("ethact", "octeth4");/* Activate Port 1 - 1Gb mode */
  else if (eth_mode == ROUT_10G_FRONT)
    setenv("ethact", "octeth1");/* Activate Port 1 - 10Gb mode */
#endif

  special_eth_test_mode = MFG_TEST_MODE;  /* place Uboot in spec test mode */
  ping_received = FALSE;                  /* init BIST ping received flag */

  /* Activate Port 1 - now works for 1GB or 10GB mode */
  setenv("ethact", QLM3_ETH_NAME);

#if 0 /* DEBUG */
  active_eth_port = getenv("ethact");
  printf ("\nNew Current active Ethernet port = %s\n",active_eth_port);
  printf ("\nTesting Front Panel Ethernet Port 1...");
#endif

  special_eth_test_mode = MFG_TEST_MODE;  /* place Uboot in spec test mode */
  ping_received = FALSE;                  /* init BIST ping received flag */

  port_ip_addr = getenv("ipaddr"); /* get the ip address of our board */

  /* call Uboot resources to send a Ping */
  NetPingIP = string_to_ip(port_ip_addr);

  result = NetLoop(PING);          /* send a PING request on Port 1 */

  /* Check the BIST flag to see if the Ping request was ever reveived
     by the uboot code.  If not, report an error */
  if (ping_received != TRUE)
    {
    eh.call_type = EH_FAIL_USR_MSG;
    eh.error_stop = ES2760;
    eh.sup_error_stop = SES0000;
    eh.severity = SLEVEL_FATAL;
    eh.data_exp[0] = (unsigned int) 0;
    eh.data_rec[0] = (unsigned int) 0;
    eh.fail_adrs = (unsigned int) 0;
    eh.disp_size = DISP_SIZE_1B;
    eh.void_ptr = "Port 1 was set to XAUI mux loopback mode when test "
                  "failed.";
    eh.fru_list[0] = mb;
    eh.fru_list[1] = 0xFF;

    /* report the error to the BIST system */
    error_handler(&eh);

    reconfigure_eth_back_to_normal(); /* put all eth hw back to nornal */
    return FAIL;
    }

  special_eth_test_mode = NORMAL_MODE;

  printf("Passed\n");

  return PASS;       /* all tests & verifications passed */

}

/****************************************************************************
 **             Front Panel Ethernet Internal Loopback Test
 **
 **   This test verifies the Ethernet ports connected to the front panel are
 ** capable of looping traffic internally through the AMCC 1Gb/10Gb Q2225 PHY.
 **   So for this test all traffic is moved through the QLM1 & QLM3, through
 ** the XAUI muxes, through each PHY and back to the Octeon again.  Since we 
 ** are looping data internally, no data actually leaves the AMC card.
 **
 **   Each port is put into a loopback mode and then a Ping packet is 
 ** transmitted to the port's own ip address.  Although at the time this test 
 ** was written, the TPNA-5651x Uboot code was not equipped to respond to a 
 ** ping request, the logic still received the request thereby proving the path 
 ** was in working order.
 **
 ** NOTE:  You must use different logical ports for 1Gb vs 10Gb setup as 
 **        follows:
 **
 **               Front Panel  ethact
 **        Speed     Port      set to
 **        ----- -----------  ---------
 **         1Gb    Port 0      octeth0
 **         1Gb    Port 1      octeth4  (Old code)
 **         1Gb    Port 1      octeth1  (New code)
 **         10Gb   Port 0      octeth0
 **         10Gb   Port 1      octeth1
 **
 ** ALSO NOTE:  This test must be executed after function "sfpLinkSetup()" has
 **             been called.
 **
 ** INPUT - Nothing
 **
 ** RETURN - "PASS" is returned if all tests and verifications pass.  "FAIL"
 **          is returned if any anomalies are detected during the test.
 **
 ****************************************************************************/
static int front_panel_internal_phy_test(void)
{
  char * port_ip_addr;              /* pointer to IP address of this board */
  int result;                       /* results of various function calls */
  struct errhand_info eh;           /* err info structure */
  //int i;

  /**
   **    Test Port 0, (if it is routed out the front panel) with the PHY 
   ** in the internal loopback mode.
   **/
  eth_mode = get_phy_mode(ETH_PORT_0); /* see how eth port 0 is configured */

  /* if port 0 is routed out the AMC connector, just exit for now.  Eventually
     we will set the XAUI mux to route out the front panel and run this test.
  */
  if (eth_mode == ROUT_AMC_CONN)
    return PASS;

  /* subtest sign on message */
  printf("                - Looping data internally through PHYs...");

  /* Force the muxes to connect to the Phys */
  h8_config_xaui_mux(DIAG_BOARD_CONFIG_PORTS_FORCEFRONT);

  set_phy_loopback_mode(MDIO_BUS_0); /* put chan 0 phy in loopback mode */

  special_eth_test_mode = MFG_TEST_MODE;  /* place Uboot in spec test mode */
  ping_received = FALSE;                  /* init BIST ping received flag */

  /* test works with this added here if it has not been executed already */
  //sfpLinkSetup(); 

#if 0 /* DEBUG */
  //active_eth_port = getenv("ethact");
  //printf ("\nCurrent active Ethernet port = %s\n",active_eth_port);

  printf ("\nTesting Front Panel Ethernet Port 0...");
#endif

  /* select Port zero as the active port */
  setenv("ethact", QLM1_ETH_NAME); 

  port_ip_addr = getenv("ipaddr"); /* get the ip address of our board */
  if (port_ip_addr == 0)
    { /* if no IP address is yet set, use a temporary IP address for now */
      //printf("\nNo IP address current set. Using default IP address...\n");
    setenv("ipaddr", DEFAULT_IP_ADRS); /* set system ip adrs */
    port_ip_addr = DEFAULT_IP_ADRS;
    }

  /* set up the IP adrs (our board) to be used in any network transactions */
  NetPingIP = string_to_ip(port_ip_addr); 

  result = NetLoop(PING);         /* call Uboot logic to send a Ping */

  /* Check the BIST flag to see if the Ping request was ever reveived
     by the uboot code.  If not, report an error */
  if (ping_received != TRUE)
    {
    eh.call_type = EH_FAIL_USR_MSG;
    eh.error_stop = ES2710;
    eh.sup_error_stop = SES0000;
    eh.severity = SLEVEL_FATAL;
    eh.data_exp[0] = (unsigned int) 0;
    eh.data_rec[0] = (unsigned int) 0;
    eh.fail_adrs = (unsigned int) 0;
    eh.disp_size = DISP_SIZE_1B;
    eh.void_ptr = "PHY on port 0 was set to internal loopback mode when test "
                  "failed.";
    eh.fru_list[0] = mb;
    eh.fru_list[1] = 0xFF;

    /* report the error to the BIST system */
    error_handler(&eh);

    reconfigure_eth_back_to_normal(); /* put all eth hw back to nornal */
    return FAIL;
    }

  /**
   **    Test Port 1, (if it is routed out the front panel) with the PHY 
   ** in the internal loopback mode.
   **/

  set_phy_loopback_mode(MDIO_BUS_1); /* put chan 1 phy in loopback mode */

  eth_mode = get_phy_mode(ETH_PORT_1); /* see how eth port 1 is configured */

  special_eth_test_mode = MFG_TEST_MODE;  /* place Uboot in spec test mode */
  ping_received = FALSE;                  /* init BIST ping received flag */

  /* Activate Port 1 - now works for 1GB or 10GB mode */
  setenv("ethact", QLM3_ETH_NAME);

#if 0 /* DEBUG */
  active_eth_port = getenv("ethact");
  printf ("\nNew Current active Ethernet port = %s\n",active_eth_port);
  printf ("\nTesting Front Panel Ethernet Port 1...");
#endif

  special_eth_test_mode = MFG_TEST_MODE;  /* place Uboot in spec test mode */
  ping_received = FALSE;                  /* init BIST ping received flag */

  port_ip_addr = getenv("ipaddr"); /* get the ip address of our board */

  /* call Uboot resources to send a Ping */
  NetPingIP = string_to_ip(port_ip_addr);

  result = NetLoop(PING);          /* send a PING request on Port 1 */

  /* Check the BIST flag to see if the Ping request was ever reveived
     by the uboot code.  If not, report an error */
  if (ping_received != TRUE)
    {
    eh.call_type = EH_FAIL_USR_MSG;
    eh.error_stop = ES2720;
    eh.sup_error_stop = SES0000;
    eh.severity = SLEVEL_FATAL;
    eh.data_exp[0] = (unsigned int) 0;
    eh.data_rec[0] = (unsigned int) 0;
    eh.fail_adrs = (unsigned int) 0;
    eh.disp_size = DISP_SIZE_1B;
    eh.void_ptr = "PHY on port 1 was set to internal loopback mode when test "
                  "failed.";
    eh.fru_list[0] = mb;
    eh.fru_list[1] = 0xFF;

    /* report the error to the BIST system */
    error_handler(&eh);

    reconfigure_eth_back_to_normal(); /* put all eth hw back to nornal */
    return FAIL;
    }

  special_eth_test_mode = NORMAL_MODE;

  /* print "Passed" only if external loopback tests execute next */
  //printf("\ntest_modes = %04X\n",test_modes);
  if ((test_modes & TM_EN_LB_TESTS) == TM_EN_LB_TESTS)
    printf("Passed\n");

  return PASS;       /* all tests & verifications passed */

}

/****************************************************************************
 **             Front Panel Ethernet External Loopback Test
 **
 **   This test verifies the Ethernet ports connected to the front panel are
 ** capable of looping traffic externally out the SFP, through a fiber loopback
 ** cable, and back into the SFP.
 **   So for this test all traffic is moved through the QLM1 & QLM3, through
 ** the XAUI muxes, through each PHY, out the SFS, back into the SFPs, and back
 ** to the Octeon again.
 **
 ** NOTE:  This test will only execute if the front ports are enabled,and
 **        configured in the 10GB mode, and the external loopback test mode is 
 **        selected from the BIST menu.
 **
 **   Each port is put into a loopback mode and then a Ping packet is 
 ** transmitted to the port's own ip address.  Although at the time this test 
 ** was written, the TPNA-5651x Uboot code was not equipped to respond to a 
 ** ping request, the logic still received the request thereby proving the path 
 ** was in working order.
 **
 ** NOTE:  You must use different logical ports for 1Gb vs 10Gb setup as 
 **        follows:
 **
 **               Front Panel  ethact
 **        Speed     Port      set to
 **        ----- -----------  ---------
 **         1Gb    Port 0      octeth0
 **         1Gb    Port 1      octeth0
 **         10Gb   Port 0      octeth0
 **         10Gb   Port 1      octeth1
 **
 ** ALSO NOTE:  This test must be executed after function "sfpLinkSetup()" has
 **             been called.
 **
 ** INPUT - Nothing
 **
 ** RETURN - "PASS" is returned if all tests and verifications pass.  "FAIL"
 **          is returned if any anomalies are detected during the test.
 **
 ****************************************************************************/
static int front_panel_external_loopback_test(void)
{
  //char * active_eth_port;           /* current active ethernet port */

  char * port_ip_addr;              /* pointer to IP address of this board */
  uint16_t eth_mode;                /* mode of current eth chan under test */
  int result;                       /* results of various function calls */
  struct errhand_info eh;          /* err info structure */
  unsigned short test_modes;        /* test modes retrieved from SEEPROM */
  //int i;

  /**    Perform this test only if the current "test mode" includes 
   ** external loopback tests.
   **/
  result = read_select_data_from_seeprom_timed((unsigned char *) &test_modes,
                                               TEST_MODE_OS, TOT_TMODE_BYTES);

  if ((test_modes & TM_EN_LB_TESTS) != TM_EN_LB_TESTS)
    {
      //printf("                - External loopback tests are not enabled...");
    return PASS;   /* exit now if external loopback tests are not selected */
    }

  /* subtest sign on message */
  printf("                - Looping data externally...");

  eth_mode = get_phy_mode(ETH_PORT_0); /* see how eth port 0 is configured */

  /**
   **    Do an external loopback test on Test Port 0, (if it is routed out the 
   ** front panel).  This test assumes an external 10Gb fiber loopback cable is
   ** installed on port 0.
   **/

  /* if port 0 is routed out the AMC connector, just exit for now.  Eventually
     we will set the XAUI mux to route out the front panel and run this test.
  */
  if (eth_mode == ROUT_AMC_CONN)
    {
    printf("routed to AMC.  External loopback not possible!\n");
    return PASS;
    }

  /* put all PHYS and muxes back to normal */
  reconfigure_eth_back_to_normal();

  special_eth_test_mode = MFG_TEST_MODE;  /* place Uboot in spec test mode */
  ping_received = FALSE;                  /* init BIST ping received flag */

#if 0 /* DEBUG */
  active_eth_port = getenv("ethact");
  printf ("\nCurrent active Ethernet port = %s\n",active_eth_port);

  printf ("\nTesting Front Panel Ethernet Port 0...");
#endif

  /* select Port zero as the active port */
  setenv("ethact", QLM1_ETH_NAME); 

  port_ip_addr = getenv("ipaddr"); /* get the ip address of our board */
  if (port_ip_addr == 0)
    { /* if no IP address is yet set, use a temporary IP address for now */
      //printf("\nNo IP address current set. Using default IP address...\n");
    setenv("ipaddr", DEFAULT_IP_ADRS); /* set system ip adrs */
    port_ip_addr = DEFAULT_IP_ADRS;
    }

  /* set up the IP adrs (our board) to be used in any network transactions */
  NetPingIP = string_to_ip(port_ip_addr); 

  result = NetLoop(PING);         /* call Uboot logic to send a Ping */

  /* Check the BIST flag to see if the Ping request was ever reveived
     by the uboot code.  If not, report an error */
  if (ping_received != TRUE)
    {
    eh.call_type = EH_FAIL_USR_MSG;
    eh.error_stop = ES2730;
    eh.sup_error_stop = SES0000;
    eh.severity = SLEVEL_FATAL;
    eh.data_exp[0] = (unsigned int) 0;
    eh.data_rec[0] = (unsigned int) 0;
    eh.fail_adrs = (unsigned int) 0;
    eh.disp_size = DISP_SIZE_1B;
    eh.void_ptr = "Front panel port 0 failed Ethernet external loopback test.";
    eh.fru_list[0] = mb;
    eh.fru_list[1] = 0xFF;

    /* report the error to the BIST system */
    error_handler(&eh);

    reconfigure_eth_back_to_normal(); /* put all eth hw back to nornal */
    return FAIL;
    }

#if 1 /* LEAVE THIS CODE ENABLED FOR NORMAL OPERATION
         DEBUG - disable one port if we only have one external loopback cable */
   /**
   **    Do an external loopback test on Test Port 1, (if it is routed out the 
   ** front panel).  This test assumes an external 10Gb fiber loopback cable is
   ** installed on port 1.
   **/

  eth_mode = get_phy_mode(ETH_PORT_1); /* see how eth port 1 is configured */
  special_eth_test_mode = MFG_TEST_MODE;  /* place Uboot in spec test mode */
  ping_received = FALSE;                  /* init BIST ping received flag */

  setenv("ethact", QLM3_ETH_NAME);/* Activate Port 1 */

#if 0 /* DEBUG */
  active_eth_port = getenv("ethact");
  printf ("\nNew Current active Ethernet port = %s\n",active_eth_port);
  printf ("\nTesting Front Panel Ethernet Port 1...");
#endif

  special_eth_test_mode = MFG_TEST_MODE;  /* place Uboot in spec test mode */
  ping_received = FALSE;                  /* init BIST ping received flag */

  port_ip_addr = getenv("ipaddr"); /* get the ip address of our board */

  /* call Uboot resources to send a Ping */
  NetPingIP = string_to_ip(port_ip_addr);

  result = NetLoop(PING);          /* send a PING request on Port 1 */

  /* Check the BIST flag to see if the Ping request was ever reveived
     by the uboot code.  If not, report an error */
  if (ping_received != TRUE)
    {
    eh.call_type = EH_FAIL_USR_MSG;
    eh.error_stop = ES2740;
    eh.sup_error_stop = SES0000;
    eh.severity = SLEVEL_FATAL;
    eh.data_exp[0] = (unsigned int) 0;
    eh.data_rec[0] = (unsigned int) 0;
    eh.fail_adrs = (unsigned int) 0;
    eh.disp_size = DISP_SIZE_1B;
    eh.void_ptr = "Front panel port 1 failed Ethernet external loopback test.";
    eh.fru_list[0] = mb;
    eh.fru_list[1] = 0xFF;

    /* report the error to the BIST system */
    error_handler(&eh);

    reconfigure_eth_back_to_normal(); /* put all eth hw back to nornal */
    return FAIL;
    }

  special_eth_test_mode = NORMAL_MODE;

#endif /* if 1 - testing 2nd 10GB PHY external loopback */

  return PASS;       /* all tests & verifications passed */

}

/****************************************************************************
 **                    BIST Ping Handler Function
 **
 **     The BIST code sets a special global flag "special_eth_test_mode" 
 ** during BIST Ethernet tests to signal the Uboot code to call this handler
 ** if any Ping requests are received by the Ethernet hardware.
 ** During BIST testing this flag is set to "TRUE".  For normal operation this
 ** flag is set to "FALSE".
 **
 ** INPUT - Global flag "special_eth_test_mode" must be set to "TRUE" in or
 **         for this function to be called when a Ping request is received.
 **
 ** OUTPUT - Module global variable "ping_received" will be set to "TRUE"
 **          when this function is executed.
 **        - Global variable "NetState" will be set to "NETLOOP_SUCCESS".
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
void BIST_PingHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
{
  /* Let the BIST logic know that we did receive a PING request */
  ping_received = TRUE;  

  //printf("\nGOT HERE!!  In BIST PING handler.\n");

  /* Let the Uboot "Receive" logic know we got the packet we were looking 
     for so it exits immediately instead of waiting up to the maximum time
     for the packet to be received. */
  NetState = NETLOOP_SUCCESS; 
}

/****************************************************************************
 **               Re-Configure Ethernet Hardware Back To Normal
 **
 **     This function re-configures the Ethernet hardware back to where normal
 ** Uboot had it set before BIST Ethernet tests wre executed.
 **
 ** INPUT - Nothing
 **
 ** OUTPUT - Various Module global variables and program global variabls will
 **          be reset to there original values befre BIST testsing was executed.
 **          Various hardware registsers may also be re-initialized back to
 **          there original values.
 **
 ** RETURN - Nothing
 **
 ** NOTE: MOST OF THIS ROUTINE WILL HAVE TO BE REMOVED AS SOON AS WE DETERMINE
 **       WHICH LOOPBACK MODE IS REVERSABLE.
 ****************************************************************************/
static void reconfigure_eth_back_to_normal(void)
{

  /* make sure special test modes are disabled */
  special_eth_test_mode = NORMAL_MODE;

  /* make sure both PHYs are not in loopback mode */
  clear_phy_loopback_mode(MDIO_BUS_0); /* take phy 0 out of LB mode */
  clear_phy_loopback_mode(MDIO_BUS_1); /* take phy 1 out of LB mode */

  /* put XAUI mux back to normal */
  h8_config_xaui_mux(DIAG_BOARD_CONFIG_PORTS_INACTIVE);
}

/****************************************************************************
 **             Put Ehthernet Channel In Internal Loopback Mode
 **
 **     This function configures the PHY, for the selected channel, for internal
 ** loopback mode.
 **
 ** INPUT - "channel" = The Ethernet channel on which the PHY should be 
 **         configured.
 **
 ** OUTPUT - The AMCC PHY for the channel selected will be placed into the 
 **          internal loopback mode.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
static void set_phy_loopback_mode(int channel)
{
  uint16_t swork;                   /* 16-bit working reg */
  uint16_t eth_mode;                /* mode of current eth chan under test */

  eth_mode = get_phy_mode(channel); /* get how seltd eth port is configured */
  //printf("\neth_mode = %0d\n",eth_mode);

  /**   If traffic is routed out the AMC connector for this port, ???
   ** EITHER: Force the set up of the port
   **        - - OR - -
   **        Print an error msg after the sign-on msg and skip this
   **        portion of the test.
   **
   **  If you decide to force the set up of the PHY, pick a speed and set
   ** "eth_mode" accordingly so the remainder of this function sets up the
   ** appropriate loopback register(s).
   **/
  if (eth_mode == ROUT_AMC_CONN)
    {/* decide what to do here later */
      printf("Not tested!\n");
      return;
    }

  if (eth_mode == ROUT_1G_FRONT)
    { /* traffic is routed out the front panel for this port in 1GB mode */

    /* Read control register */
    phyRegRead(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PMA_CORE_CONT2_REG, &swork,
               AMCC_DEV_ADDR_PMA_PMD, channel);

#ifdef ENABLE_ETH_DEBUG_MSGS
    printf("Set:Port #%0d:Before: Group #%0d, adrs = %04x, data = %04x\n", 
           channel,AMCC_DEV_ADDR_PMA_PMD, QT2025_PMA_CORE_CONT2_REG, swork);
#endif

    swork |= PMA_CORE_CNT2_REG_LB; /* set the loopback bit */

#ifdef ENABLE_ETH_DEBUG_MSGS
    printf("Set:Port #%0d:After: Group #%0d, adrs = %04x, data = %04x\n", 
           channel,AMCC_DEV_ADDR_PMA_PMD, QT2025_PMA_CORE_CONT2_REG, swork);
#endif

    /* put PHY 0 in loopback mode */
    phyRegWrite(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PMA_CORE_CONT2_REG, 
                0x0000 /*mask*/, swork /*data*/, 0, AMCC_DEV_ADDR_PMA_PMD,
                channel);
    }
  else
    { /* traffic is routed out the front panel for this port in 10 GB mode 
         This works for port 0 but not port 1 in 10GB mode */

    /**   Loopback data override bit must be set before going into 
     ** loopback mode.
     **/
    /* Read register */
    phyRegRead(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PCS_VENDOR_SPECIFIC_REG, 
               &swork, AMCC_DEV_ADDR_PCS, channel);

#ifdef ENABLE_ETH_DEBUG_MSGS
    printf("Port #%0d :Before: Group #%0d, adrs = %04x, data = %04x\n",channel,
           AMCC_DEV_ADDR_PCS, QT2025_PCS_VENDOR_SPECIFIC_REG, swork);
#endif

    swork |= PCS_VEND_SPEC_LB; /* set the loopback bit */

    /* put PHY in loopback mode */
    phyRegWrite(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PCS_VENDOR_SPECIFIC_REG, 
                0x0000 /*mask*/, swork /*data*/, 0, AMCC_DEV_ADDR_PCS,
                channel);

    /**
     **  Now you can put the selected PHY into loopback mode.
     **/

     /* Read register */
    phyRegRead(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PMA_PMD_CTRL1_REG, 
               &swork, AMCC_DEV_ADDR_PCS, channel);

#ifdef ENABLE_ETH_DEBUG_MSGS
    printf("Set:Port #%0d :Before: Group #%0d, adrs = %04x, data = %04x\n",
           channel,AMCC_DEV_ADDR_PCS, QT2025_PMA_PMD_CTRL1_REG, swork);
#endif

    swork |= PCS_CNT1_LB; /* set the loopback bit */

#ifdef ENABLE_ETH_DEBUG_MSGS
    printf("Set:Port #%0d :After: Group #%0d, adrs = %04x, data = %04x\n",
           channel,AMCC_DEV_ADDR_PCS, QT2025_PMA_PMD_CTRL1_REG, swork);
#endif

    phyRegWrite(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PMA_PMD_CTRL1_REG, 
                0x0000 /*mask*/, swork /*data*/, 0, AMCC_DEV_ADDR_PCS,
                channel);
   }

}

/****************************************************************************
 **           Take Ehthernet Channel Out Of Internal Loopback Mode
 **
 **     This function takes the PHY, for the selected channel, out of internal
 ** loopback mode.
 **
 ** INPUT - "channel" = The Ethernet channel on which the PHY should be 
 **         configured.
 **
 ** OUTPUT - The AMCC PHY for the channel selected will be placed into the 
 **          internal loopback mode.
 **
 ** RETURN - Nothing
 **
 ****************************************************************************/
static void clear_phy_loopback_mode(int channel)
{
  uint16_t swork;                    /* 16-bit working reg */

  /**  This does not appear to work for 1GB mode
   **/
  if (eth_mode == ROUT_1G_FRONT)
    { /* traffic is routed out the front panel for this port in 1 GB mode */

    /* Read control register */
    phyRegRead(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PMA_CORE_CONT2_REG, &swork,
               AMCC_DEV_ADDR_PMA_PMD, channel);

#ifdef ENABLE_ETH_DEBUG_MSGS
    printf("Clr:Port #%0d:Before: Group #%0d, adrs = %04x, data = %04x\n", 
           channel, AMCC_DEV_ADDR_PMA_PMD, QT2025_PMA_CORE_CONT2_REG, swork);
#endif

    swork &= ~PMA_CORE_CNT2_REG_LB; /* clear the loopback bit */

#ifdef ENABLE_ETH_DEBUG_MSGS
     printf("Clr:Port #%0d:After: Group #%0d, adrs = %04x, data = %04x\n", 
           channel, AMCC_DEV_ADDR_PMA_PMD, QT2025_PMA_CORE_CONT2_REG, swork);
#endif

   /* put PHY 0 in loopback mode */
    phyRegWrite(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PMA_CORE_CONT2_REG, 
                0x0000 /*mask*/, swork /*data*/, 0, AMCC_DEV_ADDR_PMA_PMD,
                channel);
    }
  else
    { /* traffic is routed out the front panel for this port in 10 GB mode */

    /**
     **  First take the selected PHY out of loopback mode.
     **/

     /* Read register */
    phyRegRead(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PMA_PMD_CTRL1_REG, 
               &swork, AMCC_DEV_ADDR_PCS, channel);

#ifdef ENABLE_ETH_DEBUG_MSGS
    printf("Clr:Port #%0d :Before: Group #%0d, adrs = %04x, data = %04x\n",
           channel,AMCC_DEV_ADDR_PCS, QT2025_PMA_PMD_CTRL1_REG, swork);
#endif

    swork &= ~PCS_CNT1_LB; /* clear the loopback bit */

#ifdef ENABLE_ETH_DEBUG_MSGS
    printf("Clr:Port #%0d :After: Group #%0d, adrs = %04x, data = %04x\n",
           channel,AMCC_DEV_ADDR_PCS, QT2025_PMA_PMD_CTRL1_REG, swork);
#endif

    /* take PHY out of loopback mode */
    phyRegWrite(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PMA_PMD_CTRL1_REG, 
                0x0000 /*mask*/, swork /*data*/, 0, AMCC_DEV_ADDR_PCS,
                channel);

    /**   Loopback data override bit must be cleared after coming out of  
     ** loopback mode.
     **/

    /* Read register */
    phyRegRead(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PCS_VENDOR_SPECIFIC_REG, 
               &swork, AMCC_DEV_ADDR_PCS, channel);

#ifdef ENABLE_ETH_DEBUG_MSGS
    printf("Port #%0d :Before: Group #%0d, adrs = %04x, data = %04x\n",channel,
           AMCC_DEV_ADDR_PCS, QT2025_PCS_VENDOR_SPECIFIC_REG, swork);
#endif

    swork &= ~PCS_VEND_SPEC_LB; /* clear the loopback bit */

    phyRegWrite(BOARD_10G_PHY0_MDIO_ADDR, QT2025_PCS_VENDOR_SPECIFIC_REG, 
                0x0000 /*mask*/, swork /*data*/, 0, AMCC_DEV_ADDR_PCS,
                channel);

   }

}

