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

Subversion Repositories openrisc

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/or1ksim/peripheral
    from Rev 450 to Rev 451
    Reverse comparison

Rev 450 → Rev 451

/eth.c
70,6 → 70,8
# define ETH_DEBUG 1
#endif
 
/*! Period (clock cycles) for rescheduling Rx and Tx controllers. */
#define RTX_RESCHED_PERIOD 1
 
/*! MAC address that is always accepted. */
static const unsigned char mac_broadcast[ETHER_ADDR_LEN] =
94,6 → 96,7
unsigned char mac_address[ETHER_ADDR_LEN]; /* Ext HW address */
unsigned long int phy_addr; /* Int HW address */
unsigned long int mac_int; /* interrupt line number */
int dummy_crc; /* Flag indicating if we add CRC */
int int_line_stat; /* interrupt line status */
 
/* External interface deatils */
141,141 → 144,7
};
 
 
 
/* -------------------------------------------------------------------------- */
/*!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.
 
This writes a single Ethernet packet to a FILE interface. The format is to
538,7 → 407,7
}
 
/* 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 () */
 
789,10 → 658,15
#endif
/* Write result to BD.
@todo Why is the length 4 more than the packet length? Is that for
the CRC? */
SET_FIELD (bd_info, ETH_RX_BD, LENGTH, packet_length + 4);
 
The OpenRISC MAC hardware passes on the CRC (which it should not). The
Linux drivers have been written to expect a value (which they ignore). So
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);
SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, RXB);
830,51 → 704,69
 
 
/* -------------------------------------------------------------------------- */
/*!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.
 
@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
eth_ignore_packet (struct eth_device *eth)
static int
eth_ignore_tap_packets (struct eth_device *eth)
{
unsigned char buf[ETH_MAXPL];
ssize_t nread = eth_read_packet (eth, buf);
int result = 0;
int n;
/* Read packets until there are none left. */
do
{
struct pollfd fds[1];
 
if (nread < 0)
{
fprintf (stderr,
"Warning: Read of when Ethernet busy failed %s.\n",
strerror (errno));
}
else if (nread > 0)
{
/* Record that a packet was thrown away. */
SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, BUSY);
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))
/* 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)
{
if (eth->int_line_stat)
/* 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];
ssize_t nread = eth_read_packet (eth, buf);
 
if (nread < 0)
{
fprintf (stderr, "Warning: Interrupt active during ignore.\n");
/* Give up with a warning if read fails */
fprintf (stderr,
"Warning: Read of when Ethernet busy failed %s.\n",
strerror (errno));
return result;
}
else
else if (nread > 0)
{
/* Record that a packet was thrown away. */
result = 1;
#if ETH_DEBUG
printf ("Ethernet Rx BUSY interrupt\n");
printf ("Ethernet discarding %d bytes from TAP while BD full.\n",
nread);
#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.
 
916,29 → 808,55
@note We don't do this for file I/O, since it would discard
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
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 () */
 
 
/* ========================================================================= */
/* -------------------------------------------------------------------------- */
/*!VAPI connection to outside.
 
/* ========================================================================= */
Used for remote testing of the interface. Currently does nothing.
 
 
/*
* VAPI connection to outside
*/
@param[in] id The VAPI ID to use.
@param[in] data Any data associated (unused here).
@param[in] dat The Ethernet data structure, cast to a void pointer. */
/* -------------------------------------------------------------------------- */
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;
 
which = id - eth->base_vapi_id;
957,123 → 875,202
}
}
 
 
/* -------------------------------------------------------------------------- */
/*!Reset the Ethernet.
/*!Print register values on stdout
 
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)
eth_status (void *dat)
{
struct eth_device *eth = dat;
struct ifreq ifr;
 
#if ETH_DEBUG
printf ("Resetting Ethernet\n");
PRINTF ("\nEthernet MAC at 0x%" PRIxADDR ":\n", eth->baseaddr);
PRINTF ("MODER : 0x%08lX\n", eth->regs.moder);
PRINTF ("INT_SOURCE : 0x%08lX\n", eth->regs.int_source);
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);
 
} /* eth_status () */
 
 
/* -------------------------------------------------------------------------- */
/*!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 */
if (eth->rxfd >= 0)
{
close (eth->rxfd);
}
 
if (eth->txfd >= 0)
{
close (eth->txfd);
}
 
eth->rxfd = -1;
eth->txfd = -1;
 
