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
- from Rev 450 to Rev 451
- ↔ Reverse comparison
Rev 450 → Rev 451
/doc/or1ksim.info
2261,6 → 2261,26
device configured for the system (*note Ethernet TUN/TAP |
Interface: Ethernet TUN/TAP Interface.) |
|
`phy_addr = VALUE' |
VALUE specifies the address for emulated ethernet PHY (default 0). |
If there are multiple Ethernet peripherals, they should each have a |
different PHY value. |
|
`dummy_crc = 0|1' |
If 1 (true, the default), the length of the data transferred to |
the core will be increased by 4 bytes, as though the CRC were |
included. |
|
Note: This is for historical consistency with the OpenRISC |
Ethernet hardware MAC, which passes on the CRC in the data |
packet. This is unusual behavior for a MAC, but the OpenRISC |
Linux device drivers have been written to expect it. |
|
`phy_addr = VALUE' |
VALUE specifies the address for emulated ethernet PHY (default 0). |
If there are multiple Ethernet peripherals, they should each have a |
different PHY value. |
|
`vapi_id = VALUE' |
VALUE specifies the value of the Verification API (VAPI) base |
address to be used with the Ethernet PHY. *Note Verification API: |
2267,12 → 2287,7
Verification API, for more details, which details the use of the |
VAPI with the DMA controller. |
|
`phy_addr = VALUE' |
VALUE specifies the address for emulated ethernet PHY (default 0). |
If there are multiple Ethernet peripherals, they should each have a |
different PHY value. |
|
|
|
File: or1ksim.info, Node: GPIO Configuration, Next: Display Interface Configuration, Prev: Ethernet Configuration, Up: Peripheral Configuration |
|
4106,6 → 4121,8
(line 6) |
* doze mode (power management register): Power Management Configuration. |
(line 15) |
* dummy_crc (Ethernet configuration): Ethernet Configuration. |
(line 104) |
* dv (Interactive CLI): Interactive Command Line. |
(line 124) |
* dynamic clock gating (power management register): Power Management Configuration. |
4381,7 → 4398,7
* persistent TAP device creation: Setting Up a Persistent TAP device. |
(line 6) |
* phy_addr: Ethernet Configuration. |
(line 105) |
(line 99) |
* PIC configuration: Interrupt Configuration. |
(line 6) |
* pio (ATA/ATAPI device configuration): Disc Interface Configuration. |
4685,7 → 4702,7
* vapi_id (debug interface configuration): Debug Interface Configuration. |
(line 43) |
* vapi_id (DMA configuration) <1>: Ethernet Configuration. |
(line 99) |
(line 119) |
* vapi_id (DMA configuration): DMA Configuration. (line 38) |
* vapi_id (GPIO configuration): GPIO Configuration. (line 32) |
* vapi_id (UART configuration): UART Configuration. (line 85) |
4748,23 → 4765,23
Node: UART Configuration75659 |
Node: DMA Configuration79178 |
Node: Ethernet Configuration81045 |
Node: GPIO Configuration85690 |
Node: Display Interface Configuration87323 |
Node: Frame Buffer Configuration89632 |
Node: Keyboard Configuration91496 |
Node: Disc Interface Configuration93734 |
Node: Generic Peripheral Configuration98838 |
Node: Interactive Command Line101133 |
Node: Verification API108107 |
Node: Code Internals112537 |
Node: Coding Conventions113120 |
Node: Global Data Structures117547 |
Node: Concepts120204 |
Ref: Output Redirection120349 |
Ref: Interrupts Internal120887 |
Node: Internal Debugging122040 |
Node: Regression Testing122564 |
Node: GNU Free Documentation License126353 |
Node: Index148760 |
Node: GPIO Configuration86324 |
Node: Display Interface Configuration87957 |
Node: Frame Buffer Configuration90266 |
Node: Keyboard Configuration92130 |
Node: Disc Interface Configuration94368 |
Node: Generic Peripheral Configuration99472 |
Node: Interactive Command Line101767 |
Node: Verification API108741 |
Node: Code Internals113171 |
Node: Coding Conventions113754 |
Node: Global Data Structures118181 |
Node: Concepts120838 |
Ref: Output Redirection120983 |
Ref: Interrupts Internal121521 |
Node: Internal Debugging122674 |
Node: Regression Testing123198 |
Node: GNU Free Documentation License126987 |
Node: Index149394 |
|
End Tag Table |
/doc/or1ksim.texi
2736,6 → 2736,30
persistent TAP device configured for the system (@pxref{Ethernet TUN/TAP |
Interface, , Ethernet TUN/TAP Interface}) |
|
@item phy_addr = @var{value} |
@cindex @code{phy_addr} |
@var{value} specifies the address for emulated ethernet PHY (default |
0). If there are multiple Ethernet peripherals, they should each have a |
different PHY value. |
|
@item dummy_crc = 0|1 |
@cindex @code{dummy_crc} (Ethernet configuration) |
If 1 (true, the default), the length of the data transferred to the core |
will be increased by 4 bytes, as though the CRC were included. |
|
@quotation Note |
This is for historical consistency with the OpenRISC Ethernet hardware |
MAC, which passes on the CRC in the data packet. This is unusual |
behavior for a MAC, but the OpenRISC Linux device drivers have been |
written to expect it. |
@end quotation |
|
@item phy_addr = @var{value} |
@cindex @code{phy_addr} |
@var{value} specifies the address for emulated ethernet PHY (default |
0). If there are multiple Ethernet peripherals, they should each have a |
different PHY value. |
|
@item vapi_id = @var{value} |
@cindex @code{vapi_id} (DMA configuration) |
@var{value} specifies the value of the Verification API (VAPI) base |
2743,12 → 2767,6
Verification API}, for more details, which details the use of the VAPI |
with the DMA controller. |
|
@item phy_addr = @var{value} |
@cindex @code{phy_addr} |
@var{value} specifies the address for emulated ethernet PHY (default |
0). If there are multiple Ethernet peripherals, they should each have a |
different PHY value. |
|
@end table |
|
@node GPIO Configuration |
/doc/version.texi
1,4 → 1,4
@set UPDATED 10 December 2010 |
@set UPDATED 15 December 2010 |
@set UPDATED-MONTH December 2010 |
@set EDITION 2010-12-15 |
@set VERSION 2010-12-15 |
/ChangeLog
1,8 → 1,27
2010-12-15 Jeremy Bennett <jeremy@jeremybennett.com> |
|
* peripheral/eth.c <RTX_RESCHED_PERIOD>: Added. |
(eth_controller_tx_clock, eth_controller_rx_clock): Reschedule for |
RTX_RESCHED_PERIOD. |
(eth_controller_tx_clock): dummy_crc parameter controls whether |
CRC is added. |
(eth_ignore_tap_packet): Deleted. |
(eth_ignore_tap_packets): Added (based on eth_ignore_tap_packet). |
(eth_reset): I/O opening moved into eth_open_if. |
(eth_open_if, eth_open_file_if, eth_open_tap_if): Created. |
(eth_regname): Created. |
(eth_read32, eth_write32): Unified debug printing. |
(eth_dummy_crc): Created. |
(eth_sec_start): Initialize dummy_crc. |
(reg_ethernet_sec): Add dummy_crc parameter. |
* doc/or1ksim.texi: Updated Ethernet configuration section for |
dummy_crc. |
|
2010-12-15 Jeremy Bennett <jeremy@jeremybennett.com> |
|
* configure: Regenerated. |
* configure.ac: Updated version. |
* peripheral/eth.c <mac_address>: Defined to ff:ff:ff:ff:ff:ff. |
* peripheral/eth.c <mac_broadcast>: Defined to ff:ff:ff:ff:ff:ff. |
<struct eth_device>: loopback_offset removed. State reduced to |
just BD indices, buffers removed. |
(eth_read_rx_file, eth_skip_rx_file, eth_rx_next_packet): Deleted. |
/peripheral/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() */ |
|