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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [peripheral/] [eth.c] - Diff between revs 457 and 460

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

Rev 457 Rev 460
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. */
/*! Period (clock cycles) for rescheduling Rx and Tx controllers.
#define  RTX_RESCHED_PERIOD  10000
    Experimenting with FTP on one machine suggests that a value of 500-2000 is
 
    optimal. It's a trade off between prompt response and extra computational
 
    load for Or1ksim. */
 
#define  RTX_RESCHED_PERIOD  2000
 
 
/*! 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 287... Line 290...
  unsigned long int  bd_info = eth->regs.bd_ram[eth->tx_bd_index];
  unsigned long int  bd_info = eth->regs.bd_ram[eth->tx_bd_index];
  unsigned long int  bd_addr = eth->regs.bd_ram[eth->tx_bd_index + 1];
  unsigned long int  bd_addr = eth->regs.bd_ram[eth->tx_bd_index + 1];
  unsigned char      buf[ETH_MAXPL];
  unsigned char      buf[ETH_MAXPL];
  long int           packet_length;
  long int           packet_length;
  long int           bytes_sent;
  long int           bytes_sent;
 
  int                ok_to_int_p;
 
 
  /* Get the packet length */
  /* Get the packet length */
  packet_length = GET_FIELD (bd_info, ETH_TX_BD, LENGTH);
  packet_length = GET_FIELD (bd_info, ETH_TX_BD, LENGTH);
 
 
  /* Clear error status bits and retry count. */
  /* Clear error status bits and retry count. */
Line 318... Line 322...
     write the whole packet, then we retry. */
     write the whole packet, then we retry. */
  if (eth_write_packet (eth, buf, packet_length) == packet_length)
  if (eth_write_packet (eth, buf, packet_length) == packet_length)
    {
    {
      CLEAR_FLAG (bd_info, ETH_TX_BD, READY);
      CLEAR_FLAG (bd_info, ETH_TX_BD, READY);
      SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXB);
      SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXB);
 
      ok_to_int_p = TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, TXB_M);
    }
    }
  else
  else
    {
    {
      /* Does this retry mechanism really work? */
      /* Does this retry mechanism really work? */
      CLEAR_FLAG (bd_info, ETH_TX_BD, READY);
      CLEAR_FLAG (bd_info, ETH_TX_BD, READY);
      CLEAR_FLAG (bd_info, ETH_TX_BD, COLLISION);
      CLEAR_FLAG (bd_info, ETH_TX_BD, COLLISION);
      SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXE);
      SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXE);
 
      ok_to_int_p = TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, TXE_M);
#if ETH_DEBUG
#if ETH_DEBUG
      printf ("Transmit retry request.\n");
      printf ("Transmit retry request.\n");
#endif
#endif
    }
    }
 
 