eth->rxfd = open (eth->rxfile, O_RDONLY);
if (eth->rxfd < 0)
{
fprintf (stderr, "Warning: Cannot open Ethernet RX file \"%s\": %s\n",
eth->rxfile, strerror (errno));
}
 
eth->txfd = open (eth->txfile,
#if defined(O_SYNC) /* BSD/MacOS X doesn't know about O_SYNC */
O_SYNC |
#endif
/* Nothing to do if we do not have a base address set.
O_RDWR | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (eth->txfd < 0)
{
fprintf (stderr, "Warning: Cannot open Ethernet TX file \"%s\": %s\n",
eth->txfile, strerror (errno));
}
} /* eth_open_file_if () */
 
TODO: Surely this should test for being enabled? */
if (0 == eth->baseaddr)
 
/* -------------------------------------------------------------------------- */
/*!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?
 
@param[in] eth The Ethernet interface data structure. */
/* -------------------------------------------------------------------------- */
static void
eth_open_tap_if (struct eth_device *eth)
{
struct ifreq ifr;
 
/* We don't support re-opening. If it's open, it stays open. */
if (eth->rtx_fd >= 0)
{
return;
}
 
switch (eth->rtx_type)
/* Open the TUN/TAP device */
eth->rtx_fd = open ("/dev/net/tun", O_RDWR);
if( eth->rtx_fd < 0 )
{
case ETH_RTX_FILE:
fprintf (stderr, "Warning: Failed to open TUN/TAP device: %s\n",
strerror (errno));
eth->rtx_fd = -1;
return;
}
 
/* (Re-)open TX/RX files */
if (eth->rxfd >= 0)
{
close (eth->rxfd);
}
/* Turn it into a specific TAP device. If we haven't specified a specific
(persistent) device, one will be created, but that requires superuser, or
at least CAP_NET_ADMIN capabilities. */
memset (&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
strncpy (ifr.ifr_name, eth->tap_dev, IFNAMSIZ);
 
if (eth->txfd >= 0)
{
close (eth->txfd);
}
if (ioctl (eth->rtx_fd, TUNSETIFF, (void *) &ifr) < 0)
{
fprintf (stderr, "Warning: Failed to set TAP device: %s\n",
strerror (errno));
close (eth->rtx_fd);
eth->rtx_fd = -1;
return;
}
#if ETH_DEBUG
PRINTF ("Opened TAP %s\n", ifr.ifr_name);
#endif
} /* eth_open_tap_if () */
 
eth->rxfd = -1;
eth->txfd = -1;
 
eth->rxfd = open (eth->rxfile, O_RDONLY);
if (eth->rxfd < 0)
{
fprintf (stderr, "Warning: Cannot open Ethernet RX file \"%s\": %s\n",
eth->rxfile, strerror (errno));
}
/* -------------------------------------------------------------------------- */
/*!Open the external interface to the Ethernet
 
eth->txfd = open (eth->txfile,
#if defined(O_SYNC) /* BSD/MacOS X doesn't know about O_SYNC */
O_SYNC |
#endif
O_RDWR | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (eth->txfd < 0)
{
fprintf (stderr, "Warning: Cannot open Ethernet TX file \"%s\": %s\n",
eth->txfile, strerror (errno));
}
Calls the appropriate function for the interface type.
 
@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 () */
 
case ETH_RTX_TAP:
 
/* (Re-)open TAP interface if necessary */
if (eth->rtx_fd != 0)
{
break;
}
/* -------------------------------------------------------------------------- */
/*!Reset the Ethernet.
 
/* Open the TUN/TAP device */
eth->rtx_fd = open ("/dev/net/tun", O_RDWR);
if( eth->rtx_fd < 0 )
{
fprintf (stderr, "Warning: Failed to open TUN/TAP device: %s\n",
strerror (errno));
eth->rtx_fd = 0;
return;
}
Open the correct type of simulation interface to the outside world.
 
/* Turn it into a specific TAP device. If we haven't specified a
specific (persistent) device, one will be created, but that requires
superuser, or at least CAP_NET_ADMIN capabilities. */
memset (&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
strncpy (ifr.ifr_name, eth->tap_dev, IFNAMSIZ);
Initialize all registers to default and places devices in memory address
space.
 
if (ioctl (eth->rtx_fd, TUNSETIFF, (void *) &ifr) < 0)
{
fprintf (stderr, "Warning: Failed to set TAP device: %s\n",
strerror (errno));
close (eth->rtx_fd);
eth->rtx_fd = 0;
return;
}
@param[in] dat The Ethernet interface data structure. */
/* -------------------------------------------------------------------------- */
static void
eth_reset (void *dat)
{
struct eth_device *eth = dat;
 
#if ETH_DEBUG
PRINTF ("Opened TAP %s\n", ifr.ifr_name);
printf ("Resetting Ethernet\n");
#endif
/* Do we need to flush any packets? */
break;
 
/* 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;
eth->regs.ipgt = 0x00000012;
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;
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;
1091,302 → 1088,447
} /* eth_reset () */
 
 
/*
Print register values on stdout
*/
static void
eth_status (void *dat)
#if ETH_DEBUG
/* -------------------------------------------------------------------------- */
/*!Map a register address to its name
 
@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);
PRINTF ("MODER : 0x%08lX\n", eth->regs.moder);
PRINTF ("INT_SOURCE : 0x%08lX\n", eth->regs.int_source);
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);
}
switch (addr)
{
case ETH_MODER: return "MODER";
case ETH_INT_SOURCE: return "INT_SOURCE";
case ETH_INT_MASK: return "INT_MASK";
case ETH_IPGT: return "IPGT";
case ETH_IPGR1: return "IPGR1";
case ETH_IPGR2: return "IPGR2";
case ETH_PACKETLEN: return "PACKETLEN";
case ETH_COLLCONF: return "COLLCONF";
case ETH_TX_BD_NUM: return "TX_BD_NUM";
case ETH_CTRLMODER: return "CTRLMODER";
case ETH_MIIMODER: return "MIIMODER";
case ETH_MIICOMMAND: return "MIICOMMAND";
case ETH_MIIADDRESS: return "MIIADDRESS";
case ETH_MIITX_DATA: return "MIITX_DATA";
case ETH_MIIRX_DATA: return "MIIRX_DATA";
case ETH_MIISTATUS: return "MIISTATUS";
case ETH_MAC_ADDR0: return "MAC_ADDR0";
case ETH_MAC_ADDR1: return "MAC_ADDR1";
case ETH_HASH0: return "HASH0";
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
*/
/* -------------------------------------------------------------------------- */
/*!Read a register
 
@param[in] addr The address of the register to read (offset from base).
@param[in] dat The Ethernet interface data structure, cast to a void
pointer.
 
@return The value read. */
/* -------------------------------------------------------------------------- */
static uint32_t
eth_read32 (oraddr_t addr, void *dat)
eth_read32 (oraddr_t addr,
void *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)
{
case ETH_MODER:
return eth->regs.moder;
case ETH_INT_SOURCE:
return eth->regs.int_source;
case ETH_INT_MASK:
return eth->regs.int_mask;
case ETH_IPGT:
return eth->regs.ipgt;
case ETH_IPGR1:
return eth->regs.ipgr1;
case ETH_IPGR2:
return eth->regs.ipgr2;
case ETH_PACKETLEN:
return eth->regs.packetlen;
case ETH_COLLCONF:
return eth->regs.collconf;
case ETH_TX_BD_NUM:
return eth->regs.tx_bd_num;
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:
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:
return (((unsigned long) eth->mac_address[0]) << 8) |
(unsigned long) eth->mac_address[1];
case ETH_HASH0:
return eth->regs.hash0;
case ETH_HASH1:
return eth->regs.hash1;
/*case ETH_DMA_RX_TX: return eth_rx( eth ); */
printf ("eth_read32: %s = 0x%08lx\n", eth_regname (addr),
(unsigned long int) res);
}
#endif
 
if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE))
return eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4];
return res;
 
PRINTF ("eth_read32( 0x%" PRIxADDR " ): Illegal address\n",
addr + eth->baseaddr);
return 0;
}
} /* eth_read32 () */
 
