Line 6... |
Line 6... |
//// Do ethernet receive path testing ////
|
//// Do ethernet receive path testing ////
|
//// Relies on testbench to provide simulus - expects at least ////
|
//// Relies on testbench to provide simulus - expects at least ////
|
//// 256 packets to be sent. ////
|
//// 256 packets to be sent. ////
|
//// ////
|
//// ////
|
//// Author(s): ////
|
//// Author(s): ////
|
//// - jb, jb@orsoc.se, with parts taken from Linux kernel ////
|
//// - Julius Baxter, julius@opencores.org ////
|
//// open_eth driver. ////
|
|
//// ////
|
//// ////
|
//// ////
|
//// ////
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
//// ////
|
//// ////
|
//// Copyright (C) 2009 Authors and OPENCORES.ORG ////
|
//// Copyright (C) 2009 Authors and OPENCORES.ORG ////
|
Line 38... |
Line 37... |
//// from http://www.opencores.org/lgpl.shtml ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// ////
|
//// ////
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
|
|
#include "cpu-utils.h"
|
#include "cpu-utils.h"
|
//#include "spr-defs.h"
|
|
#include "board.h"
|
#include "board.h"
|
#include "int.h"
|
#include "int.h"
|
#include "uart.h"
|
|
#include "ethmac.h"
|
#include "ethmac.h"
|
#include "printf.h"
|
|
#include "eth-phy-mii.h"
|
#include "eth-phy-mii.h"
|
|
|
volatile unsigned tx_done;
|
volatile unsigned tx_done;
|
volatile unsigned rx_done;
|
volatile unsigned rx_done;
|
|
|
/* Functions in this file */
|
/* Functions in this file */
|
void ethmac_setup(void);
|
void ethmac_setup(void);
|
void ethphy_init(void);
|
|
void oeth_dump_bds();
|
void oeth_dump_bds();
|
/* Interrupt functions */
|
/* Interrupt functions */
|
void oeth_interrupt(void);
|
void oeth_interrupt(void);
|
static void oeth_rx(void);
|
static void oeth_rx(void);
|
static void oeth_tx(void);
|
static void oeth_tx(void);
|
|
/* Function to calculate checksum of ping responses we send */
|
|
unsigned short calculate_checksum(char* dats, unsigned int len) ;
|
|
|
/* Defining RTLSIM turns off use of real printf'ing to save time in simulation */
|
|
#define RTLSIM
|
|
|
|
#ifdef RTLSIM
|
|
#define printk
|
|
#else
|
|
#define printk printf
|
|
#endif
|
|
/* Let the ethernet packets use a space beginning here for buffering */
|
/* Let the ethernet packets use a space beginning here for buffering */
|
#define ETH_BUFF_BASE 0x01000000
|
#define ETH_BUFF_BASE 0x01000000
|
|
|
|
|
#define RXBUFF_PREALLOC 1
|
#define RXBUFF_PREALLOC 1
|
#define TXBUFF_PREALLOC 1
|
#define TXBUFF_PREALLOC 1
|
//#undef RXBUFF_PREALLOC
|
|
//#undef TXBUFF_PREALLOC
|
|
|
|
/* The transmitter timeout
|
/* The transmitter timeout
|
*/
|
*/
|
#define TX_TIMEOUT (2*HZ)
|
#define TX_TIMEOUT (2*HZ)
|
|
|
/* Buffer number (must be 2^n)
|
/* Buffer number (must be 2^n)
|
|
* Note: if changing these, must also change settings in eth_stim.v testbench
|
|
* file!
|
*/
|
*/
|
#define OETH_RXBD_NUM 16
|
#define OETH_RXBD_NUM 16
|
#define OETH_TXBD_NUM 16
|
#define OETH_TXBD_NUM 16
|
#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1)
|
#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1)
|
#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1)
|
#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1)
|
Line 114... |
Line 102... |
|
|
// struct net_device_stats stats;
|
// struct net_device_stats stats;
|
};
|
};
|
|
|
|
|
#define PHYNUM 7
|
char CHECKSUM_BUFFER[OETH_RX_BUFF_SIZE]; // Big enough to hold a packet
|
|
|
/* Scan the MIIM bus for PHYs */
|
|
void scan_ethphys(void)
|
|
{
|
|
unsigned int phynum,regnum, i;
|
|
|
|
volatile oeth_regs *regs;
|
|
regs = (oeth_regs *)(OETH_REG_BASE);
|
|
|
|
regs->miitx_data = 0;
|
|
|
|
for(phynum=0;phynum<32;phynum++)
|
|
{
|
|
for (regnum=0;regnum<8;regnum++)
|
|
{
|
|
printk("scan_ethphys: phy %d r%d ",phynum, regnum);
|
|
|
|
/* Now actually perform the read on the MIIM bus*/
|
|
regs->miiaddress = (regnum << 8) | phynum; /* Basic Control Register */
|
|
regs->miicommand = OETH_MIICOMMAND_RSTAT;
|
|
|
|
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/
|
|
|
|
regs->miicommand = 0;
|
|
|
|
while(regs->miistatus & OETH_MIISTATUS_BUSY);
|
|
|
|
printk("%x\n",regs->miirx_data);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ethmac_scanstatus(void)
|
|
{
|
|
volatile oeth_regs *regs;
|
|
regs = (oeth_regs *)(OETH_REG_BASE);
|
|
|
|
|
|
printk("Oeth: regs->miistatus %x regs->miirx_data %x\n",regs->miistatus, regs->miirx_data);
|
|
regs->miiaddress = 0;
|
|
regs->miitx_data = 0;
|
|
regs->miicommand = OETH_MIICOMMAND_SCANSTAT;
|
|
printk("Oeth: regs->miiaddress %x regs->miicommand %x\n",regs->miiaddress, regs->miicommand);
|
|
//regs->miicommand = 0;
|
|
volatile int i; for(i=0;i<1000;i++);
|
|
while(regs->miistatus & OETH_MIISTATUS_BUSY) ;
|
|
//spin_cursor();
|
|
//printk("\r");
|
|
//or32_exit(0);
|
|
}
|
|
|
|
void
|
|
eth_mii_write(char phynum, short regnum, short data)
|
|
{
|
|
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE);
|
|
regs->miiaddress = (regnum << 8) | phynum;
|
|
regs->miitx_data = data;
|
|
regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;
|
|
regs->miicommand = 0;
|
|
while(regs->miistatus & OETH_MIISTATUS_BUSY);
|
|
}
|
|
|
|
short
|
|
eth_mii_read(char phynum, short regnum)
|
|
{
|
|
static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE);
|
|
regs->miiaddress = (regnum << 8) | phynum;
|
|
regs->miicommand = OETH_MIICOMMAND_RSTAT;
|
|
regs->miicommand = 0;
|
|
while(regs->miistatus & OETH_MIISTATUS_BUSY);
|
|
|
|
return regs->miirx_data;
|
|
}
|
|
|
|
void ethphy_init(void)
|
|
{
|
|
|
|
/* Init the Alaska 88E1111 Phy */
|
|
char alaska88e1111_ml501_phynum = 0x7;
|
|
|
|
/* Init, reset */
|
|
short ctl = eth_mii_read(alaska88e1111_ml501_phynum, MII_BMCR);
|
|
ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
|
|
ctl |= BMCR_SPEED100; // 100MBit
|
|
ctl |= BMCR_FULLDPLX; // Full duplex
|
|
eth_mii_write(alaska88e1111_ml501_phynum, MII_BMCR, ctl);
|
|
|
|
// Setup Autoneg
|
|
short adv = eth_mii_read(alaska88e1111_ml501_phynum, MII_ADVERTISE);
|
|
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_1000XFULL
|
|
|ADVERTISE_1000XHALF | ADVERTISE_1000XPAUSE |
|
|
ADVERTISE_1000XPSE_ASYM);
|
|
adv |= ADVERTISE_10HALF;
|
|
adv |= ADVERTISE_10FULL;
|
|
adv |= ADVERTISE_100HALF;
|
|
adv |= ADVERTISE_100FULL;
|
|
eth_mii_write(alaska88e1111_ml501_phynum, MII_ADVERTISE, adv);
|
|
// Disable gigabit???
|
|
adv = eth_mii_read(alaska88e1111_ml501_phynum, MII_M1011_PHY_SPEC_CONTROL);
|
|
adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
|
|
MII_1000BASETCONTROL_HALFDUPLEXCAP);
|
|
eth_mii_write(alaska88e1111_ml501_phynum, MII_M1011_PHY_SPEC_CONTROL, adv);
|
|
// Even more disable gigabit?!
|
|
adv = eth_mii_read(alaska88e1111_ml501_phynum, MII_CTRL1000);
|
|
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
|
|
eth_mii_write(alaska88e1111_ml501_phynum, MII_CTRL1000, adv);
|
|
|
|
// Restart autoneg
|
|
printk("Resetting phy...\n");
|
|
ctl = eth_mii_read(alaska88e1111_ml501_phynum, MII_BMCR);
|
|
ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
|
|
eth_mii_write(alaska88e1111_ml501_phynum, MII_BMCR, ctl);
|
|
|
|
|
|
}
|
|
|
|
|
#define PHYNUM 7
|
|
|
void ethmac_setup(void)
|
void ethmac_setup(void)
|
{
|
{
|
// from arch/or32/drivers/open_eth.c
|
// from arch/or32/drivers/open_eth.c
|
volatile oeth_regs *regs;
|
volatile oeth_regs *regs;
|
Line 351... |
Line 223... |
regs->moder |= OETH_MODER_RXEN /* | OETH_MODER_TXEN*/;
|
regs->moder |= OETH_MODER_RXEN /* | OETH_MODER_TXEN*/;
|
|
|
return;
|
return;
|
}
|
}
|
|
|
|
void
|
|
ethmac_halt(void)
|
|
{
|
|
volatile oeth_regs *regs;
|
|
|
|
regs = (oeth_regs *)(OETH_REG_BASE);
|
|
|
|
// Disable receive and transmit
|
|
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);
|
|
|
|
}
|
|
|
|
|
/* The interrupt handler.
|
/* The interrupt handler.
|
*/
|
*/
|
void
|
void
|
oeth_interrupt(void)
|
oeth_interrupt(void)
|
Line 414... |
Line 298... |
int pkt_len, i;
|
int pkt_len, i;
|
int bad = 0;
|
int bad = 0;
|
|
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM;
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM;
|
|
|
printk("r");
|
|
|
|
/* Find RX buffers marked as having received data */
|
/* Find RX buffers marked as having received data */
|
for(i = 0; i < OETH_RXBD_NUM; i++)
|
for(i = 0; i < OETH_RXBD_NUM; i++)
|
{
|
{
|
bad=0;
|
bad=0;
|
if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ /* Looking for NOT empty buffers desc. */
|
/* Looking for buffer descriptors marked not empty */
|
|
if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){
|
/* Check status for errors.
|
/* Check status for errors.
|
*/
|
*/
|
report(i);
|
report(i);
|
report(rx_bdp[i].len_status);
|
report(rx_bdp[i].len_status);
|
if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
|
if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
|
Line 457... |
Line 340... |
|
|
continue;
|
continue;
|
}
|
}
|
else {
|
else {
|
/*
|
/*
|
Process the incoming frame.
|
* Process the incoming frame.
|
*/
|
*/
|
pkt_len = rx_bdp[i].len_status >> 16;
|
pkt_len = rx_bdp[i].len_status >> 16;
|
|
|
|
// Do a bit of work - ie. copy it, process it
|
|
memcpy(CHECKSUM_BUFFER, rx_bdp[i].addr, pkt_len);
|
|
report(0xc4eccccc);
|
|
report(calculate_checksum(CHECKSUM_BUFFER, pkt_len));
|
|
|
/* finish up */
|
/* finish up */
|
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; /* Clear stats */
|
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; /* Clear stats */
|
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; /* Mark RX BD as empty */
|
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; /* Mark RX BD as empty */
|
rx_done++;
|
rx_done++;
|
report(rx_done);
|
report(rx_done);
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
// Calculate checksum on received data.
|
|
// From http://lkml.indiana.edu/hypermail/linux/kernel/9612.3/0060.html
|
|
unsigned short calculate_checksum(char* dats, unsigned int len)
|
|
{
|
|
unsigned int itr;
|
|
unsigned long accum = 0;
|
|
unsigned long longsum;
|
|
|
|
// Sum all pairs of data
|
|
for(itr=0;itr<(len & ~0x1);itr+=2)
|
|
accum += (unsigned long)(((dats[itr]<<8)&0xff00)|(dats[itr+1]&0x00ff));
|
|
|
|
if (len & 0x1) // Do leftover
|
|
accum += (unsigned long) ((dats[itr-1]<<8)&0xff00);
|
|
|
|
longsum = (unsigned long) (accum & 0xffff);
|
|
longsum += (unsigned long) (accum >> 16); // Sum the carries
|
|
longsum += (longsum >> 16);
|
|
return (unsigned short)((longsum ^ 0xffff) & 0xffff);
|
|
|
|
}
|
|
|
|
|
static void
|
static void
|
oeth_tx(void)
|
oeth_tx(void)
|
{
|
{
|
Line 495... |
Line 404... |
/* Probably good to check for TX errors here */
|
/* Probably good to check for TX errors here */
|
|
|
/* set our test variable */
|
/* set our test variable */
|
tx_done = 1;
|
tx_done = 1;
|
|
|
printk("T%d",i);
|
|
|
|
}
|
}
|
}
|
}
|
return;
|
return;
|
}
|
}
|
|
|
Line 515... |
Line 422... |
if ((n % c) == 0)
|
if ((n % c) == 0)
|
return 0;
|
return 0;
|
return 1;
|
return 1;
|
}
|
}
|
|
|
int main ()
|
int
|
|
main ()
|
{
|
{
|
|
|
/* Initialise handler vector */
|
/* Initialise handler vector */
|
int_init();
|
int_init();
|
|
|
Line 527... |
Line 435... |
int_add(ETH0_IRQ, oeth_interrupt, 0);
|
int_add(ETH0_IRQ, oeth_interrupt, 0);
|
|
|
/* Enable interrupts in supervisor register */
|
/* Enable interrupts in supervisor register */
|
cpu_enable_user_interrupts();
|
cpu_enable_user_interrupts();
|
|
|
|
/* Enable CPU timer */
|
|
cpu_enable_timer();
|
|
|
rx_done = 0;
|
rx_done = 0;
|
|
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX in MODER */
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX in MODER */
|
|
|
|
|
#define NUM_PRIMES_TO_CHECK 1000
|
#define NUM_PRIMES_TO_CHECK 1000
|
|
#define RX_TEST_LENGTH_PACKETS 50
|
|
|
char prime_check_results[NUM_PRIMES_TO_CHECK];
|
char prime_check_results[NUM_PRIMES_TO_CHECK];
|
unsigned long num_to_check;
|
unsigned long num_to_check;
|
|
|
for(num_to_check=2;num_to_check<NUM_PRIMES_TO_CHECK;num_to_check++)
|
for(num_to_check=2;num_to_check<NUM_PRIMES_TO_CHECK;num_to_check++)
|
{
|
{
|
prime_check_results[num_to_check-2]
|
prime_check_results[num_to_check-2]
|
= (char) is_prime_number(num_to_check);
|
= (char) is_prime_number(num_to_check);
|
report(num_to_check | (0x1e<<24));
|
report(num_to_check | (0x1e<<24));
|
report(prime_check_results[num_to_check-2] | (0x2e<<24));
|
report(prime_check_results[num_to_check-2] | (0x2e<<24));
|
if (rx_done >= 255) // Check number of packets received, testbench
|
// Check number of packets received, testbench will hopefully send at
|
// will hopefully send at least 256 packets
|
// least this many packets
|
|
if (rx_done >= (RX_TEST_LENGTH_PACKETS - 1))
|
exit(0x8000000d);
|
exit(0x8000000d);
|
}
|
}
|
exit(0xbaaaaaad);
|
|
|
ethmac_halt();
|
|
|
|
exit(0x8000000d);
|
|
|
|
//exit(0xbaaaaaad);
|
|
|
|
return 0;
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|