Line 336... Line 342...
  eth->regs.bd_ram[eth->tx_bd_index] = bd_info;
  eth->regs.bd_ram[eth->tx_bd_index] = bd_info;
 
 
  /* Generate interrupt to indicate transfer complete, under the
  /* Generate interrupt to indicate transfer complete, under the
     following criteria all being met:
     following criteria all being met:
     - either INT_MASK flag for Tx (OK or error) is set
     - either INT_MASK flag for Tx (OK or error) is set
     - the bugger descriptor has its IRQ flag set
     - the buffer descriptor has its IRQ flag set
     - there is no interrupt in progress.
     - there is no interrupt in progress.
 
 
     @todo We ought to warn if we get here and fail to set an IRQ. */
     @todo We ought to warn if we get here and fail to set an IRQ. */
  if ((TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, TXE_M) ||
  if (ok_to_int_p && TEST_FLAG (bd_info, ETH_TX_BD, IRQ))
       TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, TXB_M)) &&
 
      TEST_FLAG (bd_info, ETH_TX_BD, IRQ))
 
    {
    {
      if (eth->int_line_stat)
      if (eth->int_line_stat)
        {
        {
          fprintf (stderr, "Warning: Interrupt active during Tx.\n");
          fprintf (stderr, "Warning: Interrupt active during Tx.\n");
        }
        }
Line 404... Line 408...
        {
        {
          eth_flush_bd (eth);
          eth_flush_bd (eth);
        }
        }
    }
    }
 
 
  /* Wake up again after 1 ticks (was 10, changed by Julius). */
  /* Reschedule to wake up again. */
  SCHED_ADD (eth_controller_tx_clock, dat, RTX_RESCHED_PERIOD);
  SCHED_ADD (eth_controller_tx_clock, dat, RTX_RESCHED_PERIOD);
 
 
}       /* eth_controller_tx_clock () */
}       /* eth_controller_tx_clock () */
 
 
 
 
Line 833... Line 837...
                }
                }
            }
            }
        }
        }
    }
    }
 
 
  /* Whatever happens, we reschedule a wake up in the future. This used to be
  /* Whatever happens, we reschedule a wake up in the future. */
     every 10 ticks, but now it is very 1 tick. */
 
  SCHED_ADD (eth_controller_rx_clock, dat, RTX_RESCHED_PERIOD);
  SCHED_ADD (eth_controller_rx_clock, dat, RTX_RESCHED_PERIOD);
 
 
}       /* eth_controller_rx_clock () */
}       /* eth_controller_rx_clock () */
 
 
 
 
Line 1357... Line 1360...
 
 
 
 
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/*!Write a register
/*!Write a register
 
 
 
   @note Earlier versions of this code treated ETH_INT_SOURCE as an "interrupt
 
         pending" register and reissued interrupts if ETH_INT_MASK was
 
         changed, enabling an interrupt that had previously been cleared. This
 
         led to spurious double interrupt. In the present version, the only
 
         way an interrupt can be generated is at the time ETH_INT_SOURCE is
 
         set in the Tx/Rx controllers and the only way an interrupt can be
 
         cleared is by writing to ETH_INT_SOURCE.
 
 
   @param[in] addr   The address of the register to read (offset from base).
   @param[in] addr   The address of the register to read (offset from base).
   @param[in] value  The value to write.
   @param[in] value  The value to write.
   @param[in] dat    The Ethernet interface data structure, cast to a void
   @param[in] dat    The Ethernet interface data structure, cast to a void
                     pointer.                                                 */
                     pointer.                                                 */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
