From 4a22671053cc3e237a17d1f91573eb9934c304f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Fr=C3=B6schle?= Date: Mon, 23 Dec 2013 12:55:19 +0000 Subject: [PATCH] added code to support FEC networking --- BaS_gcc/Makefile | 17 ++-- BaS_gcc/bas.lk.in | 7 ++ BaS_gcc/include/udp.h | 27 ++--- BaS_gcc/net/bootp.c | 33 ++++++ BaS_gcc/net/fec.c | 5 +- BaS_gcc/net/fecbd.c | 226 ++++++++++++++++++++++++++++++++++++++++++ BaS_gcc/net/nbuf.c | 120 ++++++++++------------ BaS_gcc/net/nif.c | 118 ++++++++++++++++++++++ BaS_gcc/net/queue.c | 114 +++++++++++++++++++++ BaS_gcc/net/udp.c | 180 +++++++++++++++++++++++++++++++++ BaS_gcc/sys/BaS.c | 8 ++ 11 files changed, 759 insertions(+), 96 deletions(-) create mode 100644 BaS_gcc/net/bootp.c create mode 100644 BaS_gcc/net/fecbd.c create mode 100644 BaS_gcc/net/nif.c create mode 100644 BaS_gcc/net/queue.c create mode 100644 BaS_gcc/net/udp.c diff --git a/BaS_gcc/Makefile b/BaS_gcc/Makefile index 07f809a..7af89ac 100644 --- a/BaS_gcc/Makefile +++ b/BaS_gcc/Makefile @@ -67,6 +67,7 @@ CSRCS= \ bas_string.c \ BaS.c \ cache.c \ + mmu.c \ mmc.c \ unicode.c \ ff.c \ @@ -84,15 +85,18 @@ CSRCS= \ MCD_dmaApi.c \ MCD_tasks.c \ MCD_tasksInit.c \ - \ usb.c \ ohci-hcd.c \ ehci-hcd.c \ usb_mouse.c \ - \ ikbd.c \ \ - fec.c\ + nbuf.c \ + queue.c \ + nif.c \ + fecbd.c \ + fec.c \ + udp.c \ \ basflash.c \ basflash_start.c @@ -101,9 +105,8 @@ ASRCS= \ startcf.S \ printf_helper.S \ exceptions.S \ - mmu.S \ xhdi_vec.S - + SRCS=$(ASRCS) $(CSRCS) COBJS=$(patsubst %.c,%.o,$(CSRCS)) AOBJS=$(patsubst %.S,%.o,$(ASRCS)) @@ -155,8 +158,8 @@ $(foreach DIR,$(TRGTDIRS),$(eval $(call CC_TEMPLATE,$(DIR)))) # rules for depend define DEP_TEMPLATE -ifneq (clean,$(MAKECMDGOALS)) --include $(1)/depend +ifneq (clean,$$(MAKECMDGOALS)) +include $(1)/depend endif ifeq (firebee,$(1)) diff --git a/BaS_gcc/bas.lk.in b/BaS_gcc/bas.lk.in index 50e778e..6300048 100644 --- a/BaS_gcc/bas.lk.in +++ b/BaS_gcc/bas.lk.in @@ -50,6 +50,13 @@ SECTIONS OBJDIR/ehci-hcd.o(.text) OBJDIR/wait.o(.text) + OBJDIR/nbuf.o(.text) + OBJDIR/queue.o(.text) + OBJDIR/nif.o(.text) + OBJDIR/fecbd.o(.text) + OBJDIR/fec.o(.text) + OBJDIR/udp.o(text) + OBJDIR/unicode.o(.text) OBJDIR/mmc.o(.text) OBJDIR/ff.o(.text) diff --git a/BaS_gcc/include/udp.h b/BaS_gcc/include/udp.h index c2ce44e..de87dc3 100644 --- a/BaS_gcc/include/udp.h +++ b/BaS_gcc/include/udp.h @@ -35,26 +35,13 @@ typedef struct /********************************************************************/ -void -udp_init (void); - -void -udp_prime_port (uint16_t); - -uint16_t -udp_obtain_free_port (void); - -void -udp_bind_port ( uint16_t, void (*)(NIF *,NBUF *)); - -void -udp_free_port (uint16_t); - -int -udp_send (NIF *, uint8_t *, int, int, NBUF *); - -void -udp_handler (NIF *, NBUF *); +extern void udp_init(void); +extern void udp_prime_port(uint16_t); +extern uint16_t udp_obtain_free_port(void); +extern void udp_bind_port( uint16_t, void (*)(NIF *,NBUF *)); +extern void udp_free_port(uint16_t); +extern int udp_send(NIF *, uint8_t *, int, int, NBUF *); +extern void udp_handler(NIF *, NBUF *); /********************************************************************/ diff --git a/BaS_gcc/net/bootp.c b/BaS_gcc/net/bootp.c new file mode 100644 index 0000000..b15eab3 --- /dev/null +++ b/BaS_gcc/net/bootp.c @@ -0,0 +1,33 @@ +#include "bas_types.h" +#include +#include + +static bool bootp_initialized = false; + +/* + * bootp client state + */ + +struct bootp_client +{ + uint8_t state; + uint8_t mode; + uint8_t socket_handle; + uint16_t timer_handle; + uint16_t boot_secs; +}; + +static struct bootp_client client; + +int bootpc_init(int mode) +{ + if (bootp_initialized) + { + return true; + } + + /* + * get socket handle + */ + client.socket_handle = udp_getsocket + diff --git a/BaS_gcc/net/fec.c b/BaS_gcc/net/fec.c index d4d6f4a..d48a6f0 100644 --- a/BaS_gcc/net/fec.c +++ b/BaS_gcc/net/fec.c @@ -16,6 +16,7 @@ #include "dma.h" #include "bas_string.h" #include "bas_printf.h" +#include "util.h" #include #if defined(MACHINE_FIREBEE) @@ -412,8 +413,8 @@ void fec_reset (uint8_t ch) MCF_FEC_ECR(ch) = MCF_FEC_ECR_RESET; /* Wait at least 8 clock cycles */ - for (i=0; i<10; ++i) - nop(); + for (i = 0; i < 10; ++i) + NOP(); } /********************************************************************/ diff --git a/BaS_gcc/net/fecbd.c b/BaS_gcc/net/fecbd.c new file mode 100644 index 0000000..63ed476 --- /dev/null +++ b/BaS_gcc/net/fecbd.c @@ -0,0 +1,226 @@ +/* + * File: fecbd.c + * Purpose: Provide a simple buffer management driver + * + * Notes: + */ +#include "MCD_dma.h" +#include "fecbd.h" +#include "nbuf.h" +#include "eth.h" +#include "bas_printf.h" +#include + +/* + * This implements a simple static buffer descriptor + * ring for each channel and each direction + * + * FEC Buffer Descriptors need to be aligned to a 4-byte boundary. + * In order to accomplish this, data is over-allocated and manually + * aligned at runtime + * + * Enough space is allocated for each of the two FEC channels to have + * NRXBD Rx BDs and NTXBD Tx BDs + * + */ + +FECBD unaligned_bds[(2 * NRXBD) + (2 * NTXBD) + 1]; + +/* + * These pointers are used to reference into the chunck of data set + * aside for buffer descriptors + */ +FECBD *RxBD; +FECBD *TxBD; + +/* + * Macros to easier access to the BD ring + */ +#define RxBD(ch,i) RxBD[(ch * NRXBD) + i] +#define TxBD(ch,i) TxBD[(ch * NTXBD) + i] + +/* + * Buffer descriptor indexes + */ +static int iTxbd_new; +static int iTxbd_old; +static int iRxbd; + +/* + * Initialize the FEC Buffer Descriptor ring + * Buffer Descriptor format is defined by the MCDAPI + * + * Parameters: + * ch FEC channel + */ +void fecbd_init(uint8_t ch) +{ + NBUF *nbuf; + int i; + + /* + * Align Buffer Descriptors to 4-byte boundary + */ + RxBD = (FECBD *)(((int)unaligned_bds + 3) & 0xFFFFFFFC); + TxBD = (FECBD *)((int)RxBD + (sizeof(FECBD) * 2 * NRXBD)); + + /* + * Initialize the Rx Buffer Descriptor ring + */ + for (i = 0; i < NRXBD; ++i) + { + /* Grab a network buffer from the free list */ + nbuf = nbuf_alloc(); + if (nbuf == NULL) + { + xprintf("%s: could not allocate network buffer\r\n", __FUNCTION__); + return; + } + + /* Initialize the BD */ + RxBD(ch,i).status = RX_BD_E | RX_BD_INTERRUPT; + RxBD(ch,i).length = RX_BUF_SZ; + RxBD(ch,i).data = nbuf->data; + + /* Add the network buffer to the Rx queue */ + nbuf_add(NBUF_RX_RING, nbuf); + } + + /* + * Set the WRAP bit on the last one + */ + RxBD(ch,i-1).status |= RX_BD_W; + + /* + * Initialize the Tx Buffer Descriptor ring + */ + for (i = 0; i < NTXBD; ++i) + { + TxBD(ch,i).status = TX_BD_INTERRUPT; + TxBD(ch,i).length = 0; + TxBD(ch,i).data = NULL; + } + + /* + * Set the WRAP bit on the last one + */ + TxBD(ch,i-1).status |= TX_BD_W; + + /* + * Initialize the buffer descriptor indexes + */ + iTxbd_new = iTxbd_old = iRxbd = 0; +} + +void fecbd_dump(uint8_t ch) +{ + #ifdef DEBUG_PRINT + int i; + + printf("\n------------ FEC%d BDs -----------\n",ch); + printf("RxBD Ring\n"); + for (i=0; idata = (uint8 *)((uint32)(unaligned_buffers[i] + 15) & 0xFFFFFFF0); - if (!nbuf->data) + unaligned_buffers[i] = driver_mem_alloc(NBUF_SZ + 16); + nbuf->data = (uint8_t *)((uint32_t)(unaligned_buffers[i] + 15) & 0xFFFFFFF0); + if (!nbuf->data) { - ASSERT(nbuf->data); - return 1; + return 1; } /* Initialize the network buffer */ @@ -81,32 +76,30 @@ nbuf_init(void) return 0; } -/********************************************************************/ + /* * Return all the allocated memory to the heap */ -void -nbuf_flush(void) +void nbuf_flush(void) { NBUF *nbuf; - int i, level = asm_set_ipl(7); + int i, level = set_ipl(7); int n = 0; - for (i=0; ioffset = 0; nbuf->length = NBUF_SZ; queue_add(&nbuf_queue[NBUF_FREE],(QNODE *)nbuf); - asm_set_ipl(level); + set_ipl(level); } -/********************************************************************/ + /* * Remove a network buffer from the specified queue * * Parameters: * q The index that identifies the queue to pull the buffer from */ -NBUF * -nbuf_remove(int q) +NBUF *nbuf_remove(int q) { NBUF *nbuf; - int level = asm_set_ipl(7); + int level = set_ipl(7); - nbuf = (NBUF *)queue_remove(&nbuf_queue[q]); - asm_set_ipl(level); + nbuf = (NBUF *) queue_remove(&nbuf_queue[q]); + set_ipl(level); + return nbuf; } -/********************************************************************/ + /* * Add a network buffer to the specified queue * * Parameters: * q The index that identifies the queue to add the buffer to */ -void -nbuf_add(int q, NBUF *nbuf) +void nbuf_add(int q, NBUF *nbuf) { - int level = asm_set_ipl(7); + int level = set_ipl(7); queue_add(&nbuf_queue[q],(QNODE *)nbuf); - asm_set_ipl(level); + set_ipl(level); } -/********************************************************************/ + /* * Put all the network buffers back into the free list */ -void -nbuf_reset(void) +void nbuf_reset(void) { NBUF *nbuf; - int i, level = asm_set_ipl(7); + int i, level = set_ipl(7); - for (i=1; i +#include + +int nif_protocol_exist(NIF *nif, uint16_t protocol) +{ + /* + * This function searches the list of supported protocols + * on the particular NIF and if a protocol handler exists, + * true is returned. This function is useful for network cards + * that needn't read in the entire frame but can discard frames + * arbitrarily. + */ + int index; + + for (index = 0; index < nif->num_protocol; ++index) + { + if (nif->protocol[index].protocol == protocol) + { + return true; + } + } + return false; +} + +void nif_protocol_handler(NIF *nif, uint16_t protocol, NBUF *pNbuf) +{ + /* + * This function searches the list of supported protocols + * on the particular NIF and if a protocol handler exists, + * the protocol handler is invoked. This routine called by + * network device driver after receiving a frame. + */ + int index; + + for (index = 0; index < nif->num_protocol; ++index) + { + if (nif->protocol[index].protocol == protocol) + nif->protocol[index].handler(nif,pNbuf); + } +} + +void *nif_get_protocol_info (NIF *nif, uint16_t protocol) +{ + /* + * This function searches the list of supported protocols + * on the particular NIF and returns a pointer to the + * config info for 'protocol', otherwise NULL is returned. + */ + int index; + + for (index = 0; index < nif->num_protocol; ++index) + { + if (nif->protocol[index].protocol == protocol) + return (void *)nif->protocol[index].info; + } + return (void *)0; +} + +int nif_bind_protocol (NIF *nif, uint16_t protocol, + void (*handler)(NIF *,NBUF *), + void *info) +{ + /* + * This function registers 'protocol' as a supported + * protocol in 'nif'. + */ + if (nif->num_protocol < (MAX_SUP_PROTO - 1)) + { + nif->protocol[nif->num_protocol].protocol = protocol; + nif->protocol[nif->num_protocol].handler = (void(*)(NIF*,NBUF*))handler; + nif->protocol[nif->num_protocol].info = info; + ++nif->num_protocol; + return true; + } + return false; +} + +NIF *nif_init (NIF *nif) +{ + int i; + + for (i = 0; i < ETH_ADDR_LEN; ++i) + { + nif->hwa[i] = 0; + nif->broadcast[i] = 0xFF; + } + + for (i = 0; i < MAX_SUP_PROTO; ++i) + { + nif->protocol[i].protocol = 0; + nif->protocol[i].handler = 0; + nif->protocol[i].info = 0; + } + nif->num_protocol = 0; + + nif->mtu = 0; + nif->ch = 0; + nif->send = 0; + + nif->f_rx = 0; + nif->f_tx = 0; + nif->f_rx_err = 0; + nif->f_tx_err = 0; + nif->f_err = 0; + + return nif; +} diff --git a/BaS_gcc/net/queue.c b/BaS_gcc/net/queue.c new file mode 100644 index 0000000..756a9a7 --- /dev/null +++ b/BaS_gcc/net/queue.c @@ -0,0 +1,114 @@ +/* + * File: queue.c + * Purpose: Implement a first in, first out linked list + * + * Notes: + */ +#include "bas_string.h" +#include "queue.h" + +/* + * Initialize the specified queue to an empty state + * + * Parameters: + * q Pointer to queue structure + */ +void queue_init(QUEUE *q) +{ + q->head = NULL; +} + +/* + * Check for an empty queue + * + * Parameters: + * q Pointer to queue structure + * + * Return Value: + * 1 if Queue is empty + * 0 otherwise + */ +int queue_isempty(QUEUE *q) +{ + return (q->head == NULL); +} + +/* + * Add an item to the end of the queue + * + * Parameters: + * q Pointer to queue structure + * node New node to add to the queue + */ +void queue_add(QUEUE *q, QNODE *node) +{ + if (queue_isempty(q)) + { + q->head = q->tail = node; + } + else + { + q->tail->next = node; + q->tail = node; + } + + node->next = NULL; +} + +/* + * Remove and return first (oldest) entry from the specified queue + * + * Parameters: + * q Pointer to queue structure + * + * Return Value: + * Node at head of queue - NULL if queue is empty + */ +QNODE *queue_remove(QUEUE *q) +{ + QNODE *oldest; + + if (queue_isempty(q)) + return NULL; + + oldest = q->head; + q->head = oldest->next; + return oldest; +} + +/* + * Peek into the queue and return pointer to first (oldest) entry. + * The queue is not modified + * + * Parameters: + * q Pointer to queue structure + * + * Return Value: + * Node at head of queue - NULL if queue is empty + */ +QNODE *queue_peek(QUEUE *q) +{ + return q->head; +} + +/* + * Move entire contents of one queue to the other + * + * Parameters: + * src Pointer to source queue + * dst Pointer to destination queue + */ +void queue_move(QUEUE *dst, QUEUE *src) +{ + if (queue_isempty(src)) + return; + + if (queue_isempty(dst)) + dst->head = src->head; + else + dst->tail->next = src->head; + + dst->tail = src->tail; + src->head = NULL; + return; +} diff --git a/BaS_gcc/net/udp.c b/BaS_gcc/net/udp.c new file mode 100644 index 0000000..6cca10e --- /dev/null +++ b/BaS_gcc/net/udp.c @@ -0,0 +1,180 @@ +/* + * File: udp.c + * Purpose: User Datagram Protocol driver + * + * Notes: + * + * Modifications: + * + */ +#include "bas_types.h" +#include "net.h" + +#ifdef DBUG_NETWORK + +/********************************************************************/ +typedef struct +{ + uint16_t port; + void (*handler)(NIF *, NBUF *); +} UDP_BOUND_PORT; + +/********************************************************************/ + +#define UDP_MAX_PORTS (5) /* plenty for this implementation */ + + +static UDP_BOUND_PORT +udp_port_table[UDP_MAX_PORTS]; + +static uint16 +udp_port; + +/********************************************************************/ +void +udp_init (void) +{ + int index; + + for (index = 0; index < UDP_MAX_PORTS; ++index) + { + udp_port_table[index].port = 0; + } + + udp_port = DEFAULT_UDP_PORT; /* next free port */ +} +/********************************************************************/ +void +udp_prime_port (uint16 init_port) +{ + udp_port = init_port; +} +/********************************************************************/ +void +udp_bind_port (uint16 port, void (*handler)(NIF *, NBUF *)) +{ + int index; + + for (index = 0; index < UDP_MAX_PORTS; ++index) + { + if (udp_port_table[index].port == 0) + { + udp_port_table[index].port = port; + udp_port_table[index].handler = handler; + return; + } + } +} +/********************************************************************/ +void +udp_free_port (uint16 port) +{ + int index; + + for (index = 0; index < UDP_MAX_PORTS; ++index) + { + if (udp_port_table[index].port == port) + { + udp_port_table[index].port = 0; + return; + } + } +} +/********************************************************************/ +static void * +udp_port_handler (uint16 port) +{ + int index; + + for (index = 0; index < UDP_MAX_PORTS; ++index) + { + if (udp_port_table[index].port == port) + { + return (void *)udp_port_table[index].handler; + } + } + return NULL; +} +/********************************************************************/ +uint16 +udp_obtain_free_port (void) +{ + uint16 port; + + port = udp_port; + if (--udp_port <= 255) + udp_port = DEFAULT_UDP_PORT; + + return port; +} +/********************************************************************/ +int +udp_send ( NIF *nif, uint8 *dest, int sport, int dport, NBUF *pNbuf) +{ + /* + * This function takes data and creates a UDP frame and + * passes it onto the IP layer + */ + udp_frame_hdr *udpframe; + + udpframe = (udp_frame_hdr *)&pNbuf->data[UDP_HDR_OFFSET]; + + /* Set UDP source port */ + udpframe->src_port = (uint16)sport; + + /* Set UDP destination port */ + udpframe->dest_port = (uint16)dport; + + /* Set length */ + udpframe->length = (uint16)(pNbuf->length + UDP_HDR_SIZE); + + /* No checksum calcualation needed */ + udpframe->chksum = (uint16)0; + + /* Add the length of the UDP packet to the total length of the packet */ + pNbuf->length += 8; + + return (ip_send(nif, + dest, + ip_get_myip(nif_get_protocol_info(nif,ETH_FRM_IP)), + IP_PROTO_UDP, + pNbuf)); +} +/********************************************************************/ +void +udp_handler (NIF *nif, NBUF *pNbuf) +{ + /* + * This function handles incoming UDP packets + */ + udp_frame_hdr *udpframe; + void (*handler)(NIF *, NBUF *); + + udpframe = (udp_frame_hdr *)&pNbuf->data[pNbuf->offset]; + + /* + * Adjust the length and valid data offset of the packet we are + * passing on + */ + pNbuf->length -= UDP_HDR_SIZE; + pNbuf->offset += UDP_HDR_SIZE; + + /* + * Traverse the list of bound ports to see if there is a higher + * level protocol to pass the packet on to + */ + if ((handler = (void(*)(NIF*,NBUF*))udp_port_handler(UDP_DEST(udpframe))) != NULL) + handler(nif, pNbuf); + else + { + #ifdef DBUG_PRINT + printf("Received UDP packet for non-supported port\n"); + #endif + nbuf_free(pNbuf); + } + + return; +} +/********************************************************************/ + +#endif /* #ifdef DBUG_NETWORK */ diff --git a/BaS_gcc/sys/BaS.c b/BaS_gcc/sys/BaS.c index e3ce9ec..ad8974c 100644 --- a/BaS_gcc/sys/BaS.c +++ b/BaS_gcc/sys/BaS.c @@ -39,6 +39,9 @@ #include "ff.h" #include "s19reader.h" #include "dma.h" +#include "eth.h" +#include "nbuf.h" +#include "nif.h" /* imported routines */ extern int mmu_init(); @@ -56,6 +59,11 @@ extern uint8_t _EMUTOS[]; extern uint8_t _EMUTOS_SIZE[]; #define EMUTOS_SIZE ((uint32_t)_EMUTOS_SIZE) /* size of EmuTOS, in bytes */ +NIF nif1; +#ifdef MACHINE_M5484LITE +NIF nif2; +#endif + /* * check if it is possible to transfer data to PIC */