/* ========================================================================= */
 
/* -------------------------------------------------------------------------- */
/*!Emulate MIIM transaction to ethernet PHY
 
/*
Write a register
*/
@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
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
eth_write32 (oraddr_t addr, uint32_t value, void *dat)
{
struct eth_device *eth = dat;
unsigned char buf[ETH_MAXPL];
 
#if ETH_DEBUG
/* Only trace registers of particular interest */
switch (addr)
{
case ETH_MODER:
#if ETH_DEBUG
printf("eth_write32: MODER 0x%x\n",value);
case ETH_INT_SOURCE:
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
 
switch (addr)
{
case ETH_MODER:
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 {
n = poll (fds, 1, 0);
if (n < 0)
{
fprintf (stderr, "Warning: Poll in while emptying TAP: %s: ignored.\n",
strerror (errno));
}
else if ((n > 0) && ((fds[0].revents & POLLIN) == POLLIN))
{
nread = read (eth->rtx_fd, buf, ETH_MAXPL);
if (nread < 0)
{
fprintf (stderr,
"Warning: Read failed %s: ignored\n",
strerror (errno));
}
}
} while (n > 0);
}
/* Enabling receive, flush any oustanding input (TAP only), reset
the BDs and schedule the Rx controller on the next clock
cycle. */
if (ETH_RTX_TAP == eth->rtx_type)
{
(void) eth_ignore_tap_packets (eth);
}
 
eth->rx_bd_index = eth->regs.tx_bd_num * 2;
SCHED_ADD (eth_controller_rx_clock, dat, 1);
}
else if (!TEST_FLAG (value, ETH_MODER, RXEN) &&
TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN))
SCHED_FIND_REMOVE (eth_controller_rx_clock, dat);
{
/* Disabling Rx, so stop scheduling the Rx controller. */
SCHED_FIND_REMOVE (eth_controller_rx_clock, dat);
}
 
