OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [peripheral/] [eth.c] - Diff between revs 450 and 451

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 450 Rev 451
Line 68... Line 68...
#define ETH_DEBUG 0
#define ETH_DEBUG 0
#ifndef ETH_DEBUG
#ifndef ETH_DEBUG
# define ETH_DEBUG  1
# define ETH_DEBUG  1
#endif
#endif
 
 
 
/*! Period (clock cycles) for rescheduling Rx and Tx controllers. */
 
#define  RTX_RESCHED_PERIOD  1
 
 
/*! MAC address that is always accepted. */
/*! MAC address that is always accepted. */
static const unsigned char mac_broadcast[ETHER_ADDR_LEN] =
static const unsigned char mac_broadcast[ETHER_ADDR_LEN] =
  { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
 
Line 92... Line 94...
 
 
  /* Details of the hardware */
  /* Details of the hardware */
  unsigned char      mac_address[ETHER_ADDR_LEN];  /* Ext HW address */
  unsigned char      mac_address[ETHER_ADDR_LEN];  /* Ext HW address */
  unsigned long int  phy_addr;          /* Int HW address */
  unsigned long int  phy_addr;          /* Int HW address */
  unsigned long int  mac_int;           /* interrupt line number */
  unsigned long int  mac_int;           /* interrupt line number */
 
  int                dummy_crc;         /* Flag indicating if we add CRC */
  int                int_line_stat;     /* interrupt line status */
  int                int_line_stat;     /* interrupt line status */
 
 
  /* External interface deatils */
  /* External interface deatils */
  int rtx_type;                         /* Type of external i/f: FILE or TAP */
  int rtx_type;                         /* Type of external i/f: FILE or TAP */
 
 
Line 139... Line 142...
    unsigned long int  bd_ram[ETH_BD_SPACE / 4];
    unsigned long int  bd_ram[ETH_BD_SPACE / 4];
  } regs;
  } regs;
};
};
 
 
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Emulate MIIM transaction to ethernet PHY
 
 
 
   @param[in]  eth  Ethernet device datastruture.                           */
 
/* -------------------------------------------------------------------------- */
 
static void
 
eth_miim_trans (struct eth_device *eth)
 
{
 
  switch (eth->regs.miicommand)
 
    {
 
    case ((1 << ETH_MIICOMM_WCDATA_OFFSET)):
 
      /* Perhaps something to emulate here later, but for now do nothing */
 
      break;
 
 
 
    case ((1 << ETH_MIICOMM_RSTAT_OFFSET)):
 
      /*
 
      printf("or1ksim: eth_miim_trans: phy %d\n",(int)
 
             ((eth->regs.miiaddress >> ETH_MIIADDR_FIAD_OFFSET)&
 
              ETH_MIIADDR_FIAD_MASK));
 
      printf("or1ksim: eth_miim_trans: reg %d\n",(int)
 
             ((eth->regs.miiaddress >> ETH_MIIADDR_RGAD_OFFSET)&
 
              ETH_MIIADDR_RGAD_MASK));
 
      */
 
      /*First check if it's the correct PHY to address */
 
      if (((eth->regs.miiaddress >> ETH_MIIADDR_FIAD_OFFSET)&
 
           ETH_MIIADDR_FIAD_MASK) == eth->phy_addr)
 
        {
 
          /* Correct PHY - now switch based on the register address in the PHY*/
 
          switch ((eth->regs.miiaddress >> ETH_MIIADDR_RGAD_OFFSET)&
 
                  ETH_MIIADDR_RGAD_MASK)
 
            {
 
            case MII_BMCR:
 
              eth->regs.miirx_data = BMCR_FULLDPLX;
 
              break;
 
            case MII_BMSR:
 
              eth->regs.miirx_data = BMSR_LSTATUS | BMSR_ANEGCOMPLETE |
 
                BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | BMSR_100FULL;
 
              break;
 
            case MII_PHYSID1:
 
              eth->regs.miirx_data = 0x22; /* Micrel PHYID */
 
              break;
 
            case MII_PHYSID2:
 
              eth->regs.miirx_data = 0x1613; /* Micrel PHYID */
 
              break;
 
            case MII_ADVERTISE:
 
              eth->regs.miirx_data = ADVERTISE_FULL;
 
              break;
 
            case MII_LPA:
 
              eth->regs.miirx_data = LPA_DUPLEX | LPA_100;
 
              break;
 
            case MII_EXPANSION:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_CTRL1000:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_STAT1000:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_ESTATUS:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_DCOUNTER:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_FCSCOUNTER:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_NWAYTEST:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_RERRCOUNTER:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_SREVISION:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_RESV1:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_LBRERROR:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_PHYADDR:
 
              eth->regs.miirx_data = eth->phy_addr;
 
              break;
 
            case MII_RESV2:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_TPISTATUS:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_NCONFIG:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            default:
 
              eth->regs.miirx_data = 0xffff;
 
              break;
 
            }
 
        }
 
      else
 
        {
 
          eth->regs.miirx_data = 0xffff; /* PHY doesn't exist, read all 1's */
 
        }
 
 
 
      break;
 
 
 
    case ((1 << ETH_MIICOMM_SCANS_OFFSET)):
 
      /* From MAC's datasheet:
 
         A host initiates the Scan Status Operation by asserting the SCANSTAT
 
         signal. The MIIM performs a continuous read operation of the PHY
 
         Status register. The PHY is selected by the FIAD[4:0] signals. The
 
         link status LinkFail signal is asserted/deasserted by the MIIM module
 
         and reflects the link status bit of the PHY Status register. The
 
         signal NVALID is used for qualifying the validity of the LinkFail
 
         signals and the status data PRSD[15:0]. These signals are invalid
 
         until the first scan status operation ends. During the scan status
 
         operation, the BUSY signal is asserted until the last read is
 
         performed (the scan status operation is stopped).
 
 
 
         So for now - do nothing, leave link status indicator as permanently
 
         with link.
 
      */
 
 
 
      break;
 
 
 
    default:
 
      break;
 
    }
 
}       /* eth_miim_trans () */
 
 
 
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*!Write an Ethernet packet to a FILE interface.
/*!Write an Ethernet packet to a FILE interface.
 
 
   This writes a single Ethernet packet to a FILE interface. The format is to
   This writes a single Ethernet packet to a FILE interface. The format is to
   write the length, then the data.
   write the length, then the data.
Line 536... Line 405...
          eth_flush_bd (eth);
          eth_flush_bd (eth);
        }
        }
    }
    }
 
 
  /* Wake up again after 1 ticks (was 10, changed by Julius). */
  /* Wake up again after 1 ticks (was 10, changed by Julius). */
  SCHED_ADD (eth_controller_tx_clock, dat, 1);
  SCHED_ADD (eth_controller_tx_clock, dat, RTX_RESCHED_PERIOD);
 
 
}       /* eth_controller_tx_clock () */
}       /* eth_controller_tx_clock () */
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
Line 788... Line 657...
  printf("BD filled with 0x%08lx bytes.\n", bytes_read);
  printf("BD filled with 0x%08lx bytes.\n", bytes_read);
