📄 adam.c
字号:
// file: adam.c
//
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "..\..\stripe.h"
#include "mode_ctrl00.h"
#include "adam.h"
#include "serial.h" // for readtimeXs()
#include "utils.h" // only for debug, dump_pkt(), decode_pkt()
//============================================
int eth_descriptor_initialise(type_eth_descriptors *eth);
//============================================
// globals
// this buffer is used to copy a fragmented received packet into so that
// a single buffer can be passed up the stack
UCHAR rbuf[2000];
//UCHAR rbuf[1518];
//============================================
int eth_config(type_eth_descriptors *eth)
{
int i;
/*
debug
00 - none
01 - T/R
02 - T: tbuf = 0x01234567, tlen = 0x1234 / R: ...
04 - dump buffer
08 - decode buffer
*/
eth->debug = 0x0;
// special multicast address for control frames
eth->macaddr[0] = 0x01;
eth->macaddr[1] = 0x80;
eth->macaddr[2] = 0xc2;
eth->macaddr[3] = 0x00;
eth->macaddr[4] = 0x00;
eth->macaddr[5] = 0x01;
// local MAC address
eth->macaddr[6] = 0x00;
eth->macaddr[7] = 0xe8;
eth->macaddr[8] = 0xca;
eth->macaddr[9] = 0x11;
eth->macaddr[10] = 0xba;
eth->macaddr[11] = 0x01;
// default pause frame
eth->macaddr[0x78] = 0x88; // special MAC control type_len field
eth->macaddr[0x79] = 0x08;
eth->macaddr[0x7a] = 0x00; // pause op_code, 0001
eth->macaddr[0x7b] = 0x01;
eth->macaddr[0x7c] = 0x12; // pause duration, 1234
eth->macaddr[0x7d] = 0x34;
eth->macaddr[0x7e] = 0x00;
eth->macaddr[0x7f] = 0x00;
for (i=12; i<0x78; i++) eth->macaddr[i] = 0;
eth->nummacs = 2;
// eth->arcmode = UNICAST | BROADCAST;
eth->arcmode = UNICAST | BROADCAST | MULTICAST;
// eth->arcmode = BROADCAST | PROMISCUOUS | MULTICAST | UNICAST;
eth->fullduplex = 1;
eth->tx_desc = TX_DESC;
eth->tx_desc_done = TX_DESC;
eth->rx_bl_desc = RX_BL_DESC;
eth->rx_fda_desc = RX_FDA_DESC;
eth->tx_desc_base = TX_DESC;
eth->tx_num_descs = NUM_TX_DESC;
eth->tx_num_buffs = NUM_TX_BUFFS;
eth->rx_bl_desc_base = RX_BL_DESC;
eth->rx_buffer_base = RX_BUFFER;
eth->rx_buffer_length = RX_BUFFER_LEN;
eth->rx_num_descs = NUM_RX_DESC;
eth->rx_num_buffs = NUM_RX_BUFFS;
eth->rx_fda_desc_base = RX_FDA_DESC;
eth->rx_fda_limit = RX_FDA_LIMIT;
return 0;
}
int eth_init(type_eth_descriptors * eth)
{
int i;
ULONG mask;
eth_descriptor_initialise(eth);
// set up ARC
for (i=0; i<0x80; i+=4)
{
write_csr(MAC_ARC_ADDR, i);
write_csr(MAC_ARC_DATA, ((eth->macaddr[i+0] & 0xff) << 24) | ((eth->macaddr[i+1] & 0xff) << 16) | ((eth->macaddr[i+2] & 0xff) << 8) | ((eth->macaddr[i+3] & 0xff) << 0));
}
// seup up MC#1, MC#2
for (i=0x80; i<0x84; i+=4)
{
write_csr(MAC_ARC_ADDR, i);
write_csr(MAC_ARC_DATA, 0x00000000);
}
mask = 0;
for (i=0; i<eth->nummacs; i++)
mask = (mask << 1) | 1;
write_csr(MAC_ARC_ENA, mask);
write_csr(MAC_ARC_CTL, eth->arcmode);
// set up mac
write_csr(MAC_MAC_CTL, 0x00000100 | ((eth->fullduplex) ? 8 : 0)); // default + duplex
write_csr(MAC_TX_CTL, 0x00007f01); // set TxEN, enable all interrupts
write_csr(MAC_RX_CTL, 0x00006f91); // set RxEN, enable all interrupts, strip crc, disable LenErr
// set up dma
//HB write_csr(DMA_CTL, 0x00000020); // burst length = 8 cycles
write_csr(DMA_CTL, 0x00000040); // burst length = 16 cycles
write_csr(DMA_TX_THRESH, 0x00000020);
write_csr(DMA_TX_TPOLLCTR, 0x00000001);
write_csr(DMA_RX_FRAGSIZE, 0x00000000);
write_csr(DMA_INT_EN, 0x00000fff);
write_csr(DMA_FDA_BASE, eth->rx_fda_desc_base);
write_csr(DMA_FDA_LIMIT, eth->rx_fda_limit - (0x10 + (8*(0x600/RX_BUFFER_LEN)))); // max # buffers req'd for packet
// enable irq - must be in supervisor mode ...
__asm{mrs r0,CPSR};
__asm{bic r0, r0, #0x80};
__asm{msr CPSR_c, r0};
// This kicks off TxPro, so set up other registers first.
write_csr(DMA_TX_FRMPTR, eth->tx_desc_base); // transmit frame pointer
// This kicks off RxCon, so set up other registers first.
write_csr(DMA_BLFRMPTR, eth->rx_bl_desc_base); // buffer list frame pointer
return 0;
}
int eth_descriptor_initialise(type_eth_descriptors *eth)
{
ULONG rxbuff;
int i,j;
// set up the tx descriptors
eth->tx_desc = eth->tx_desc_base;
// initialise all NUM_TX_DESC frame descriptors, retain own bit
for (i=0; i<eth->tx_num_descs; i++)
{
// initialise the frame descriptor
*(volatile ULONG *)(eth->tx_desc+0x00) = eth->tx_desc+0x10 + (8*eth->tx_num_buffs); // fdnext
*(volatile ULONG *)(eth->tx_desc+0x04) = 0x00000000; // fdsystem[32] - not used
*(volatile ULONG *)(eth->tx_desc+0x08) = 0x00000000; // fdstat
*(volatile ULONG *)(eth->tx_desc+0x0c) = 0x00010000; // fdctl[16], (fdlength[16] not used on tx)
// no need to initialise the transmit buffer descriptors here
// this is done by the send_packet routine
// there may be NUM_TX_BUFFS buffers per descriptor
eth->tx_desc += 0x10 + (8*eth->tx_num_buffs);
}
// create a loop in the descriptors
*(volatile ULONG *)(eth->tx_desc-(0x10 + (8*eth->tx_num_buffs))) = eth->tx_desc_base; // fdnext
// no need to initialise transmit buffers
// set up the rx ram
eth->rx_bl_desc = eth->rx_bl_desc_base;
rxbuff = eth->rx_buffer_base;
// initialise all NUM_RX_DESC frame descriptors
for (i=0; i<eth->rx_num_descs; i++)
{
// free buffer descriptor
*(volatile ULONG *)(eth->rx_bl_desc+0x00) = eth->rx_bl_desc+0x10 + (8*eth->rx_num_buffs); // fdnext
*(volatile ULONG *)(eth->rx_bl_desc+0x04) = eth->rx_bl_desc; // fdsystem - identify descriptor
*(volatile ULONG *)(eth->rx_bl_desc+0x08) = 0x00000000; // fdstat
*(volatile ULONG *)(eth->rx_bl_desc+0x0c) = 0x80000000 | eth->rx_num_buffs; // fdctl_fdlength
// free buffer list
for (j=0; j<eth->rx_num_buffs; j++)
{
*(volatile ULONG *)(eth->rx_bl_desc+0x10+(8*j)) = rxbuff;
*(volatile ULONG *)(eth->rx_bl_desc+0x14+(8*j)) = 0x80000000 | eth->rx_buffer_length;
rxbuff += eth->rx_buffer_length;
}
// there may be NUM_RX_BUFFS buffers per descriptor
eth->rx_bl_desc += 0x10 + (8*eth->rx_num_buffs);
}
// create a loop in the descriptors
*(volatile ULONG *)(eth->rx_bl_desc-(0x10 + (8*eth->rx_num_buffs))) = eth->rx_bl_desc_base; // fdnext
// initialise the fda descriptors
eth->rx_fda_desc = eth->rx_fda_desc_base;
for (i=0; i<eth->rx_fda_limit; i+=4)
{
*(volatile ULONG *)(eth->rx_fda_desc+i) = 0xffffffff;
}
// these are global - make sure they start at the beginning
eth->tx_desc = eth->tx_desc_base;
eth->tx_desc_done = eth->tx_desc_base;
eth->rx_fda_desc = eth->rx_fda_desc_base;
return 0;
}
int eth_transmit(type_eth_descriptors *eth, void *tbuf, int tlen, int wait)
{
ULONG rdata;
ULONG tstart, tnow;
if (eth->debug & 0x01) printf("T");
if (eth->debug & 0x02) printf("T: tbuf = 0x%08lx, tlen = 0x%x, eth->tx_desc = 0x%08lx\n",(ULONG)tbuf, tlen, eth->tx_desc);
if (eth->debug & 0x04) dump_pkt((pkt_type *)tbuf, tlen);
if (eth->debug & 0x08) decode_pkt((pkt_type *)tbuf, tlen);
readtimeus();
// check for line plugged in ????
// check status of any previously transmitted packets
eth_transmit_status(eth);
// check descriptor is not owned by core
if (*(volatile ULONG *)(eth->tx_desc+0x0c) & 0x80000000)
{
// printf("*** TX_DESCRIPTOR_QUEUE FULL - dropping packet, eth->tx_desc=%lx, eth->tx_desc[0x0c]=%lx ***", eth->tx_desc, *(volatile ULONG *)(eth->tx_desc+0x0c));
return -1;
}
// set up the transmit descriptors
// use only 1 buffer per packet
*(volatile ULONG *)(eth->tx_desc+0x10) = (ULONG)tbuf; // set pointer to data
*(volatile ULONG *)(eth->tx_desc+0x14) = 0x80000000 | tlen; // set own bit, set data length
*(volatile ULONG *)(eth->tx_desc+0x18) = (ULONG)0; // set pointer to data
*(volatile ULONG *)(eth->tx_desc+0x1c) = 0x80000000 | 0; // set own bit, set data length
// transmit frame descriptor - must be aligned on 16 byte boundaries
*(volatile ULONG *)(eth->tx_desc+0x0c) = 0x80010000; // set own bit, set 1 buffer descriptors
// move on the frame descriptor
eth->tx_desc = *(volatile ULONG *)(eth->tx_desc + 0x00);
// give the core a kick, rather than wait for the polling
rdata = read_csr(DMA_CTL);
write_csr(DMA_CTL, (rdata & 0xffffffff) | 0x00010000);
// !! beware that buffer should not be freed until packet has actually been transmitted
// or at least been read by the DMA controller
// be afraid of re-using tx buffers ...
// could wait for desc to be read by dma..
tstart = readtimems();
tnow = readtimems() - tstart;
// timeout after 100ms
if (wait)
{
while (eth_transmit_status(eth) && (tnow < 100)) tnow = readtimems() - tstart;
if (tnow >= 100) printf("*** eth_transmit() - transmit timeout ***\n");
}
return 0;
}
// we need a routine to check the status of transmitted packets
// the eth_transmit() routine sets the own bit
// the controller clears it, and sets the tx_status
// we need to monitor this and check the status
// when should this be called ???
// - could call it from tx_completed interrupt
// - could call it before sending a packet
// - could call it after sending a packet
int eth_transmit_status(type_eth_descriptors *eth)
{
ULONG stat;
// check if the q is empty
while (eth->tx_desc_done != eth->tx_desc)
{
// check the own bit
if (!(*(volatile ULONG *)(eth->tx_desc_done+0x0c) & 0x80000000))
{
// get the status
stat = *(volatile ULONG *)(eth->tx_desc_done+0x08);
if (stat & 0x1350)
{
printf("\n*** tx error ***\n");
printf("MAC_TX_STAT = %08lx\n", stat);
if (stat & 0x0010) printf("*** excessive collisions ***\n");
if (stat & 0x0040) printf("*** paused ***\n");
if (stat & 0x0100) printf("*** underrun ***\n");
if (stat & 0x0200) printf("*** excessive deferrals ***\n");
if (stat & 0x1000) printf("*** late collision ***\n");
if (stat & 0x10000) printf("*** MAC control packet ***\n");
if (stat & 0x20000) printf("*** MAC control PAUSE packet ***\n");
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -