URL
https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk
Subversion Repositories openrisc_me
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/orpsocv2/sw/tests/eth
- from Rev 408 to Rev 409
- ↔ Reverse comparison
Rev 408 → Rev 409
/board/eth-ping.c
File deleted
/board/eth-phy-mii.h
File deleted
/board/open-eth.h
File deleted
/board/ethmac-ping.c
0,0 → 1,1964
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Interrupt-driven Ethernet MAC test code for use on board //// |
//// //// |
//// Description //// |
//// Controllable ping program - also responds to ARP requests //// |
//// //// |
//// Author(s): //// |
//// - jb, jb@orsoc.se, with parts taken from Linux kernel //// |
//// open_eth driver. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
#include "cpu-utils.h" |
//#include "spr-defs.h" |
#include "board.h" |
#include "int.h" |
#include "uart.h" |
#include "ethmac.h" |
#include "printf.h" |
#include "eth-phy-mii.h" |
|
volatile unsigned tx_done; |
static int next_tx_buf_num; |
|
//#define OUR_IP_BYTES 0xc0,0xa8,0x64,0x9b // 192.168.100.155 |
//#define OUR_IP_LONG 0xc0a8649b |
|
//#define OUR_IP_BYTES 0xc0,0xa8,0x0,0x14 // 192.168.0.20 |
//#define OUR_IP_LONG 0xc0a80014 |
|
#define OUR_IP_BYTES 0xc0,0xa8,0x1,0x2 // 192.168.1.2 |
#define OUR_IP_LONG 0xc0a80102 |
|
static char our_ip[4] = {OUR_IP_BYTES}; |
|
//#define DEST_IP_BYTES 0xc0,0xa8,0x64,0x69 // 192 .168.100.105 |
#define DEST_IP_BYTES 0xc0,0xa8,0x01,0x08 // 192 .168.1.8 |
|
/* Functions in this file */ |
void ethmac_setup(void); |
void oeth_printregs(void); |
void ethphy_init(void); |
void oeth_dump_bds(); |
/* Interrupt functions */ |
void oeth_interrupt(void); |
static void oeth_rx(void); |
static void oeth_tx(void); |
|
#define NEVER_PRINT_PACKET 1 |
|
#define DISABLE_PRINTF 0 |
|
#if DISABLE_PRINTF==1 |
#undef printf |
#endif |
/* Let the ethernet packets use a space beginning here for buffering */ |
#define ETH_BUFF_BASE 0x01000000 |
|
|
#define RXBUFF_PREALLOC 1 |
#define TXBUFF_PREALLOC 1 |
//#undef RXBUFF_PREALLOC |
//#undef TXBUFF_PREALLOC |
|
/* The transmitter timeout |
*/ |
#define TX_TIMEOUT (2*HZ) |
|
/* Buffer number (must be 2^n) |
*/ |
#define OETH_RXBD_NUM 8 |
#define OETH_TXBD_NUM 8 |
#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1) |
#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1) |
|
/* Buffer size |
*/ |
#define OETH_RX_BUFF_SIZE 2048 |
#define OETH_TX_BUFF_SIZE 2048 |
|
/* OR32 Page size def */ |
#define PAGE_SHIFT 13 |
#define PAGE_SIZE (1UL << PAGE_SHIFT) |
|
/* How many buffers per page |
*/ |
#define OETH_RX_BUFF_PPGAE (PAGE_SIZE/OETH_RX_BUFF_SIZE) |
#define OETH_TX_BUFF_PPGAE (PAGE_SIZE/OETH_TX_BUFF_SIZE) |
|
/* How many pages is needed for buffers |
*/ |
#define OETH_RX_BUFF_PAGE_NUM (OETH_RXBD_NUM/OETH_RX_BUFF_PPGAE) |
#define OETH_TX_BUFF_PAGE_NUM (OETH_TXBD_NUM/OETH_TX_BUFF_PPGAE) |
|
/* Buffer size (if not XXBUF_PREALLOC |
*/ |
#define MAX_FRAME_SIZE 0x600 |
//#define MAX_FRAME_SIZE 2500 |
|
/* The buffer descriptors track the ring buffers. |
*/ |
struct oeth_private { |
//struct sk_buff* rx_skbuff[OETH_RXBD_NUM]; |
//struct sk_buff* tx_skbuff[OETH_TXBD_NUM]; |
|
unsigned short tx_next;/* Next buffer to be sent */ |
unsigned short tx_last;/* Next buffer to be checked if packet sent */ |
unsigned short tx_full;/* Buffer ring fuul indicator */ |
unsigned short rx_cur; /* Next buffer to be checked if packet received */ |
|
oeth_regs *regs; /* Address of controller registers. */ |
oeth_bd *rx_bd_base; /* Address of Rx BDs. */ |
oeth_bd *tx_bd_base; /* Address of Tx BDs. */ |
|
// struct net_device_stats stats; |
}; |
|
|
void oeth_printregs(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
printf("Oeth regs: Mode Register : 0x%lx\n", |
(unsigned long) regs->moder); /* Mode Register */ |
printf("Oeth regs: Interrupt Source Register 0x%lx\n", |
(unsigned long) regs->int_src); /* Interrupt Source Register */ |
printf("Oeth regs: Interrupt Mask Register 0x%lx\n", |
(unsigned long) regs->int_mask); /* Interrupt Mask Register */ |
printf("Oeth regs: Back to Bak Inter Packet Gap Register 0x%lx\n", |
(unsigned long) regs->ipgt); /* Back to Bak Inter Packet Gap Register */ |
printf("Oeth regs: Non Back to Back Inter Packet Gap Register 1 0x%lx\n", |
(unsigned long) regs->ipgr1); /* Non Back to Back Inter Packet Gap Register 1 */ |
printf("Oeth regs: Non Back to Back Inter Packet Gap Register 2 0x%lx\n", |
(unsigned long) regs->ipgr2); /* Non Back to Back Inter Packet Gap Register 2 */ |
printf("Oeth regs: Packet Length Register (min. and max.) 0x%lx\n", |
(unsigned long) regs->packet_len); /* Packet Length Register (min. and max.) */ |
printf("Oeth regs: Collision and Retry Configuration Register 0x%lx\n", |
(unsigned long) regs->collconf); /* Collision and Retry Configuration Register */ |
printf("Oeth regs: Transmit Buffer Descriptor Number Register 0x%lx\n", |
(unsigned long) regs->tx_bd_num); /* Transmit Buffer Descriptor Number Register */ |
printf("Oeth regs: Control Module Mode Register 0x%lx\n", |
(unsigned long) regs->ctrlmoder); /* Control Module Mode Register */ |
printf("Oeth regs: MII Mode Register 0x%lx\n", |
(unsigned long) regs->miimoder); /* MII Mode Register */ |
printf("Oeth regs: MII Command Register 0x%lx\n", |
(unsigned long) regs->miicommand); /* MII Command Register */ |
printf("Oeth regs: MII Address Register 0x%lx\n", |
(unsigned long) regs->miiaddress); /* MII Address Register */ |
printf("Oeth regs: MII Transmit Data Register 0x%lx\n", |
(unsigned long) regs->miitx_data); /* MII Transmit Data Register */ |
printf("Oeth regs: MII Receive Data Register 0x%lx\n", |
(unsigned long) regs->miirx_data); /* MII Receive Data Register */ |
printf("Oeth regs: MII Status Register 0x%lx\n", |
(unsigned long) regs->miistatus); /* MII Status Register */ |
printf("Oeth regs: MAC Individual Address Register 0 0x%lx\n", |
(unsigned long) regs->mac_addr0); /* MAC Individual Address Register 0 */ |
printf("Oeth regs: MAC Individual Address Register 1 0x%lx\n", |
(unsigned long) regs->mac_addr1); /* MAC Individual Address Register 1 */ |
printf("Oeth regs: Hash Register 0 0x%lx\n", |
(unsigned long) regs->hash_addr0); /* Hash Register 0 */ |
printf("Oeth regs: Hash Register 1 0x%lx\n", |
(unsigned long) regs->hash_addr1); /* Hash Register 1 */ |
|
} |
|
static int last_char; |
|
void spin_cursor(void) |
{ |
#ifdef RTLSIM |
return; |
#endif |
volatile unsigned int i; // So the loop doesn't get optimised away |
printf(" \r"); |
if (last_char == 0) |
printf("/"); |
else if (last_char == 1) |
printf("-"); |
else if (last_char == 2) |
printf("\\"); |
else if (last_char == 3) |
printf("|"); |
else if (last_char == 4) |
printf("/"); |
else if (last_char == 5) |
printf("-"); |
else if (last_char == 6) |
printf("\\"); |
else if (last_char == 7) |
{ |
printf("|"); |
last_char=-1; |
} |
|
last_char++; |
|
for(i=0;i<150000;i++); |
|
} |
|
#define PHYNUM 7 |
|
/* 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++) |
{ |
printf("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); |
|
printf("%x\n",regs->miirx_data); |
} |
} |
} |
|
|
/* Scan the MIIM bus for PHYs */ |
void scan_ethphy(unsigned int phynum) |
{ |
unsigned int regnum, i; |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
regs->miitx_data = 0; |
|
for (regnum=0;regnum<29;regnum++) |
{ |
printf("scan_ethphy%d: r%x ",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); |
|
printf("%x\n",regs->miirx_data); |
} |
|
} |
|
|
|
void ethmac_scanstatus(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
|
printf("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; |
printf("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(); |
//printf("\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_reset(int phynum) |
{ |
eth_mii_write(phynum, MII_BMCR, |
(eth_mii_read(phynum,MII_BMCR)|BMCR_RESET)); |
} |
|
|
void |
ethphy_reneg(int phynum) |
{ |
eth_mii_write(phynum, MII_BMCR, |
(eth_mii_read(phynum,MII_BMCR)|BMCR_ANRESTART)); |
} |
|
void |
ethphy_set_10mbit(int phynum) |
{ |
// Hardset PHY to just use 10Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr &= ~BMCR_ANENABLE; // Clear auto negotiate bit |
cr &= ~BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
void |
ethphy_set_100mbit(int phynum) |
{ |
// Hardset PHY to just use 10Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr &= !BMCR_ANENABLE; // Clear auto negotiate bit |
cr |= BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
void |
ethphy_set_autoneg(int phynum) |
{ |
// Hardset PHY to just use 10Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr |= BMCR_ANENABLE; // Clear auto negotiate bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
|
|
void m88e111_config_init(int phyaddr) |
{ |
short ctl; |
short adv; |
#if 1 |
// Soft reset |
eth_mii_write(phyaddr, MII_BMCR, BMCR_RESET); |
while(eth_mii_read(phyaddr, MII_BMCR) & BMCR_RESET); |
|
ctl = eth_mii_read(phyaddr, MII_BMCR); |
ctl &= ~(BMCR_SPD2); |
eth_mii_write(phyaddr, MII_BMCR, ctl); |
|
eth_mii_read(phyaddr, 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(phyaddr, MII_ADVERTISE, adv); |
// Disable gigabit??? |
adv = eth_mii_read(phyaddr, MII_M1011_PHY_SPEC_CONTROL); |
adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | |
MII_1000BASETCONTROL_HALFDUPLEXCAP); |
eth_mii_write(phyaddr, MII_M1011_PHY_SPEC_CONTROL, adv); |
// Even more disable gigabit?! |
adv = eth_mii_read(phyaddr, MII_CTRL1000); |
adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); |
eth_mii_write(phyaddr, MII_CTRL1000, adv); |
|
// Restart autoneg |
printf("Resetting phy...\n"); |
eth_mii_write(phyaddr, MII_BMCR, BMCR_RESET); |
ctl = eth_mii_read(phyaddr, MII_BMCR); |
ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); |
eth_mii_write(phyaddr, MII_BMCR, ctl); |
#endif |
|
#if 0 |
// Adapted from kernel: drivers/net/phy/marvell.c |
// Soft reset |
eth_mii_write(phyaddr, MII_BMCR, BMCR_RESET); |
|
eth_mii_write(phyaddr, 0x1d, 0x1f); |
eth_mii_write(phyaddr, 0x1e, 0x200c); |
eth_mii_write(phyaddr, 0x1d, 0x5); |
eth_mii_write(phyaddr, 0x1e, 0); |
eth_mii_write(phyaddr, 0x1e, 0x100); |
#define MII_M1011_PHY_SCR 0x10 |
#define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 |
eth_mii_write(phyaddr, MII_M1011_PHY_SCR, |
MII_M1011_PHY_SCR_AUTO_CROSS); |
#define MII_M1111_PHY_LED_CONTROL 0x18 |
#define MII_M1111_PHY_LED_DIRECT 0x4100 |
eth_mii_write(phyaddr, MII_M1111_PHY_LED_CONTROL, |
MII_M1111_PHY_LED_DIRECT); |
|
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | |
ADVERTISE_PAUSE_ASYM); |
adv |= ADVERTISE_10HALF; |
adv |= ADVERTISE_10FULL; |
adv |= ADVERTISE_100HALF; |
adv |= ADVERTISE_100FULL; |
adv |= ADVERTISE_PAUSE_CAP; |
adv |= ADVERTISE_PAUSE_ASYM; |
eth_mii_write(phyaddr, MII_ADVERTISE, adv); |
|
|
ctl = eth_mii_read(phyaddr, MII_BMCR); |
ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); |
eth_mii_write(phyaddr, MII_BMCR, ctl); |
|
#endif |
|
#if 0 |
ctl = eth_mii_read(phyaddr, MII_BMCR); |
ctl &= ~(BMCR_ANENABLE); // Disable autoneg... |
// Try forcing config |
ctl = BMCR_SPEED100 | BMCR_FULLDPLX; |
eth_mii_write(phyaddr, MII_BMCR, ctl); |
|
|
|
|
#endif |
|
} |
|
|
void ethphy_print_status(int phyaddr) |
{ |
short regnum, ctl; |
int bitnum; |
int bitset; |
printf("phyaddr %d\n",phyaddr); |
for (regnum = 0;regnum<16; regnum++) |
{ |
ctl = eth_mii_read(phyaddr, regnum); |
printf("\treg 0x%x: ", regnum); |
switch(regnum) |
{ |
case 0: |
printf("basic control\n"); |
for(bitnum = 0; bitnum<16;bitnum++) |
{ |
bitset = !!(ctl & (1<<bitnum)); |
switch(bitnum) |
{ |
case 0: |
printf("\t\tbit%d:\t%d \t(disable transmitter)\n",bitnum,bitset); |
break; |
case 6: |
printf("\t\tbit%d:\t%d \t(msb speed (1000))\n",bitnum,bitset); |
break; |
case 7: |
printf("\t\tbit%d:\t%d \t(collision test)\n",bitnum,bitset); |
break; |
case 8: |
printf("\t\tbit%d:\t%d \t(duplex mode)\n",bitnum,bitset); |
break; |
case 9: |
printf("\t\tbit%d:\t%d \t(restart autoneg)\n",bitnum,bitset); |
break; |
case 10: |
printf("\t\tbit%d:\t%d \t(isloate)\n",bitnum,bitset); |
break; |
case 11: |
printf("\t\tbit%d:\t%d \t(power down)\n",bitnum,bitset); |
break; |
case 12: |
printf("\t\tbit%d:\t%d \t(autoneg enable)\n",bitnum,bitset); |
break; |
case 13: |
printf("\t\tbit%d:\t%d \t(speed select)\n",bitnum,bitset); |
break; |
case 14: |
printf("\t\tbit%d:\t%d \t(loop back)\n",bitnum,bitset); |
break; |
case 15: |
printf("\t\tbit%d:\t%d \t(reset)\n",bitnum,bitset); |
break; |
default: |
break; |
} |
} |
break; |
case 1: |
printf("basic status\n"); |
for(bitnum = 0; bitnum<16;bitnum++) |
{ |
bitset = !!(ctl & (1<<bitnum)); |
switch(bitnum) |
{ |
case 0: |
printf("\t\tbit%d:\t%d \t(extend capability)\n",bitnum,bitset); |
break; |
case 1: |
printf("\t\tbit%d:\t%d \t(jabber detect)\n",bitnum,bitset); |
break; |
case 2: |
printf("\t\tbit%d:\t%d \t(link status)\n",bitnum,bitset); |
break; |
case 3: |
printf("\t\tbit%d:\t%d \t(autoneg capability)\n",bitnum,bitset); |
break; |
case 4: |
printf("\t\tbit%d:\t%d \t(remote fault)\n",bitnum,bitset); |
break; |
case 5: |
printf("\t\tbit%d:\t%d \t(autoneg complete)\n",bitnum,bitset); |
break; |
case 6: |
printf("\t\tbit%d:\t%d \t(no preamble)\n",bitnum,bitset); |
break; |
case 11: |
printf("\t\tbit%d:\t%d \t(10base-t half dup.)\n",bitnum,bitset); |
break; |
case 12: |
printf("\t\tbit%d:\t%d \t(10base-t full dup.)\n",bitnum,bitset); |
break; |
case 13: |
printf("\t\tbit%d:\t%d \t(100base-t half dup.)\n",bitnum,bitset); |
break; |
case 14: |
printf("\t\tbit%d:\t%d \t(100base-t full dup.)\n",bitnum,bitset); |
break; |
case 15: |
printf("\t\tbit%d:\t%d \t(100base-t4)\n",bitnum,bitset); |
break; |
default: |
break; |
|
} |
} |
break; |
case 4: |
printf("autoneg advertise reg\n"); |
for(bitnum = 0; bitnum<16;bitnum++) |
{ |
bitset = !!(ctl & (1<<bitnum)); |
switch(bitnum) |
{ |
case 5: |
printf("\t\tbit%d:\t%d \t(10mbps cap.)\n",bitnum,bitset); |
break; |
case 6: |
printf("\t\tbit%d:\t%d \t(10base-5 full dup. cap.)\n",bitnum,bitset); |
break; |
case 7: |
printf("\t\tbit%d:\t%d \t(100base-tx cap.)\n",bitnum,bitset); |
break; |
case 8: |
printf("\t\tbit%d:\t%d \t(100base-tx full dup. cap.)\n",bitnum,bitset); |
break; |
case 9: |
printf("\t\tbit%d:\t%d \t(100base-t4 cap.)\n",bitnum,bitset); |
break; |
case 10: |
printf("\t\tbit%d:\t%d \t(pause cap.)\n",bitnum,bitset); |
break; |
case 13: |
printf("\t\tbit%d:\t%d \t(remote fault sup.)\n",bitnum,bitset); |
break; |
case 15: |
printf("\t\tbit%d:\t%d \t(next page cap.)\n",bitnum,bitset); |
break; |
|
default: |
break; |
} |
} |
break; |
case 5: |
printf("autoneg link partner ability\n"); |
for(bitnum = 0; bitnum<16;bitnum++) |
{ |
bitset = !!(ctl & (1<<bitnum)); |
switch(bitnum) |
{ |
case 5: |
printf("\t\tbit%d:\t%d \t(10mbps cap.)\n",bitnum,bitset); |
break; |
case 6: |
printf("\t\tbit%d:\t%d \t(10base-5 full dup. cap.)\n",bitnum,bitset); |
break; |
case 7: |
printf("\t\tbit%d:\t%d \t(100base-tx cap.)\n",bitnum,bitset); |
break; |
case 8: |
printf("\t\tbit%d:\t%d \t(100base-tx full dup. cap.)\n",bitnum,bitset); |
break; |
case 9: |
printf("\t\tbit%d:\t%d \t(100base-t4 cap.)\n",bitnum,bitset); |
break; |
case 10: |
printf("\t\tbit%d:\t%d \t(pause cap bit0)\n",bitnum,bitset); |
break; |
case 11: |
printf("\t\tbit%d:\t%d \t(pause cap bit1)\n",bitnum,bitset); |
break; |
|
case 13: |
printf("\t\tbit%d:\t%d \t(remote fault sup.)\n",bitnum,bitset); |
break; |
case 14: |
printf("\t\tbit%d:\t%d \t(acknowledge)\n",bitnum,bitset); |
break; |
case 15: |
printf("\t\tbit%d:\t%d \t(next page cap.)\n",bitnum,bitset); |
break; |
|
default: |
break; |
} |
} |
break; |
case 9: |
printf("1000mbit advertise\n"); |
for(bitnum = 0; bitnum<16;bitnum++) |
{ |
bitset = !!(ctl & (1<<bitnum)); |
switch(bitnum) |
{ |
case 8: |
printf("\t\tbit%d:\t%d \t(1000base-t half dup)\n",bitnum,bitset); |
break; |
case 9: |
printf("\t\tbit%d:\t%d \t(1000base-t full dup)\n",bitnum,bitset); |
break; |
default: |
break; |
} |
} |
break; |
case 0xf: |
printf("extended status\n"); |
for(bitnum = 0; bitnum<16;bitnum++) |
{ |
bitset = !!(ctl & (1<<bitnum)); |
switch(bitnum) |
{ |
case 12: |
printf("\t\tbit%d:\t%d \t(1000mb half dup.)\n",bitnum,bitset); |
break; |
case 13: |
printf("\t\tbit%d:\t%d \t(1000mb full dup.)\n",bitnum,bitset); |
break; |
default: |
break; |
} |
} |
break; |
/* case 1: |
for(bitnum = 0; bitnum<16;bitnum++) |
{ |
bitset = !!(ctl & (1<<bitnum)); |
switch(bitnum) |
{ |
case 0: |
printf("\t\tbit%d:\t%d \t()\n",bitnum,bitset); |
break; |
default: |
break; |
} |
} |
break; |
*/ |
default: |
printf("ignored\n"); |
break; |
} |
} |
|
|
|
} |
|
void ethphy_init(void) |
{ |
|
/* Init the Alaska 88E1111 Phy */ |
char alaska88e1111_ml501_phynum = 0x7; |
m88e111_config_init(alaska88e1111_ml501_phynum); |
|
return; |
|
/* 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 |
printf("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); |
|
printf("\nOeth: PHY control reg: 0x%.4x\n", |
eth_mii_read(alaska88e1111_ml501_phynum, MII_BMCR)); |
printf("Oeth: PHY control reg: 0x%.4x\n", |
eth_mii_read(alaska88e1111_ml501_phynum, MII_BMSR)); |
printf("Oeth: PHY id0: 0x%.4x\n", |
eth_mii_read(alaska88e1111_ml501_phynum, MII_PHYSID1)); |
printf("Oeth: PHY id1: 0x%.4x\n", |
eth_mii_read(alaska88e1111_ml501_phynum, MII_PHYSID2)); |
printf("Oeth: PHY adv: 0x%.4x\n", |
eth_mii_read(alaska88e1111_ml501_phynum, MII_ADVERTISE)); |
printf("Oeth: PHY lpa: 0x%.4x\n", |
eth_mii_read(alaska88e1111_ml501_phynum, MII_LPA)); |
printf("Oeth: PHY physpec: 0x%.4x\n", |
eth_mii_read(alaska88e1111_ml501_phynum, MII_M1011_PHY_SPEC_CONTROL)); |
printf("Oeth: PHY expansion: 0x%.4x\n", |
eth_mii_read(alaska88e1111_ml501_phynum, MII_EXPANSION )); |
printf("Oeth: PHY ctrl1000: 0x%.4x\n", |
eth_mii_read(alaska88e1111_ml501_phynum, MII_CTRL1000)); |
printf("Oeth: PHY stat1000: 0x%.4x\n", |
eth_mii_read(alaska88e1111_ml501_phynum, MII_STAT1000)); |
printf("Oeth: PHY estatus: 0x%.4x\n", |
eth_mii_read(alaska88e1111_ml501_phynum, MII_ESTATUS)); |
|
|
} |
|
|
void ethmac_setup(void) |
{ |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/*printf("\nbefore reset\n\n"); |
oeth_printregs();*/ |
|
/* Reset MII mode module */ |
regs->miimoder = OETH_MIIMODER_RST; /* MII Reset ON */ |
regs->miimoder &= ~OETH_MIIMODER_RST; /* MII Reset OFF */ |
regs->miimoder = 0x64; /* Clock divider for MII Management interface */ |
|
/* Reset the controller. |
*/ |
regs->moder = OETH_MODER_RST; /* Reset ON */ |
regs->moder &= ~OETH_MODER_RST; /* Reset OFF */ |
|
//printf("\nafter reset\n\n"); |
//oeth_printregs(); |
|
/* Setting TXBD base to OETH_TXBD_NUM. |
*/ |
regs->tx_bd_num = OETH_TXBD_NUM; |
|
|
/* Set min/max packet length |
*/ |
//regs->packet_len = 0x00400600; |
regs->packet_len = (0x0040 << 16) | (MAX_FRAME_SIZE & 0xffff); |
|
/* Set IPGT register to recomended value |
*/ |
regs->ipgt = 0x12; |
|
/* Set IPGR1 register to recomended value |
*/ |
regs->ipgr1 = 0x0000000c; |
|
/* Set IPGR2 register to recomended value |
*/ |
regs->ipgr2 = 0x00000012; |
|
/* Set COLLCONF register to recomended value |
*/ |
regs->collconf = 0x000f003f; |
|
/* Set control module mode |
*/ |
#if 0 |
regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW; |
#else |
regs->ctrlmoder = 0; |
#endif |
|
/* Clear MIIM registers */ |
regs->miitx_data = 0; |
regs->miiaddress = 0; |
regs->miicommand = 0; |
|
regs->mac_addr1 = ETH_MACADDR0 << 8 | ETH_MACADDR1; |
regs->mac_addr0 = ETH_MACADDR2 << 24 | ETH_MACADDR3 << 16 | ETH_MACADDR4 << 8 | ETH_MACADDR5; |
|
/* Clear all pending interrupts |
*/ |
regs->int_src = 0xffffffff; |
|
/* Promisc, IFG, CRCEn |
*/ |
regs->moder |= OETH_MODER_PRO | OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN | OETH_MODER_FULLD; |
|
/* Enable interrupt sources. |
*/ |
|
regs->int_mask = OETH_INT_MASK_TXB | |
OETH_INT_MASK_TXE | |
OETH_INT_MASK_RXF | |
OETH_INT_MASK_RXE | |
OETH_INT_MASK_BUSY | |
OETH_INT_MASK_TXC | |
OETH_INT_MASK_RXC; |
#ifndef RTLSIM |
printf("\nafter config\n\n"); |
oeth_printregs(); |
#endif |
// Buffer setup stuff |
volatile oeth_bd *tx_bd, *rx_bd; |
int i,j,k; |
|
/* Initialize TXBD pointer |
*/ |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
|
/* Initialize RXBD pointer |
*/ |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
/* Preallocated ethernet buffer setup */ |
unsigned long mem_addr = ETH_BUFF_BASE; /* Defined at top */ |
|
/* Setup for TX buffers*/ |
for(i = 0, k = 0; i < OETH_TX_BUFF_PAGE_NUM; i++) { |
for(j = 0; j < OETH_TX_BUFF_PPGAE; j++, k++) { |
//tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ; |
tx_bd[k].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; |
tx_bd[k].addr = mem_addr; |
mem_addr += OETH_TX_BUFF_SIZE; |
} |
} |
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; |
|
/* Setup for RX buffers */ |
for(i = 0, k = 0; i < OETH_RX_BUFF_PAGE_NUM; i++) { |
for(j = 0; j < OETH_RX_BUFF_PPGAE; j++, k++) { |
rx_bd[k].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; /* Enable interrupt */ |
rx_bd[k].addr = mem_addr; |
mem_addr += OETH_RX_BUFF_SIZE; |
} |
} |
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; /* Final buffer has wrap bit set */ |
|
/* Enable receiver and transmiter |
*/ |
regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN; |
|
next_tx_buf_num = 0; // init tx buffer pointer |
|
return; |
} |
|
void |
ethmac_togglehugen(void) |
{ |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
regs->moder ^= OETH_MODER_HUGEN; // Toggle huge packet enable |
|
if (regs->moder & OETH_MODER_HUGEN) // If we just enabled huge packets |
regs->packet_len = (0x0040 << 16) | (((64*1024)-4) & 0xffff); |
else |
// back to normal |
regs->packet_len = (0x0040 << 16) | (MAX_FRAME_SIZE & 0xffff); |
|
return; |
|
} |
|
void |
oeth_reset_tx_bd_pointer(void) |
{ |
printf("Resetting TX BD pointer\n"); |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
// Toggle TXEN bit, resetting TX BD number |
regs->moder &= OETH_MODER_TXEN; |
regs->moder |= OETH_MODER_TXEN; |
|
next_tx_buf_num = 0; // init tx buffer pointer |
|
} |
|
|
|
/* Find the next available transmit buffer */ |
struct oeth_bd* get_next_tx_bd() |
{ |
|
int i; |
volatile oeth_bd *tx_bd; |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* Go through the TX buffs, search for unused one */ |
for(i = next_tx_buf_num; i < OETH_TXBD_NUM; i++) { |
|
if(!(tx_bd[i].len_status & OETH_TX_BD_READY)) /* Looking for buffer NOT ready for transmit. ie we can manipulate it */ |
{ |
#if NEVER_PRINT_PACKET==0 |
printf("Oeth: Using TX_bd at 0x%lx\n",(unsigned long)&tx_bd[i]); |
#endif |
if (next_tx_buf_num == OETH_TXBD_NUM-1) next_tx_buf_num = 0; |
else next_tx_buf_num++; |
|
return (struct oeth_bd*) &tx_bd[i]; |
} |
|
if ((i == OETH_TXBD_NUM-1) && (next_tx_buf_num != 0)) |
i = 0; |
|
} |
|
printf("No free tx buffers\n"); |
/* Set to null our returned buffer */ |
tx_bd = (volatile oeth_bd *) 0; |
return (struct oeth_bd*) tx_bd; |
|
} |
|
/* print packet contents */ |
static void |
oeth_print_packet(unsigned long add, int len) |
{ |
#if NEVER_PRINT_PACKET==1 |
return; |
#endif |
|
int truncate = (len > 256); |
int length_to_print = truncate ? 256 : len; |
|
int i; |
printf("\nipacket: add = %lx len = %d\n", add, len); |
for(i = 0; i < length_to_print; i++) { |
if(!(i % 8)) |
printf(" "); |
if(!(i % 16)) |
printf("\n"); |
printf(" %.2x", *(((unsigned char *)add) + i)); |
|
} |
printf("\n"); |
|
if (truncate) |
printf("\ttruncated....\n"); |
|
} |
|
/* Setup buffer descriptors with data */ |
/* length is in BYTES */ |
void tx_packet(void* data, int length) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
volatile int i; |
|
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
tx_bd = (struct oeth_bd*) &tx_bd[next_tx_buf_num]; |
|
/*if((tx_bd = (volatile oeth_bd *) get_next_tx_bd()) == NULL) |
{ |
printf("No more TX buffers available\n"); |
return; |
} |
*/ |
#if NEVER_PRINT_PACKET==0 |
printf("Oeth: Using TX_bd buffer address: 0x%lx\n",(unsigned long) tx_bd->addr); |
#endif |
|
/* Clear all of the status flags. |
*/ |
tx_bd->len_status &= ~OETH_TX_BD_STATS; |
|
/* If the frame is short, tell CPM to pad it. |
*/ |
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ |
if (length <= ETH_ZLEN) |
tx_bd->len_status |= OETH_TX_BD_PAD; |
else |
tx_bd->len_status &= ~OETH_TX_BD_PAD; |
|
//printf("Oeth: Copying %d bytes from 0x%lx to TX_bd buffer at 0x%lx\n",length,(unsigned long) data,(unsigned long) tx_bd->addr); |
|
/* Copy the data into the transmit buffer, byte at a time */ |
char* data_p = (char*) data; |
char* data_b = (char*) tx_bd->addr; |
for(i=0;i<length;i++) |
{ |
data_b[i] = data_p[i]; |
} |
//printf("Oeth: Data copied to buffer\n"); |
|
/* Set the length of the packet's data in the buffer descriptor */ |
tx_bd->len_status = (tx_bd->len_status & 0x0000ffff) | |
((length&0xffff) << 16); |
|
//oeth_print_packet(tx_bd->addr, (tx_bd->len_status >> 16)); |
|
/* Send it on its way. Tell controller its ready, interrupt when sent |
* and to put the CRC on the end. |
*/ |
tx_bd->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_CRC | OETH_TX_BD_IRQ); |
|
next_tx_buf_num = (next_tx_buf_num + 1) & OETH_TXBD_NUM_MASK; |
|
return; |
|
|
} |
|
/* enable RX, loop waiting for arrived packets and print them out */ |
void oeth_monitor_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Set RXEN in MAC MODER */ |
regs->moder = OETH_MODER_RXEN | regs->moder; |
|
|
volatile oeth_bd *rx_bd; |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
volatile int i; |
|
for(i=0;i<OETH_RXBD_NUM;i++) |
{ |
if (!(rx_bd[i].len_status & OETH_RX_BD_EMPTY)) /* Not empty */ |
{ |
// Something in this buffer! |
printf("Oeth: RX in buf %d - len_status: 0x%lx\n",i, rx_bd[i].len_status); |
oeth_print_packet(rx_bd[i].addr, rx_bd[i].len_status >> 16); |
/* Clear recieved bit */ |
rx_bd[i].len_status |= OETH_RX_BD_EMPTY; |
printf("\t end of packet\n\n"); |
} |
} |
} |
|
/* Print out all buffer descriptors */ |
void oeth_dump_bds() |
{ |
unsigned long* bd_base = (unsigned long*) OETH_BD_BASE; |
|
int i; |
for(i=0;i<OETH_TXBD_NUM;i++) |
{ |
printf("oeth: tx_bd%d: len_status: %lx ",i,*bd_base++); |
printf("addr: %lx\n", *bd_base++); |
} |
|
for(i=0;i<OETH_RXBD_NUM;i++) |
{ |
printf("oeth: rx_bd%d: len_status: %lx ",i,*bd_base++); |
printf("addr: %lx\n", *bd_base++); |
} |
|
} |
|
|
|
char broadcast_ping_packet[] = { |
0xff,0xff,0xff,0xff,0xff,0xff, /*SRC MAC*/ |
0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, /*SRC MAC*/ |
0x08,0x00, |
0x45, |
0x00, |
// 0x00,0x54, /* length */ |
0x01,0x1c, /* length */ |
0x00,0x00, |
0x40, |
0x00, |
0x40, |
0x01, |
0xee,0xf5, |
OUR_IP_BYTES, /* Source IP */ |
0xc0,0xa8,0x64,0xff, /* Dest. IP */ |
/* ICMP Message body */ |
0x08,0x00,0x7d,0x65,0xa7,0x20,0x00,0x01,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, |
15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39, |
40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, |
65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89, |
90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110, |
111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129, |
130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148, |
149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167, |
168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, |
187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205, |
206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224, |
225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243, |
244,245,246,247,248,249,250,251,252,253,254,255}; |
|
|
char big_ping_packet[] = { |
0x00, 0x24, 0xe8, 0x91, 0x7c, 0x0d, /*DST MAC*/ |
//0xff,0xff,0xff,0xff,0xff,0xff, /*SRC MAC*/ |
0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, /*SRC MAC*/ |
0x08,0x00, |
0x45, |
0x00, |
0x05,0xdc, /* length */ |
0x00,0x00, |
0x40, |
0x00, |
0x40, |
0x01, |
0xea,0xcb, /* Header checksum */ |
OUR_IP_BYTES, /* Source IP */ |
DEST_IP_BYTES, /* Dest. IP */ |
/* ICMP Message body */ |
0x08,0x00, /* Type */ |
0x04,0x48, /* ICMP checksum */ |
0x02,0x00, /* Identifier */ |
0x3a,0x00, /* sequence number */ |
0x61,0x62,0x63,0x64,0x65,0x66,0x67, |
0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76, |
0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e, |
0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66, |
0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75, |
0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d, |
0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65, |
0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74, |
0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c, |
0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64, |
0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73, |
0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b, |
0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63, |
0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72, |
0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a, |
0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62, |
0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71, |
0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69, |
0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61, |
0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70, |
0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68, |
0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77, |
0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, |
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67, |
0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76, |
0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e, |
0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66, |
0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75, |
0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d, |
0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65, |
0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74, |
0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c, |
0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64, |
0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73, |
0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b, |
0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63, |
0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72, |
0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a, |
0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62, |
0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71, |
0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69, |
0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61, |
0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70, |
0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68, |
0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77, |
0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, |
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67, |
0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76, |
0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e, |
0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66, |
0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75, |
0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d, |
0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65, |
0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74, |
0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c, |
0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64, |
0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73, |
0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b, |
0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63, |
0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72, |
0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a, |
0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62, |
0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71, |
0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69, |
0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61, |
0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70, |
0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68, |
0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77, |
0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, |
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67, |
0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76, |
0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e, |
0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66, |
0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75, |
0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d, |
0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65, |
0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74, |
0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c, |
0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64, |
0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73, |
0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b, |
0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63, |
0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72, |
0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a, |
0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62, |
0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71, |
0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69, |
0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61, |
0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70, |
0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68, |
0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77, |
0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, |
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67, |
0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76, |
0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e, |
0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66, |
0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75, |
0x76,0x77,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d, |
0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77}; |
|
|
/* This should be 98 bytes big */ |
char ping_packet[] = { |
0x00, 0x24, 0xe8, 0x91, 0x7c, 0x0d, /*DST MAC*/ |
//0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*DST MAC*/ |
0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, /*SRC MAC*/ |
0x08, 0x00, /*TYPE*/ |
/* IP */ |
0x45, /* Version, header length*/ |
0x00, /* Differentiated services field */ |
0x00, 0x54, /* Total length */ |
0x00, 0x00, /* Identification */ |
0x40, /* Flags */ |
0x00, /* Fragment offset */ |
0x40, /* Time to live */ |
0x01, /* Protocol (0x01 = ICMP */ |
0xf0, 0x53, /* Header checksum */ |
//0xc0, 0xa8, 0x64, 0xDE, /* Source IP */ |
OUR_IP_BYTES, /* Source IP */ |
DEST_IP_BYTES, /* Dest. IP */ |
/* ICMP Message body */ |
0x08, 0x00, 0x9a, 0xd4, 0xc8, 0x18, 0x00, 0x01, 0xd9, 0x8c, 0x54, |
0x4a, 0x7b, 0x37, 0x01, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, |
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, |
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, |
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, |
0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 |
}; |
|
void send_test_packet() |
{ |
|
/*Send packet */ |
//tx_packet((void*) ping_packet, 102); |
tx_packet((void*) broadcast_ping_packet, 102); |
|
} |
|
|
/* The interrupt handler. |
*/ |
void |
oeth_interrupt(void) |
{ |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
uint int_events; |
int serviced; |
|
serviced = 0; |
|
/* Get the interrupt events that caused us to be here. |
*/ |
int_events = regs->int_src; |
regs->int_src = int_events; |
|
|
/* Indicate busy */ |
if (int_events & OETH_INT_BUSY) |
{ |
printf("\tBusy flag\n"); |
/* |
printf("\n=tx_ | %x | %x | %x | %x | %x | %x | %x | %x\n", |
((oeth_bd *)(OETH_BD_BASE))->len_status, |
((oeth_bd *)(OETH_BD_BASE+8))->len_status, |
((oeth_bd *)(OETH_BD_BASE+16))->len_status, |
((oeth_bd *)(OETH_BD_BASE+24))->len_status, |
((oeth_bd *)(OETH_BD_BASE+32))->len_status, |
((oeth_bd *)(OETH_BD_BASE+40))->len_status, |
((oeth_bd *)(OETH_BD_BASE+48))->len_status, |
((oeth_bd *)(OETH_BD_BASE+56))->len_status); |
*/ |
printf("=rx_ | %x | %x | %x | %x | %x | %x | %x | %x\n", |
((oeth_bd *)(OETH_BD_BASE+64))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+8))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+16))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+24))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+32))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+40))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+48))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+56))->len_status); |
|
printf("=int | txb %d | txe %d | rxb %d | rxe %d | busy %d\n", |
(int_events & OETH_INT_TXB) > 0, |
(int_events & OETH_INT_TXE) > 0, |
(int_events & OETH_INT_RXF) > 0, |
(int_events & OETH_INT_RXE) > 0, |
(int_events & OETH_INT_BUSY) > 0); |
} |
|
/* Handle receive event in its own function. |
*/ |
if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) { |
serviced |= 0x1; |
oeth_rx(); |
} |
|
/* Handle transmit event in its own function. |
*/ |
if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) { |
serviced |= 0x2; |
oeth_tx(); |
serviced |= 0x2; |
|
} |
|
return; |
} |
|
// ARP stuff |
|
typedef unsigned long IPaddr_t; |
|
/* |
* Ethernet header |
*/ |
typedef struct { |
unsigned char et_dest[6]; /* Destination node */ |
unsigned char et_src[6]; /* Source node */ |
unsigned short et_protlen; /* Protocol or length */ |
unsigned char et_dsap; /* 802 DSAP */ |
unsigned char et_ssap; /* 802 SSAP */ |
unsigned char et_ctl; /* 802 control */ |
unsigned char et_snap1; /* SNAP */ |
unsigned char et_snap2; |
unsigned char et_snap3; |
unsigned short et_prot; /* 802 protocol */ |
} Ethernet_t; |
|
#define ETHER_HDR_SIZE 14 /* Ethernet header size */ |
#define E802_HDR_SIZE 22 /* 802 ethernet header size */ |
#define PROT_IP 0x0800 /* IP protocol */ |
#define PROT_ARP 0x0806 /* IP ARP protocol */ |
#define PROT_RARP 0x8035 /* IP ARP protocol */ |
|
|
/* |
* Internet Protocol (IP) header. |
*/ |
typedef struct { |
unsigned char ip_hl_v; /* header length and version*/ |
unsigned char ip_tos; /* type of service */ |
unsigned short ip_len; /* total length */ |
unsigned short ip_id; /* identification */ |
unsigned short ip_off; /* fragment offset field */ |
unsigned char ip_ttl; /* time to live */ |
unsigned char ip_p; /* protocol */ |
unsigned short ip_sum; /* checksum */ |
IPaddr_t ip_src; /* Source IP address */ |
IPaddr_t ip_dst; /* Destination IP address */ |
unsigned short udp_src; /* UDP source port */ |
unsigned short udp_dst; /* UDP destination port */ |
unsigned short udp_len; /* Length of UDP packet */ |
unsigned short udp_xsum; /* Checksum */ |
} IP_t; |
|
#define IP_HDR_SIZE_NO_UDP (sizeof (IP_t) - 8) |
#define IP_HDR_SIZE (sizeof (IP_t)) |
|
#define IPPROTO_ICMP 1 /* Internet Control Message Protocol */ |
#define IPPROTO_UDP 17 /* User Datagram Protocol */ |
|
|
/* |
* ICMP stuff (just enough to handle (host) redirect messages) |
*/ |
#define ICMP_REDIRECT 5 /* Redirect (change route) */ |
|
/* Codes for REDIRECT. */ |
#define ICMP_REDIR_NET 0 /* Redirect Net */ |
#define ICMP_REDIR_HOST 1 /* Redirect Host */ |
|
#define ICMP_TYPE_ECHO_REPLY 0x00 |
#define ICMP_TYPE_ECHO_REQ 0x08 |
|
unsigned char ip_reply_packet[0x600] __attribute__ ((aligned (4))); // Save space for a full ICMP reply packet |
|
typedef struct { |
unsigned char type; |
unsigned char code; |
unsigned short checksum; |
union { |
struct { |
unsigned short id; |
unsigned short sequence; |
} echo; |
unsigned long gateway; |
struct { |
unsigned short __unused; |
unsigned short mtu; |
} frag; |
} un; |
} ICMP_t; |
|
// 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); |
|
} |
|
void |
packet_check_icmp_header(void * pkt) |
{ |
Ethernet_t * eth_pkt; |
IP_t * ip; |
ICMP_t * icmp; |
|
unsigned int zero = 0; |
|
eth_pkt = (Ethernet_t *) pkt; |
|
// Check it's for our MAC |
char* eth_pkt_dst_mac = (char*) eth_pkt; |
if (!( |
((eth_pkt_dst_mac[0] == (char) ETH_MACADDR0) && // Either our MAC |
(eth_pkt_dst_mac[1] == (char) ETH_MACADDR1) && |
(eth_pkt_dst_mac[2] == (char) ETH_MACADDR2) && |
(eth_pkt_dst_mac[3] == (char) ETH_MACADDR3) && |
(eth_pkt_dst_mac[4] == (char) ETH_MACADDR4) && |
(eth_pkt_dst_mac[5] == (char) ETH_MACADDR5)) || |
((eth_pkt_dst_mac[0] == (char) 0xff) && // or broadcast MAC |
(eth_pkt_dst_mac[1] == (char) 0xff) && |
(eth_pkt_dst_mac[2] == (char) 0xff) && |
(eth_pkt_dst_mac[3] == (char) 0xff) && |
(eth_pkt_dst_mac[4] == (char) 0xff) && |
(eth_pkt_dst_mac[5] == (char) 0xff)) |
) |
) |
|
return ; |
|
// Check it's an IP packet |
if (!(eth_pkt->et_protlen == PROT_IP)) |
return ; |
|
pkt += ETHER_HDR_SIZE; // Skip eth header stuff |
|
ip = (IP_t*) pkt; |
|
// Check if this is an ICMP packet |
if (!(ip->ip_p == IPPROTO_ICMP)) |
return ; |
|
// Check if this is for our IP, get pointer to the DST IP part of IP header |
// which is end of IP section - 4 bytes |
char * internet_protocol_adr = ((unsigned char*)ip + (IP_HDR_SIZE_NO_UDP-4)); |
|
if (!((internet_protocol_adr[0] == our_ip[0]) && |
(internet_protocol_adr[1] == our_ip[1]) && |
(internet_protocol_adr[2] == our_ip[2]) && |
(internet_protocol_adr[3] == our_ip[3]))) |
return ; |
|
pkt += IP_HDR_SIZE_NO_UDP; |
|
icmp = (ICMP_t*) pkt; |
|
// Currently we only support replying to echo (ping) requests |
|
// Check for ICMP echo request type |
if (!(icmp->type == ICMP_TYPE_ECHO_REQ)) |
return; |
|
// Go ahead and construct a response packet |
// Setup pointers |
Ethernet_t * reply_pkt = (Ethernet_t *) &ip_reply_packet[0]; |
IP_t * reply_IP = (IP_t*) &ip_reply_packet[ETHER_HDR_SIZE]; |
ICMP_t * reply_ICMP = (ICMP_t*) &ip_reply_packet[ETHER_HDR_SIZE+ |
IP_HDR_SIZE_NO_UDP]; |
// Setup Ethernet header |
// Copy source MAC to destination MAC |
memcpy( (void*)&reply_pkt->et_dest , (void*)ð_pkt->et_src , 6); |
reply_pkt->et_src[0] = ETH_MACADDR0; |
reply_pkt->et_src[1] = ETH_MACADDR1; |
reply_pkt->et_src[2] = ETH_MACADDR2; |
reply_pkt->et_src[3] = ETH_MACADDR3; |
reply_pkt->et_src[4] = ETH_MACADDR4; |
reply_pkt->et_src[5] = ETH_MACADDR5; |
reply_pkt->et_protlen = PROT_IP; |
|
// IP header |
reply_IP->ip_hl_v = 0x45; // version 4, 20 byte long header, not 100% on this! |
reply_IP->ip_tos = 0x00 ; // ToS (DSCP) - usually used for QoS, set to 0 |
unsigned short ip_indicated_length; |
// First copy total length indicated in received IP header to a variable, we |
// need it again later... |
memcpy ((void*)&ip_indicated_length, (void*)&ip->ip_len, 2); |
// Now copy into reply IP packet |
memcpy ((void*)&reply_IP->ip_len, (void*)&ip_indicated_length, 2); |
memcpy ((void*)&reply_IP->ip_id, (void*)&ip->ip_id, 2); // Copy ID |
reply_IP->ip_ttl = 0x40; // Packet TTL - 64, typical value |
reply_IP->ip_p = IPPROTO_ICMP; // Duh, this is an ICMP echo reply |
// Clear header checksum for now |
|
memcpy ((void*)&reply_IP->ip_sum, (void*)&zero, 2); |
memcpy ((void*)&reply_IP->ip_src, (void*)&our_ip[0], 4); // Copy in our IP |
// "...return to sender... budupbadah address ....KNOWN ..." |
// WTF this memcpy() fails with alignment error...(?!?!) |
//memcpy (&reply_IP->ip_dst, &ip->ip_src, sizeof(IPaddr_t)); |
//...OK then, do it manually..... |
unsigned char *ptr1, *ptr2; |
ptr1 = &reply_IP->ip_dst; ptr2 = &ip->ip_src; |
ptr1[0] = ptr2[0]; |
ptr1[1] = ptr2[1]; |
ptr1[2] = ptr2[2]; |
ptr1[3] = ptr2[3]; |
|
// Now calculate the CRC, probably move this to a fuction.... |
unsigned short ip_sum = 0; // Initialise checksum value to 0 |
int itr; |
char* sum_data_ptr = (char*)reply_IP; |
ip_sum = calculate_checksum(sum_data_ptr,IP_HDR_SIZE_NO_UDP); |
/* |
for(itr=0;itr<IP_HDR_SIZE_NO_UDP;itr+=2) |
ip_sum += (((sum_data_ptr[itr]<<8)&0xff00)|(sum_data_ptr[itr+1]&0x00ff)); |
while (ip_sum>>16) |
ip_sum = (ip_sum & 0xffff) + (ip_sum>>16); |
ip_sum = ~ip_sum; |
*/ |
|
memcpy ((void*)&reply_IP->ip_sum, (void*)&ip_sum, 2); |
|
// |
// Now construct ICMP part of packet |
// |
reply_ICMP->type = ICMP_TYPE_ECHO_REPLY; // ping response type |
reply_ICMP->code = icmp->code; // ICMP code same as sender (is this right?) |
|
// Clear ICMP checksum for now |
memcpy ((void*)&reply_ICMP->checksum, (void*)&zero, 2); |
|
// |
// Simply copy in the data from the received packet |
// Figure out how much there is after the checksum |
// It should be : |
// length_from_received_IP_header - IP_header_length - initial_ICMP_packet_dat |
// |
unsigned long icmp_data_length = ip_indicated_length - IP_HDR_SIZE_NO_UDP - 4; |
memcpy ((void*)&reply_ICMP->un,(void*)&icmp->un, icmp_data_length); |
|
// Now calculate checksum for ICMP data |
unsigned short icmp_sum = 0; |
sum_data_ptr = (char*)reply_ICMP; |
icmp_sum = calculate_checksum(sum_data_ptr,icmp_data_length+4); |
|
memcpy ((void*)&reply_ICMP->checksum, (void*)&icmp_sum, 2); |
|
// All done! |
|
tx_packet((void*)ip_reply_packet,ETHER_HDR_SIZE+ip_indicated_length); |
|
} |
|
|
|
/* |
* Address Resolution Protocol (ARP) header. |
*/ |
typedef struct |
{ |
unsigned short ar_hrd; /* Format of hardware address */ |
# define ARP_ETHER 1 /* Ethernet hardware address */ |
unsigned short ar_pro; /* Format of protocol address */ |
unsigned char ar_hln; /* Length of hardware address */ |
unsigned char ar_pln; /* Length of protocol address */ |
unsigned short ar_op; /* Operation */ |
# define ARPOP_REQUEST 1 /* Request to resolve address */ |
# define ARPOP_REPLY 2 /* Response to previous request */ |
|
# define RARPOP_REQUEST 3 /* Request to resolve address */ |
# define RARPOP_REPLY 4 /* Response to previous request */ |
|
/* |
* The remaining fields are variable in size, according to |
* the sizes above, and are defined as appropriate for |
* specific hardware/protocol combinations. |
*/ |
unsigned char ar_data[0]; |
#if 0 |
unsigned char ar_sha[]; /* Sender hardware address */ |
unsigned char ar_spa[]; /* Sender protocol address */ |
unsigned char ar_tha[]; /* Target hardware address */ |
unsigned char ar_tpa[]; /* Target protocol address */ |
#endif /* 0 */ |
} ARP_t; |
|
#define ARP_HDR_SIZE (8+20) /* Size assuming ethernet */ |
|
char arp_reply_packet[(ETHER_HDR_SIZE + ARP_HDR_SIZE)]; |
|
void |
packet_check_arp_header(void * pkt) |
{ |
Ethernet_t * eth_pkt; |
|
ARP_t * arp; |
|
//printf("packet_check_arp_header: pkt data at 0x%.8x\n",(unsigned long) pkt); |
eth_pkt = (Ethernet_t *) pkt; |
|
if (eth_pkt->et_protlen == 0x0806) |
{ |
// Is an ARP request |
// Check the IP |
pkt += ETHER_HDR_SIZE; // Skip eth header stuff |
//printf("Is ARP protocol\npkt header now at 0x%.8x\n",pkt); |
|
arp = (ARP_t*) pkt; |
|
if (arp->ar_hrd == ARP_ETHER && arp->ar_op == ARPOP_REQUEST) |
{ |
// Skip forward to the target I.P address |
|
char * internet_protocol_adr = (((unsigned long)&arp->ar_data[0]) + (arp->ar_hln * 2) + (arp->ar_pln)); |
|
//printf("Is ARP ethernet request\ncheck adr at 0x%.8x\n",internet_protocol_adr); |
if ((internet_protocol_adr[0] == our_ip[0]) && |
(internet_protocol_adr[1] == our_ip[1]) && |
(internet_protocol_adr[2] == our_ip[2]) && |
(internet_protocol_adr[3] == our_ip[3])) |
{ |
//printf("Got valid ARP request\n"); |
// Send ARP reply |
|
Ethernet_t * reply_pkt = (Ethernet_t *)&arp_reply_packet[0]; |
ARP_t * reply_arp = (ARP_t*)&arp_reply_packet[ETHER_HDR_SIZE]; |
memcpy( (void*)&reply_pkt->et_dest , (void*)ð_pkt->et_src , 6); |
reply_pkt->et_src[0] = ETH_MACADDR0; |
reply_pkt->et_src[1] = ETH_MACADDR1; |
reply_pkt->et_src[2] = ETH_MACADDR2; |
reply_pkt->et_src[3] = ETH_MACADDR3; |
reply_pkt->et_src[4] = ETH_MACADDR4; |
reply_pkt->et_src[5] = ETH_MACADDR5; |
reply_pkt->et_protlen = 0x0806; |
// ARP part of packet |
reply_arp->ar_hrd = ARP_ETHER; |
reply_arp->ar_pro = 0x0800; // IP Protocol |
reply_arp->ar_hln = 0x06; |
reply_arp->ar_pln = 0x04; |
reply_arp->ar_op = ARPOP_REPLY; |
// My MAC |
memcpy( (void*)&reply_arp->ar_data[0] , (void*)&reply_pkt->et_src , 6); |
// My IP |
memcpy( (void*)&reply_arp->ar_data[6] , (void*)&our_ip , 4); |
// Their MAC |
memcpy( (void*)&reply_arp->ar_data[10] , (void*)ð_pkt->et_src , 6); |
// Their IP |
char * their_internet_protocol_adr = |
(((unsigned long)&arp->ar_data[0]) + arp->ar_hln ); |
memcpy( (void*)&reply_arp->ar_data[16] , (void*)&their_internet_protocol_adr[0] , 4); |
|
tx_packet((void*)arp_reply_packet,(ETHER_HDR_SIZE+ARP_HDR_SIZE) ); |
|
} |
} |
} |
} |
|
|
|
static void |
oeth_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *rx_bdp; |
int pkt_len, i; |
int bad = 0; |
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
#if NEVER_PRINT_PACKET==0 |
printf("rx"); |
#endif |
|
/* Find RX buffers marked as having received data */ |
for(i = 0; i < OETH_RXBD_NUM; i++) |
{ |
if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ /* Looking for NOT empty buffers desc. */ |
/* Check status for errors. |
*/ |
if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) { |
bad = 1; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) { |
bad = 1; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) { |
bad = 1; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) { |
bad = 1; |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_MISS) { |
|
} |
if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) { |
bad = 1; |
} |
|
if (bad) { |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; |
|
continue; |
} |
else { |
|
/* Process the incoming frame. |
*/ |
pkt_len = rx_bdp[i].len_status >> 16; |
|
/* Do something here with the data - copy it into userspace, perhaps. */ |
// See if it's an ARP packet |
packet_check_arp_header((void *)rx_bdp[i].addr ); |
// See if it's an ICMP echo request |
packet_check_icmp_header((void *)rx_bdp[i].addr ); |
#if NEVER_PRINT_PACKET==0 |
oeth_print_packet(rx_bdp[i].addr, rx_bdp[i].len_status >> 16); |
printf("\t end of packet\n\n"); |
#endif |
/* finish up */ |
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 */ |
|
|
} |
} |
} |
} |
|
|
|
static void |
oeth_tx(void) |
{ |
volatile oeth_bd *tx_bd; |
int i; |
#if NEVER_PRINT_PACKET==0 |
printf("tx"); |
#endif |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* Go through the TX buffs, search for one that was just sent */ |
for(i = 0; i < OETH_TXBD_NUM; i++) |
{ |
/* Looking for buffer NOT ready for transmit. and IRQ enabled */ |
if( (!(tx_bd[i].len_status & (OETH_TX_BD_READY))) && (tx_bd[i].len_status & (OETH_TX_BD_IRQ)) ) |
{ |
//oeth_print_packet(tx_bd[i].addr, (tx_bd[i].len_status >> 16)); |
/* Single threaded so no chance we have detected a buffer that has had its IRQ bit set but not its BD_READ flag. Maybe this won't work in linux */ |
tx_bd[i].len_status &= ~OETH_TX_BD_IRQ; |
|
/* Probably good to check for TX errors here */ |
|
#if NEVER_PRINT_PACKET==0 |
printf("T%d",i); |
#endif |
|
} |
} |
return; |
} |
|
|
int main () |
{ |
|
/* Initialise vector handler */ |
int_init(); |
|
/* Install ethernet interrupt handler, it is enabled here too */ |
int_add(ETH0_IRQ, oeth_interrupt, 0); |
|
/* Enable interrupts */ |
cpu_enable_user_interrupts(); |
|
last_char=0; /* Variable init for spin_cursor() */ |
next_tx_buf_num = 4; /* init for tx buffer counter */ |
|
#ifndef RTLSIM |
uart_init(DEFAULT_UART); // init the UART before we can printf |
printf("\n\teth ping program\n\n"); |
printf("\n\tboard IP: %d.%d.%d.%d\n",our_ip[0]&0xff,our_ip[1]&0xff, |
our_ip[2]&0xff,our_ip[3]&0xff); |
#endif |
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX and TX in MODER */ |
|
//scan_ethphys(); /* Scan MIIM bus for PHYs */ |
//jb ethphy_init(); /* Attempt reset and configuration of PHY via MIIM */ |
//ethmac_scanstatus(); /* Enable scanning of status register via MIIM */ |
|
/* clear tx_done, the tx interrupt handler will set it when it's been transmitted */ |
tx_done = 0; |
|
|
#ifndef RTLSIM |
/* Loop, monitoring user input from TTY */ |
while(1) |
{ |
char c; |
|
while(!uart_check_for_char(DEFAULT_UART)) |
{ |
spin_cursor(); |
oeth_monitor_rx(); |
} |
|
c = uart_getc(DEFAULT_UART); |
|
if (c == 's') |
tx_packet((void*) ping_packet, 98); |
if (c == 'S') |
tx_packet((void*)big_ping_packet, 1514); |
if (c == 'h') |
scan_ethphys(); |
if (c == 'i') |
ethphy_init(); |
if (c == 'p') |
oeth_printregs(); |
if (c == '0') |
scan_ethphy(0); |
if (c == '1') |
scan_ethphy(1); |
if (c == '7') |
{ |
scan_ethphy(7); |
ethphy_print_status(7); |
} |
if (c == 'r') |
ethphy_reset(0); |
if (c == 'R') |
oeth_reset_tx_bd_pointer(); |
if (c == 'n') |
ethphy_reneg(0); |
if (c == 'N') |
ethphy_set_autoneg(0); |
if (c == 'm') |
ethmac_togglehugen(); |
if (c == 't') |
ethphy_set_10mbit(0); |
if ( c == 'b' ) |
{ |
printf("\n\t---\n"); |
oeth_dump_bds(); |
printf("\t---\n"); |
} |
|
} |
|
|
|
#endif |
|
} |
/sim/eth-rx.c
File deleted
/sim/eth-tx.c
File deleted
/sim/eth-rxtx.c
File deleted
/sim/ethmac-rxtx.c
0,0 → 1,774
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Interrupt-driven Ethernet MAC transmit test code //// |
//// //// |
//// Description //// |
//// Send packets while receiving packets //// |
//// //// |
//// Test data comes from pre-calculated array of random values, //// |
//// MAC TX buffer pointers are set to addresses in this array, //// |
//// saving copying the data around before transfers. //// |
//// //// |
//// Author(s): //// |
//// - jb, jb@orsoc.se, with parts taken from Linux kernel //// |
//// open_eth driver. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
#include "or32-utils.h" |
#include "spr-defs.h" |
#include "board.h" |
#include "int.h" |
//#include "uart.h" // comment this out, UART uses simulation putc() |
#include "open-eth.h" |
#include "printf.h" |
#include "eth-phy-mii.h" |
|
volatile unsigned tx_done; |
volatile unsigned rx_done; |
static int next_tx_buf_num; |
|
/* Functions in this file */ |
void ethmac_setup(void); |
/* Interrupt functions */ |
void oeth_interrupt(void); |
static void oeth_rx(void); |
static void oeth_tx(void); |
|
/* 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 */ |
#define ETH_BUFF_BASE 0x01000000 |
|
|
#define RXBUFF_PREALLOC 1 |
#define TXBUFF_PREALLOC 1 |
//#undef RXBUFF_PREALLOC |
//#undef TXBUFF_PREALLOC |
|
/* The transmitter timeout |
*/ |
#define TX_TIMEOUT (2*HZ) |
|
/* Buffer number (must be 2^n) |
*/ |
#define OETH_RXBD_NUM 16 |
#define OETH_TXBD_NUM 16 |
#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1) |
#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1) |
|
/* Buffer size |
*/ |
#define OETH_RX_BUFF_SIZE 0x600-4 |
#define OETH_TX_BUFF_SIZE 0x600-4 |
|
/* OR32 Page size def */ |
#define PAGE_SHIFT 13 |
#define PAGE_SIZE (1UL << PAGE_SHIFT) |
|
/* How many buffers per page |
*/ |
#define OETH_RX_BUFF_PPGAE (PAGE_SIZE/OETH_RX_BUFF_SIZE) |
#define OETH_TX_BUFF_PPGAE (PAGE_SIZE/OETH_TX_BUFF_SIZE) |
|
/* How many pages is needed for buffers |
*/ |
#define OETH_RX_BUFF_PAGE_NUM (OETH_RXBD_NUM/OETH_RX_BUFF_PPGAE) |
#define OETH_TX_BUFF_PAGE_NUM (OETH_TXBD_NUM/OETH_TX_BUFF_PPGAE) |
|
/* Buffer size (if not XXBUF_PREALLOC |
*/ |
#define MAX_FRAME_SIZE 1518 |
|
/* The buffer descriptors track the ring buffers. |
*/ |
struct oeth_private { |
//struct sk_buff* rx_skbuff[OETH_RXBD_NUM]; |
//struct sk_buff* tx_skbuff[OETH_TXBD_NUM]; |
|
unsigned short tx_next; /* Next buffer to be sent */ |
unsigned short tx_last; /* Next buffer to be checked if packet sent */ |
unsigned short tx_full; /* Buffer ring fuul indicator */ |
unsigned short rx_cur; /* Next buffer to be checked if packet |
received */ |
|
oeth_regs *regs; /* Address of controller registers. */ |
oeth_bd *rx_bd_base; /* Address of Rx BDs. */ |
oeth_bd *tx_bd_base; /* Address of Tx BDs. */ |
|
// struct net_device_stats stats; |
}; |
|
#define PHYNUM 7 |
|
// Data array of data to transmit, tx_data_array[] |
#include "eth-rxtx-data.h" |
int tx_data_pointer; |
|
/* 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; |
regs->miicommand = OETH_MIICOMMAND_RSTAT; |
/* Wait for command to be registered*/ |
while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); |
|
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; |
} |
|
|
|
// Wait here until all packets have been transmitted |
void wait_until_all_tx_clear(void) |
{ |
|
int i; |
volatile oeth_bd *tx_bd; |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
int some_tx_waiting = 1; |
|
while (some_tx_waiting) |
{ |
some_tx_waiting = 0; |
/* Go through the TX buffs, search for unused one */ |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
|
if((tx_bd[i].len_status & OETH_TX_BD_READY)) // Looking for buffer ready for transmit |
some_tx_waiting = 1; |
|
} |
} |
} |
|
|
void |
ethphy_set_10mbit(int phynum) |
{ |
wait_until_all_tx_clear(); |
// Hardset PHY to just use 10Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr &= ~BMCR_ANENABLE; // Clear auto negotiate bit |
cr &= ~BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
|
void |
ethphy_set_100mbit(int phynum) |
{ |
wait_until_all_tx_clear(); |
// Hardset PHY to just use 100Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr |= BMCR_ANENABLE; // Clear auto negotiate bit |
cr |= BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
|
void ethmac_setup(void) |
{ |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Reset MII mode module */ |
regs->miimoder = OETH_MIIMODER_RST; /* MII Reset ON */ |
regs->miimoder &= ~OETH_MIIMODER_RST; /* MII Reset OFF */ |
regs->miimoder = 0x64; /* Clock divider for MII Management interface */ |
|
/* Reset the controller. |
*/ |
regs->moder = OETH_MODER_RST; /* Reset ON */ |
regs->moder &= ~OETH_MODER_RST; /* Reset OFF */ |
|
/* Setting TXBD base to OETH_TXBD_NUM. |
*/ |
regs->tx_bd_num = OETH_TXBD_NUM; |
|
|
/* Set min/max packet length |
*/ |
regs->packet_len = 0x00400600; |
|
/* Set IPGT register to recomended value |
*/ |
regs->ipgt = 0x12; |
|
/* Set IPGR1 register to recomended value |
*/ |
regs->ipgr1 = 0x0000000c; |
|
/* Set IPGR2 register to recomended value |
*/ |
regs->ipgr2 = 0x00000012; |
|
/* Set COLLCONF register to recomended value |
*/ |
regs->collconf = 0x000f003f; |
|
/* Set control module mode |
*/ |
#if 0 |
regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW; |
#else |
regs->ctrlmoder = 0; |
#endif |
|
/* Clear MIIM registers */ |
regs->miitx_data = 0; |
regs->miiaddress = 0; |
regs->miicommand = 0; |
|
regs->mac_addr1 = ETH_MACADDR0 << 8 | ETH_MACADDR1; |
regs->mac_addr0 = ETH_MACADDR2 << 24 | ETH_MACADDR3 << 16 | ETH_MACADDR4 << 8 | ETH_MACADDR5; |
|
/* Clear all pending interrupts |
*/ |
regs->int_src = 0xffffffff; |
|
/* Promisc, IFG, CRCEn |
*/ |
regs->moder |= OETH_MODER_PRO | OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN | OETH_MODER_FULLD; |
|
/* Enable interrupt sources. |
*/ |
|
regs->int_mask = OETH_INT_MASK_TXB | |
OETH_INT_MASK_TXE | |
OETH_INT_MASK_RXF | |
OETH_INT_MASK_RXE | |
OETH_INT_MASK_BUSY | |
OETH_INT_MASK_TXC | |
OETH_INT_MASK_RXC; |
|
// Buffer setup stuff |
volatile oeth_bd *tx_bd, *rx_bd; |
int i,j,k; |
|
/* Initialize TXBD pointer |
*/ |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
|
/* Initialize RXBD pointer |
*/ |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
/* Preallocated ethernet buffer setup */ |
unsigned long mem_addr = ETH_BUFF_BASE; /* Defined at top */ |
|
// Setup TX Buffers |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
//tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ; |
tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; |
tx_bd[i].addr = mem_addr; |
mem_addr += OETH_TX_BUFF_SIZE; |
} |
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; |
|
// Setup RX buffers |
for(i = 0; i < OETH_RXBD_NUM; i++) { |
rx_bd[i].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; // Init. with IRQ |
rx_bd[i].addr = mem_addr; |
mem_addr += OETH_RX_BUFF_SIZE; |
} |
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; // Last buffer wraps |
|
/* Enable JUST the transmiter |
*/ |
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN); |
regs->moder |= /*OETH_MODER_RXEN |*/ OETH_MODER_TXEN; |
|
next_tx_buf_num = 0; // init tx buffer pointer |
|
return; |
} |
|
// Enable RX in ethernet MAC |
void |
oeth_enable_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
regs->moder |= OETH_MODER_RXEN; |
} |
|
// Disable RX in ethernet MAC |
void |
oeth_disable_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
regs->moder &= ~(OETH_MODER_RXEN); |
} |
|
|
/* Setup buffer descriptors with data */ |
/* length is in BYTES */ |
void tx_packet(void* data, int length) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
volatile int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
tx_bd = (struct oeth_bd*) &tx_bd[next_tx_buf_num]; |
|
// If it's in use - wait |
while ((tx_bd->len_status & OETH_TX_BD_IRQ)); |
|
/* Clear all of the status flags. |
*/ |
tx_bd->len_status &= ~OETH_TX_BD_STATS; |
|
/* If the frame is short, tell CPM to pad it. |
*/ |
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ |
if (length <= ETH_ZLEN) |
tx_bd->len_status |= OETH_TX_BD_PAD; |
else |
tx_bd->len_status &= ~OETH_TX_BD_PAD; |
|
#ifdef _ETH_RXTX_DATA_H_ |
// Set the address pointer to the place |
// in memory where the data is and transmit from there |
|
tx_bd->addr = (char*) &tx_data_array[tx_data_pointer&~(0x3)]; |
|
tx_data_pointer += length + 1; |
if (tx_data_pointer > (255*1024)) |
tx_data_pointer = 0; |
|
|
#else |
if (data){ |
//Copy the data into the transmit buffer, byte at a time |
char* data_p = (char*) data; |
char* data_b = (char*) tx_bd->addr; |
for(i=0;i<length;i++) |
{ |
data_b[i] = data_p[i]; |
} |
} |
#endif |
|
/* Set the length of the packet's data in the buffer descriptor */ |
tx_bd->len_status = (tx_bd->len_status & 0x0000ffff) | |
((length&0xffff) << 16); |
|
/* Send it on its way. Tell controller its ready, interrupt when sent |
* and to put the CRC on the end. |
*/ |
tx_bd->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_CRC | OETH_TX_BD_IRQ); |
|
next_tx_buf_num = (next_tx_buf_num + 1) & OETH_TXBD_NUM_MASK; |
|
return; |
|
|
} |
|
/* The interrupt handler. |
*/ |
void |
oeth_interrupt(void) |
{ |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
uint int_events; |
int serviced; |
|
serviced = 0; |
|
/* Get the interrupt events that caused us to be here. |
*/ |
int_events = regs->int_src; |
regs->int_src = int_events; |
|
/* Handle receive event in its own function. |
*/ |
if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) { |
serviced |= 0x1; |
oeth_rx(); |
} |
|
/* Handle transmit event in its own function. |
*/ |
if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) { |
serviced |= 0x2; |
oeth_tx(); |
serviced |= 0x2; |
|
} |
|
/* Check for receive busy, i.e. packets coming but no place to |
* put them. |
*/ |
if (int_events & OETH_INT_BUSY) { |
serviced |= 0x4; |
if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE))) |
oeth_rx(); |
} |
|
return; |
} |
|
|
|
static void |
oeth_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *rx_bdp; |
int pkt_len, i; |
int bad = 0; |
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
printk("r"); |
|
|
/* Find RX buffers marked as having received data */ |
for(i = 0; i < OETH_RXBD_NUM; i++) |
{ |
bad=0; |
if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ /* Looking for NOT empty buffers desc. */ |
/* Check status for errors. |
*/ |
if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) { |
bad = 1; |
report(0xbaad0001); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) { |
bad = 1; |
report(0xbaad0002); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) { |
bad = 1; |
report(0xbaad0003); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) { |
bad = 1; |
report(0xbaad0004); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_MISS) { |
report(0xbaad0005); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) { |
bad = 1; |
report(0xbaad0006); |
} |
if (bad) { |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; |
exit(0xbaaaaaad); |
|
continue; |
} |
else { |
/* Process the incoming frame. |
*/ |
pkt_len = rx_bdp[i].len_status >> 16; |
|
/* finish up */ |
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_done++; |
} |
} |
} |
} |
|
|
|
static void |
oeth_tx(void) |
{ |
volatile oeth_bd *tx_bd; |
int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* Go through the TX buffs, search for one that was just sent */ |
for(i = 0; i < OETH_TXBD_NUM; i++) |
{ |
/* Looking for buffer NOT ready for transmit. and IRQ enabled */ |
if( (!(tx_bd[i].len_status & (OETH_TX_BD_READY))) && (tx_bd[i].len_status & (OETH_TX_BD_IRQ)) ) |
{ |
/* Single threaded so no chance we have detected a buffer that has had its IRQ bit set but not its BD_READ flag. Maybe this won't work in linux */ |
tx_bd[i].len_status &= ~OETH_TX_BD_IRQ; |
|
/* Probably good to check for TX errors here */ |
|
/* set our test variable */ |
tx_done++; |
|
printk("T%d",i); |
|
} |
} |
return; |
} |
|
// A function and defines to fill and transmit a packet |
#define MAX_TX_BUFFER 1532 |
static char tx_buffer[MAX_TX_BUFFER]; |
static unsigned long tx_data = 0x26fab2f2; |
static inline char gen_next_tx_byte(void) |
{ |
// Bit of LFSR action |
tx_data = ((~(((((tx_data&(1<<25))>>25)^((tx_data&(1<<13))>>13))^((tx_data&(1<<2))>>2)))&0x01) | (tx_data<<1)); |
//tx_data =(!((tx_data>>26) ^ (tx_data>>14) ^ (tx_data>>5) ^ (tx_data>>3)) & 0x1) | (tx_data<<1); |
return (char) tx_data & 0xff; |
} |
|
void |
fill_and_tx_packet(int size) |
{ |
int i; |
char tx_byte; |
|
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
|
//tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
tx_bd = (volatile oeth_bd*) &tx_bd[next_tx_buf_num]; |
|
|
// If it's in use - wait |
while ((tx_bd->len_status & OETH_TX_BD_IRQ)); |
|
#ifndef _ETH_RXTX_DATA_H_ |
/* Copy the data into the transmit buffer, byte at a time */ |
char* data_b = (char*) tx_bd->addr; |
for(i=0;i<size;i++) |
{ |
data_b[i] = gen_next_tx_byte(); |
} |
#endif |
|
tx_packet((void*)0, size); |
} |
|
|
// Loop to check if a number is prime by doing mod divide of the number |
// to test by every number less than it |
int |
is_prime_number(unsigned long n) |
{ |
unsigned long c; |
if (n < 2) return 0; |
for(c=2;c<n;c++) |
if ((n % c) == 0) |
return 0; |
return 1; |
} |
|
|
//#define WAIT_PACKET_TX(x) while(tx_done<x) |
#define WAIT_PACKET_TX(x) |
|
int main () |
{ |
tx_data_pointer = 0; |
/* Initialise handler vector */ |
int_init(); |
|
/* Install ethernet interrupt handler, it is enabled here too */ |
int_add(ETH0_IRQ, oeth_interrupt, 0); |
|
/* Enable interrupts in supervisor register */ |
mtspr (SPR_SR, mfspr (SPR_SR) | SPR_SR_IEE); |
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX and TX in MODER */ |
|
/* clear tx_done, the tx interrupt handler will set it when it's been |
transmitted */ |
tx_done = 0; |
rx_done = 0; |
|
printf("Start of large txdata buffer: 0x%x\n", |
(unsigned long)&tx_data_array[0]); |
printf("Slut of large txdata buffer: 0x%x\n", |
(unsigned long)&tx_data_array[262144]); |
|
|
ethphy_set_100mbit(0); |
|
oeth_enable_rx(); |
|
#define ETH_TX_MIN_PACKET_SIZE 512 |
#define ETH_TX_NUM_PACKETS (ETH_TX_MIN_PACKET_SIZE + 32) |
|
#define CALCULATE_PRIMES 0 |
|
char prime_check_results[2048]; |
unsigned long num_to_check; |
for(num_to_check=ETH_TX_MIN_PACKET_SIZE; |
num_to_check<ETH_TX_NUM_PACKETS; |
num_to_check++) |
{ |
fill_and_tx_packet(num_to_check); |
#if CALCULATE_PRIMES==1 |
prime_check_results[num_to_check-5] |
= (char) is_prime_number(num_to_check); |
report(num_to_check | (0x1e<<24)); |
report(prime_check_results[num_to_check-5] | (0x2e<<24)); |
#endif |
} |
|
oeth_disable_rx(); |
|
// Now for 10mbit mode... |
ethphy_set_10mbit(0); |
|
oeth_enable_rx(); |
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE; |
num_to_check<ETH_TX_NUM_PACKETS; |
num_to_check++) |
{ |
fill_and_tx_packet(num_to_check); |
#if CALCULATE_PRIMES==1 |
prime_check_results[num_to_check+(OETH_TX_BUFF_SIZE-5)] |
= (char) is_prime_number(num_to_check+OETH_TX_BUFF_SIZE); |
report(num_to_check | (0x1e<<24)); |
report(prime_check_results[num_to_check+(OETH_TX_BUFF_SIZE-5)] |
| (0x2e<<24) |
); |
#endif |
} |
|
oeth_disable_rx(); |
|
// Go back to 100-mbit mode |
ethphy_set_100mbit(0); |
|
oeth_enable_rx(); |
|
for(num_to_check=ETH_TX_MIN_PACKET_SIZE; |
num_to_check<ETH_TX_NUM_PACKETS; |
num_to_check++) |
{ |
fill_and_tx_packet(num_to_check); |
#if CALCULATE_PRIMES==1 |
prime_check_results[num_to_check+(OETH_TX_BUFF_SIZE-5)] |
= (char) is_prime_number(num_to_check+OETH_TX_BUFF_SIZE); |
report(num_to_check | (0x1e<<24)); |
report(prime_check_results[num_to_check+(OETH_TX_BUFF_SIZE-5)] |
| (0x2e<<24) |
); |
#endif |
} |
|
|
exit(0x8000000d); |
|
|
} |
/sim/ethmac-rx.c
0,0 → 1,552
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Interrupt-driven Ethernet MAC test code //// |
//// //// |
//// Description //// |
//// Do ethernet receive path testing //// |
//// Relies on testbench to provide simulus - expects at least //// |
//// 256 packets to be sent. //// |
//// //// |
//// Author(s): //// |
//// - jb, jb@orsoc.se, with parts taken from Linux kernel //// |
//// open_eth driver. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
#include "cpu-utils.h" |
//#include "spr-defs.h" |
#include "board.h" |
#include "int.h" |
#include "uart.h" |
#include "ethmac.h" |
#include "printf.h" |
#include "eth-phy-mii.h" |
|
volatile unsigned tx_done; |
volatile unsigned rx_done; |
|
/* Functions in this file */ |
void ethmac_setup(void); |
void ethphy_init(void); |
void oeth_dump_bds(); |
/* Interrupt functions */ |
void oeth_interrupt(void); |
static void oeth_rx(void); |
static void oeth_tx(void); |
|
/* 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 */ |
#define ETH_BUFF_BASE 0x01000000 |
|
|
#define RXBUFF_PREALLOC 1 |
#define TXBUFF_PREALLOC 1 |
//#undef RXBUFF_PREALLOC |
//#undef TXBUFF_PREALLOC |
|
/* The transmitter timeout |
*/ |
#define TX_TIMEOUT (2*HZ) |
|
/* Buffer number (must be 2^n) |
*/ |
#define OETH_RXBD_NUM 16 |
#define OETH_TXBD_NUM 16 |
#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1) |
#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1) |
|
/* Buffer size |
*/ |
#define OETH_RX_BUFF_SIZE 0x600 |
#define OETH_TX_BUFF_SIZE 0x600 |
|
/* Buffer size (if not XXBUF_PREALLOC |
*/ |
#define MAX_FRAME_SIZE 1518 |
|
/* The buffer descriptors track the ring buffers. |
*/ |
struct oeth_private { |
//struct sk_buff* rx_skbuff[OETH_RXBD_NUM]; |
//struct sk_buff* tx_skbuff[OETH_TXBD_NUM]; |
|
unsigned short tx_next; /* Next buffer to be sent */ |
unsigned short tx_last; /* Next buffer to be checked if packet sent */ |
unsigned short tx_full; /* Buffer ring fuul indicator */ |
unsigned short rx_cur; /* Next buffer to be checked if packet received */ |
|
oeth_regs *regs; /* Address of controller registers. */ |
oeth_bd *rx_bd_base; /* Address of Rx BDs. */ |
oeth_bd *tx_bd_base; /* Address of Tx BDs. */ |
|
// struct net_device_stats stats; |
}; |
|
|
#define PHYNUM 7 |
|
/* 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); |
|
|
} |
|
|
void ethmac_setup(void) |
{ |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Reset MII mode module */ |
regs->miimoder = OETH_MIIMODER_RST; /* MII Reset ON */ |
regs->miimoder &= ~OETH_MIIMODER_RST; /* MII Reset OFF */ |
regs->miimoder = 0x64; /* Clock divider for MII Management interface */ |
|
/* Reset the controller. |
*/ |
regs->moder = OETH_MODER_RST; /* Reset ON */ |
regs->moder &= ~OETH_MODER_RST; /* Reset OFF */ |
|
/* Setting TXBD base to OETH_TXBD_NUM. |
*/ |
regs->tx_bd_num = OETH_TXBD_NUM; |
|
|
/* Set min/max packet length |
*/ |
regs->packet_len = 0x00400600; |
|
/* Set IPGT register to recomended value |
*/ |
regs->ipgt = 0x12; |
|
/* Set IPGR1 register to recomended value |
*/ |
regs->ipgr1 = 0x0000000c; |
|
/* Set IPGR2 register to recomended value |
*/ |
regs->ipgr2 = 0x00000012; |
|
/* Set COLLCONF register to recomended value |
*/ |
regs->collconf = 0x000f003f; |
|
/* Set control module mode |
*/ |
#if 0 |
regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW; |
#else |
regs->ctrlmoder = 0; |
#endif |
|
/* Clear MIIM registers */ |
regs->miitx_data = 0; |
regs->miiaddress = 0; |
regs->miicommand = 0; |
|
regs->mac_addr1 = ETH_MACADDR0 << 8 | ETH_MACADDR1; |
regs->mac_addr0 = ETH_MACADDR2 << 24 | ETH_MACADDR3 << 16 | ETH_MACADDR4 << 8 | ETH_MACADDR5; |
|
/* Clear all pending interrupts |
*/ |
regs->int_src = 0xffffffff; |
|
/* Promisc, IFG, CRCEn |
*/ |
regs->moder |= OETH_MODER_PRO | OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN | OETH_MODER_FULLD; |
|
/* Enable interrupt sources. |
*/ |
|
regs->int_mask = OETH_INT_MASK_TXB | |
OETH_INT_MASK_TXE | |
OETH_INT_MASK_RXF | |
OETH_INT_MASK_RXE | |
OETH_INT_MASK_BUSY | |
OETH_INT_MASK_TXC | |
OETH_INT_MASK_RXC; |
|
// Buffer setup stuff |
volatile oeth_bd *tx_bd, *rx_bd; |
int i,j,k; |
|
/* Initialize TXBD pointer |
*/ |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
|
/* Initialize RXBD pointer |
*/ |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
/* Preallocated ethernet buffer setup */ |
unsigned long mem_addr = ETH_BUFF_BASE; /* Defined at top */ |
|
// Setup TX Buffers |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
//tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ; |
tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; |
tx_bd[i].addr = mem_addr; |
mem_addr += OETH_TX_BUFF_SIZE; |
} |
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; |
|
// Setup RX buffers |
for(i = 0; i < OETH_RXBD_NUM; i++) { |
rx_bd[i].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; // Init. with IRQ |
rx_bd[i].addr = mem_addr; |
mem_addr += OETH_RX_BUFF_SIZE; |
} |
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; // Last buffer wraps |
|
/* Enable just the receiver |
*/ |
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN); |
regs->moder |= OETH_MODER_RXEN /* | OETH_MODER_TXEN*/; |
|
return; |
} |
|
|
/* The interrupt handler. |
*/ |
void |
oeth_interrupt(void) |
{ |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
uint int_events; |
int serviced; |
|
serviced = 0; |
|
/* Get the interrupt events that caused us to be here. |
*/ |
int_events = regs->int_src; |
regs->int_src = int_events; |
|
|
/* Handle receive event in its own function. |
*/ |
if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) { |
serviced |= 0x1; |
oeth_rx(); |
} |
|
/* Handle transmit event in its own function. |
*/ |
if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) { |
serviced |= 0x2; |
oeth_tx(); |
serviced |= 0x2; |
|
} |
|
/* Check for receive busy, i.e. packets coming but no place to |
* put them. |
*/ |
if (int_events & OETH_INT_BUSY) { |
serviced |= 0x4; |
if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE))) |
oeth_rx(); |
} |
|
return; |
} |
|
|
|
static void |
oeth_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *rx_bdp; |
int pkt_len, i; |
int bad = 0; |
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
printk("r"); |
|
/* Find RX buffers marked as having received data */ |
for(i = 0; i < OETH_RXBD_NUM; i++) |
{ |
bad=0; |
if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ /* Looking for NOT empty buffers desc. */ |
/* Check status for errors. |
*/ |
report(i); |
report(rx_bdp[i].len_status); |
if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) { |
bad = 1; |
report(0xbaad0001); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) { |
bad = 1; |
report(0xbaad0002); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) { |
bad = 1; |
report(0xbaad0003); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) { |
bad = 1; |
report(0xbaad0004); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_MISS) { |
report(0xbaad0005); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) { |
bad = 1; |
report(0xbaad0006); |
} |
if (bad) { |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; |
//exit(0xbaaaaaad); |
|
continue; |
} |
else { |
/* |
Process the incoming frame. |
*/ |
pkt_len = rx_bdp[i].len_status >> 16; |
|
/* finish up */ |
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_done++; |
report(rx_done); |
} |
} |
} |
} |
|
|
|
static void |
oeth_tx(void) |
{ |
volatile oeth_bd *tx_bd; |
int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* Go through the TX buffs, search for one that was just sent */ |
for(i = 0; i < OETH_TXBD_NUM; i++) |
{ |
/* Looking for buffer NOT ready for transmit. and IRQ enabled */ |
if( (!(tx_bd[i].len_status & (OETH_TX_BD_READY))) && (tx_bd[i].len_status & (OETH_TX_BD_IRQ)) ) |
{ |
/* Single threaded so no chance we have detected a buffer that has had its IRQ bit set but not its BD_READ flag. Maybe this won't work in linux */ |
tx_bd[i].len_status &= ~OETH_TX_BD_IRQ; |
|
/* Probably good to check for TX errors here */ |
|
/* set our test variable */ |
tx_done = 1; |
|
printk("T%d",i); |
|
} |
} |
return; |
} |
|
// Loop to check if a number is prime by doing mod divide of the number |
// to test by every number less than it |
int |
is_prime_number(unsigned long n) |
{ |
unsigned long c; |
if (n < 2) return 0; |
for(c=2;c<n;c++) |
if ((n % c) == 0) |
return 0; |
return 1; |
} |
|
int main () |
{ |
|
/* Initialise handler vector */ |
int_init(); |
|
/* Install ethernet interrupt handler, it is enabled here too */ |
int_add(ETH0_IRQ, oeth_interrupt, 0); |
|
/* Enable interrupts in supervisor register */ |
cpu_enable_user_interrupts(); |
|
rx_done = 0; |
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX in MODER */ |
|
#define NUM_PRIMES_TO_CHECK 1000 |
|
char prime_check_results[NUM_PRIMES_TO_CHECK]; |
unsigned long 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] |
= (char) is_prime_number(num_to_check); |
report(num_to_check | (0x1e<<24)); |
report(prime_check_results[num_to_check-2] | (0x2e<<24)); |
if (rx_done >= 255) // Check number of packets received, testbench |
// will hopefully send at least 256 packets |
exit(0x8000000d); |
} |
exit(0xbaaaaaad); |
} |
/sim/ethmac-tx.c
0,0 → 1,859
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Interrupt-driven Ethernet MAC transmit test code //// |
//// //// |
//// Description //// |
//// Transmits packets, testing both 100mbit and 10mbit modes. //// |
//// Expects testbench to be checking each packet sent. //// |
//// Define, ETH_TX_TEST_LENGTH, set further down, controls how //// |
//// many packets the test will send. //// |
//// //// |
//// Test data comes from pre-calculated array of random values, //// |
//// MAC TX buffer pointers are set to addresses in this array, //// |
//// saving copying the data around before transfers. //// |
//// //// |
//// Author(s): //// |
//// - jb, jb@orsoc.se, with parts taken from Linux kernel //// |
//// open_eth driver. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2009 Authors and OPENCORES.ORG //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
|
#include "or32-utils.h" |
#include "spr-defs.h" |
#include "board.h" |
#include "int.h" |
#include "uart.h" |
#include "open-eth.h" |
#include "printf.h" |
#include "eth-phy-mii.h" |
|
volatile unsigned tx_done; |
volatile unsigned rx_done; |
static int next_tx_buf_num; |
|
/* Functions in this file */ |
void ethmac_setup(void); |
/* Interrupt functions */ |
void oeth_interrupt(void); |
static void oeth_rx(void); |
static void oeth_tx(void); |
|
/* 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 */ |
#define ETH_BUFF_BASE 0x01000000 |
|
|
#define RXBUFF_PREALLOC 1 |
#define TXBUFF_PREALLOC 1 |
//#undef RXBUFF_PREALLOC |
//#undef TXBUFF_PREALLOC |
|
/* The transmitter timeout |
*/ |
#define TX_TIMEOUT (2*HZ) |
|
/* Buffer number (must be 2^n) |
*/ |
#define OETH_RXBD_NUM 16 |
#define OETH_TXBD_NUM 16 |
#define OETH_RXBD_NUM_MASK (OETH_RXBD_NUM-1) |
#define OETH_TXBD_NUM_MASK (OETH_TXBD_NUM-1) |
|
/* Buffer size |
*/ |
#define OETH_RX_BUFF_SIZE 0x600 - 4 |
#define OETH_TX_BUFF_SIZE 0x600 - 4 |
|
/* OR32 Page size def */ |
#define PAGE_SHIFT 13 |
#define PAGE_SIZE (1UL << PAGE_SHIFT) |
|
/* How many buffers per page |
*/ |
#define OETH_RX_BUFF_PPGAE (PAGE_SIZE/OETH_RX_BUFF_SIZE) |
#define OETH_TX_BUFF_PPGAE (PAGE_SIZE/OETH_TX_BUFF_SIZE) |
|
/* How many pages is needed for buffers |
*/ |
#define OETH_RX_BUFF_PAGE_NUM (OETH_RXBD_NUM/OETH_RX_BUFF_PPGAE) |
#define OETH_TX_BUFF_PAGE_NUM (OETH_TXBD_NUM/OETH_TX_BUFF_PPGAE) |
|
/* Buffer size (if not XXBUF_PREALLOC |
*/ |
#define MAX_FRAME_SIZE 1518 |
|
/* The buffer descriptors track the ring buffers. |
*/ |
struct oeth_private { |
//struct sk_buff* rx_skbuff[OETH_RXBD_NUM]; |
//struct sk_buff* tx_skbuff[OETH_TXBD_NUM]; |
|
unsigned short tx_next; /* Next buffer to be sent */ |
unsigned short tx_last; /* Next buffer to be checked if packet sent */ |
unsigned short tx_full; /* Buffer ring fuul indicator */ |
unsigned short rx_cur; /* Next buffer to be checked if packet received */ |
|
oeth_regs *regs; /* Address of controller registers. */ |
oeth_bd *rx_bd_base; /* Address of Rx BDs. */ |
oeth_bd *tx_bd_base; /* Address of Tx BDs. */ |
|
// struct net_device_stats stats; |
}; |
|
|
// Data array of data to transmit, tx_data_array[] |
#include "eth-rxtx-data.h" |
int tx_data_pointer; |
|
#define PHYNUM 7 |
|
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; |
} |
|
|
// Wait here until all packets have been transmitted |
void wait_until_all_tx_clear(void) |
{ |
|
int i; |
volatile oeth_bd *tx_bd; |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
int some_tx_waiting = 1; |
|
while (some_tx_waiting) |
{ |
some_tx_waiting = 0; |
/* Go through the TX buffs, search for unused one */ |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
|
if((tx_bd[i].len_status & OETH_TX_BD_READY)) // Looking for buffer ready for transmit |
some_tx_waiting = 1; |
|
} |
} |
|
} |
|
|
void |
ethphy_set_10mbit(int phynum) |
{ |
wait_until_all_tx_clear(); |
// Hardset PHY to just use 10Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr &= ~BMCR_ANENABLE; // Clear auto negotiate bit |
cr &= ~BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
|
void |
ethphy_set_100mbit(int phynum) |
{ |
wait_until_all_tx_clear(); |
// Hardset PHY to just use 100Mbit mode |
short cr = eth_mii_read(phynum, MII_BMCR); |
cr |= BMCR_ANENABLE; // Clear auto negotiate bit |
cr |= BMCR_SPEED100; // Clear fast eth. bit |
eth_mii_write(phynum, MII_BMCR, cr); |
} |
|
|
void ethmac_setup(void) |
{ |
// from arch/or32/drivers/open_eth.c |
volatile oeth_regs *regs; |
|
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Reset MII mode module */ |
regs->miimoder = OETH_MIIMODER_RST; /* MII Reset ON */ |
regs->miimoder &= ~OETH_MIIMODER_RST; /* MII Reset OFF */ |
regs->miimoder = 0x64; /* Clock divider for MII Management interface */ |
|
/* Reset the controller. |
*/ |
regs->moder = OETH_MODER_RST; /* Reset ON */ |
regs->moder &= ~OETH_MODER_RST; /* Reset OFF */ |
|
/* Setting TXBD base to OETH_TXBD_NUM. |
*/ |
regs->tx_bd_num = OETH_TXBD_NUM; |
|
|
/* Set min/max packet length |
*/ |
regs->packet_len = 0x00400600; |
|
/* Set IPGT register to recomended value |
*/ |
regs->ipgt = 0x12; |
|
/* Set IPGR1 register to recomended value |
*/ |
regs->ipgr1 = 0x0000000c; |
|
/* Set IPGR2 register to recomended value |
*/ |
regs->ipgr2 = 0x00000012; |
|
/* Set COLLCONF register to recomended value |
*/ |
regs->collconf = 0x000f003f; |
|
/* Set control module mode |
*/ |
#if 0 |
regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW; |
#else |
regs->ctrlmoder = 0; |
#endif |
|
/* Clear MIIM registers */ |
regs->miitx_data = 0; |
regs->miiaddress = 0; |
regs->miicommand = 0; |
|
regs->mac_addr1 = ETH_MACADDR0 << 8 | ETH_MACADDR1; |
regs->mac_addr0 = ETH_MACADDR2 << 24 | ETH_MACADDR3 << 16 | ETH_MACADDR4 << 8 | ETH_MACADDR5; |
|
/* Clear all pending interrupts |
*/ |
regs->int_src = 0xffffffff; |
|
/* Promisc, IFG, CRCEn |
*/ |
regs->moder |= OETH_MODER_PRO | OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN | OETH_MODER_FULLD; |
|
/* Enable interrupt sources. |
*/ |
|
regs->int_mask = OETH_INT_MASK_TXB | |
OETH_INT_MASK_TXE | |
OETH_INT_MASK_RXF | |
OETH_INT_MASK_RXE | |
OETH_INT_MASK_BUSY | |
OETH_INT_MASK_TXC | |
OETH_INT_MASK_RXC; |
|
// Buffer setup stuff |
volatile oeth_bd *tx_bd, *rx_bd; |
int i,j,k; |
|
/* Initialize TXBD pointer |
*/ |
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
|
/* Initialize RXBD pointer |
*/ |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
/* Preallocated ethernet buffer setup */ |
unsigned long mem_addr = ETH_BUFF_BASE; /* Defined at top */ |
|
// Setup TX Buffers |
for(i = 0; i < OETH_TXBD_NUM; i++) { |
//tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ; |
tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; |
tx_bd[i].addr = mem_addr; |
mem_addr += OETH_TX_BUFF_SIZE; |
} |
tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP; |
|
// Setup RX buffers |
for(i = 0; i < OETH_RXBD_NUM; i++) { |
rx_bd[i].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; // Init. with IRQ |
rx_bd[i].addr = mem_addr; |
mem_addr += OETH_RX_BUFF_SIZE; |
} |
rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; // Last buffer wraps |
|
/* Enable JUST the transmiter |
*/ |
regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN); |
regs->moder |= /*OETH_MODER_RXEN |*/ OETH_MODER_TXEN; |
|
next_tx_buf_num = 0; // init tx buffer pointer |
|
return; |
} |
|
|
|
/* Setup buffer descriptors with data */ |
/* length is in BYTES */ |
void tx_packet(void* data, int length) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
volatile int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
tx_bd = (struct oeth_bd*) &tx_bd[next_tx_buf_num]; |
|
// If it's in use - wait |
while ((tx_bd->len_status & OETH_TX_BD_IRQ)); |
|
/* Clear all of the status flags. |
*/ |
tx_bd->len_status &= ~OETH_TX_BD_STATS; |
|
/* If the frame is short, tell CPM to pad it. |
*/ |
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ |
if (length <= ETH_ZLEN) |
tx_bd->len_status |= OETH_TX_BD_PAD; |
else |
tx_bd->len_status &= ~OETH_TX_BD_PAD; |
|
#ifdef _ETH_RXTX_DATA_H_ |
// Set the address pointer to the place |
// in memory where the data is and transmit from there |
|
tx_bd->addr = (char*) &tx_data_array[tx_data_pointer&~(0x3)]; |
|
tx_data_pointer += length; |
if (tx_data_pointer > (255*1024)) |
tx_data_pointer = 0; |
|
|
#else |
if (data){ |
//Copy the data into the transmit buffer, byte at a time |
char* data_p = (char*) data; |
char* data_b = (char*) tx_bd->addr; |
for(i=0;i<length;i++) |
{ |
data_b[i] = data_p[i]; |
} |
} |
#endif |
|
/* Set the length of the packet's data in the buffer descriptor */ |
tx_bd->len_status = (tx_bd->len_status & 0x0000ffff) | |
((length&0xffff) << 16); |
|
/* Send it on its way. Tell controller its ready, interrupt when sent |
* and to put the CRC on the end. |
*/ |
tx_bd->len_status |= (OETH_TX_BD_READY | OETH_TX_BD_CRC | OETH_TX_BD_IRQ); |
|
next_tx_buf_num = (next_tx_buf_num + 1) & OETH_TXBD_NUM_MASK; |
|
return; |
|
} |
|
/* enable RX, loop waiting for arrived packets and print them out */ |
void oeth_monitor_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
/* Set RXEN in MAC MODER */ |
regs->moder = OETH_MODER_RXEN | regs->moder; |
|
|
volatile oeth_bd *rx_bd; |
rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
volatile int i; |
|
while (1) |
{ |
|
for(i=0;i<OETH_RXBD_NUM;i++) |
{ |
if (!(rx_bd[i].len_status & OETH_RX_BD_EMPTY)) /* Not empty */ |
{ |
// Something in this buffer! |
printk("Oeth: RX in buf %d - len_status: 0x%lx\n",i, rx_bd[i].len_status); |
/* Clear recieved bit */ |
rx_bd[i].len_status |= OETH_RX_BD_EMPTY; |
printk("\t end of packet\n\n"); |
} |
} |
} |
} |
|
|
char broadcast_ping_packet[] = { |
0xff,0xff,0xff,0xff,0xff,0xff, /*SRC MAC*/ |
0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, /*SRC MAC*/ |
0x08,0x00, |
0x45, |
0x00, |
0x00,0x54, |
0x00,0x00, |
0x40, |
0x00, |
0x40, |
0x01, |
0xef,0xef, |
0xc0,0xa8,0x64,0x58, /* Source IP */ |
0xc0,0xa8,0x64,0xff, /* Dest. IP */ |
/* ICMP Message body */ |
0x08,0x00,0x7d,0x65,0xa7,0x20,0x00,0x01,0x68,0x25,0xa5,0x4a,0xcf,0x05,0x0c,0x00,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37}; |
|
|
char big_broadcast_ping_packet[] = { |
0xff,0xff,0xff,0xff,0xff,0xff, /*SRC MAC*/ |
0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, /*SRC MAC*/ |
0x08,0x00, |
0x45, |
0x00, |
// 0x00,0x54, /* length */ |
0x05,0x1c, /* length */ |
0x00,0x00, |
0x40, |
0x00, |
0x40, |
0x01, |
0xee,0xf5, |
0xc0,0xa8,0x64,0x9b, /* Source IP */ |
0xc0,0xa8,0x64,0xff, /* Dest. IP */ |
/* ICMP Message body */ |
0x08,0x00,0x7d,0x65,0xa7,0x20,0x00,0x01,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, |
15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39, |
40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, |
65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89, |
90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110, |
111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129, |
130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148, |
149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167, |
168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, |
187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205, |
206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224, |
225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243, |
244,245,246,247,248,249,250,251,252,253,254,255, |
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, |
15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39, |
40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, |
65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89, |
90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110, |
111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129, |
130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148, |
149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167, |
168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, |
187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205, |
206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224, |
225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243, |
244,245,246,247,248,249,250,251,252,253,254,255, |
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, |
15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39, |
40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, |
65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89, |
90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110, |
111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129, |
130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148, |
149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167, |
168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, |
187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205, |
206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224, |
225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243, |
244,245,246,247,248,249,250,251,252,253,254,255, |
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, |
15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39, |
40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, |
65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89, |
90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110, |
111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129, |
130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148, |
149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167, |
168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, |
187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205, |
206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224, |
225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243, |
244,245,246,247,248,249,250,251,252,253,254,255, |
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, |
15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39, |
40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64, |
65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89, |
90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110, |
111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129, |
130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148, |
149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167, |
168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, |
187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205, |
206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224, |
225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243, |
244,245,246,247,248,249,250,251,252,253,254,255}; |
|
|
/* This should be 98 bytes big */ |
char ping_packet[] = { |
0x00, 0x24, 0xe8, 0x91, 0x7c, 0x0d, /*DST MAC*/ |
//0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*DST MAC*/ |
0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, /*SRC MAC*/ |
0x08, 0x00, /*TYPE*/ |
/* IP */ |
0x45, /* Version, header length*/ |
0x00, /* Differentiated services field */ |
0x00, 0x54, /* Total length */ |
0x00, 0x00, /* Identification */ |
0x40, /* Flags */ |
0x00, /* Fragment offset */ |
0x40, /* Time to live */ |
0x01, /* Protocol (0x01 = ICMP */ |
0xef, 0xf3, /* Header checksum */ |
//0xc0, 0xa8, 0x64, 0xDE, /* Source IP */ |
0xc0, 0xa8, 0x0, 0x58, /* Source IP */ |
//0xa, 0x1, 0x1, 0x3, /* Source IP */ |
0xc0, 0xa8, 0x64, 0x69, /* Dest. IP */ |
0xc0, 0xa8, 0x0, 0xb, /* Dest. IP */ |
//0xa, 0x1, 0x1, 0x1, /* Dest. IP */ |
/* ICMP Message body */ |
0x08, 0x00, 0x9a, 0xd4, 0xc8, 0x18, 0x00, 0x01, 0xd9, 0x8c, 0x54, |
0x4a, 0x7b, 0x37, 0x01, 0x00, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, |
0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, |
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, |
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, |
0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 |
}; |
|
|
/* The interrupt handler. |
*/ |
void |
oeth_interrupt(void) |
{ |
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
uint int_events; |
int serviced; |
|
serviced = 0; |
|
/* Get the interrupt events that caused us to be here. |
*/ |
int_events = regs->int_src; |
regs->int_src = int_events; |
|
|
#ifndef RTLSIM |
printk("."); |
|
printk("\n=tx_ | %x | %x | %x | %x | %x | %x | %x | %x\n", |
((oeth_bd *)(OETH_BD_BASE))->len_status, |
((oeth_bd *)(OETH_BD_BASE+8))->len_status, |
((oeth_bd *)(OETH_BD_BASE+16))->len_status, |
((oeth_bd *)(OETH_BD_BASE+24))->len_status, |
((oeth_bd *)(OETH_BD_BASE+32))->len_status, |
((oeth_bd *)(OETH_BD_BASE+40))->len_status, |
((oeth_bd *)(OETH_BD_BASE+48))->len_status, |
((oeth_bd *)(OETH_BD_BASE+56))->len_status); |
|
printk("=rx_ | %x | %x | %x | %x | %x | %x | %x | %x\n", |
((oeth_bd *)(OETH_BD_BASE+64))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+8))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+16))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+24))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+32))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+40))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+48))->len_status, |
((oeth_bd *)(OETH_BD_BASE+64+56))->len_status); |
|
printk("=int | txb %d | txe %d | rxb %d | rxe %d | busy %d\n", |
(int_events & OETH_INT_TXB) > 0, |
(int_events & OETH_INT_TXE) > 0, |
(int_events & OETH_INT_RXF) > 0, |
(int_events & OETH_INT_RXE) > 0, |
(int_events & OETH_INT_BUSY) > 0); |
#endif |
|
|
|
/* Handle receive event in its own function. |
*/ |
if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) { |
serviced |= 0x1; |
oeth_rx(); |
} |
|
/* Handle transmit event in its own function. |
*/ |
if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) { |
serviced |= 0x2; |
oeth_tx(); |
serviced |= 0x2; |
|
} |
|
/* Check for receive busy, i.e. packets coming but no place to |
* put them. |
*/ |
if (int_events & OETH_INT_BUSY) { |
serviced |= 0x4; |
#ifndef RTLSIM |
printk("b"); |
#endif |
if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE))) |
oeth_rx(); |
} |
|
|
#if 0 |
if (serviced == 0) { |
void die(const char * str, struct pt_regs * regs, long err); |
int show_stack(unsigned long *esp); |
printk("!"); |
// printk("unserviced irq\n"); |
// show_stack(NULL); |
// die("unserviced irq\n", regs, 801); |
} |
#endif |
|
if (serviced == 0) |
printk("\neth interrupt called but nothing serviced\n"); |
|
else /* Something happened ... either RX or TX */ |
printk(" | serviced 0x%x\n", serviced); |
|
return; |
} |
|
|
|
static void |
oeth_rx(void) |
{ |
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *rx_bdp; |
int pkt_len, i; |
int bad = 0; |
|
rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM; |
|
printk("r"); |
|
|
/* Find RX buffers marked as having received data */ |
for(i = 0; i < OETH_RXBD_NUM; i++) |
{ |
bad=0; |
if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ /* Looking for NOT empty buffers desc. */ |
/* Check status for errors. |
*/ |
if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) { |
bad = 1; |
report(0xbaad0001); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) { |
bad = 1; |
report(0xbaad0002); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) { |
bad = 1; |
report(0xbaad0003); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) { |
bad = 1; |
report(0xbaad0004); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_MISS) { |
report(0xbaad0005); |
} |
if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) { |
bad = 1; |
report(0xbaad0006); |
} |
if (bad) { |
rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; |
rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; |
exit(0xbaaaaaad); |
|
continue; |
} |
else { |
/* Process the incoming frame. |
*/ |
pkt_len = rx_bdp[i].len_status >> 16; |
|
/* Do something here with the data - copy it into userspace, perhaps*/ |
printk("\t end of packet\n\n"); |
|
|
/* finish up */ |
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_done++; |
} |
} |
} |
} |
|
|
|
static void |
oeth_tx(void) |
{ |
volatile oeth_bd *tx_bd; |
int i; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/ |
|
/* Go through the TX buffs, search for one that was just sent */ |
for(i = 0; i < OETH_TXBD_NUM; i++) |
{ |
/* Looking for buffer NOT ready for transmit. and IRQ enabled */ |
if( (!(tx_bd[i].len_status & (OETH_TX_BD_READY))) && (tx_bd[i].len_status & (OETH_TX_BD_IRQ)) ) |
{ |
/* Single threaded so no chance we have detected a buffer that has had its IRQ bit set but not its BD_READ flag. Maybe this won't work in linux */ |
tx_bd[i].len_status &= ~OETH_TX_BD_IRQ; |
|
/* Probably good to check for TX errors here */ |
|
/* set our test variable */ |
tx_done++; |
|
printk("T%d",i); |
|
} |
} |
return; |
} |
|
// A function and defines to fill and transmit a packet |
#define MAX_TX_BUFFER 1532 |
static char tx_buffer[MAX_TX_BUFFER]; |
static unsigned long tx_data = 0x2ef2e242; |
static inline char gen_next_tx_byte(void) |
{ |
// Bit of LFSR action |
tx_data = ((~(((((tx_data&(1<<25))>>25)^((tx_data&(1<<13))>>13))^((tx_data&(1<<2))>>2)))&0x01) | (tx_data<<1)); |
//tx_data++; |
return (char) tx_data & 0xff; |
} |
|
void |
fill_and_tx_packet(int size) |
{ |
int i; |
char tx_byte; |
|
|
volatile oeth_regs *regs; |
regs = (oeth_regs *)(OETH_REG_BASE); |
|
volatile oeth_bd *tx_bd; |
|
tx_bd = (volatile oeth_bd *)OETH_BD_BASE; |
tx_bd = (struct oeth_bd*) &tx_bd[next_tx_buf_num]; |
|
|
// If it's in use - wait |
while ((tx_bd->len_status & OETH_TX_BD_IRQ)); |
|
#ifndef _ETH_RXTX_DATA_H_ |
/* Copy the data into the transmit buffer, byte at a time */ |
char* data_b = (char*) tx_bd->addr; |
for(i=0;i<size;i++) |
{ |
data_b[i] = gen_next_tx_byte(); |
} |
#endif |
|
tx_packet((void*)0, size); |
} |
|
//#define WAIT_PACKET_TX(x) while(tx_done<x) |
#define WAIT_PACKET_TX(x) |
|
int main () |
{ |
tx_data_pointer = 0; |
|
/* Initialise handler vector */ |
int_init(); |
|
/* Install ethernet interrupt handler, it is enabled here too */ |
int_add(ETH0_IRQ, oeth_interrupt, 0); |
|
/* Enable interrupts in supervisor register */ |
mtspr (SPR_SR, mfspr (SPR_SR) | SPR_SR_IEE); |
|
ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX and TX in MODER */ |
|
/* clear tx_done, the tx interrupt handler will set it when it's been transmitted */ |
tx_done = 0; |
rx_done = 0; |
|
int i; |
ethphy_set_100mbit(0); |
|
#ifndef ETH_TX_TEST_LENGTH |
# define ETH_TX_TEST_LENGTH 128 |
//# define ETH_TX_TEST_LENGTH OETH_TX_BUFF_SIZE |
#endif |
|
for(i=5;i<ETH_TX_TEST_LENGTH;i+=1) |
fill_and_tx_packet(i); |
|
ethphy_set_10mbit(0); |
for(i=5;i<ETH_TX_TEST_LENGTH;i+=1) |
fill_and_tx_packet(i); |
|
exit(0x8000000d); |
|
|
} |