#endif
#endif
 
 
  /* Write result to BD.
  /* Write result to BD.
 
 
     @todo Why is the length 4 more than the packet length? Is that for
     The OpenRISC MAC hardware passes on the CRC (which it should not). The
     the CRC? */
     Linux drivers have been written to expect a value (which they ignore). So
  SET_FIELD (bd_info, ETH_RX_BD, LENGTH, packet_length + 4);
     for consistency, we pretend the length is 4 bytes longer.
 
 
 
     This is now controlled by a configuration parameter, dummy_crc. For
 
     backwards compatibility, it defaults to TRUE. */
 
  SET_FIELD (bd_info, ETH_RX_BD, LENGTH,
 
             packet_length + (eth->dummy_crc ? 4 : 0));
  CLEAR_FLAG (bd_info, ETH_RX_BD, READY);
  CLEAR_FLAG (bd_info, ETH_RX_BD, READY);
  SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, RXB);
  SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, RXB);
 
 
  eth->regs.bd_ram[eth->rx_bd_index] = bd_info;
  eth->regs.bd_ram[eth->rx_bd_index] = bd_info;
 
 
Line 828... Line 702...
    }
    }
}       /* eth_fill_bd () */
}       /* eth_fill_bd () */
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*!Ignore a packet from the outside world.
/*!Ignore a packet from the TAP interface.
 
 
   We don't have a BD ready, so any packets waiting should be thrown away.
   We don't have a BD ready, so any packets waiting should be thrown away.
 
 
   @param[in] eth  The Ethernet data structure.                               */
   @param[in] eth  The Ethernet data structure.
 
 
 
   @return  1 (TRUE) if more or more packets were discarded, zero otherwise.  */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static void
static int
eth_ignore_packet (struct eth_device *eth)
eth_ignore_tap_packets (struct eth_device *eth)
 
{
 
  int  result = 0;
 
  int  n;
 
 
 
  /* Read packets until there are none left. */
 
  do
 
    {
 
      struct pollfd  fds[1];
 
 
 
      /* Poll to see if there is anything to be read. */
 
      fds[0].fd     = eth->rtx_fd;
 
      fds[0].events = POLLIN;
 
 
 
      n = poll (fds, 1, 0);
 
      if (n < 0)
 
        {
 
          /* Give up with a warning if poll fails */
 
          fprintf (stderr,
 
                   "Warning: Poll error while emptying TAP: %s: ignored.\n",
 
                   strerror (errno));
 
          return  result;
 
        }
 
      else if ((n > 0) && ((fds[0].revents & POLLIN) == POLLIN))
{
{
  unsigned char  buf[ETH_MAXPL];
  unsigned char  buf[ETH_MAXPL];
  ssize_t        nread = eth_read_packet (eth, buf);
  ssize_t        nread = eth_read_packet (eth, buf);
 
 
  if (nread < 0)
  if (nread < 0)
    {
    {
 
              /* Give up with a warning if read fails */
      fprintf (stderr,
      fprintf (stderr,
               "Warning: Read of when Ethernet busy failed %s.\n",
               "Warning: Read of when Ethernet busy failed %s.\n",
               strerror (errno));
               strerror (errno));
 
              return  result;
    }
    }
  else if (nread > 0)
  else if (nread > 0)
    {
    {
      /* Record that a packet was thrown away. */
      /* Record that a packet was thrown away. */
      SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, BUSY);
              result = 1;
      PRINTF ("Ethernet discarding %d bytes from TAP while BD full.\n",
 
              nread);
 
 
 
      /* Raise an interrupt if necessary. */
 
      if (TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, BUSY_M))
 
        {
 
          if (eth->int_line_stat)
 
            {
 
              fprintf (stderr, "Warning: Interrupt active during ignore.\n");
 
            }
 
          else
 
            {
 
#if ETH_DEBUG
#if ETH_DEBUG
              printf ("Ethernet Rx BUSY interrupt\n");
              printf ("Ethernet discarding %d bytes from TAP while BD full.\n",
 
                      nread);
#endif
#endif
              report_interrupt (eth->mac_int);
 
              eth->int_line_stat = 1;
 
            }
            }
        }
        }
    }
    }
}       /* eth_ignore_packet () */
  while (n > 0);
 
 
 
  return  result;
 
 
 
}       /* eth_ignore_tap_packets () */
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*!Rx clock function.
/*!Rx clock function.
 
 
Line 914... Line 806...
             TAP interface. We can't take any more, so we'll throw oustanding
             TAP interface. We can't take any more, so we'll throw oustanding
             input packets on the floor.
             input packets on the floor.
 
 
             @note We don't do this for file I/O, since it would discard
             @note We don't do this for file I/O, since it would discard
             everything immediately! */
             everything immediately! */
          eth_ignore_packet (eth);
          if (eth_ignore_tap_packets (eth))
 
            {
 
              /* A packet has been thrown away, so mark the INT_SOURCE
 
                 register accordingly. */
 
              SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, BUSY);
 
 
 
              /* Raise an interrupt if necessary. */
 
              if (TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, BUSY_M))
 
                {
 
                  if (eth->int_line_stat)
 
                    {
 
                      fprintf (stderr,
 
                               "Warning: Interrupt active during ignore.\n");
 
                    }
 
                  else
 
                    {
 
#if ETH_DEBUG
 
                      printf ("Ethernet Rx BUSY interrupt\n");
 
#endif
 
                      report_interrupt (eth->mac_int);
 
                      eth->int_line_stat = 1;
 
                    }
 
                }
 
            }
        }
        }
    }
    }
 
 
  /* Whatever happens, we reschedule a wake up in the future. This used to be
  /* Whatever happens, we reschedule a wake up in the future. This used to be
     every 10 ticks, but now it is very 1 tick. */
     every 10 ticks, but now it is very 1 tick. */
  SCHED_ADD (eth_controller_rx_clock, dat, 1);
  SCHED_ADD (eth_controller_rx_clock, dat, RTX_RESCHED_PERIOD);
 
 
}       /* eth_controller_rx_clock () */
}       /* eth_controller_rx_clock () */
 
 
 
 
/* ========================================================================= */
/* -------------------------------------------------------------------------- */
 
/*!VAPI connection to outside.
/* ========================================================================= */
 
 
 
 
   Used for remote testing of the interface. Currently does nothing.
 
 
/*
   @param[in] id  The VAPI ID to use.
 *   VAPI connection to outside
   @param[in] data  Any data associated (unused here).
 */
   @param[in] dat   The Ethernet data structure, cast to a void pointer.      */
 
/* -------------------------------------------------------------------------- */
static void
static void
eth_vapi_read (unsigned long id, unsigned long data, void *dat)
eth_vapi_read (unsigned long int  id,
 
               unsigned long int  data,
 
               void              *dat)
{
{
  unsigned long which;
  unsigned long int  which;
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
  which = id - eth->base_vapi_id;
  which = id - eth->base_vapi_id;
 
 
  if (!eth)
  if (!eth)
Line 955... Line 873...
    case ETH_VAPI_CTRL:
    case ETH_VAPI_CTRL:
      break;
      break;
    }
    }
}
}
 
 
/* -------------------------------------------------------------------------- */
 
/*!Reset the Ethernet.
 
 
 
   Open the correct type of simulation interface to the outside world.
 
 
 
   Initialize all registers to default and places devices in memory address
/* -------------------------------------------------------------------------- */
   space.