if (!TEST_FLAG (eth->regs.moder, 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;
SCHED_ADD (eth_controller_tx_clock, dat, 1);
}
else if (!TEST_FLAG (value, ETH_MODER, TXEN) &&
TEST_FLAG (eth->regs.moder, ETH_MODER, TXEN))
SCHED_FIND_REMOVE (eth_controller_tx_clock, dat);
{
/* Disabling Tx, so stop scheduling the Tx controller. */
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))
{
eth_reset (dat);
}
 
if (TEST_FLAG (value, ETH_MODER, RST))
eth_reset (dat);
return;
eth->regs.moder = value; /* Update the register */
break;
 
case ETH_INT_SOURCE:
#if ETH_DEBUG
printf("eth_write32: INT_SOURCE 0x%x\n",value);
#endif
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)
{
clear_interrupt (eth->mac_int);
eth->int_line_stat = 0;
}
return;
break;
 
case ETH_INT_MASK:
#if ETH_DEBUG
printf("eth_write32: INT_MASK 0x%x\n",value);
#endif
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)
report_interrupt (eth->mac_int);
else
if (eth->int_line_stat)
{
clear_interrupt (eth->mac_int);
eth->int_line_stat = 0;
}
return;
case ETH_IPGT:
eth->regs.ipgt = value;
return;
case ETH_IPGR1:
eth->regs.ipgr1 = value;
return;
case ETH_IPGR2:
eth->regs.ipgr2 = value;
return;
case ETH_PACKETLEN:
eth->regs.packetlen = value;
return;
case ETH_COLLCONF:
eth->regs.collconf = value;
return;
{
report_interrupt (eth->mac_int);
}
else if (eth->int_line_stat)
{
clear_interrupt (eth->mac_int);
eth->int_line_stat = 0;
}
break;
 
case ETH_IPGT: eth->regs.ipgt = value; break;
case ETH_IPGR1: eth->regs.ipgr1 = value; break;
case ETH_IPGR2: eth->regs.ipgr2 = value; break;
case ETH_PACKETLEN: eth->regs.packetlen = value; break;
case ETH_COLLCONF: eth->regs.collconf = value; break;
 
case ETH_TX_BD_NUM:
/* When TX_BD_NUM is written, also reset current RX BD index */
eth->regs.tx_bd_num = value & 0xFF;
eth->rx_bd_index = eth->regs.tx_bd_num << 1;
return;
case ETH_CTRLMODER:
eth->regs.controlmoder = value;
return;
case ETH_MIIMODER:
eth->regs.miimoder = value;
return;
eth->rx_bd_index = eth->regs.tx_bd_num * 2;
break;
 
case ETH_CTRLMODER: eth->regs.controlmoder = value; break;
case ETH_MIIMODER: eth->regs.miimoder = value; break;
 
case ETH_MIICOMMAND:
eth->regs.miicommand = value;
/* Perform MIIM transaction, if required */
eth_miim_trans (eth);
return;
case ETH_MIIADDRESS:
eth->regs.miiaddress = value;
return;
case ETH_MIITX_DATA:
eth->regs.miitx_data = value;
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;
break;
 
