]> git.sur5r.net Git - freertos/blob - Demo/lwIP_MCF5235_GCC/lwip/contrib/port/FreeRTOS/MCF5235/netif/fec.c
Add PIC24, dsPIC and Coldfire files.
[freertos] / Demo / lwIP_MCF5235_GCC / lwip / contrib / port / FreeRTOS / MCF5235 / netif / fec.c
1 /*
2  * Copyright (c) 2006 Christian Walter
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25  * OF SUCH DAMAGE.
26  *
27  * Author: Christian Walter <wolti@sil.at>
28  *
29  * TODO:
30  *  - Introduce another task create function in the sys_arch layer which allows
31  *    for passing the stack size.
32  *  - Avoid copying the buffers - this requires changeing the nbuf driver code
33  *    to use the lwIP pbuf buffer implementation.
34  *
35  * File: $Id: fec.c,v 1.3 2006/08/29 18:53:46 wolti Exp $
36  */
37
38 /* ------------------------ System includes ------------------------------- */
39 #include <stdlib.h>
40
41 /* ------------------------ Platform includes ----------------------------- */
42 #include "mcf5xxx.h"
43 #include "mcf523x.h"
44
45 #include "nbuf.h"
46
47 /* ------------------------ lwIP includes --------------------------------- */
48 #include "lwip/opt.h"
49 #include "lwip/def.h"
50 #include "lwip/mem.h"
51 #include "lwip/pbuf.h"
52 #include "lwip/sys.h"
53 #include "lwip/stats.h"
54 #include "lwip/debug.h"
55 #include "netif/etharp.h"
56
57 /* ------------------------ Defines --------------------------------------- */
58 #ifdef FEC_DEBUG
59 #define FEC_DEBUG_INIT \
60     do \
61     { \
62         MCF_GPIO_PDDR_FECI2C = ( MCF_GPIO_PDDR_FECI2C_PDDR_FECI2C0 | \
63                                  MCF_GPIO_PDDR_FECI2C_PDDR_FECI2C1 ); \
64     } while( 0 )
65
66 #define FEC_DEBUG_RX_TIMING( x ) \
67     do \
68     { \
69         if( x ) \
70             MCF_GPIO_PPDSDR_FECI2C = MCF_GPIO_PDDR_FECI2C_PDDR_FECI2C0; \
71         else \
72             MCF_GPIO_PCLRR_FECI2C = ~( MCF_GPIO_PDDR_FECI2C_PDDR_FECI2C0 ); \
73     } while( 0 )
74
75 #define FEC_DEBUG_TX_TIMING( x ) \
76     do \
77     { \
78         if( x ) \
79             MCF_GPIO_PPDSDR_FECI2C = MCF_GPIO_PDDR_FECI2C_PDDR_FECI2C1; \
80         else \
81             MCF_GPIO_PCLRR_FECI2C = ~( MCF_GPIO_PDDR_FECI2C_PDDR_FECI2C1 ); \
82     } while( 0 )
83
84 #else
85 #define FEC_DEBUG               DBG_OFF
86 #define FEC_DEBUG_INIT
87 #define FEC_DEBUG_RX_TIMING( x )
88 #define FEC_DEBUG_TX_TIMING( x )
89 #endif
90
91 #define MCF_FEC_INT_LEVEL       ( 6 )
92 #define MCF_FEC_INT_PRIORITY    ( 0 )
93 #define MCF_FEC_VEC_RXF         ( 64 + 27 )
94 #define MCF_FEC_MTU             ( 1518 )
95
96 #define ETH_ADDR_LEN            ( 6 )
97
98 #define TASK_PRIORITY           ( configMAX_PRIORITIES - 1 )
99
100 /* ------------------------ Type definitions ------------------------------ */
101 typedef struct
102 {
103     struct netif   *netif;      /* lwIP network interface. */
104     struct eth_addr *self;      /* MAC address of FEC interface. */
105     sys_sem_t       tx_sem;     /* Control access to transmitter. */
106     sys_sem_t       rx_sem;     /* Semaphore to signal receive thread. */
107 } mcf523xfec_if_t;
108
109 /* ------------------------ Static variables ------------------------------ */
110 static mcf523xfec_if_t *fecif_g;
111
112 /* ------------------------ Static functions ------------------------------ */
113 static err_t    mcf523xfec_output( struct netif *, struct pbuf *, struct ip_addr * );
114 static err_t    mcf523xfec_output_raw( struct netif *, struct pbuf * );
115
116 static void     mcf523xfec_reset( mcf523xfec_if_t * fecif );
117 static void     mcf523xfec_enable( mcf523xfec_if_t * fecif );
118 static void     mcf523xfec_disable( mcf523xfec_if_t * fecif );
119 static void     mcf523xfec_get_mac( mcf523xfec_if_t * fecif, struct eth_addr *mac );
120 static void     mcf523xfec_rx_irq( void );
121 static void     mcf523xfec_rx_task( void *arg );
122
123 static void     arp_timer( void *arg );
124 static void     eth_input( struct netif *netif, struct pbuf *p );
125
126 /* ------------------------ Start implementation -------------------------- */
127
128 static void
129 arp_timer( void *arg )
130 {
131     ( void )arg;
132     etharp_tmr(  );
133     sys_timeout( ARP_TMR_INTERVAL, arp_timer, NULL );
134 }
135
136 err_t
137 mcf523xfec_output_raw( struct netif *netif, struct pbuf *p )
138 {
139     err_t           res;
140     nbuf_t         *pNBuf;
141     mcf523xfec_if_t *fecif = netif->state;
142     int             i;
143     struct pbuf    *q;
144
145 #if ETH_PAD_SIZE
146     pbuf_header( p, -ETH_PAD_SIZE );    /* drop the padding word */
147 #endif
148
149
150     /* Test if we can handle such big frames. If not drop it. */
151     if( p->tot_len > MCF_FEC_MTU )
152     {
153 #if LINK_STATS
154         lwip_stats.link.lenerr++;
155 #endif
156         res = ERR_BUF;
157     }
158     /* Test if our network buffer scheme can handle a packet of this size. If
159      * not drop it and return a memory error. */
160     else if( p->tot_len > TX_BUFFER_SIZE )
161     {
162 #ifdef LINK_STATS
163         lwip_stats.link.memerr++;
164 #endif
165         res = ERR_MEM;
166     }
167     /* Allocate a transmit buffer. If no buffer is available drop the frame. */
168     else if( ( pNBuf = nbuf_tx_allocate(  ) ) == NULL )
169     {
170         LWIP_ASSERT( "mcf523xfec_output_raw: pNBuf != NULL\n", pNBuf != NULL );
171 #ifdef LINK_STATS
172         lwip_stats.link.memerr++;
173 #endif
174         res = ERR_MEM;
175     }
176     else
177     {
178         q = p;
179         i = 0;
180         do
181         {
182             memcpy( &pNBuf->data[i], q->payload, q->len );
183             i += q->len;
184         }
185         while( ( q = q->next ) != NULL );
186         pNBuf->length = p->tot_len;
187
188         /* Set Frame ready for transmission. */
189         pNBuf->status |= TX_BD_R;
190         /* Mark the buffer as not in use so the FEC can take it. */
191         nbuf_tx_release( pNBuf );
192         /* Indicate that a new transmit buffer has been produced. */
193         MCF_FEC_TDAR = 1;
194 #if LINK_STATS
195         lwip_stats.link.xmit++;
196 #endif
197         res = ERR_OK;
198     }
199
200     sys_sem_signal( fecif->tx_sem );
201 #if ETH_PAD_SIZE
202     buf_header( p, ETH_PAD_SIZE );
203 #endif
204
205     return res;
206 }
207
208 /* This function is called by the TCP/IP stack when an IP packet should be
209  * sent. It uses the ethernet ARP module provided by lwIP to resolve the
210  * destination MAC address. The ARP module will later call our low level
211  * output function mcf523xfec_output_raw.
212  */
213 err_t
214 mcf523xfec_output( struct netif * netif, struct pbuf * p, struct ip_addr * ipaddr )
215 {
216     err_t           res;
217     mcf523xfec_if_t *fecif = netif->state;
218
219     FEC_DEBUG_TX_TIMING( 1 );
220     /* Make sure only one thread is in this function. */
221     sys_sem_wait( fecif->tx_sem );
222     res = etharp_output( netif, ipaddr, p );
223     FEC_DEBUG_TX_TIMING( 0 );
224     return res;
225 }
226
227 void
228 mcf523xfec_rx_task( void *arg )
229 {
230     mcf523xfec_if_t *fecif = arg;
231     struct pbuf    *p, *q;
232     nbuf_t         *pNBuf;
233     uint8          *pPayLoad;
234
235     do
236     {
237         sys_sem_wait( fecif->rx_sem );
238         while( nbuf_rx_next_ready(  ) )
239         {
240             pNBuf = nbuf_rx_allocate(  );
241             if( pNBuf != NULL )
242             {
243                 LWIP_ASSERT( "mcf523xfec_rx_task: pNBuf->status & RX_BD_L ",
244                              pNBuf->status & RX_BD_L );
245
246                 /* This flags indicate that the frame has been damaged. In
247                  * this case we must update the link stats if enabled and
248                  * remove the frame from the FEC. */
249                 if ( pNBuf->status & ( RX_BD_LG | RX_BD_NO |
250                                        RX_BD_CR | RX_BD_OV ) )
251                 {
252 #ifdef LINK_STATS
253                     lwip_stats.link.drop++;
254                     if ( pNBuf->status & RX_BD_LG)
255                     {
256                         lwip_stats.link.lenerr++;
257                     }
258                     else if ( pNBuf->status & ( RX_BD_NO | RX_BD_OV ) )
259                     {
260                         lwip_stats.link.err++;
261                     }
262                     else
263                     {
264                         lwip_stats.link.chkerr++;
265                     }
266 #endif
267                 }
268                 else
269                 {
270                     /* The frame must no be valid. Perform some checks to see if the FEC
271                      * driver is working correctly.
272                      */
273                     LWIP_ASSERT( "mcf523xfec_rx_task: pNBuf->length != 0", pNBuf->length != 0 );
274                     p = pbuf_alloc( PBUF_RAW, pNBuf->length, PBUF_POOL );
275                     if( p != NULL )
276                     {
277 #if ETH_PAD_SIZE
278                         pbuf_header( p, -ETH_PAD_SIZE );
279 #endif
280                         pPayLoad = pNBuf->data;
281                         for( q = p; q != NULL; q = q->next )
282                         {
283                             memcpy( q->payload, pPayLoad, q->len );
284                             pPayLoad += q->len;
285                         }
286 #if ETH_PAD_SIZE
287                         pbuf_header( p, ETH_PAD_SIZE );
288 #endif
289
290                         /* Ethernet frame received. Handling it is not device
291                          * dependent and therefore done in another function.
292                          */
293                         eth_input( fecif->netif, p );
294                     }
295                 }
296                 nbuf_rx_release( pNBuf );
297
298                 /* Tell the HW that there are new free RX buffers. */
299                 MCF_FEC_RDAR = 1;
300             }
301             else
302             {
303 #if LINK_STATS
304                 lwip_stats.link.memerr++;
305                 lwip_stats.link.drop++;
306 #endif
307             }
308         }
309         /* Set RX Debug PIN to low since handling of next frame is possible. */
310         FEC_DEBUG_RX_TIMING( 0 );
311     }
312     while( 1 );
313 }
314
315 void
316 eth_input( struct netif *netif, struct pbuf *p )
317 {
318     struct eth_hdr *eth_hdr = p->payload;
319
320     LWIP_ASSERT( "eth_input: p != NULL ", p != NULL );
321
322     switch ( htons( eth_hdr->type ) )
323     {
324     case ETHTYPE_IP:
325         /* Pass to ARP layer. */
326         etharp_ip_input( netif, p );
327
328         /* Skip Ethernet header. */
329         pbuf_header( p, ( s16_t ) - sizeof( struct eth_hdr ) );
330
331         /* Pass to network layer. */
332         netif->input( p, netif );
333         break;
334
335     case ETHTYPE_ARP:
336         /* Pass to ARP layer. */
337         etharp_arp_input( netif, ( struct eth_addr * )netif->hwaddr, p );
338         break;
339
340     default:
341         pbuf_free( p );
342         break;
343     }
344 }
345
346 void
347 mcf523xfec_rx_irq( void )
348 {
349     static portBASE_TYPE xNeedSwitch = pdFALSE;
350
351     /* Workaround GCC if frame pointers are enabled. This is an ISR and
352      * we must not modify the stack before portENTER_SWITCHING_ISR( )
353      * has been called. */
354 #if _GCC_USES_FP == 1
355     asm volatile    ( "unlk %fp\n\t" );
356 #endif
357
358     /* This ISR can cause a context switch, so the first statement must be
359      * a call to the portENTER_SWITCHING_ISR() macro.
360      */
361     portENTER_SWITCHING_ISR(  );
362
363     /* Set Debug PIN to high to measure RX latency. */
364     FEC_DEBUG_RX_TIMING( 1 );
365
366     /* Clear FEC RX Event from the Event Register (by writing 1) */
367     if( MCF_FEC_EIR & ( MCF_FEC_EIR_RXB | MCF_FEC_EIR_RXF ) )
368     {
369         /* Clear interrupt from EIR register immediately */
370         MCF_FEC_EIR = ( MCF_FEC_EIR_RXB | MCF_FEC_EIR_RXF );
371         xNeedSwitch = xSemaphoreGiveFromISR( fecif_g->rx_sem, pdFALSE );
372     }
373     portEXIT_SWITCHING_ISR( xNeedSwitch );
374 }
375
376 void
377 mcf523xfec_reset( mcf523xfec_if_t * fecif )
378 {
379     extern void     ( *__RAMVEC[] ) (  );
380
381     int             old_ipl = asm_set_ipl( 7 );
382
383     /* Reset the FEC - equivalent to a hard reset */
384     MCF_FEC_ECR = MCF_FEC_ECR_RESET;
385
386     /* Wait for the reset sequence to complete */
387     while( MCF_FEC_ECR & MCF_FEC_ECR_RESET );
388
389     /* Disable all FEC interrupts by clearing the EIMR register */
390     MCF_FEC_EIMR = 0;
391
392     /* Clear any interrupts by setting all bits in the EIR register */
393     MCF_FEC_EIR = 0xFFFFFFFFUL;
394
395     /* Configure Interrupt vectors. */
396     __RAMVEC[MCF_FEC_VEC_RXF] = mcf523xfec_rx_irq;
397
398     /* Set the source address for the controller */
399     MCF_FEC_PALR =
400         ( fecif->self->addr[0] << 24U ) | ( fecif->self->addr[1] << 16U ) |
401         ( fecif->self->addr[2] << 8U ) | ( fecif->self->addr[3] << 0U );
402     MCF_FEC_PAUR = ( fecif->self->addr[4] << 24U ) | ( fecif->self->addr[5] << 16U );
403
404     /* Initialize the hash table registers */
405     MCF_FEC_IAUR = 0;
406     MCF_FEC_IALR = 0;
407
408     /* Set Receive Buffer Size */
409 #if RX_BUFFER_SIZE != 2048
410 #error "RX_BUFFER_SIZE must be set to 2048 for safe FEC operation."
411 #endif
412     MCF_FEC_EMRBR = RX_BUFFER_SIZE - 1;
413
414     /* Point to the start of the circular Rx buffer descriptor queue */
415     MCF_FEC_ERDSR = nbuf_get_start( NBUF_RX );
416
417     /* Point to the start of the circular Tx buffer descriptor queue */
418     MCF_FEC_ETDSR = nbuf_get_start( NBUF_TX );
419
420     /* Set the tranceiver interface to MII mode */
421     MCF_FEC_RCR = MCF_FEC_RCR_MAX_FL( MCF_FEC_MTU ) | MCF_FEC_RCR_MII_MODE;
422
423     /* Set MII Speed Control Register for 2.5Mhz */
424     MCF_FEC_MSCR = MCF_FEC_MSCR_MII_SPEED( FSYS_2 / ( 2UL * 2500000UL ) );
425
426     /* Only operate in half-duplex, no heart beat control */
427     MCF_FEC_TCR = 0;
428
429     /* Enable Debug support */
430     FEC_DEBUG_INIT;
431     FEC_DEBUG_RX_TIMING( 0 );
432     FEC_DEBUG_TX_TIMING( 0 );
433     ( void )asm_set_ipl( old_ipl );
434 }
435
436 void
437 mcf523xfec_get_mac( mcf523xfec_if_t * hw, struct eth_addr *mac )
438 {
439     int             i;
440     static const struct eth_addr mac_default = {
441         {0x00, 0xCF, 0x52, 0x35, 0x00, 0x01}
442     };
443
444     ( void )hw;
445
446     for( i = 0; i < ETH_ADDR_LEN; i++ )
447     {
448         mac->addr[i] = mac_default.addr[i];
449     }
450 }
451
452 void
453 mcf523xfec_enable( mcf523xfec_if_t * fecif )
454 {
455     ( void )fecif;
456
457     int             old_ipl = asm_set_ipl( 7 );
458
459     /* Configure I/O pins for the FEC. */
460     MCF_GPIO_PAR_FECI2C = ( MCF_GPIO_PAR_FECI2C_PAR_EMDC_FEC | MCF_GPIO_PAR_FECI2C_PAR_EMDIO_FEC );
461
462     /* Allow interrupts by setting IMR register */
463     MCF_FEC_EIMR = MCF_FEC_EIMR_RXF;
464
465     /* Configure the interrupt controller. */
466     MCF_INTC0_ICR27 = ( MCF_INTC0_ICRn_IL( MCF_FEC_INT_LEVEL ) |
467                         MCF_INTC0_ICRn_IP( MCF_FEC_INT_PRIORITY ) );
468     MCF_INTC0_IMRL &= ~( MCF_INTC0_IMRL_INT_MASK27 | MCF_INTC0_IMRL_MASKALL );
469
470     /* Enable FEC */
471     MCF_FEC_ECR = MCF_FEC_ECR_ETHER_EN;
472
473     /* Indicate that there have been empty receive buffers produced */
474     MCF_FEC_RDAR = 1;
475     ( void )asm_set_ipl( old_ipl );
476 }
477
478 void
479 mcf523xfec_disable( mcf523xfec_if_t * fecif )
480 {
481     ( void )fecif;
482
483     int             old_ipl = asm_set_ipl( 7 );
484
485     /* Set the Graceful Transmit Stop bit */
486     MCF_FEC_TCR = ( MCF_FEC_TCR | MCF_FEC_TCR_GTS );
487
488     /* Wait for the current transmission to complete */
489     while( !( MCF_FEC_EIR & MCF_FEC_EIR_GRA ) );
490
491     /* Clear the GRA event */
492     MCF_FEC_EIR = MCF_FEC_EIR_GRA;
493
494     /* Disable the FEC */
495     MCF_FEC_ECR = 0;
496
497     /* Disable all FEC interrupts by clearing the IMR register */
498     MCF_FEC_EIMR = 0;
499
500     /* Unconfigure the interrupt controller. */
501     MCF_INTC0_ICR27 = MCF_INTC0_ICRn_IL( 0 ) | MCF_INTC0_ICRn_IP( 0 );
502     MCF_INTC0_IMRL |= MCF_INTC0_IMRL_INT_MASK27;
503
504     /* Clear the GTS bit so frames can be tranmitted when restarted */
505     MCF_FEC_TCR = ( MCF_FEC_TCR & ~MCF_FEC_TCR_GTS );
506
507     /* Disable I/O pins used by the FEC. */
508     MCF_GPIO_PAR_FECI2C &= ~( MCF_GPIO_PAR_FECI2C_PAR_EMDC_FEC |
509                               MCF_GPIO_PAR_FECI2C_PAR_EMDIO_FEC );
510     ( void )asm_set_ipl( old_ipl );
511 }
512
513 err_t
514 mcf523xfec_init( struct netif *netif )
515 {
516     err_t           res;
517
518     mcf523xfec_if_t *fecif = mem_malloc( sizeof( mcf523xfec_if_t ) );
519
520     if( fecif != NULL )
521     {
522         /* Global copy used in ISR. */
523         fecif_g = fecif;
524         fecif->self = ( struct eth_addr * )&netif->hwaddr[0];
525         fecif->netif = netif;
526         fecif->tx_sem = NULL;
527         fecif->rx_sem = NULL;
528
529         if( ( fecif->tx_sem = sys_sem_new( 1 ) ) == NULL )
530         {
531             res = ERR_MEM;
532         }
533         else if( ( fecif->rx_sem = sys_sem_new( 0 ) ) == NULL )
534         {
535             res = ERR_MEM;
536         }
537         else if( sys_thread_new( mcf523xfec_rx_task, fecif, TASK_PRIORITY ) == NULL )
538         {
539             res = ERR_MEM;
540         }
541         else
542         {
543             netif->state = fecif;
544             netif->name[0] = 'C';
545             netif->name[1] = 'F';
546             netif->hwaddr_len = ETH_ADDR_LEN;
547             netif->mtu = MCF_FEC_MTU;
548             netif->flags = NETIF_FLAG_BROADCAST;
549             netif->output = mcf523xfec_output;
550             netif->linkoutput = mcf523xfec_output_raw;
551
552             nbuf_init(  );
553             mcf523xfec_get_mac( fecif, fecif->self );
554             mcf523xfec_reset( fecif );
555             mcf523xfec_enable( fecif );
556
557             etharp_init(  );
558             sys_timeout( ARP_TMR_INTERVAL, arp_timer, NULL );
559
560             res = ERR_OK;
561         }
562
563         if( res != ERR_OK )
564         {
565             free( fecif );
566             if( fecif->tx_sem != NULL )
567             {
568                 mem_free( fecif->tx_sem );
569             }
570             if( fecif->rx_sem != NULL )
571             {
572                 mem_free( fecif->rx_sem );
573             }
574         }
575     }
576     else
577     {
578         res = ERR_MEM;
579     }
580
581     return res;
582 }