/*!Print register values on stdout
 
 
   @param[in] dat  The Ethernet interface data structure.                     */
   @param[in] dat  The Ethernet interface data structure.                     */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static void
static void
eth_reset (void *dat)
eth_status (void *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
  struct ifreq       ifr;
 
 
 
#if ETH_DEBUG
  PRINTF ("\nEthernet MAC at 0x%" PRIxADDR ":\n", eth->baseaddr);
  printf ("Resetting Ethernet\n");
  PRINTF ("MODER        : 0x%08lX\n", eth->regs.moder);
#endif
  PRINTF ("INT_SOURCE   : 0x%08lX\n", eth->regs.int_source);
  /* Nothing to do if we do not have a base address set.
  PRINTF ("INT_MASK     : 0x%08lX\n", eth->regs.int_mask);
 
  PRINTF ("IPGT         : 0x%08lX\n", eth->regs.ipgt);
 
  PRINTF ("IPGR1        : 0x%08lX\n", eth->regs.ipgr1);
 
  PRINTF ("IPGR2        : 0x%08lX\n", eth->regs.ipgr2);
 
  PRINTF ("PACKETLEN    : 0x%08lX\n", eth->regs.packetlen);
 
  PRINTF ("COLLCONF     : 0x%08lX\n", eth->regs.collconf);
 
  PRINTF ("TX_BD_NUM    : 0x%08lX\n", eth->regs.tx_bd_num);
 
  PRINTF ("CTRLMODER    : 0x%08lX\n", eth->regs.controlmoder);
 
  PRINTF ("MIIMODER     : 0x%08lX\n", eth->regs.miimoder);
 
  PRINTF ("MIICOMMAND   : 0x%08lX\n", eth->regs.miicommand);
 
  PRINTF ("MIIADDRESS   : 0x%08lX\n", eth->regs.miiaddress);
 
  PRINTF ("MIITX_DATA   : 0x%08lX\n", eth->regs.miitx_data);
 
  PRINTF ("MIIRX_DATA   : 0x%08lX\n", eth->regs.miirx_data);
 
  PRINTF ("MIISTATUS    : 0x%08lX\n", eth->regs.miistatus);
 
  PRINTF ("MAC Address  : %02X:%02X:%02X:%02X:%02X:%02X\n",
 
          eth->mac_address[5], eth->mac_address[4], eth->mac_address[3],
 
          eth->mac_address[2], eth->mac_address[1], eth->mac_address[0]);
 
  PRINTF ("HASH0        : 0x%08lX\n", eth->regs.hash0);
 
  PRINTF ("HASH1        : 0x%08lX\n", eth->regs.hash1);
 
 
     TODO: Surely this should test for being enabled? */
}       /* eth_status () */
  if (0 == eth->baseaddr)
 
    {
 
      return;
 
    }
 
 
 
  switch (eth->rtx_type)
 
    {
 
    case ETH_RTX_FILE:
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Open the external file interface to the Ethernet
 
 
 
   The data is represented by an input and an output file.
 
 
 
   @param[in] eth  The Ethernet interface data structure.                     */
 
/* -------------------------------------------------------------------------- */
 
static void
 
eth_open_file_if (struct eth_device *eth)
 
{
      /* (Re-)open TX/RX files */
      /* (Re-)open TX/RX files */
      if (eth->rxfd >= 0)
      if (eth->rxfd >= 0)
        {
        {
          close (eth->rxfd);
          close (eth->rxfd);
        }
        }
Line 1018... Line 952...
      if (eth->txfd < 0)
      if (eth->txfd < 0)
        {
        {
          fprintf (stderr, "Warning: Cannot open Ethernet TX file \"%s\": %s\n",
          fprintf (stderr, "Warning: Cannot open Ethernet TX file \"%s\": %s\n",
                   eth->txfile, strerror (errno));
                   eth->txfile, strerror (errno));
        }
        }
 
}       /* eth_open_file_if () */
 
 
      break;
 
 
 
    case ETH_RTX_TAP:
/* -------------------------------------------------------------------------- */
 
/*!Open the external TAP interface to the Ethernet
 
 
 
   Packets are transferred over a TAP/TUN interface. We assume a persistent
 
   tap interface has been set up and is owned by the user, so they can open
 
   and manipulate it. See the User Guide for details of setting this up.
 
 
 
   @todo We don't flush the TAP interface. Should we?
 
 
      /* (Re-)open TAP interface if necessary */
   @param[in] eth  The Ethernet interface data structure.                     */
      if (eth->rtx_fd != 0)
/* -------------------------------------------------------------------------- */
 
static void
 
eth_open_tap_if (struct eth_device *eth)
        {
        {
          break;
  struct ifreq       ifr;
 
 
 
  /* We don't support re-opening. If it's open, it stays open. */
 
  if (eth->rtx_fd >= 0)
 
    {
 
      return;
        }
        }
 
 
      /* Open the TUN/TAP device */
      /* Open the TUN/TAP device */
      eth->rtx_fd = open ("/dev/net/tun", O_RDWR);
      eth->rtx_fd = open ("/dev/net/tun", O_RDWR);
      if( eth->rtx_fd < 0 )
      if( eth->rtx_fd < 0 )
        {
        {
          fprintf (stderr, "Warning: Failed to open TUN/TAP device: %s\n",
          fprintf (stderr, "Warning: Failed to open TUN/TAP device: %s\n",
                   strerror (errno));
                   strerror (errno));
          eth->rtx_fd = 0;
      eth->rtx_fd = -1;
          return;
          return;
        }
        }
 
 
      /* Turn it into a specific TAP device. If we haven't specified a
  /* Turn it into a specific TAP device. If we haven't specified a specific
         specific (persistent) device, one will be created, but that requires
     (persistent) device, one will be created, but that requires superuser, or
         superuser, or at least CAP_NET_ADMIN capabilities. */
     at least CAP_NET_ADMIN capabilities. */
      memset (&ifr, 0, sizeof(ifr));
      memset (&ifr, 0, sizeof(ifr));
      ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
      ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
      strncpy (ifr.ifr_name, eth->tap_dev, IFNAMSIZ);
      strncpy (ifr.ifr_name, eth->tap_dev, IFNAMSIZ);
 
 
      if (ioctl (eth->rtx_fd, TUNSETIFF, (void *) &ifr) < 0)
      if (ioctl (eth->rtx_fd, TUNSETIFF, (void *) &ifr) < 0)
        {
        {
          fprintf (stderr, "Warning: Failed to set TAP device: %s\n",
          fprintf (stderr, "Warning: Failed to set TAP device: %s\n",
                   strerror (errno));
                   strerror (errno));
          close (eth->rtx_fd);
          close (eth->rtx_fd);
          eth->rtx_fd = 0;
      eth->rtx_fd = -1;
          return;
          return;
        }
        }
#if ETH_DEBUG
#if ETH_DEBUG
      PRINTF ("Opened TAP %s\n", ifr.ifr_name);
      PRINTF ("Opened TAP %s\n", ifr.ifr_name);
#endif
#endif
      /* Do we need to flush any packets? */
}       /* eth_open_tap_if () */
      break;
 
    }
 
 
 
  /* Set registers to default values */
 
  memset (&(eth->regs), 0, sizeof (eth->regs));
 
 
 
  eth->regs.moder     = 0x0000A000;