case ETH_MIIADDRESS: eth->regs.miiaddress = value; break;
case ETH_MIITX_DATA: eth->regs.miitx_data = value; break;
case ETH_MIIRX_DATA: /* Register is R/O */ break;
case ETH_MIISTATUS: /* Register is R/O */ break;
 
case ETH_MAC_ADDR0:
eth->mac_address[5] = value & 0xFF;
eth->mac_address[4] = (value >> 8) & 0xFF;
eth->mac_address[5] = value & 0xFF;
eth->mac_address[4] = (value >> 8) & 0xFF;
eth->mac_address[3] = (value >> 16) & 0xFF;
eth->mac_address[2] = (value >> 24) & 0xFF;
return;
break;
 
case ETH_MAC_ADDR1:
eth->mac_address[1] = value & 0xFF;
eth->mac_address[0] = (value >> 8) & 0xFF;
return;
case ETH_HASH0:
eth->regs.hash0 = value;
return;
case ETH_HASH1:
eth->regs.hash1 = value;
return;
eth->mac_address[1] = value & 0xFF;
eth->mac_address[0] = (value >> 8) & 0xFF;
break;
 
/*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;
 
if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE))
{
eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4] = value;
return;
default:
if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE))
{
eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4] = value;
}
else
{
fprintf (stderr,
"Warning: eth_write32( 0x%" PRIxADDR " ): Illegal address\n",
addr + eth->baseaddr);
}
break;
}
} /* eth_write32 () */
 
PRINTF ("eth_write32( 0x%" PRIxADDR " ): Illegal address\n",
addr + eth->baseaddr);
return;
}
 
/* ========================================================================= */
 
 
/* ========================================================================= */
 
 
 
/* ========================================================================= */
 
/*-----------------------------------------------[ Ethernet configuration ]---*/
 
 
/*---------------------------------------------------------------------------*/
/*!Enable or disable the Ethernet interface
 
1620,26 → 1762,68
} /* 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
eth_vapi_id (union param_val val,
eth_phy_addr (union param_val val,
void *dat)
{
struct eth_device *eth = dat;
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
eth_dummy_crc (union param_val val,
void *dat)
{
struct eth_device *eth = dat;
eth->base_vapi_id = val.int_val;
}
 
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 */
/*---------------------------------------------------------------------------*/
static void
eth_phy_addr (union param_val val,
void *dat)
eth_vapi_id (union param_val val,
void *dat)
{
struct eth_device *eth = dat;
eth->phy_addr = val.int_val & ETH_MIIADDR_FIAD_MASK;
}
eth->base_vapi_id = val.int_val;
 
} /* eth_vapi_id () */
 
 
/*---------------------------------------------------------------------------*/
/*!Initialize a new Ethernet configuration
/*!Start the initialization of a new Ethernet configuration
 
ALL parameters are set explicitly to default values. */
/*---------------------------------------------------------------------------*/
1664,16 → 1848,24
new->rtx_type = ETH_RTX_FILE;
new->rx_channel = 0;
new->tx_channel = 0;
new->rtx_fd = 0;
new->rtx_fd = -1;
new->rxfile = strdup ("eth_rx");
new->txfile = strdup ("eth_tx");
new->tap_dev = strdup ("");
new->phy_addr = 0;
new->dummy_crc = 1;
new->base_vapi_id = 0;
new->phy_addr = 0;
 
return new;
}
 
} /* eth_sec_start () */
 
 
/*---------------------------------------------------------------------------*/
/*!Complete the initialization of a new Ethernet configuration
 
ALL parameters are set explicitly to default values. */
/*---------------------------------------------------------------------------*/
static void
eth_sec_end (void *dat)
{
1702,9 → 1894,10
reg_mem_area (eth->baseaddr, ETH_ADDR_SPACE, 0, &ops);
reg_sim_stat (eth_status, dat);
reg_sim_reset (eth_reset, dat);
}
 
} /* eth_sec_end () */
 
 
/*---------------------------------------------------------------------------*/
/*!Register a new Ethernet configuration */
/*---------------------------------------------------------------------------*/
1724,8 → 1917,8
reg_config_param (sec, "rxfile", PARAMT_STR, eth_rxfile);
reg_config_param (sec, "txfile", PARAMT_STR, eth_txfile);
reg_config_param (sec, "tap_dev", PARAMT_STR, eth_tap_dev);
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_config_param (sec, "phy_addr", PARAMT_INT, eth_phy_addr);
 
} /* reg_ethernet_sec() */
 

powered by: WebSVN 2.1.0

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