Line 1369... Line 1380...
{
{
  struct eth_device *eth = dat;
  struct eth_device *eth = dat;
 
 
#if ETH_DEBUG
#if ETH_DEBUG
  /* Only trace registers of particular interest */
  /* Only trace registers of particular interest */
 
 
  switch (addr)
  switch (addr)
  {
  {
  case ETH_MODER:
  case ETH_MODER:
  case ETH_INT_SOURCE:
  case ETH_INT_SOURCE:
  case ETH_INT_MASK:
  case ETH_INT_MASK:
Line 1384... Line 1394...
  case ETH_COLLCONF:
  case ETH_COLLCONF:
  case ETH_TX_BD_NUM:
  case ETH_TX_BD_NUM:
  case ETH_CTRLMODER:
  case ETH_CTRLMODER:
  case ETH_MAC_ADDR0:
  case ETH_MAC_ADDR0:
  case ETH_MAC_ADDR1:
  case ETH_MAC_ADDR1:
          printf ("eth_write32: 0x%08lx to %s ", (unsigned long) value,
      printf ("eth_write32: 0x%08lx to %s ", (unsigned long int) value,
                  eth_regname (addr));
                  eth_regname (addr));
 
 
  }
  }
 
 
  /* Detail register transitions on MODER, INT_SOURCE AND INT_MASK */
  /* Detail register transitions on MODER, INT_SOURCE AND INT_MASK */
 
 
  switch (addr)
  switch (addr)
  {
  {
  case ETH_MODER:
  case ETH_MODER:
          printf("0x%08lx -> ", (unsigned long) eth->regs.moder);
          printf("0x%08lx -> ", (unsigned long) eth->regs.moder);
          break;
          break;
Line 1403... Line 1411...
          break;
          break;
  case ETH_INT_MASK:
  case ETH_INT_MASK:
          printf("0x%08lx -> ", (unsigned long) eth->regs.int_mask);
          printf("0x%08lx -> ", (unsigned long) eth->regs.int_mask);
          break;
          break;
  }
  }
 
 
 
 
 
 
#endif
#endif
 
 
  switch (addr)
  switch (addr)
    {
    {
    case ETH_MODER:
    case ETH_MODER:
Line 1472... Line 1477...
      break;
      break;
 
 
    case ETH_INT_MASK:
    case ETH_INT_MASK:
      eth->regs.int_mask = value;
      eth->regs.int_mask = value;
 
 
      /* If we enable interrupts, the core is not currently processing an
      /* The old code would report an interrupt if we enabled an interrupt
         interrupt, and there is an interrupt pending, then report that
         when if we enabled interrupts and the core was not currently
         interrupt.
         processing an interrupt, and there was an interrupt pending.
 
 
 
         However this led (at least on some machines) to orphaned interrupts
 
         in the device driver. So in this version of the code we do not report
 
         interrupts on a mask change.
 
 
 
         This is not apparently consistent with the Verilog, but it does mean
 
         that the orphaned interrupts problem does not occur, and has no
 
         apparent effect on Ethernet performance. More investigation is needed
 
         to determine if this is a bug in Or1ksim interrupt handling, or a bug
 
         in the device driver, which does not manifest with real HW.
 
 
         Otherwise clear down the interrupt.
         Otherwise clear down the interrupt.
 
 
         @todo  Is this really right. */
         @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);
#if ETH_DEBUG
 
          printf ("ETH_MASK changed with apparent pending interrupt.\n");
 
#endif
        }
        }
      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;
        }
        }
 
 
      break;
      break;
 
 
    case ETH_IPGT:       eth->regs.ipgt         = value; break;
    case ETH_IPGT:       eth->regs.ipgt         = value; break;
    case ETH_IPGR1:      eth->regs.ipgr1        = value; break;
    case ETH_IPGR1:      eth->regs.ipgr1        = value; break;
    case ETH_IPGR2:      eth->regs.ipgr2        = value; break;
    case ETH_IPGR2:      eth->regs.ipgr2        = value; break;
Line 1546... Line 1564...
        }
        }
      break;
      break;
    }
    }
 
 
#if ETH_DEBUG
#if ETH_DEBUG
 
 
  switch (addr)
  switch (addr)
  {
  {
  case ETH_MODER:
  case ETH_MODER:
          printf("0x%08lx", (unsigned long) eth->regs.moder);
      printf ("0x%08lx\n", (unsigned long) eth->regs.moder);
          break;
          break;
  case ETH_INT_SOURCE:
  case ETH_INT_SOURCE:
          printf("0x%08lx", (unsigned long) eth->regs.int_source);
      printf ("0x%08lx\n", (unsigned long) eth->regs.int_source);
          break;
          break;
  case ETH_INT_MASK:
  case ETH_INT_MASK:
          printf("0x%08lx", (unsigned long) eth->regs.int_mask);
      printf ("0x%08lx\n", (unsigned long) eth->regs.int_mask);
          break;
          break;
  case ETH_IPGT:
  case ETH_IPGT:
  case ETH_IPGR1:
  case ETH_IPGR1:
  case ETH_IPGR2:
  case ETH_IPGR2:
  case ETH_PACKETLEN:
  case ETH_PACKETLEN:
  case ETH_COLLCONF:
  case ETH_COLLCONF:
  case ETH_TX_BD_NUM:
  case ETH_TX_BD_NUM:
  case ETH_CTRLMODER:
  case ETH_CTRLMODER:
  case ETH_MAC_ADDR0:
  case ETH_MAC_ADDR0:
  case ETH_MAC_ADDR1:
  case ETH_MAC_ADDR1:
 
      printf("\n");
          break;
          break;
  }
  }
 
 
  printf("\n");
 
#endif
#endif
 
 
 
 
}       /* eth_write32 () */
}       /* eth_write32 () */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Enable or disable the Ethernet interface
/*!Enable or disable the Ethernet interface

powered by: WebSVN 2.1.0

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