/* -------------------------------------------------------------------------- */
  eth->regs.ipgt      = 0x00000012;
/*!Open the external interface to the Ethernet
  eth->regs.ipgr1     = 0x0000000C;
 
  eth->regs.ipgr2     = 0x00000012;
 
  eth->regs.packetlen = 0x003C0600;
 
  eth->regs.collconf  = 0x000F003F;
 
  eth->regs.miimoder  = 0x00000064;
 
  eth->regs.tx_bd_num = 0x00000040;
 
 
 
  /* Reset TX/RX BD indexes. The Rx BD indexes start after the Tx BD indexes. */
   Calls the appropriate function for the interface type.
  eth->tx_bd_index = 0;
 
  eth->rx_bd_index = eth->regs.tx_bd_num * 2;
 
 
 
  /* Reset IRQ line status */
   @param[in] eth  The Ethernet interface data structure.                     */
 
/* -------------------------------------------------------------------------- */
 
static void
 
eth_open_if (struct eth_device *eth)
 
{
 
  switch (eth->rtx_type)
 
    {
 
    case ETH_RTX_FILE: eth_open_file_if (eth); break;
 
    case ETH_RTX_TAP:  eth_open_tap_if (eth);  break;
 
 
 
    default:
 
      fprintf (stderr, "Unknown Ethernet interface: ignored.\n");
 
      break;
 
    }
 
}       /* eth_open_if () */
 
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Reset the Ethernet.
 
 
 
   Open the correct type of simulation interface to the outside world.
 
 
 
   Initialize all registers to default and places devices in memory address
 
   space.
 
 
 
   @param[in] dat  The Ethernet interface data structure.                     */
 
/* -------------------------------------------------------------------------- */
 
static void
 
eth_reset (void *dat)
 
{
 
  struct eth_device *eth = dat;
 
 
 
#if ETH_DEBUG
 
  printf ("Resetting Ethernet\n");
 
#endif
 
 
 
  /* Nothing to do if we do not have a base address set, or we are not
 
     enabled. */
 
  if (!eth->enabled || (0 == eth->baseaddr))
 
    {
 
      return;
 
    }
 
 
 
  eth_open_if (eth);
 
 
 
  /* Set registers to default values */
 
  memset (&(eth->regs), 0, sizeof (eth->regs));
 
 
 
  eth->regs.moder     = 0x0000A000;     /* Padding & CRC enabled */
 
  eth->regs.ipgt      = 0x00000012;     /* Half duplex (matches MODER) */
 
  eth->regs.ipgr1     = 0x0000000C;     /* Recommended value */
 
  eth->regs.ipgr2     = 0x00000012;     /* Recommended value */
 
  eth->regs.packetlen = 0x003C0600;     /* MINFL 60, MAXFL 1,536 bytes */
 
  eth->regs.collconf  = 0x000F003F;     /* MAXRET 15, COLLVALID 63 */
 
  eth->regs.tx_bd_num = 0x00000040;     /* Max Tx BD */
 
  eth->regs.miimoder  = 0x00000064;     /* Send preamble, CLKDIV 100 */
 
 
 
  /* Reset TX/RX BD indexes. The Rx BD indexes start after the Tx BD indexes. */
 
  eth->tx_bd_index = 0;
 
  eth->rx_bd_index = eth->regs.tx_bd_num * 2;
 
 
 
  /* Reset IRQ line status */
  eth->int_line_stat = 0;
  eth->int_line_stat = 0;
 
 
  /* Initialize VAPI */
  /* Initialize VAPI */
  if (eth->base_vapi_id)
  if (eth->base_vapi_id)
    {
    {
Line 1089... Line 1086...
                                  eth_vapi_read, dat);
                                  eth_vapi_read, dat);
    }
    }
}       /* eth_reset () */
}       /* eth_reset () */
 
 
 
 
/*
#if ETH_DEBUG
  Print register values on stdout
/* -------------------------------------------------------------------------- */
*/
/*!Map a register address to its name
static void
 
eth_status (void *dat)
   @param[in[ addr  The address of the register to name (offset from base).
 
 
 
   @return  The name of the register.                                         */
 
/* -------------------------------------------------------------------------- */
 
static char *
 
eth_regname (oraddr_t  addr)
{
{
  struct eth_device *eth = dat;
  static char  bdstr[8];                /* For "BD[nnn]" */
 
 
  PRINTF ("\nEthernet MAC at 0x%" PRIxADDR ":\n", eth->baseaddr);
  switch (addr)
  PRINTF ("MODER        : 0x%08lX\n", eth->regs.moder);
    {
  PRINTF ("INT_SOURCE   : 0x%08lX\n", eth->regs.int_source);
    case ETH_MODER:      return  "MODER";
  PRINTF ("INT_MASK     : 0x%08lX\n", eth->regs.int_mask);
    case ETH_INT_SOURCE: return  "INT_SOURCE";
  PRINTF ("IPGT         : 0x%08lX\n", eth->regs.ipgt);
    case ETH_INT_MASK:   return  "INT_MASK";
  PRINTF ("IPGR1        : 0x%08lX\n", eth->regs.ipgr1);
    case ETH_IPGT:       return  "IPGT";
  PRINTF ("IPGR2        : 0x%08lX\n", eth->regs.ipgr2);
    case ETH_IPGR1:      return  "IPGR1";
  PRINTF ("PACKETLEN    : 0x%08lX\n", eth->regs.packetlen);
    case ETH_IPGR2:      return  "IPGR2";
  PRINTF ("COLLCONF     : 0x%08lX\n", eth->regs.collconf);
    case ETH_PACKETLEN:  return  "PACKETLEN";
  PRINTF ("TX_BD_NUM    : 0x%08lX\n", eth->regs.tx_bd_num);
    case ETH_COLLCONF:   return  "COLLCONF";
  PRINTF ("CTRLMODER    : 0x%08lX\n", eth->regs.controlmoder);
    case ETH_TX_BD_NUM:  return  "TX_BD_NUM";
  PRINTF ("MIIMODER     : 0x%08lX\n", eth->regs.miimoder);
    case ETH_CTRLMODER:  return  "CTRLMODER";
  PRINTF ("MIICOMMAND   : 0x%08lX\n", eth->regs.miicommand);
    case ETH_MIIMODER:   return  "MIIMODER";
  PRINTF ("MIIADDRESS   : 0x%08lX\n", eth->regs.miiaddress);
    case ETH_MIICOMMAND: return  "MIICOMMAND";
  PRINTF ("MIITX_DATA   : 0x%08lX\n", eth->regs.miitx_data);
    case ETH_MIIADDRESS: return  "MIIADDRESS";
  PRINTF ("MIIRX_DATA   : 0x%08lX\n", eth->regs.miirx_data);
    case ETH_MIITX_DATA: return  "MIITX_DATA";
  PRINTF ("MIISTATUS    : 0x%08lX\n", eth->regs.miistatus);
    case ETH_MIIRX_DATA: return  "MIIRX_DATA";
  PRINTF ("MAC Address  : %02X:%02X:%02X:%02X:%02X:%02X\n",
    case ETH_MIISTATUS:  return  "MIISTATUS";
          eth->mac_address[5], eth->mac_address[4], eth->mac_address[3],
    case ETH_MAC_ADDR0:  return  "MAC_ADDR0";
          eth->mac_address[2], eth->mac_address[1], eth->mac_address[0]);
    case ETH_MAC_ADDR1:  return  "MAC_ADDR1";
  PRINTF ("HASH0        : 0x%08lX\n", eth->regs.hash0);
    case ETH_HASH0:      return  "HASH0";
  PRINTF ("HASH1        : 0x%08lX\n", eth->regs.hash1);
    case ETH_HASH1:      return  "HASH1";
 
 
 
    default:
 
      /* Buffer descriptors are a special case. */
 
      if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE))
 
        {
 
          sprintf (bdstr, "BD[%.3d]", (addr - ETH_BD_BASE) / 4);
 
          return  bdstr;
 
        }
 
      else
 
        {
 
          return  "INVALID";
}
}
 
    }
 
}       /* eth_regname () */
 
#endif
 
 
/* ========================================================================= */
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Read a register
 
 
/*
   @param[in] addr  The address of the register to read (offset from base).
  Read a register
   @param[in] dat   The Ethernet interface data structure, cast to a void
*/
                    pointer.
 
 
 
   @return  The value read.                                                   */
 
/* -------------------------------------------------------------------------- */
static uint32_t
static uint32_t
eth_read32 (oraddr_t addr, void *dat)
eth_read32 (oraddr_t  addr,
 
            void     *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
  uint32_t           res;
 
 
 
  switch (addr)
 
    {
 
    case ETH_MODER:      res = eth->regs.moder;        break;
 
    case ETH_INT_SOURCE: res = eth->regs.int_source;   break;
 
    case ETH_INT_MASK:   res = eth->regs.int_mask;     break;
 
    case ETH_IPGT:       res = eth->regs.ipgt;         break;
 
    case ETH_IPGR1:      res = eth->regs.ipgr1;        break;
 
    case ETH_IPGR2:      res = eth->regs.ipgr2;        break;
 
    case ETH_PACKETLEN:  res = eth->regs.packetlen;    break;
 
    case ETH_COLLCONF:   res = eth->regs.collconf;     break;
 
    case ETH_TX_BD_NUM:  res = eth->regs.tx_bd_num;    break;
 
    case ETH_CTRLMODER:  res = eth->regs.controlmoder; break;
 
    case ETH_MIIMODER:   res = eth->regs.miimoder;     break;
 
    case ETH_MIICOMMAND: res = eth->regs.miicommand;   break;
 
    case ETH_MIIADDRESS: res = eth->regs.miiaddress;   break;
 
    case ETH_MIITX_DATA: res = eth->regs.miitx_data;   break;
 
    case ETH_MIIRX_DATA: res = eth->regs.miirx_data;   break;
 
    case ETH_MIISTATUS:  res = eth->regs.miistatus;    break;
 
    case ETH_MAC_ADDR0:
 
      res =
 
        (((unsigned long) eth->mac_address[2]) << 24) |
 
        (((unsigned long) eth->mac_address[3]) << 16) |
 
        (((unsigned long) eth->mac_address[4]) <<  8) |
 
          (unsigned long) eth->mac_address[5];
 
      break;
 
    case ETH_MAC_ADDR1:
 
      res =
 
        (((unsigned long) eth->mac_address[0]) <<  8) |
 
          (unsigned long) eth->mac_address[1];
 
      break;
 
    case ETH_HASH0:      res = eth->regs.hash0;        break;
 
    case ETH_HASH1:      res = eth->regs.hash1;        break;
 
 
 
    default:
 
      /* Buffer descriptors are a special case. */
 
      if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE))
 
        {
 
          res = eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4];
 
          break;
 
        }
 
      else
 
        {
 
          fprintf (stderr,
 
                   "Warning: eth_read32( 0x%" PRIxADDR " ): Illegal address\n",
 
                   addr + eth->baseaddr);
 
          res = 0;
 
        }
 
    }
 
 
 
#if ETH_DEBUG
 
  /* Only trace registers of particular interest */
  switch (addr)
  switch (addr)
    {
    {
    case ETH_MODER:
    case ETH_MODER:
      return eth->regs.moder;
 
    case ETH_INT_SOURCE:
    case ETH_INT_SOURCE:
      return eth->regs.int_source;
 
    case ETH_INT_MASK:
    case ETH_INT_MASK:
      return eth->regs.int_mask;
 
    case ETH_IPGT:
    case ETH_IPGT:
      return eth->regs.ipgt;
 
    case ETH_IPGR1:
    case ETH_IPGR1:
      return eth->regs.ipgr1;
 
    case ETH_IPGR2:
    case ETH_IPGR2:
      return eth->regs.ipgr2;
 
    case ETH_PACKETLEN:
    case ETH_PACKETLEN:
      return eth->regs.packetlen;
 
    case ETH_COLLCONF:
    case ETH_COLLCONF:
      return eth->regs.collconf;
 
    case ETH_TX_BD_NUM:
    case ETH_TX_BD_NUM:
      return eth->regs.tx_bd_num;
 
    case ETH_CTRLMODER:
    case ETH_CTRLMODER:
      return eth->regs.controlmoder;
 
    case ETH_MIIMODER:
 
      return eth->regs.miimoder;
 
    case ETH_MIICOMMAND:
 
      return eth->regs.miicommand;
 
    case ETH_MIIADDRESS:
 
      return eth->regs.miiaddress;
 
    case ETH_MIITX_DATA:
 
      return eth->regs.miitx_data;
 
    case ETH_MIIRX_DATA:
 
      /*printf("or1ksim: read MIIM RX: 0x%x\n",(int)eth->regs.miirx_data);*/
 
      return eth->regs.miirx_data;
 
    case ETH_MIISTATUS:
 
      return eth->regs.miistatus;
 
    case ETH_MAC_ADDR0:
    case ETH_MAC_ADDR0:
      return (((unsigned long) eth->mac_address[2]) << 24) |
 
        (((unsigned long) eth->mac_address[3]) << 16) |
 
        (((unsigned long) eth->mac_address[4]) << 8) |
 
        (unsigned long) eth->mac_address[5];
 
    case ETH_MAC_ADDR1:
    case ETH_MAC_ADDR1:
      return (((unsigned long) eth->mac_address[0]) << 8) |
      printf ("eth_read32: %s = 0x%08lx\n", eth_regname (addr),
        (unsigned long) eth->mac_address[1];
              (unsigned long int) res);
    case ETH_HASH0:
 
      return eth->regs.hash0;
 
    case ETH_HASH1:
 
      return eth->regs.hash1;
 
      /*case ETH_DMA_RX_TX: return eth_rx( eth ); */
 
    }
    }
 
#endif
 
 
  if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE))
  return  res;
    return eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4];
 
 
 
  PRINTF ("eth_read32( 0x%" PRIxADDR " ): Illegal address\n",
}       /* eth_read32 () */
          addr + eth->baseaddr);
 
  return 0;
 
 
/* -------------------------------------------------------------------------- */
 
/*!Emulate MIIM transaction to ethernet PHY
 
 
 
   @param[in] eth  Ethernet device datastruture.                              */
 
/* -------------------------------------------------------------------------- */
 
static void
 
eth_miim_trans (struct eth_device *eth)
 
