Nut/OS  4.10.3
API Reference
at91sam7x_emac.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /*
00035  * $Log$
00036  * Revision 1.9  2009/02/06 15:37:39  haraldkipp
00037  * Added stack space multiplier and addend. Adjusted stack space.
00038  *
00039  * Revision 1.8  2009/01/17 11:26:37  haraldkipp
00040  * Getting rid of two remaining BSD types in favor of stdint.
00041  * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
00042  *
00043  * Revision 1.7  2008/08/28 11:12:15  haraldkipp
00044  * Added interface flags, which will be required to implement Ethernet ioctl
00045  * functions.
00046  *
00047  * Revision 1.6  2008/08/11 06:59:05  haraldkipp
00048  * BSD types replaced by stdint types (feature request #1282721).
00049  *
00050  * Revision 1.5  2007/05/02 11:28:47  haraldkipp
00051  * Added multicast table entry.
00052  *
00053  * Revision 1.4  2006/08/31 19:19:55  haraldkipp
00054  * No time to write comments. ;-)
00055  *
00056  * Revision 1.3  2006/07/18 14:01:38  haraldkipp
00057  * Transmitter buffer handling was buggy and delayed any second packet.
00058  * Added handling of receiver overflow events.
00059  *
00060  * Revision 1.2  2006/07/15 11:11:44  haraldkipp
00061  * PHY initialization disabled user reset. Packet receiver routine filled
00062  * wrong buffer and always returned an error.
00063  * Many thanks to Andras Albert for fixing this.
00064  *
00065  * Revision 1.1  2006/07/05 07:38:44  haraldkipp
00066  * New Ethernet driver for the AT91SAM7X EMAC and the Davicom DM9161A.
00067  * This driver is not yet finished. Ethernet link auto-negotiation works
00068  * and receive interrupts are generated when sending packets to the
00069  * board. But transmitting packets fails, nothing is sent out.
00070  *
00071  */
00072 
00073 #include <cfg/os.h>
00074 #include <arch/arm.h>
00075 
00076 #include <string.h>
00077 
00078 #include <sys/atom.h>
00079 #include <sys/heap.h>
00080 #include <sys/thread.h>
00081 #include <sys/event.h>
00082 #include <sys/timer.h>
00083 #include <sys/confnet.h>
00084 
00085 #include <netinet/if_ether.h>
00086 #include <net/ether.h>
00087 #include <net/if_var.h>
00088 
00089 #include <dev/irqreg.h>
00090 #include <dev/at91sam7x_emac.h>
00091 
00092 #ifdef NUTDEBUG
00093 #include <stdio.h>
00094 #endif
00095 
00096 #ifndef NUT_THREAD_NICRXSTACK
00097 #define NUT_THREAD_NICRXSTACK   768
00098 #endif
00099 
00100 #ifndef EMAC_RX_BUFFERS
00101 #define EMAC_RX_BUFFERS         32
00102 #endif
00103 #define EMAC_RX_BUFSIZ          128
00104 
00105 #define EMAC_TX_BUFFERS         2
00106 #ifndef EMAC_TX_BUFSIZ
00107 #define EMAC_TX_BUFSIZ          1536
00108 #endif
00109 
00110 #define NIC_PHY_ADDR            31
00111 
00116 #define NIC_PHY_BMCR            0x00    
00117 #define NIC_PHY_BMCR_COLTEST    0x0080  
00118 #define NIC_PHY_BMCR_FDUPLEX    0x0100  
00119 #define NIC_PHY_BMCR_ANEGSTART  0x0200  
00120 #define NIC_PHY_BMCR_ISOLATE    0x0400  
00121 #define NIC_PHY_BMCR_PWRDN      0x0800  
00122 #define NIC_PHY_BMCR_ANEGENA    0x1000  
00123 #define NIC_PHY_BMCR_100MBPS    0x2000  
00124 #define NIC_PHY_BMCR_LOOPBACK   0x4000  
00125 #define NIC_PHY_BMCR_RESET      0x8000  
00127 #define NIC_PHY_BMSR            0x01    
00128 #define NIC_PHY_BMSR_ANCOMPL    0x0020  
00129 #define NIC_PHY_BMSR_LINKSTAT   0x0004  
00131 #define NIC_PHY_ID1             0x02    
00132 #define NIC_PHY_ID2             0x03    
00133 #define NIC_PHY_ANAR            0x04    
00134 #define NIC_PHY_ANLPAR          0x05    
00135 #define NIC_PHY_ANER            0x06    
00138 
00139 #define PHY_TXCLK_ISOLATE_BIT   0
00140 #define PHY_REFCLK_XT2_BIT      0
00141 #define PHY_TXEN_BIT            1
00142 #define PHY_TXD0_BIT            2
00143 #define PHY_TXD1_BIT            3
00144 #define PHY_CRS_AD4_BIT         4
00145 #define PHY_RXD0_AD0_BIT        5
00146 #define PHY_RXD1_AD1_BIT        6
00147 #define PHY_RXER_RXD4_RPTR_BIT  7
00148 #define PHY_MDC_BIT             8
00149 #define PHY_MDIO_BIT            9
00150 #define PHY_TXD2_BIT            10
00151 #define PHY_TXD3_BIT            11
00152 #define PHY_TXER_TXD4_BIT       12
00153 #define PHY_RXD2_AD2_BIT        13
00154 #define PHY_RXD3_AD3_BIT        14
00155 #define PHY_RXDV_TESTMODE_BIT   15
00156 #define PHY_COL_RMII_BIT        16
00157 #define PHY_RXCLK_10BTSER_BIT   17
00158 #define PHY_PWRDN_BIT           18
00159 #define PHY_MDINTR_BIT          26
00160 
00161 #define PHY_MII_PINS   _BV(PHY_REFCLK_XT2_BIT) \
00162     | _BV(PHY_TXEN_BIT) \
00163     | _BV(PHY_TXD0_BIT) \
00164     | _BV(PHY_TXD1_BIT) \
00165     | _BV(PHY_CRS_AD4_BIT) \
00166     | _BV(PHY_RXD0_AD0_BIT) \
00167     | _BV(PHY_RXD1_AD1_BIT) \
00168     | _BV(PHY_RXER_RXD4_RPTR_BIT) \
00169     | _BV(PHY_MDC_BIT) \
00170     | _BV(PHY_MDIO_BIT) \
00171     | _BV(PHY_TXD2_BIT) \
00172     | _BV(PHY_TXD3_BIT) \
00173     | _BV(PHY_TXER_TXD4_BIT) \
00174     | _BV(PHY_RXD2_AD2_BIT) \
00175     | _BV(PHY_RXD3_AD3_BIT) \
00176     | _BV(PHY_RXDV_TESTMODE_BIT) \
00177     | _BV(PHY_COL_RMII_BIT) \
00178     | _BV(PHY_RXCLK_10BTSER_BIT)
00179 
00183 struct _EMACINFO {
00184 #ifdef NUT_PERFMON
00185     uint32_t ni_rx_packets;       
00186     uint32_t ni_tx_packets;       
00187     uint32_t ni_overruns;         
00188     uint32_t ni_rx_frame_errors;  
00189     uint32_t ni_rx_crc_errors;    
00190     uint32_t ni_rx_missed_errors; 
00191 #endif
00192     HANDLE volatile ni_rx_rdy;  
00193     HANDLE volatile ni_tx_rdy;  
00194     HANDLE ni_mutex;            
00195     volatile int ni_tx_queued;  
00196     volatile int ni_tx_quelen;  
00197     volatile int ni_insane;     
00198     int ni_iomode;              
00199 };
00200 
00204 typedef struct _EMACINFO EMACINFO;
00205 
00206 /*
00207  * TODO: Buffers and their descriptors should be part of the EMACINFO
00208  * structure. Actually there will be no dual Ethernet chip (sure?),
00209  * but just to keep the code clean.
00210  */
00211 typedef struct _BufDescriptor {
00212     unsigned int addr;
00213     unsigned int stat;
00214 } BufDescriptor;
00215 
00216 static volatile BufDescriptor txBufTab[2];
00217 static volatile uint8_t txBuf[EMAC_TX_BUFFERS * EMAC_TX_BUFSIZ] __attribute__ ((aligned(8)));
00218 static unsigned int txBufIdx;
00219 
00220 static volatile BufDescriptor rxBufTab[EMAC_RX_BUFFERS];
00221 static volatile uint8_t rxBuf[EMAC_RX_BUFFERS * EMAC_RX_BUFSIZ] __attribute__ ((aligned(8)));
00222 static unsigned int rxBufIdx;
00223 
00224 #define RXBUF_OWNERSHIP     0x00000001
00225 #define RXBUF_WRAP          0x00000002
00226 #define RXBUF_ADDRMASK      0xFFFFFFFC
00227 
00228 #define RXS_BROADCAST_ADDR  0x80000000  
00229 #define RXS_MULTICAST_HASH  0x40000000  
00230 #define RXS_UNICAST_HASH    0x20000000  
00231 #define RXS_EXTERNAL_ADDR   0x10000000  
00232 #define RXS_SA1_ADDR        0x04000000  
00233 #define RXS_SA2_ADDR        0x02000000  
00234 #define RXS_SA3_ADDR        0x01000000  
00235 #define RXS_SA4_ADDR        0x00800000  
00236 #define RXS_TYPE_ID         0x00400000  
00237 #define RXS_VLAN_TAG        0x00200000  
00238 #define RXS_PRIORITY_TAG    0x00100000  
00239 #define RXS_VLAN_PRIORITY   0x000E0000  
00240 #define RXS_CFI_IND         0x00010000  
00241 #define RXS_EOF             0x00008000  
00242 #define RXS_SOF             0x00004000  
00243 #define RXS_RBF_OFFSET      0x00003000  
00244 #define RXS_LENGTH_FRAME    0x000007FF  
00246 #define TXS_USED            0x80000000  
00247 #define TXS_WRAP            0x40000000  
00248 #define TXS_ERROR           0x20000000  
00249 #define TXS_UNDERRUN        0x10000000  
00250 #define TXS_NO_BUFFER       0x08000000  
00251 #define TXS_NO_CRC          0x00010000  
00252 #define TXS_LAST_BUFF       0x00008000  
00259 
00260 
00267 static uint16_t phy_inw(uint8_t reg)
00268 {
00269     /* PHY read command. */
00270     outr(EMAC_MAN, _BV(30) | _BV(29) | _BV(17) | ((NIC_PHY_ADDR) << 23) | ((reg & 0x1F) << 18));
00271 
00272     /* Wait until PHY logic completed. */
00273     while ((inr(EMAC_NSR) & EMAC_IDLE) == 0);
00274 
00275     /* Get data from PHY maintenance register. */
00276     return (uint16_t) inr(EMAC_MAN);
00277 }
00278 
00285 static void phy_outw(uint8_t reg, uint16_t val)
00286 {
00287     /* PHY write command. */
00288     outr(EMAC_MAN, _BV(30) | _BV(28) | _BV(17) | ((NIC_PHY_ADDR) << 23) | ((reg & 0x1F) << 18) | val);
00289 
00290     /* Wait until PHY logic completed. */
00291     while ((inr(EMAC_NSR) & EMAC_IDLE) == 0);
00292 }
00293 
00299 static int EmacReset(void)
00300 {
00301     outr(PMC_PCER, _BV(PIOA_ID));
00302     outr(PMC_PCER, _BV(PIOB_ID));
00303     outr(PMC_PCER, _BV(EMAC_ID));
00304 
00305     /* Disable RMII and TESTMODE by disabling pull-ups. */
00306     outr(PIOB_PUDR, _BV(PHY_COL_RMII_BIT) | _BV(PHY_RXDV_TESTMODE_BIT));
00307 
00308     /* Disable PHY power down. */
00309     outr(PIOB_PER, _BV(PHY_PWRDN_BIT));
00310     outr(PIOB_OER, _BV(PHY_PWRDN_BIT));
00311     outr(PIOB_CODR, _BV(PHY_PWRDN_BIT));
00312 
00313     /* Toggle external hardware reset pin. */
00314     outr(RSTC_MR, RSTC_KEY | 0x00000100 | RSTC_URSTEN);
00315     outr(RSTC_CR, RSTC_KEY | RSTC_EXTRST);
00316     while ((inr(RSTC_SR) & RSTC_NRSTL) == 0);
00317 
00318     /* Configure MII port. */
00319     outr(PIOB_ASR, PHY_MII_PINS);
00320     outr(PIOB_BSR, 0);
00321     outr(PIOB_PDR, PHY_MII_PINS);
00322 
00323     /* Enable management port. */
00324     outr(EMAC_NCR, inr(EMAC_NCR) | EMAC_MPE);
00325     outr(EMAC_NCFGR, inr(EMAC_NCFGR) | EMAC_CLK_HCLK_32);
00326 
00327     /* Wait for PHY ready. */
00328     NutDelay(255);
00329 
00330     /* Clear MII isolate. */
00331     phy_inw(NIC_PHY_BMCR);
00332     phy_outw(NIC_PHY_BMCR, phy_inw(NIC_PHY_BMCR) & ~NIC_PHY_BMCR_ISOLATE);
00333 
00334     /* Wait for auto negotiation completed. */
00335     phy_inw(NIC_PHY_BMSR);
00336     for (;;) {
00337         if (phy_inw(NIC_PHY_BMSR) & NIC_PHY_BMSR_ANCOMPL) {
00338             break;
00339         }
00340     }
00341 
00342     /* Disable management port. */
00343     outr(EMAC_NCR, inr(EMAC_NCR) & ~EMAC_MPE);
00344 
00345     /* Enable receive and transmit clocks. */
00346     outr(EMAC_USRIO, EMAC_CLKEN);
00347 
00348     return 0;
00349 }
00350 
00351 /*
00352  * NIC interrupt entry.
00353  */
00354 static void EmacInterrupt(void *arg)
00355 {
00356     unsigned int isr;
00357     EMACINFO *ni = (EMACINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00358 
00359     /* Read interrupt status and disable interrupts. */
00360     isr = inr(EMAC_ISR);
00361 
00362     /* Receiver interrupt. */
00363     if ((isr & EMAC_RCOMP) != 0 || (isr & EMAC_ROVR) != 0 || (inr(EMAC_RSR) & EMAC_REC) != 0) {
00364         outr(EMAC_RSR, EMAC_REC);
00365         NutEventPostFromIrq(&ni->ni_rx_rdy);
00366     }
00367 
00368     /* Transmitter interrupt. */
00369     if ((isr & EMAC_TCOMP) != 0 || (inr(EMAC_TSR) & EMAC_COMP) != 0) {
00370         outr(EMAC_TSR, EMAC_COMP);
00371         NutEventPostFromIrq(&ni->ni_tx_rdy);
00372     }
00373 }
00374 
00380 static int EmacGetPacket(EMACINFO * ni, NETBUF ** nbp)
00381 {
00382     int rc = -1;
00383     uint16_t fbc = 0;
00384     unsigned int i;
00385 
00386     *nbp = NULL;
00387 
00388     /*
00389      * Search the next frame start. Release any fragment.
00390      */
00391     while ((rxBufTab[rxBufIdx].addr & RXBUF_OWNERSHIP) != 0 && (rxBufTab[rxBufIdx].stat & RXS_SOF) == 0) {
00392         rxBufTab[rxBufIdx].addr &= ~(RXBUF_OWNERSHIP);
00393         rxBufIdx++;
00394         if (rxBufIdx >= EMAC_RX_BUFFERS) {
00395             rxBufIdx = 0;
00396         }
00397     }
00398 
00399     /*
00400      * Determine the size of the next frame.
00401      */
00402     i = rxBufIdx;
00403     while (rxBufTab[i].addr & RXBUF_OWNERSHIP) {
00404         if ((fbc = rxBufTab[i].stat & RXS_LENGTH_FRAME) != 0) {
00405             break;
00406         }
00407         i++;
00408         if (i >= EMAC_RX_BUFFERS) {
00409             i = 0;
00410         }
00411     }
00412 
00413     if (fbc) {
00414         /*
00415          * Receiving long packets is unexpected. Let's declare the 
00416          * chip insane. Short packets will be handled by the caller.
00417          */
00418         if (fbc > EMAC_TX_BUFSIZ) {
00419             ni->ni_insane = 1;
00420         } else {
00421             *nbp = NutNetBufAlloc(0, NBAF_DATALINK, fbc);
00422             if (*nbp != NULL) {
00423                 uint8_t *bp = (uint8_t *) (* nbp)->nb_dl.vp;
00424                 unsigned int len;
00425 
00426                 while (fbc) {
00427                     if (fbc > EMAC_RX_BUFSIZ) {
00428                         len = EMAC_RX_BUFSIZ;
00429                     } else {
00430                         len = fbc;
00431                     }
00432                     memcpy(bp, (void *) (rxBufTab[rxBufIdx].addr & RXBUF_ADDRMASK), len);
00433                     rxBufTab[rxBufIdx].addr &= ~RXBUF_OWNERSHIP;
00434                     rxBufIdx++;
00435                     if (rxBufIdx >= EMAC_RX_BUFFERS) {
00436                         rxBufIdx = 0;
00437                     }
00438                     fbc -= len;
00439                     bp += len;
00440                 }
00441                 rc = 0;
00442             }
00443         }
00444     }
00445     return rc;
00446 }
00447 
00462 static int EmacPutPacket(int bufnum, EMACINFO * ni, NETBUF * nb)
00463 {
00464     int rc = -1;
00465     unsigned int sz;
00466     uint8_t *buf;
00467 
00468     /*
00469      * Calculate the number of bytes to be send. Do not send packets 
00470      * larger than the Ethernet maximum transfer unit. The MTU
00471      * consist of 1500 data bytes plus the 14 byte Ethernet header
00472      * plus 4 bytes CRC. We check the data bytes only.
00473      */
00474     if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU) {
00475         return -1;
00476     }
00477     sz += nb->nb_dl.sz;
00478     if (sz & 1) {
00479         sz++;
00480     }
00481 
00482     /* Disable EMAC interrupts. */
00483     NutIrqDisable(&sig_EMAC);
00484 
00485     /* TODO: Check for link. */
00486     if (ni->ni_insane == 0) {
00487         buf = (uint8_t *) txBufTab[bufnum].addr;
00488         memcpy(buf, nb->nb_dl.vp, nb->nb_dl.sz);
00489         buf += nb->nb_dl.sz;
00490         memcpy(buf, nb->nb_nw.vp, nb->nb_nw.sz);
00491         buf += nb->nb_nw.sz;
00492         memcpy(buf, nb->nb_tp.vp, nb->nb_tp.sz);
00493         buf += nb->nb_tp.sz;
00494         memcpy(buf, nb->nb_ap.vp, nb->nb_ap.sz);
00495         sz |= TXS_LAST_BUFF;
00496         if (bufnum) {
00497             sz |= TXS_WRAP;
00498         }
00499         txBufTab[bufnum].stat = sz;
00500         outr(EMAC_NCR, inr(EMAC_NCR) | EMAC_TSTART);
00501         rc = 0;
00502 #ifdef NUT_PERFMON
00503         ni->ni_tx_packets++;
00504 #endif
00505     }
00506 
00507     /* Enable EMAC interrupts. */
00508     NutIrqEnable(&sig_EMAC);
00509 
00510     return rc;
00511 }
00512 
00513 
00521 static int EmacStart(CONST uint8_t * mac)
00522 {
00523     int i;
00524 
00525     if (EmacReset()) {
00526         return -1;
00527     }
00528 
00529     /* Set local MAC address. */
00530     outr(EMAC_SA1L, (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]);
00531     outr(EMAC_SA1H, (mac[5] << 8) | mac[4]);
00532 
00533     /* Initialize receive buffer descriptors. */
00534     for (i = 0; i < EMAC_RX_BUFFERS - 1; i++) {
00535         rxBufTab[i].addr = (unsigned int) (&rxBuf[i * EMAC_RX_BUFSIZ]) & RXBUF_ADDRMASK;
00536     }
00537     rxBufTab[i].addr = ((unsigned int) (&rxBuf[i * EMAC_RX_BUFSIZ]) & RXBUF_ADDRMASK) | RXBUF_WRAP;
00538     outr(EMAC_RBQP, (unsigned int) rxBufTab);
00539 
00540     /* Initialize transmit buffer descriptors. */
00541     txBufTab[0].addr = (unsigned int) (&txBuf[0]);
00542     txBufTab[0].stat = TXS_USED;
00543     txBufTab[1].addr = (unsigned int) (&txBuf[EMAC_TX_BUFSIZ]);
00544     txBufTab[1].stat = TXS_USED | TXS_WRAP;
00545     outr(EMAC_TBQP, (unsigned int) txBufTab);
00546 
00547     /* Clear receiver status. */
00548     outr(EMAC_RSR, EMAC_OVR | EMAC_REC | EMAC_BNA);
00549 
00550     /* Copy all frames and discard FCS. */
00551     outr(EMAC_NCFGR, inr(EMAC_NCFGR) | EMAC_CAF | EMAC_DRFCS);
00552 
00553     /* Enable receiver, transmitter and statistics. */
00554     outr(EMAC_NCR, inr(EMAC_NCR) | EMAC_TE | EMAC_RE | EMAC_WESTAT);
00555 
00556     return 0;
00557 }
00558 
00563 THREAD(EmacRxThread, arg)
00564 {
00565     NUTDEVICE *dev;
00566     IFNET *ifn;
00567     EMACINFO *ni;
00568     NETBUF *nb;
00569 
00570     dev = arg;
00571     ifn = (IFNET *) dev->dev_icb;
00572     ni = (EMACINFO *) dev->dev_dcb;
00573 
00574     /*
00575      * This is a temporary hack. Due to a change in initialization,
00576      * we may not have got a MAC address yet. Wait until a valid one
00577      * has been set.
00578      */
00579     while (!ETHER_IS_UNICAST(ifn->if_mac)) {
00580         NutSleep(10);
00581     }
00582 
00583     /*
00584      * Do not continue unless we managed to start the NIC. We are
00585      * trapped here if the Ethernet link cannot be established.
00586      * This happens, for example, if no Ethernet cable is plugged
00587      * in.
00588      */
00589     while (EmacStart(ifn->if_mac)) {
00590         NutSleep(1000);
00591     }
00592 
00593     /* Initialize the access mutex. */
00594     NutEventPost(&ni->ni_mutex);
00595 
00596     /* Run at high priority. */
00597     NutThreadSetPriority(9);
00598 
00599     /* Enable receive interrupts. */
00600     outr(EMAC_IER, EMAC_RCOMP | EMAC_TCOMP | EMAC_ROVR);
00601     NutIrqEnable(&sig_EMAC);
00602 
00603     for (;;) {
00604         /*
00605          * Wait for the arrival of new packets or poll the receiver 
00606          * every two seconds.
00607          */
00608         NutEventWait(&ni->ni_rx_rdy, 2000);
00609 
00610         /*
00611          * Fetch all packets from the NIC's internal buffer and pass 
00612          * them to the registered handler.
00613          */
00614         while (EmacGetPacket(ni, &nb) == 0) {
00615             /* Discard short packets. */
00616             if (nb->nb_dl.sz < 60) {
00617                 NutNetBufFree(nb);
00618             } else {
00619                 (*ifn->if_recv) (dev, nb);
00620             }
00621         }
00622 
00623         /* We got a weird chip, try to restart it. */
00624         while (ni->ni_insane) {
00625             if (EmacStart(ifn->if_mac) == 0) {
00626                 ni->ni_insane = 0;
00627                 ni->ni_tx_queued = 0;
00628                 ni->ni_tx_quelen = 0;
00629                 NutIrqEnable(&sig_EMAC);
00630             } else {
00631                 NutSleep(1000);
00632             }
00633         }
00634     }
00635 }
00636 
00649 int EmacOutput(NUTDEVICE * dev, NETBUF * nb)
00650 {
00651     static uint32_t mx_wait = 5000;
00652     int rc = -1;
00653     EMACINFO *ni = (EMACINFO *) dev->dev_dcb;
00654 
00655     /*
00656      * After initialization we are waiting for a long time to give
00657      * the PHY a chance to establish an Ethernet link.
00658      */
00659     while (rc) {
00660         if (ni->ni_insane) {
00661             break;
00662         }
00663         if (NutEventWait(&ni->ni_mutex, mx_wait)) {
00664             break;
00665         }
00666 
00667         /* Check for packet queue space. */
00668         if ((txBufTab[txBufIdx].stat & TXS_USED) == 0) {
00669             if (NutEventWait(&ni->ni_tx_rdy, 500) && (txBufTab[txBufIdx].stat & TXS_USED) == 0) {
00670                 /* No queue space. Release the lock and give up. */
00671                 NutEventPost(&ni->ni_mutex);
00672                 break;
00673             }
00674         } else {
00675             if ((rc = EmacPutPacket(txBufIdx, ni, nb)) == 0) {
00676                 txBufIdx++;
00677                 txBufIdx &= 1;
00678             }
00679         }
00680         NutEventPost(&ni->ni_mutex);
00681     }
00682 
00683     /*
00684      * Probably no Ethernet link. Significantly reduce the waiting
00685      * time, so following transmission will soon return an error.
00686      */
00687     if (rc) {
00688         mx_wait = 500;
00689     } else {
00690         /* Ethernet works. Set a long waiting time in case we
00691            temporarly lose the link next time. */
00692         mx_wait = 5000;
00693     }
00694     return rc;
00695 }
00696 
00706 int EmacInit(NUTDEVICE * dev)
00707 {
00708     EMACINFO *ni = (EMACINFO *) dev->dev_dcb;
00709 
00710     /* Reset the controller. */
00711     if (EmacReset()) {
00712         return -1;
00713     }
00714 
00715     /* Clear EMACINFO structure. */
00716     memset(ni, 0, sizeof(EMACINFO));
00717 
00718     /* Register interrupt handler. */
00719     if (NutRegisterIrqHandler(&sig_EMAC, EmacInterrupt, dev)) {
00720         return -1;
00721     }
00722 
00723     /* Start the receiver thread. */
00724     if (NutThreadCreate("emacrx", EmacRxThread, dev, 
00725         (NUT_THREAD_NICRXSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD) == NULL) {
00726         return -1;
00727     }
00728     return 0;
00729 }
00730 
00731 static EMACINFO dcb_eth0;
00732 
00738 static IFNET ifn_eth0 = {
00739     IFT_ETHER,                  
00740     0,                          
00741     {0, 0, 0, 0, 0, 0},         
00742     0,                          
00743     0,                          
00744     0,                          
00745     ETHERMTU,                   
00746     0,                          
00747     0,                          
00748     0,                          
00749     NutEtherInput,              
00750     EmacOutput,                 
00751     NutEtherOutput              
00752 };
00753 
00763 NUTDEVICE devAt91Emac = {
00764     0,                          
00765     {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        
00766     IFTYP_NET,                  
00767     0,                          
00768     0,                          
00769     &ifn_eth0,                  
00770     &dcb_eth0,                  
00771     EmacInit,                   
00772     0,                          
00773     0,                          
00774     0,                          
00775 #ifdef __HARVARD_ARCH__
00776     0,                          
00777 #endif
00778     0,                          
00779     0,                          
00780     0                           
00781 };
00782