forked from Imagelibrary/rtems
@@ -1,145 +0,0 @@
|
||||
#include <rtems.h>
|
||||
#include <bsp.h>
|
||||
#include <bsp/if_mve_pub.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Demo for the mv64360 ethernet quirk:
|
||||
*
|
||||
* $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
|
||||
* $$ buffer segments < 8 bytes must be aligned $$
|
||||
* $$ to 8 bytes but larger segments are not $$
|
||||
* $$ sensitive to alignment. $$
|
||||
* $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
|
||||
*
|
||||
* How to use:
|
||||
*
|
||||
* Init MVE driver on (unused) unit 2:
|
||||
*
|
||||
* mve = mvtst_init(2)
|
||||
*
|
||||
* data = { 1,2,3,4,5,6,7,8,9,0xa,0xb, ... }
|
||||
*
|
||||
* Alloc 2-element mbuf chain (1st holds an
|
||||
* ethernet header which is > 8bytes so we can't
|
||||
* test this with only 1 mbuf. The 2nd mbuf holds
|
||||
* a small fragment of data).
|
||||
*
|
||||
* mb = mvtst_getbuf(mve)
|
||||
*
|
||||
* Copy data into aligned area inside 2nd mbuf,
|
||||
* (so that you can see if the chip starts using
|
||||
* the aligned area rather than the unaligned
|
||||
* buffer pointer). Point mbuf's data pointer
|
||||
* at 'off'set from the aligned area:
|
||||
*
|
||||
* mvtst_putbuf(mb, data, len, offset)
|
||||
*
|
||||
* Send chain off:
|
||||
*
|
||||
* BSP_mve_send_buf(mve, mb, 0, 0)
|
||||
*
|
||||
* Watch raw data:
|
||||
*
|
||||
* tcpdump -XX -vv -s0 ether host <my-ether-addr>
|
||||
*
|
||||
* E.g, if offset = 1, len = 2 then we would like
|
||||
* to see
|
||||
*
|
||||
* GOOD:
|
||||
* < 14 header bytes > 0x02, 0x03
|
||||
|
||||
* but if the chip starts DMA at aligned address
|
||||
* we see instead
|
||||
* BAD:
|
||||
* < 14 header bytes > 0x01, 0x02
|
||||
*/
|
||||
|
||||
static inline void *rmalloc(size_t l) { return malloc(l); }
|
||||
static inline void rfree(void *p) { return free(p); }
|
||||
|
||||
#define _KERNEL
|
||||
#include <sys/param.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
static void
|
||||
cleanup_buf(void *u_b, void *closure, int error)
|
||||
{
|
||||
rtems_bsdnet_semaphore_obtain();
|
||||
m_freem((struct mbuf*)u_b);
|
||||
rtems_bsdnet_semaphore_release();
|
||||
}
|
||||
|
||||
struct mbuf *mvtst_getbuf(struct mveth_private *mp)
|
||||
{
|
||||
struct mbuf *m,*n;
|
||||
|
||||
if ( !mp ) {
|
||||
printf("need driver ptr arg\n");
|
||||
return 0;
|
||||
}
|
||||
rtems_bsdnet_semaphore_obtain();
|
||||
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
||||
MGET(n, M_DONTWAIT, MT_DATA);
|
||||
m->m_next = n;
|
||||
rtems_bsdnet_semaphore_release();
|
||||
/* Ethernet header */
|
||||
memset( mtod(m, unsigned char*), 0xff, 6);
|
||||
BSP_mve_read_eaddr(mp, mtod(m, unsigned char*) + 6);
|
||||
/* Arbitrary; setting to IP but we don't bother
|
||||
* to setup a real IP header. We just watch the
|
||||
* raw packet contents...
|
||||
*/
|
||||
mtod(m, unsigned char*)[12] = 0x08;
|
||||
mtod(m, unsigned char*)[13] = 0x00;
|
||||
m->m_pkthdr.len = m->m_len = 14;
|
||||
n->m_len = 0;
|
||||
return m;
|
||||
}
|
||||
|
||||
int
|
||||
mvtst_putbuf(struct mbuf *m, void *data, int len, int off)
|
||||
{
|
||||
int i;
|
||||
if ( m ) {
|
||||
m->m_pkthdr.len += len;
|
||||
if ( ( m= m->m_next ) ) {
|
||||
m->m_len = len;
|
||||
memcpy(mtod(m, void*), data, 32);
|
||||
m->m_data += off;
|
||||
printf("m.dat: 0x%08x, m.data: 0x%08x\n", m->m_dat, m->m_data);
|
||||
for ( i=0; i< 16; i++ ) {
|
||||
printf(" %02x,",mtod(m, unsigned char*)[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *alloc_rxbuf(int *p_size, unsigned long *paddr)
|
||||
{
|
||||
return *(void**)paddr = rmalloc((*p_size = 1800));
|
||||
}
|
||||
|
||||
static void consume_buf(void *buf, void *closure, int len)
|
||||
{
|
||||
rfree(buf);
|
||||
}
|
||||
|
||||
void *
|
||||
mvtst_init(int unit)
|
||||
{
|
||||
struct mveth_private *mp;
|
||||
mp = BSP_mve_setup(
|
||||
unit, 0,
|
||||
cleanup_buf, 0,
|
||||
alloc_rxbuf,
|
||||
consume_buf, 0,
|
||||
10, 10,
|
||||
0);
|
||||
if ( mp )
|
||||
BSP_mve_init_hw(mp, 0, 0);
|
||||
return mp;
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
#ifndef KERNEL
|
||||
#define KERNEL
|
||||
#endif
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/rtems_bsdnet_internal.h>
|
||||
#include <bsp.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/mbuf.h>
|
||||
|
||||
#include "mv64340_eth_ll.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define RX_SPACING 1
|
||||
#define TX_SPACING 1
|
||||
|
||||
#define RX_RING_SIZE (MV64340_RX_QUEUE_SIZE*RX_SPACING)
|
||||
#define TX_RING_SIZE (MV64340_TX_QUEUE_SIZE*TX_SPACING)
|
||||
|
||||
|
||||
struct eth_rx_desc rx_ring[RX_RING_SIZE] __attribute__((aligned(32)));
|
||||
struct eth_rx_desc rx_ring[RX_RING_SIZE] = {{0},};
|
||||
|
||||
struct eth_tx_desc tx_ring[TX_RING_SIZE] __attribute__((aligned(32)));
|
||||
struct eth_tx_desc tx_ring[TX_RING_SIZE] = {{0},};
|
||||
|
||||
/* packet buffers */
|
||||
char rx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
|
||||
char rx_buf[MV64340_RX_QUEUE_SIZE][2048];
|
||||
|
||||
char tx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
|
||||
char tx_buf[MV64340_RX_QUEUE_SIZE][2048];
|
||||
|
||||
char BcHeader[22] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* dst */
|
||||
0x00, 0x01, 0xaf, 0x13, 0xb5, 0x3e, /* src */
|
||||
00, 00, /* len */
|
||||
0xAA, /* dsap */
|
||||
0xAA, /* ssap */
|
||||
0x03, /* ctrl */
|
||||
0x08, 0x00, 0x56, /* snap_org [stanford] */
|
||||
0x80, 0x5b, /* snap_type (stanford kernel) */
|
||||
};
|
||||
|
||||
struct mv64340_private mveth = {
|
||||
port_num: 0,
|
||||
port_mac_addr: {0x00,0x01,0xAF,0x13,0xB5,0x3C},
|
||||
/* port_config .. tx_resource_err are set by port_init */
|
||||
0
|
||||
};
|
||||
|
||||
struct pkt_info p0,p1;
|
||||
|
||||
static inline void rx_stopq(int port)
|
||||
{
|
||||
MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port), 0x0000ff00);
|
||||
}
|
||||
|
||||
static inline void tx_stopq(int port)
|
||||
{
|
||||
MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port), 0x0000ff00);
|
||||
}
|
||||
|
||||
#define MV64360_ENET2MEM_SNOOP_NONE 0x0000
|
||||
#define MV64360_ENET2MEM_SNOOP_WT 0x1000
|
||||
#define MV64360_ENET2MEM_SNOOP_WB 0x2000
|
||||
|
||||
#if 0
|
||||
int
|
||||
mveth_init(struct mv64340_private *mp)
|
||||
{
|
||||
int i;
|
||||
mp->p_rx_desc_area = rx_ring;
|
||||
mp->p_tx_desc_area = tx_ring;
|
||||
|
||||
rx_stopq(mp->port_num);
|
||||
tx_stopq(mp->port_num);
|
||||
|
||||
/* MotLoad has cache snooping disabled on the ENET2MEM windows.
|
||||
* Some comments in (linux) indicate that there are errata
|
||||
* which cause problems which is a real bummer.
|
||||
* We try it anyways...
|
||||
*/
|
||||
{
|
||||
unsigned long disbl, bar;
|
||||
disbl = MV_READ(MV64340_ETH_BASE_ADDR_ENABLE_REG);
|
||||
/* disable all 6 windows */
|
||||
MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, 0x3f);
|
||||
/* set WB snooping */
|
||||
for ( i=0; i<6*8; i+=8 ) {
|
||||
if ( (bar = MV_READ(MV64340_ETH_BAR_0 + i)) && MV_READ(MV64340_ETH_SIZE_REG_0 + i) ) {
|
||||
MV_WRITE(MV64340_ETH_BAR_0 + i, bar | MV64360_ENET2MEM_SNOOP_WB);
|
||||
/* read back to flush fifo [linux comment] */
|
||||
(void)MV_READ(MV64340_ETH_BAR_0 + i);
|
||||
}
|
||||
}
|
||||
/* restore/re-enable */
|
||||
MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, disbl);
|
||||
}
|
||||
|
||||
eth_port_init(mp);
|
||||
|
||||
sleep(1);
|
||||
|
||||
mveth_init_tx_desc_ring(mp);
|
||||
mveth_init_rx_desc_ring(mp);
|
||||
#if 0
|
||||
for ( i = 0; i<MV64340_RX_QUEUE_SIZE; i++ ) {
|
||||
p0.byte_cnt = sizeof(rx_buf[0]);
|
||||
p0.buf_ptr = (dma_addr_t)rx_buf[i];
|
||||
p0.return_info = (void*)i;
|
||||
/* other fields are not used by ll driver */
|
||||
assert ( ETH_OK == eth_rx_return_buff(mp,&p0) );
|
||||
}
|
||||
memset(&p0, 0, sizeof(p0));
|
||||
#endif
|
||||
|
||||
return eth_port_start(mp);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
mveth_stop(struct mv64340_private *mp)
|
||||
{
|
||||
extern void mveth_stop_hw();
|
||||
rtems_bsdnet_semaphore_obtain();
|
||||
mveth_stop_hw(mp);
|
||||
rtems_bsdnet_semaphore_release();
|
||||
}
|
||||
|
||||
extern int mveth_send_mbuf();
|
||||
extern int mveth_swipe_tx();
|
||||
|
||||
int
|
||||
mveth_tx(struct mv64340_private *mp, char *data, int len, int nbufs)
|
||||
{
|
||||
int rval = -1,l;
|
||||
char *p;
|
||||
struct mbuf *m;
|
||||
char *emsg = 0;
|
||||
|
||||
rtems_bsdnet_semaphore_obtain();
|
||||
MGETHDR(m, M_WAIT, MT_DATA);
|
||||
if ( !m ) {
|
||||
emsg="Unable to allocate header\n";
|
||||
goto bail;
|
||||
}
|
||||
MCLGET(m, M_WAIT);
|
||||
if ( !(m->m_flags & M_EXT) ) {
|
||||
m_freem(m);
|
||||
emsg="Unable to allocate cluster\n";
|
||||
goto bail;
|
||||
}
|
||||
p = mtod(m, char *);
|
||||
l = 0;
|
||||
switch (nbufs) {
|
||||
case 3:
|
||||
default:
|
||||
emsg="nbufs arg must be 1..3\n";
|
||||
goto bail;
|
||||
|
||||
case 1:
|
||||
l += sizeof(BcHeader);
|
||||
memcpy(p, &BcHeader, sizeof(BcHeader));
|
||||
p += sizeof(BcHeader);
|
||||
|
||||
case 2:
|
||||
memcpy(p,data,len);
|
||||
l += len;
|
||||
m->m_len = m->m_pkthdr.len = l;
|
||||
if ( 2 == nbufs ) {
|
||||
M_PREPEND(m, sizeof (BcHeader), M_WAIT);
|
||||
if (!m) {
|
||||
emsg = "Unable to prepend\n";
|
||||
goto bail;
|
||||
}
|
||||
p = mtod(m, char*);
|
||||
memcpy(p,&BcHeader,sizeof(BcHeader));
|
||||
l += sizeof(BcHeader);
|
||||
}
|
||||
break;
|
||||
}
|
||||
*(short*)(mtod(m, char*) + 12) = htons(l-14);
|
||||
rval = mveth_send_mbuf(mp,m);
|
||||
|
||||
bail:
|
||||
rtems_bsdnet_semaphore_release();
|
||||
if (emsg)
|
||||
printf(emsg);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Add local net header. If no space in first mbuf,
|
||||
* allocate another.
|
||||
*/
|
||||
M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
|
||||
if (m == 0)
|
||||
senderr(ENOBUFS);
|
||||
eh = mtod(m, struct ether_header *);
|
||||
(void)memcpy(&eh->ether_type, &type,
|
||||
sizeof(eh->ether_type));
|
||||
(void)memcpy(eh->ether_dhost, edst, sizeof (edst));
|
||||
(void)memcpy(eh->ether_shost, ac->ac_enaddr,
|
||||
sizeof(eh->ether_shost));
|
||||
#endif
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
mveth_protected(int (*p)(struct mv64340_private*), struct mv64340_private *mp)
|
||||
{
|
||||
int rval;
|
||||
rtems_bsdnet_semaphore_obtain();
|
||||
rval = p(mp);
|
||||
rtems_bsdnet_semaphore_release();
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
mveth_rx(struct mv64340_private *mp)
|
||||
{
|
||||
extern int mveth_swipe_rx();
|
||||
return mveth_protected(mveth_swipe_rx,mp);
|
||||
}
|
||||
|
||||
int
|
||||
mveth_reclaim(struct mv64340_private *mp)
|
||||
{
|
||||
extern int mveth_swipe_tx();
|
||||
return mveth_protected(mveth_swipe_tx,mp);
|
||||
}
|
||||
|
||||
|
||||
int preth(FILE *f, char *p)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<4; i++)
|
||||
fprintf(f,"%02X:",p[i]);
|
||||
fprintf(f,"%02X",p[i]);
|
||||
return 6;
|
||||
}
|
||||
|
||||
char *errcode2str(st)
|
||||
{
|
||||
char *rval;
|
||||
switch(st) {
|
||||
case ETH_OK:
|
||||
rval = "OK";
|
||||
break;
|
||||
case ETH_ERROR:
|
||||
rval = "Fundamental error.";
|
||||
break;
|
||||
case ETH_RETRY:
|
||||
rval = "Could not process request. Try later.";
|
||||
break;
|
||||
case ETH_END_OF_JOB:
|
||||
rval = "Ring has nothing to process.";
|
||||
break;
|
||||
case ETH_QUEUE_FULL:
|
||||
rval = "Ring resource error.";
|
||||
break;
|
||||
case ETH_QUEUE_LAST_RESOURCE:
|
||||
rval = "Ring resources about to exhaust.";
|
||||
break;
|
||||
default:
|
||||
rval = "UNKNOWN"; break;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int
|
||||
mveth_rx(struct mv64340_private *mp)
|
||||
{
|
||||
int st;
|
||||
struct pkt_info p;
|
||||
if ( ETH_OK != (st=eth_port_receive(mp, &p)) ) {
|
||||
fprintf(stderr,"receive: %s\n", errcode2str(st));
|
||||
return -1;
|
||||
}
|
||||
printf("%i bytes received from ", p.byte_cnt);
|
||||
preth(stdout,(char*)p.buf_ptr+6);
|
||||
printf(" (desc. stat: 0x%08x)\n", p.cmd_sts);
|
||||
|
||||
p.byte_cnt = sizeof(rx_buf[0]);
|
||||
p.buf_ptr -= RX_BUF_OFFSET;
|
||||
if ( ETH_OK != (st=eth_rx_return_buff(mp,&p) ) ) {
|
||||
fprintf(stderr,"returning buffer: %s\n", errcode2str(st));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
dring()
|
||||
{
|
||||
int i;
|
||||
if (1) {
|
||||
struct eth_rx_desc *pr;
|
||||
printf("RX:\n");
|
||||
for (i=0, pr=rx_ring; i<RX_RING_SIZE; i+=RX_SPACING, pr+=RX_SPACING) {
|
||||
dcbi(pr);
|
||||
printf("cnt: 0x%04x, size: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
|
||||
pr->byte_cnt, pr->buf_size, pr->cmd_sts, pr->next_desc_ptr, pr->buf_ptr);
|
||||
}
|
||||
}
|
||||
if (1) {
|
||||
struct eth_tx_desc *pt;
|
||||
printf("TX:\n");
|
||||
for (i=0, pt=tx_ring; i<TX_RING_SIZE; i+=TX_SPACING, pt+=TX_SPACING) {
|
||||
dcbi(pt);
|
||||
printf("cnt: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
|
||||
pt->byte_cnt, pt->cmd_sts, pt->next_desc_ptr, pt->buf_ptr);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#include <rtems.h>
|
||||
#include <porting/rtemscompat.h>
|
||||
|
||||
/* CEXP module initialization/finalization */
|
||||
|
||||
/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
|
||||
* License: see LICENSE file.
|
||||
*/
|
||||
|
||||
void
|
||||
_cexpModuleInitialize(void *unused)
|
||||
{
|
||||
extern void NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)(char *);
|
||||
METHODSPTR = &METHODS;
|
||||
/*
|
||||
#ifdef DEBUG
|
||||
NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)("192.168.2.13/255.255.255.0");
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
int
|
||||
_cexpModuleFinalize(void *unused)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
extern int NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)();
|
||||
if (NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)())
|
||||
return -1;
|
||||
METHODSPTR = 0;
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user