{
 
  switch (eth->regs.miicommand)
 
    {
 
    case ((1 << ETH_MIICOMM_WCDATA_OFFSET)):
 
      /* Perhaps something to emulate here later, but for now do nothing */
 
      break;
 
 
 
    case ((1 << ETH_MIICOMM_RSTAT_OFFSET)):
 
      /*First check if it's the correct PHY to address */
 
      if (((eth->regs.miiaddress >> ETH_MIIADDR_FIAD_OFFSET)&
 
           ETH_MIIADDR_FIAD_MASK) == eth->phy_addr)
 
        {
 
          /* Correct PHY - now switch based on the register address in the PHY*/
 
          switch ((eth->regs.miiaddress >> ETH_MIIADDR_RGAD_OFFSET)&
 
                  ETH_MIIADDR_RGAD_MASK)
 
            {
 
            case MII_BMCR:
 
              eth->regs.miirx_data = BMCR_FULLDPLX;
 
              break;
 
            case MII_BMSR:
 
              eth->regs.miirx_data = BMSR_LSTATUS | BMSR_ANEGCOMPLETE |
 
                BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | BMSR_100FULL;
 
              break;
 
            case MII_PHYSID1:
 
              eth->regs.miirx_data = 0x22; /* Micrel PHYID */
 
              break;
 
            case MII_PHYSID2:
 
              eth->regs.miirx_data = 0x1613; /* Micrel PHYID */
 
              break;
 
            case MII_ADVERTISE:
 
              eth->regs.miirx_data = ADVERTISE_FULL;
 
              break;
 
            case MII_LPA:
 
              eth->regs.miirx_data = LPA_DUPLEX | LPA_100;
 
              break;
 
            case MII_EXPANSION:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_CTRL1000:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_STAT1000:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_ESTATUS:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_DCOUNTER:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_FCSCOUNTER:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_NWAYTEST:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_RERRCOUNTER:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_SREVISION:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_RESV1:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_LBRERROR:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_PHYADDR:
 
              eth->regs.miirx_data = eth->phy_addr;
 
              break;
 
            case MII_RESV2:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_TPISTATUS:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            case MII_NCONFIG:
 
              eth->regs.miirx_data = 0;
 
              break;
 
            default:
 
              eth->regs.miirx_data = 0xffff;
 
              break;
 
            }
 
        }
 
      else
 
        {
 
          eth->regs.miirx_data = 0xffff; /* PHY doesn't exist, read all 1's */
}
}
 
 
/* ========================================================================= */
      break;
 
 
 
    case ((1 << ETH_MIICOMM_SCANS_OFFSET)):
 
      /* From MAC's datasheet:
 
         A host initiates the Scan Status Operation by asserting the SCANSTAT
 
         signal. The MIIM performs a continuous read operation of the PHY
 
         Status register. The PHY is selected by the FIAD[4:0] signals. The
 
         link status LinkFail signal is asserted/deasserted by the MIIM module
 
         and reflects the link status bit of the PHY Status register. The
 
         signal NVALID is used for qualifying the validity of the LinkFail
 
         signals and the status data PRSD[15:0]. These signals are invalid
 
         until the first scan status operation ends. During the scan status
 
         operation, the BUSY signal is asserted until the last read is
 
         performed (the scan status operation is stopped).
 
 
/*
         So for now - do nothing, leave link status indicator as permanently
  Write a register
         with link.
*/
*/
 
 
 
      break;
 
 
 
    default:
 
      break;
 
    }
 
}       /* eth_miim_trans () */
 
 
 
 
 
 
 
/* -------------------------------------------------------------------------- */
 
/*!Write a register
 
 
 
   @param[in] addr   The address of the register to read (offset from base).
 
   @param[in] value  The value to write.
 
   @param[in] dat    The Ethernet interface data structure, cast to a void
 
                     pointer.                                                 */
 
/* -------------------------------------------------------------------------- */
static void
static void
eth_write32 (oraddr_t addr, uint32_t value, void *dat)
eth_write32 (oraddr_t addr, uint32_t value, void *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
  unsigned char      buf[ETH_MAXPL];
 
 
 
 
#if ETH_DEBUG
 
  /* Only trace registers of particular interest */
  switch (addr)
  switch (addr)
    {
    {
    case ETH_MODER:
    case ETH_MODER:
#if ETH_DEBUG
    case ETH_INT_SOURCE:
      printf("eth_write32: MODER 0x%x\n",value);
    case ETH_INT_MASK:
 
    case ETH_IPGT:
 
    case ETH_IPGR1:
 
    case ETH_IPGR2:
 
    case ETH_PACKETLEN:
 
    case ETH_COLLCONF:
 
    case ETH_TX_BD_NUM:
 
    case ETH_CTRLMODER:
 
    case ETH_MAC_ADDR0:
 
    case ETH_MAC_ADDR1:
 
      printf ("eth_write32: %s = 0x%08lx\n", eth_regname (addr),
 
              (unsigned long int) value);
 
    }
#endif
#endif
      if (!TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN) &&
 
          TEST_FLAG (value, ETH_MODER, RXEN))
 
        {
 
          // Reset RX BD index
 
          eth->rx_bd_index = eth->regs.tx_bd_num << 1;
 
 
 
          // Clear TAP
 
          {
 
            /* Poll to see if there is data to read */
 
            struct pollfd  fds[1];
 
            int    n;
 
            int nread;
 
 
 
            fds[0].fd = eth->rtx_fd;
 
            fds[0].events = POLLIN;
 
 
 
            do {
  switch (addr)
              n = poll (fds, 1, 0);
 
              if (n < 0)
 
                {
                {
                  fprintf (stderr, "Warning: Poll in while emptying TAP: %s: ignored.\n",
    case ETH_MODER:
                           strerror (errno));
      if (!TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN) &&
                }
          TEST_FLAG (value, ETH_MODER, RXEN))
              else if ((n > 0) && ((fds[0].revents & POLLIN) == POLLIN))
 
                {
                {
                  nread = read (eth->rtx_fd, buf, ETH_MAXPL);
          /* Enabling receive, flush any oustanding input (TAP only), reset
 
             the BDs and schedule the Rx controller on the next clock
                  if (nread < 0)
             cycle. */
 
          if (ETH_RTX_TAP == eth->rtx_type)
                    {
                    {
                      fprintf (stderr,
              (void) eth_ignore_tap_packets (eth);
                               "Warning: Read failed %s: ignored\n",
 
                               strerror (errno));
 
                    }
 
                }
 
            } while (n > 0);
 
          }
          }
 
 
 
          eth->rx_bd_index = eth->regs.tx_bd_num * 2;
          SCHED_ADD (eth_controller_rx_clock, dat, 1);
          SCHED_ADD (eth_controller_rx_clock, dat, 1);
        }
        }
      else if (!TEST_FLAG (value, ETH_MODER, RXEN) &&
      else if (!TEST_FLAG (value, ETH_MODER, RXEN) &&
               TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN))
               TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN))
 
        {
 
          /* Disabling Rx, so stop scheduling the Rx controller. */
        SCHED_FIND_REMOVE (eth_controller_rx_clock, dat);
        SCHED_FIND_REMOVE (eth_controller_rx_clock, dat);
 
        }
 
 
      if (!TEST_FLAG (eth->regs.moder, ETH_MODER, TXEN) &&
      if (!TEST_FLAG (eth->regs.moder, ETH_MODER, TXEN) &&
          TEST_FLAG (value, ETH_MODER, TXEN))
          TEST_FLAG (value, ETH_MODER, TXEN))
        {
        {
 
          /* Enabling transmit, reset the BD and schedule the Tx controller on
 
             the next clock cycle. */
          eth->tx_bd_index = 0;
          eth->tx_bd_index = 0;
          SCHED_ADD (eth_controller_tx_clock, dat, 1);
          SCHED_ADD (eth_controller_tx_clock, dat, 1);
        }
        }
      else if (!TEST_FLAG (value, ETH_MODER, TXEN) &&
      else if (!TEST_FLAG (value, ETH_MODER, TXEN) &&
               TEST_FLAG (eth->regs.moder, ETH_MODER, TXEN))
               TEST_FLAG (eth->regs.moder, ETH_MODER, TXEN))
 
        {
 
          /* Disabling Tx, so stop scheduling the Tx controller. */
        SCHED_FIND_REMOVE (eth_controller_tx_clock, dat);
        SCHED_FIND_REMOVE (eth_controller_tx_clock, dat);
 
        }
 
 
      eth->regs.moder = value;
      /* Reset the interface if so requested. */
 
 
      if (TEST_FLAG (value, ETH_MODER, RST))
      if (TEST_FLAG (value, ETH_MODER, RST))
 
        {
        eth_reset (dat);
        eth_reset (dat);
      return;
        }
 
 
 
      eth->regs.moder = value;          /* Update the register */
 
      break;
 
 
    case ETH_INT_SOURCE:
    case ETH_INT_SOURCE:
#if ETH_DEBUG
 
      printf("eth_write32: INT_SOURCE 0x%x\n",value);
 
#endif
 
      eth->regs.int_source &= ~value;
      eth->regs.int_source &= ~value;
 
 
      // Clear IRQ line if all interrupt sources have been dealt with
      /* Clear IRQ line if all interrupt sources have been dealt with
 
 
 
         @todo  Is this really right? */
      if (!(eth->regs.int_source & eth->regs.int_mask) && eth->int_line_stat)
      if (!(eth->regs.int_source & eth->regs.int_mask) && eth->int_line_stat)
        {
        {
          clear_interrupt (eth->mac_int);
          clear_interrupt (eth->mac_int);
          eth->int_line_stat = 0;
          eth->int_line_stat = 0;
        }
        }
 
      break;
 
 
      return;
 
    case ETH_INT_MASK:
    case ETH_INT_MASK:
#if ETH_DEBUG
 
      printf("eth_write32: INT_MASK 0x%x\n",value);
 
#endif
 
      eth->regs.int_mask = value;
      eth->regs.int_mask = value;
 
 
 
      /* If we enable interrupts, the core is not currently processing an
 
         interrupt, and there is an interrupt pending, then report that
 
         interrupt.
 
 
 
         Otherwise clear down the interrupt.
 
 
 
         @todo  Is this really right. */
      if ((eth->regs.int_source & eth->regs.int_mask) && !eth->int_line_stat)
      if ((eth->regs.int_source & eth->regs.int_mask) && !eth->int_line_stat)
 
        {
        report_interrupt (eth->mac_int);
        report_interrupt (eth->mac_int);
      else
        }
        if (eth->int_line_stat)
      else if (eth->int_line_stat)
          {
          {
            clear_interrupt (eth->mac_int);
            clear_interrupt (eth->mac_int);
            eth->int_line_stat = 0;
            eth->int_line_stat = 0;
          }
          }
      return;
      break;
    case ETH_IPGT:
 
      eth->regs.ipgt = value;
    case ETH_IPGT:       eth->regs.ipgt         = value; break;
      return;
    case ETH_IPGR1:      eth->regs.ipgr1        = value; break;
    case ETH_IPGR1:
    case ETH_IPGR2:      eth->regs.ipgr2        = value; break;
      eth->regs.ipgr1 = value;
    case ETH_PACKETLEN:  eth->regs.packetlen    = value; break;
      return;
    case ETH_COLLCONF:   eth->regs.collconf     = value; break;
    case ETH_IPGR2:
 
      eth->regs.ipgr2 = value;
 
      return;
 
    case ETH_PACKETLEN:
 
      eth->regs.packetlen = value;
 
      return;
 
    case ETH_COLLCONF:
 
      eth->regs.collconf = value;
 
      return;
 
    case ETH_TX_BD_NUM:
    case ETH_TX_BD_NUM:
      /* When TX_BD_NUM is written, also reset current RX BD index */
      /* When TX_BD_NUM is written, also reset current RX BD index */
      eth->regs.tx_bd_num = value & 0xFF;
      eth->regs.tx_bd_num = value & 0xFF;
      eth->rx_bd_index = eth->regs.tx_bd_num << 1;
      eth->rx_bd_index = eth->regs.tx_bd_num * 2;
      return;
      break;
    case ETH_CTRLMODER:
 
      eth->regs.controlmoder = value;
    case ETH_CTRLMODER:  eth->regs.controlmoder = value; break;
      return;
    case ETH_MIIMODER:   eth->regs.miimoder     = value; break;
    case ETH_MIIMODER:
 
      eth->regs.miimoder = value;
 
      return;
 
    case ETH_MIICOMMAND:
    case ETH_MIICOMMAND:
      eth->regs.miicommand = value;
      eth->regs.miicommand = value;
      /* Perform MIIM transaction, if required */
      /* Perform MIIM transaction, if required */
      eth_miim_trans (eth);
      eth_miim_trans (eth);
      return;
      break;
    case ETH_MIIADDRESS:
 
      eth->regs.miiaddress = value;
    case ETH_MIIADDRESS: eth->regs.miiaddress   = value; break;
      return;
    case ETH_MIITX_DATA: eth->regs.miitx_data   = value; break;
    case ETH_MIITX_DATA:
    case ETH_MIIRX_DATA: /* Register is R/O */           break;
      eth->regs.miitx_data = value;
    case ETH_MIISTATUS:  /* Register is R/O */           break;
      return;
 
    case ETH_MIIRX_DATA:
 
      /* Register is R/O
 
      eth->regs.miirx_data = value;
 
      */
 
      return;
 
    case ETH_MIISTATUS:
 
      /* Register is R/O
 
      eth->regs.miistatus = value;
 
      */
 
      return;
 
 
 
    case ETH_MAC_ADDR0:
    case ETH_MAC_ADDR0:
      eth->mac_address[5] = value & 0xFF;
      eth->mac_address[5] = value & 0xFF;
      eth->mac_address[4] = (value >> 8) & 0xFF;
      eth->mac_address[4] = (value >> 8) & 0xFF;
      eth->mac_address[3] = (value >> 16) & 0xFF;
      eth->mac_address[3] = (value >> 16) & 0xFF;
      eth->mac_address[2] = (value >> 24) & 0xFF;
      eth->mac_address[2] = (value >> 24) & 0xFF;
      return;
      break;
 
 
    case ETH_MAC_ADDR1:
    case ETH_MAC_ADDR1:
      eth->mac_address[1] = value & 0xFF;
      eth->mac_address[1] = value & 0xFF;
      eth->mac_address[0] = (value >> 8) & 0xFF;
      eth->mac_address[0] = (value >> 8) & 0xFF;
      return;
      break;
    case ETH_HASH0:
 
      eth->regs.hash0 = value;
 
      return;
 
    case ETH_HASH1:
 
      eth->regs.hash1 = value;
 
      return;
 
 
 
      /*case ETH_DMA_RX_TX: eth_tx( eth, value ); return; */
    case ETH_HASH0:      eth->regs.hash0 = value;        break;
    }
    case ETH_HASH1:      eth->regs.hash1 = value;        break;
 
 
 
    default:
  if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE))
  if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE))
    {
    {
      eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4] = value;
      eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4] = value;
      return;
 
    }
    }
 
      else
  PRINTF ("eth_write32( 0x%" PRIxADDR " ): Illegal address\n",
        {
 
          fprintf (stderr,
 
                   "Warning: eth_write32( 0x%" PRIxADDR " ): Illegal address\n",
          addr + eth->baseaddr);
          addr + eth->baseaddr);
  return;
 
}
}
 
      break;
/* ========================================================================= */
    }
 
}       /* eth_write32 () */
 
 
/* ========================================================================= */
 
 
 
 
 
 
 
/* ========================================================================= */
 
 
 
/*-----------------------------------------------[ Ethernet configuration ]---*/
 
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Enable or disable the Ethernet interface
/*!Enable or disable the Ethernet interface
 
 
Line 1618... Line 1760...
      exit (-1);
      exit (-1);
    }
    }
}       /* eth_tap_dev() */
}       /* eth_tap_dev() */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Set the PHY address
 
 
 
   Used to identify different physical interfaces (important for MII).
 
 
 
   @param[in] val  The value to use.
 
   @param[in] dat  The config data structure                                 */
 
/*---------------------------------------------------------------------------*/
static void
static void
eth_vapi_id (union param_val  val,
eth_phy_addr (union param_val  val,
             void            *dat)
             void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
  eth->base_vapi_id = val.int_val;
  eth->phy_addr = val.int_val & ETH_MIIADDR_FIAD_MASK;
}
 
 
}       /* eth_phy_addr () */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Enable or disable a dummy CRC
 
 
 
   The MAC should not report anything about the CRC back to the core. However
 
   the hardware implementation of the OpenRISC MAC does, and the Linux drivers
 
   have been written to expect the value (which they ignore).
 
 
 
   Setting this parameter causes a dummy CRC to be added. For consistency with
 
   the hardware, its default setting is TRUE.
 
 
 
   @param[in] val  The value to use
 
   @param[in] dat  The config data structure                                 */
 
/*---------------------------------------------------------------------------*/
static void
static void
eth_phy_addr (union param_val  val,
eth_dummy_crc (union param_val  val,
              void            *dat)
              void            *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
  eth->phy_addr = val.int_val & ETH_MIIADDR_FIAD_MASK;
 
}
 
 
 
 
  eth->dummy_crc = val.int_val;
 
 
 
}       /* eth_dummy_crc() */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Set the VAPI id
 
 
 
   Used for remote testing of the interface.
 
 
 
   @param[in] val  The value to use.
 
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Initialize a new Ethernet configuration
static void
 
eth_vapi_id (union param_val  val,
 
             void            *dat)
 
{
 
  struct eth_device *eth = dat;
 
  eth->base_vapi_id = val.int_val;
 
 
 
}       /* eth_vapi_id () */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Start the initialization of a new Ethernet configuration
 
 
   ALL parameters are set explicitly to default values.                      */
   ALL parameters are set explicitly to default values.                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void *
static void *
eth_sec_start (void)
eth_sec_start (void)
Line 1662... Line 1846...
  new->mac_int      = 0;
  new->mac_int      = 0;
  new->int_line_stat= 0;
  new->int_line_stat= 0;
  new->rtx_type     = ETH_RTX_FILE;
  new->rtx_type     = ETH_RTX_FILE;
  new->rx_channel   = 0;
  new->rx_channel   = 0;
  new->tx_channel   = 0;
  new->tx_channel   = 0;
  new->rtx_fd       = 0;
  new->rtx_fd       = -1;
  new->rxfile       = strdup ("eth_rx");
  new->rxfile       = strdup ("eth_rx");
  new->txfile       = strdup ("eth_tx");
  new->txfile       = strdup ("eth_tx");
  new->tap_dev      = strdup ("");
  new->tap_dev      = strdup ("");
  new->base_vapi_id = 0;
 
  new->phy_addr     = 0;
  new->phy_addr     = 0;
 
  new->dummy_crc    = 1;
 
  new->base_vapi_id = 0;
 
 
  return new;
  return new;
}
 
 
 
 
}       /* eth_sec_start () */
 
 
 
 
 
/*---------------------------------------------------------------------------*/
 
/*!Complete the initialization of a new Ethernet configuration
 
 
 
   ALL parameters are set explicitly to default values.                      */
 
/*---------------------------------------------------------------------------*/
static void
static void
eth_sec_end (void *dat)
eth_sec_end (void *dat)
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
  struct mem_ops ops;
  struct mem_ops ops;
Line 1700... Line 1892...
  ops.delayr = 2;
  ops.delayr = 2;
  ops.delayw = 2;
  ops.delayw = 2;
  reg_mem_area (eth->baseaddr, ETH_ADDR_SPACE, 0, &ops);
  reg_mem_area (eth->baseaddr, ETH_ADDR_SPACE, 0, &ops);
  reg_sim_stat (eth_status, dat);
  reg_sim_stat (eth_status, dat);
  reg_sim_reset (eth_reset, dat);
  reg_sim_reset (eth_reset, dat);
}
 
 
}       /* eth_sec_end () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Register a new Ethernet configuration                                     */
/*!Register a new Ethernet configuration                                     */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
Line 1722... Line 1915...
  reg_config_param (sec, "rx_channel", PARAMT_INT,  eth_rx_channel);
  reg_config_param (sec, "rx_channel", PARAMT_INT,  eth_rx_channel);
  reg_config_param (sec, "tx_channel", PARAMT_INT,  eth_tx_channel);
  reg_config_param (sec, "tx_channel", PARAMT_INT,  eth_tx_channel);
  reg_config_param (sec, "rxfile",     PARAMT_STR,  eth_rxfile);
  reg_config_param (sec, "rxfile",     PARAMT_STR,  eth_rxfile);
  reg_config_param (sec, "txfile",     PARAMT_STR,  eth_txfile);
  reg_config_param (sec, "txfile",     PARAMT_STR,  eth_txfile);
  reg_config_param (sec, "tap_dev",    PARAMT_STR,  eth_tap_dev);
  reg_config_param (sec, "tap_dev",    PARAMT_STR,  eth_tap_dev);
  reg_config_param (sec, "vapi_id",    PARAMT_INT,  eth_vapi_id);
 
  reg_config_param (sec, "phy_addr",   PARAMT_INT,  eth_phy_addr);
  reg_config_param (sec, "phy_addr",   PARAMT_INT,  eth_phy_addr);
 
  reg_config_param (sec, "dummy_crc",  PARAMT_INT,  eth_dummy_crc);
 
  reg_config_param (sec, "vapi_id",    PARAMT_INT,  eth_vapi_id);
 
 
}       /* reg_ethernet_sec() */
}       /* reg_ethernet_sec() */
 
 
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.