| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143 |
- /*
- * Copyright (C) 2006-2007 by egnite Software GmbH. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- *
- */
- /*
- * $Id: at91_emac.c 5472 2013-12-06 00:16:28Z olereinhardt $
- */
- #include <cfg/os.h>
- #include <cfg/dev.h>
- #include <arch/arm.h>
- #include <cfg/arch/gpio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/atom.h>
- #include <sys/heap.h>
- #include <sys/thread.h>
- #include <sys/event.h>
- #include <sys/timer.h>
- #include <sys/confnet.h>
- #include <netinet/if_ether.h>
- #include <net/ether.h>
- #include <net/if_var.h>
- #include <dev/irqreg.h>
- #include <dev/at91_emac.h>
- #include <dev/phy.h>
- #include <stdio.h>
- /* WARNING: Variadic macros are C99 and may fail with C89 compilers. */
- #ifdef NUTDEBUG
- #include <stdio.h>
- #include <arpa/inet.h>
- #define EMPRINTF(args,...) printf(args,##__VA_ARGS__);fflush(stdout)
- #else
- #define EMPRINTF(args,...)
- #endif
- #ifndef NUT_THREAD_NICRXSTACK
- /* arm-elf-gcc used 168 bytes with optimized, 412 bytes with debug code. */
- #define NUT_THREAD_NICRXSTACK 320
- #endif
- #ifndef EMAC_RX_BUFFERS
- #define EMAC_RX_BUFFERS 32
- #endif
- #define EMAC_RX_BUFSIZ 128
- #define EMAC_TX_BUFFERS 2
- #ifndef EMAC_TX_BUFSIZ
- #define EMAC_TX_BUFSIZ 1536
- #endif
- #ifndef EMAC_LINK_LOOPS
- #define EMAC_LINK_LOOPS 1000
- #endif
- /*!
- * \brief PHY address.
- *
- * Any other than 0 seems to create problems with Atmel's evaluation kits.
- */
- #ifndef NIC_PHY_ADDR
- #define NIC_PHY_ADDR 0
- #endif
- /*!
- * \brief PHY ID.
- *
- * If set to 0xffffffff, the PHY id will be ignored.
- */
- #ifndef NIC_PHY_UID
- #define NIC_PHY_UID 0xffffffff
- #endif
- /*!
- * \brief Check all known PHY IDs.
- *
- * If defined, perform the old PHY checks. This ensures compatibility
- * at the cost of bloat. Should be removed later on when all boards
- * have their PHY ids in their configuration.
- */
- #define CHECK_ALL_KNOWN_PHY_IDS
- #if defined (MCU_AT91SAM9260) || defined(MCU_AT91SAM9XE512)
- /*!
- * The AT91SAM9260-EK board is delivered with RMII by default. Thus.
- * we use the reduced MII for this CPU. However, this should be
- * handled by the Configurator.
- */
- #define PHY_MODE_RMII
- //#define EMAC_PIO_PER PIOA_PER
- //#define EMAC_PIO_OER PIOA_OER
- //#define EMAC_PIO_CODR PIOA_CODR
- #define EMAC_PIO_ASR PIOA_ASR
- #define EMAC_PIO_BSR PIOA_BSR
- #define EMAC_PIO_PDR PIOA_PDR
- #define PHY_TXD0_BIT PA12_ETX0_A /*!< \brief Transmit data bit 0 pin. */
- #define PHY_TXD1_BIT PA13_ETX1_A /*!< \brief Transmit data bit 1 pin. */
- #define PHY_RXD0_AD0_BIT PA14_ERX0_A /*!< \brief Receive data bit 0 pin. */
- #define PHY_RXD1_AD1_BIT PA15_ERX1_A /*!< \brief Receive data bit 1 pin. */
- #define PHY_TXEN_BIT PA16_ETXEN_A /*!< \brief Transmit enable pin. */
- #define PHY_RXDV_TESTMODE_BIT PA17_ERXDV_A /*!< \brief Data valid pin. */
- #define PHY_RXER_RXD4_RPTR_BIT PA18_ERXER_A /*!< \brief Receive error pin. */
- #define PHY_TXCLK_ISOLATE_BIT PA19_ETXCK_A /*!< \brief Transmit clock pin. */
- #define PHY_MDC_BIT PA20_EMDC_A /*!< \brief Management data clock pin. */
- #define PHY_MDIO_BIT PA21_EMDIO_A /*!< \brief Management data I/O pin. */
- #ifndef PHY_MODE_RMII
- #define PHY_TXD2_BIT PA10_ETX2_B /*!< \brief Transmit data bit 2 pin. */
- #define PHY_TXD3_BIT PA11_ETX3_B /*!< \brief Transmit data bit 3 pin. */
- #define PHY_TXER_TXD4_BIT PA22_ETXER_B /*!< \brief Transmit error pin. */
- #define PHY_RXCLK_10BTSER_BIT PA27_ERXCK_B /*!< \brief Receive clock pin. */
- #define PHY_COL_RMII_BIT PA29_ECOL_B /*!< \brief Collision detect pin. */
- #endif
- #define PHY_RXD2_AD2_BIT PA25_ERX2_B /*!< \brief Receive data bit 2 pin. */
- #define PHY_RXD3_AD3_BIT PA26_ERX3_B /*!< \brief Receive data bit 3 pin. */
- #define PHY_CRS_AD4_BIT PA28_ECRS_B /*!< \brief Carrier sense pin. */
- #define PHY_MII_PINS_A 0 \
- | _BV(PHY_TXD0_BIT) \
- | _BV(PHY_TXD1_BIT) \
- | _BV(PHY_RXD0_AD0_BIT) \
- | _BV(PHY_RXD1_AD1_BIT) \
- | _BV(PHY_TXEN_BIT) \
- | _BV(PHY_RXDV_TESTMODE_BIT) \
- | _BV(PHY_RXER_RXD4_RPTR_BIT) \
- | _BV(PHY_TXCLK_ISOLATE_BIT) \
- | _BV(PHY_MDC_BIT) \
- | _BV(PHY_MDIO_BIT)
- #ifdef PHY_MODE_RMII
- #define PHY_MII_PINS_B 0
- #else
- #define PHY_MII_PINS_B 0 \
- | _BV(PHY_TXD2_BIT) \
- | _BV(PHY_TXD3_BIT) \
- | _BV(PHY_TXER_TXD4_BIT) \
- | _BV(PHY_RXD2_AD2_BIT) \
- | _BV(PHY_RXD3_AD3_BIT) \
- | _BV(PHY_RXCLK_10BTSER_BIT) \
- | _BV(PHY_CRS_AD4_BIT) \
- | _BV(PHY_COL_RMII_BIT)
- #endif
- #elif defined (MCU_AT91SAM7X)
- #define EMAC_PIO_PER PIOB_PER
- #define EMAC_PIO_OER PIOB_OER
- #define EMAC_PIO_CODR PIOB_CODR
- #define EMAC_PIO_SODR PIOB_SODR
- #define EMAC_PIO_PUER PIOB_PUER
- #define EMAC_PIO_PUDR PIOB_PUDR
- #define EMAC_PIO_ASR PIOB_ASR
- #define EMAC_PIO_BSR PIOB_BSR
- #define EMAC_PIO_PDR PIOB_PDR
- #define PHY_TXCLK_ISOLATE_BIT 0
- #define PHY_REFCLK_XT2_BIT 0
- #define PHY_TXEN_BIT 1
- #define PHY_TXD0_BIT 2
- #define PHY_TXD1_BIT 3
- #define PHY_CRS_AD4_BIT 4
- #define PHY_RXD0_AD0_BIT 5
- #define PHY_RXD1_AD1_BIT 6
- #define PHY_RXER_RXD4_RPTR_BIT 7
- #define PHY_MDC_BIT 8
- #define PHY_MDIO_BIT 9
- #define PHY_TXD2_BIT 10
- #define PHY_TXD3_BIT 11
- #define PHY_TXER_TXD4_BIT 12
- #define PHY_RXD2_AD2_BIT 13
- #define PHY_RXD3_AD3_BIT 14
- #define PHY_RXDV_TESTMODE_BIT 15
- #define PHY_COL_RMII_BIT 16
- #define PHY_RXCLK_10BTSER_BIT 17
- #define PHY_MDINTR_BIT 26
- #define PHY_MII_PINS_A 0 \
- | _BV(PHY_REFCLK_XT2_BIT) \
- | _BV(PHY_TXEN_BIT) \
- | _BV(PHY_TXD0_BIT) \
- | _BV(PHY_TXD1_BIT) \
- | _BV(PHY_CRS_AD4_BIT) \
- | _BV(PHY_RXD0_AD0_BIT) \
- | _BV(PHY_RXD1_AD1_BIT) \
- | _BV(PHY_RXER_RXD4_RPTR_BIT) \
- | _BV(PHY_MDC_BIT) \
- | _BV(PHY_MDIO_BIT) \
- | _BV(PHY_TXD2_BIT) \
- | _BV(PHY_TXD3_BIT) \
- | _BV(PHY_TXER_TXD4_BIT) \
- | _BV(PHY_RXD2_AD2_BIT) \
- | _BV(PHY_RXD3_AD3_BIT) \
- | _BV(PHY_RXDV_TESTMODE_BIT) \
- | _BV(PHY_COL_RMII_BIT) \
- | _BV(PHY_RXCLK_10BTSER_BIT)
- #define PHY_MII_PINS_B 0
- #endif
- /*!
- * \brief Network interface controller information structure.
- */
- struct _EMACINFO {
- #ifdef NUT_PERFMON
- uint32_t ni_rx_packets; /*!< Number of packets received. */
- uint32_t ni_tx_packets; /*!< Number of packets sent. */
- uint32_t ni_overruns; /*!< Number of packet overruns. */
- uint32_t ni_rx_frame_errors; /*!< Number of frame errors. */
- uint32_t ni_rx_crc_errors; /*!< Number of CRC errors. */
- uint32_t ni_rx_missed_errors; /*!< Number of missed packets. */
- #endif
- HANDLE volatile ni_rx_rdy; /*!< Receiver event queue. */
- HANDLE volatile ni_tx_rdy; /*!< Transmitter event queue. */
- HANDLE ni_mutex; /*!< Access mutex semaphore. */
- volatile int ni_tx_queued; /*!< Number of packets in transmission queue. */
- volatile int ni_tx_quelen; /*!< Number of bytes in transmission queue not sent. */
- volatile int ni_insane; /*!< Set by error detection. */
- int ni_iomode; /*!< 8 or 16 bit access. 32 bit is not supported. */
- };
- /*!
- * \brief Network interface controller information type.
- */
- typedef struct _EMACINFO EMACINFO;
- /*
- * TODO: Buffers and their descriptors should be part of the EMACINFO
- * structure. Actually there will be no dual Ethernet chip (sure?),
- * but just to keep the code clean.
- */
- typedef struct _BufDescriptor {
- unsigned int addr;
- unsigned int stat;
- } BufDescriptor;
- static volatile BufDescriptor txBufTab[EMAC_TX_BUFFERS];
- static volatile uint8_t txBuf[EMAC_TX_BUFFERS * EMAC_TX_BUFSIZ] NUT_ALIGNED_TYPE(8);
- static unsigned int txBufIdx;
- static volatile BufDescriptor rxBufTab[EMAC_RX_BUFFERS];
- static volatile uint8_t rxBuf[EMAC_RX_BUFFERS * EMAC_RX_BUFSIZ] NUT_ALIGNED_TYPE(8);
- static unsigned int rxBufIdx;
- #define RXBUF_OWNERSHIP 0x00000001
- #define RXBUF_WRAP 0x00000002
- #define RXBUF_ADDRMASK 0xFFFFFFFC
- #define RXS_BROADCAST_ADDR 0x80000000 /*!< \brief Broadcast address detected. */
- #define RXS_MULTICAST_HASH 0x40000000 /*!< \brief Multicast hash match. */
- #define RXS_UNICAST_HASH 0x20000000 /*!< \brief Unicast hash match. */
- #define RXS_EXTERNAL_ADDR 0x10000000 /*!< \brief External address match. */
- #define RXS_SA1_ADDR 0x04000000 /*!< \brief Specific address register 1 match. */
- #define RXS_SA2_ADDR 0x02000000 /*!< \brief Specific address register 2 match. */
- #define RXS_SA3_ADDR 0x01000000 /*!< \brief Specific address register 3 match. */
- #define RXS_SA4_ADDR 0x00800000 /*!< \brief Specific address register 4 match. */
- #define RXS_TYPE_ID 0x00400000 /*!< \brief Type ID match. */
- #define RXS_VLAN_TAG 0x00200000 /*!< \brief VLAN tag detected. */
- #define RXS_PRIORITY_TAG 0x00100000 /*!< \brief Priority tag detected. */
- #define RXS_VLAN_PRIORITY 0x000E0000 /*!< \brief VLAN priority. */
- #define RXS_CFI_IND 0x00010000 /*!< \brief Concatenation format indicator. */
- #define RXS_EOF 0x00008000 /*!< \brief End of frame. */
- #define RXS_SOF 0x00004000 /*!< \brief Start of frame. */
- #define RXS_RBF_OFFSET 0x00003000 /*!< \brief Receive buffer offset mask. */
- #define RXS_LENGTH_FRAME 0x000007FF /*!< \brief Length of frame including FCS. */
- #define TXS_USED 0x80000000 /*!< \brief Used buffer. */
- #define TXS_WRAP 0x40000000 /*!< \brief Last descriptor. */
- #define TXS_ERROR 0x20000000 /*!< \brief Retry limit exceeded. */
- #define TXS_UNDERRUN 0x10000000 /*!< \brief Transmit underrun. */
- #define TXS_NO_BUFFER 0x08000000 /*!< \brief Buffer exhausted. */
- #define TXS_NO_CRC 0x00010000 /*!< \brief CRC not appended. */
- #define TXS_LAST_BUFF 0x00008000 /*!< \brief Last buffer of frame. */
- #define MII_DM9161_ID 0x0181b8a0
- #define MII_AM79C875_ID 0x00225540
- #define MII_MICREL_ID 0x00221610
- #define MII_LAN8700_ID 0x0007c0c0
- #define MII_LAN8710_ID 0x0007C0F0
- /*!
- * \addtogroup xgNutArchArmAt91Emac
- */
- /*@{*/
- /*!
- * \brief Read contents of PHY register.
- *
- * \param reg PHY register number.
- *
- * \return Contents of the specified register.
- */
- static uint16_t phy_inw(uint8_t reg)
- {
- /* PHY read command. */
- outr(EMAC_MAN, EMAC_SOF | EMAC_RW_READ | EMAC_CODE |
- (NIC_PHY_ADDR << EMAC_PHYA_LSB) | (reg << EMAC_REGA_LSB));
- /* Wait until PHY logic completed. */
- while ((inr(EMAC_NSR) & EMAC_IDLE) == 0);
- /* Get data from PHY maintenance register. */
- return (uint16_t) (inr(EMAC_MAN) >> EMAC_DATA_LSB);
- }
- /*!
- * \brief Write value to PHY register.
- *
- * \param reg PHY register number.
- * \param val Value to write.
- */
- static void phy_outw(uint8_t reg, uint16_t val)
- {
- /* PHY write command. */
- outr(EMAC_MAN, EMAC_SOF | EMAC_RW_WRITE | EMAC_CODE |
- (NIC_PHY_ADDR << EMAC_PHYA_LSB) | (reg << EMAC_REGA_LSB) | val);
- /* Wait until PHY logic completed. */
- while ((inr(EMAC_NSR) & EMAC_IDLE) == 0);
- }
- /*!
- * \brief Reset the Ethernet controller.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int EmacReset(uint32_t tmo)
- {
- int rc = 0;
- uint32_t reg_ncfgr;
- uint32_t phyval;
- int link_wait;
- EMPRINTF("EmacReset(%lu)\n", tmo);
- /* Enable power sources if not yet enabled */
- outr(PMC_PCER, _BV(PIOA_ID));
- outr(PMC_PCER, _BV(PIOB_ID));
- outr(PMC_PCER, _BV(EMAC_ID));
- /* Configure MII port. */
- outr(EMAC_PIO_ASR, PHY_MII_PINS_A);
- outr(EMAC_PIO_BSR, PHY_MII_PINS_B);
- outr(EMAC_PIO_PDR, PHY_MII_PINS_A | PHY_MII_PINS_B);
- /* Enable receive and transmit clocks and set MII mode. */
- #ifdef PHY_MODE_RMII
- outr(EMAC_USRIO, EMAC_RMII | EMAC_CLKEN);
- #else
- outr(EMAC_USRIO, EMAC_CLKEN);
- #endif
- /* Enable management port. */
- outr(EMAC_NCR, inr(EMAC_NCR) | EMAC_MPE);
- outr(EMAC_NCFGR, inr(EMAC_NCFGR) | EMAC_CLK_HCLK_64);
- /* Wait for PHY ready. */
- NutDelay(255);
- /* Register PHY */
- rc = NutRegisterPhy( 1, phy_outw, phy_inw);
- #if NIC_PHY_UID == MII_LAN8710_ID
- /* Set LAN8710 to AUTO-MDIX and MII mode.
- * This overides configuration set by config pins of the chip.
- */
- phyval = 18 << 16; // Store phy register address in upper 16 bits
- NutPhyCtl (PHY_GET_REGVAL, &phyval);
- phyval |= 0x00E0;
- phyval |= 18 << 16; // Store phy register address in upper 16 bits again
- NutPhyCtl (PHY_SET_REGVAL, &phyval);
- /* Soft Reset LAN7810 */
- phyval = 1;
- NutPhyCtl(PHY_CTL_RESET, &phyval);
- #endif
- #ifndef PHY_MODE_RMII
- /* Clear MII isolate. */
- phyval = 0;
- NutPhyCtl(PHY_CTL_ISOLATE, &phyval);
- #endif
- /* Restart autonegotiation */
- phyval = 1;
- NutPhyCtl(PHY_CTL_AUTONEG_RE, &phyval);
- /* Wait for auto negotiation completed and link established. */
- for (link_wait = tmo;; link_wait--) {
- phyval = 0;
- NutPhyCtl(PHY_GET_STATUS, &phyval);
- if((phyval & PHY_STATUS_HAS_LINK) && (phyval & PHY_STATUS_AUTONEG_OK)) {
- /* Check link state and configure EMAC accordingly */
- reg_ncfgr = inr(EMAC_NCFGR);
- if (phyval & PHY_STATUS_FULLDUPLEX) {
- reg_ncfgr |= EMAC_FD;
- } else {
- reg_ncfgr &= ~EMAC_FD;
- }
- if (phyval & PHY_STATUS_100M) {
- reg_ncfgr |= EMAC_SPD;
- } else {
- reg_ncfgr &= ~EMAC_SPD;
- }
- outr(EMAC_NCFGR, reg_ncfgr);
- break;
- }
- if (link_wait == 0) {
- EMPRINTF("NO LINK!\n");
- /* Return error on link timeout. */
- outr(EMAC_NCR, inr(EMAC_NCR) & ~EMAC_MPE);
- return -1;
- }
- NutSleep(10);
- }
- /* Disable management port. */
- outr(EMAC_NCR, inr(EMAC_NCR) & ~EMAC_MPE);
- EMPRINTF("EmacReset() DONE\n");
- return rc;
- }
- /*
- * NIC interrupt entry.
- */
- static void EmacInterrupt(void *arg)
- {
- unsigned int isr;
- EMACINFO *ni = (EMACINFO *) ((NUTDEVICE *) arg)->dev_dcb;
- /* Read interrupt status and disable interrupts. */
- isr = inr(EMAC_ISR);
- /* Receiver interrupt. */
- //if ((isr & EMAC_RCOMP) != 0 || (isr & EMAC_ROVR) != 0 || (inr(EMAC_RSR) & EMAC_REC) != 0) {
- if ((isr & (EMAC_RCOMP | EMAC_ROVR | EMAC_RXUBR)) != 0) {
- //outr(EMAC_RSR, EMAC_REC);
- outr(EMAC_IDR, EMAC_RCOMP | EMAC_ROVR | EMAC_RXUBR);
- NutEventPostFromIrq(&ni->ni_rx_rdy);
- }
- /* Transmitter interrupt. */
- if ((isr & EMAC_TCOMP) != 0 || (inr(EMAC_TSR) & EMAC_COMP) != 0) {
- //outr(EMAC_TSR, EMAC_COMP);
- NutEventPostFromIrq(&ni->ni_tx_rdy);
- }
- }
- /*!
- * \brief Fetch the next packet out of the receive buffers.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int EmacGetPacket(EMACINFO * ni, NETBUF ** nbp)
- {
- int rc = -1;
- unsigned int fbc = 0;
- unsigned int i;
- *nbp = NULL;
- /*
- * Search the next frame start. Release any fragment.
- */
- while ((rxBufTab[rxBufIdx].addr & RXBUF_OWNERSHIP) != 0 && (rxBufTab[rxBufIdx].stat & RXS_SOF) == 0) {
- rxBufTab[rxBufIdx].addr &= ~(RXBUF_OWNERSHIP);
- rxBufIdx++;
- if (rxBufIdx >= EMAC_RX_BUFFERS) {
- rxBufIdx = 0;
- }
- }
- /*
- * Determine the size of the next frame.
- */
- i = rxBufIdx;
- while (rxBufTab[i].addr & RXBUF_OWNERSHIP) {
- if (i != rxBufIdx && (rxBufTab[i].stat & RXS_SOF) != 0) {
- do {
- rxBufTab[rxBufIdx].addr &= ~(RXBUF_OWNERSHIP);
- rxBufIdx++;
- if (rxBufIdx >= EMAC_RX_BUFFERS) {
- rxBufIdx = 0;
- }
- } while ((rxBufTab[rxBufIdx].addr & RXBUF_OWNERSHIP) != 0 && (rxBufTab[rxBufIdx].stat & RXS_SOF) == 0);
- break;
- }
- if ((fbc = rxBufTab[i].stat & RXS_LENGTH_FRAME) != 0) {
- break;
- }
- i++;
- if (i >= EMAC_RX_BUFFERS) {
- i = 0;
- }
- }
- if (fbc) {
- /*
- * Receiving long packets is unexpected. Let's declare the
- * chip insane. Short packets will be handled by the caller.
- */
- if (fbc > 1536) {
- ni->ni_insane = 1;
- } else {
- *nbp = NutNetBufAlloc(0, NBAF_DATALINK + 2, (uint16_t)fbc);
- if (*nbp != NULL) {
- uint8_t *bp = (uint8_t *) (* nbp)->nb_dl.vp;
- unsigned int len;
- while (fbc) {
- if (fbc > EMAC_RX_BUFSIZ) {
- len = EMAC_RX_BUFSIZ;
- } else {
- len = fbc;
- }
- memcpy(bp, (void *) (rxBufTab[rxBufIdx].addr & RXBUF_ADDRMASK), len);
- rxBufTab[rxBufIdx].addr &= ~RXBUF_OWNERSHIP;
- rxBufIdx++;
- if (rxBufIdx >= EMAC_RX_BUFFERS) {
- rxBufIdx = 0;
- }
- fbc -= len;
- bp += len;
- }
- rc = 0;
- }
- }
- }
- return rc;
- }
- /*!
- * \brief Load a packet into the nic's transmit ring buffer.
- *
- * \todo This routine simply does not work. Any idea?
- *
- * \param nb Network buffer structure containing the packet to be sent.
- * The structure must have been allocated by a previous
- * call NutNetBufAlloc(). This routine will automatically
- * release the buffer in case of an error.
- *
- * \return 0 on success, -1 in case of any errors. Errors
- * will automatically release the network buffer
- * structure.
- */
- static int EmacPutPacket(int bufnum, EMACINFO * ni, NETBUF * nb)
- {
- int rc = -1;
- unsigned int sz;
- uint8_t *buf;
- /*
- * Calculate the number of bytes to be send. Do not send packets
- * larger than the Ethernet maximum transfer unit. The MTU
- * consist of 1500 data bytes plus the 14 byte Ethernet header
- * plus 4 bytes CRC. We check the data bytes only.
- */
- if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU) {
- return -1;
- }
- sz += nb->nb_dl.sz;
- if (sz & 1) {
- sz++;
- }
- /* Disable EMAC interrupts. */
- NutIrqDisable(&sig_EMAC);
- /* TODO: Check for link. */
- if (ni->ni_insane == 0) {
- buf = (uint8_t *) txBufTab[bufnum].addr;
- memcpy(buf, nb->nb_dl.vp, nb->nb_dl.sz);
- buf += nb->nb_dl.sz;
- memcpy(buf, nb->nb_nw.vp, nb->nb_nw.sz);
- buf += nb->nb_nw.sz;
- memcpy(buf, nb->nb_tp.vp, nb->nb_tp.sz);
- buf += nb->nb_tp.sz;
- memcpy(buf, nb->nb_ap.vp, nb->nb_ap.sz);
- sz |= TXS_LAST_BUFF;
- if (bufnum) {
- sz |= TXS_WRAP;
- }
- txBufTab[bufnum].stat = sz;
- outr(EMAC_NCR, inr(EMAC_NCR) | EMAC_TSTART);
- rc = 0;
- #ifdef NUT_PERFMON
- ni->ni_tx_packets++;
- #endif
- }
- /* Enable EMAC interrupts. */
- NutIrqEnable(&sig_EMAC);
- return rc;
- }
- /*!
- * \brief Fire up the network interface.
- *
- * NIC interrupts must be disabled when calling this function.
- *
- * \param mac Six byte unique MAC address.
- */
- static int EmacStart(const uint8_t * mac)
- {
- unsigned int i;
- EMPRINTF("EmacStart(%02x:%02x:%02x:%02x:%02x:%02x)\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
- /* Set local MAC address. */
- outr(EMAC_SA1L, (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]);
- outr(EMAC_SA1H, (mac[5] << 8) | mac[4]);
- /* Initialize receive buffer descriptors. */
- for (i = 0; i < EMAC_RX_BUFFERS - 1; i++) {
- rxBufTab[i].addr = (unsigned int) (&rxBuf[i * EMAC_RX_BUFSIZ]) & RXBUF_ADDRMASK;
- }
- rxBufTab[i].addr = ((unsigned int) (&rxBuf[i * EMAC_RX_BUFSIZ]) & RXBUF_ADDRMASK) | RXBUF_WRAP;
- outr(EMAC_RBQP, (unsigned int) rxBufTab);
- /* Initialize transmit buffer descriptors. */
- txBufTab[0].addr = (unsigned int) (&txBuf[0]);
- txBufTab[0].stat = TXS_USED;
- txBufTab[1].addr = (unsigned int) (&txBuf[EMAC_TX_BUFSIZ]);
- txBufTab[1].stat = TXS_USED | TXS_WRAP;
- outr(EMAC_TBQP, (unsigned int) txBufTab);
- /* Clear receiver status. */
- outr(EMAC_RSR, EMAC_OVR | EMAC_REC | EMAC_BNA);
- /* Discard FCS. */
- outr(EMAC_NCFGR, inr(EMAC_NCFGR) | EMAC_DRFCS);
- /* Enable receiver, transmitter and statistics. */
- outr(EMAC_NCR, inr(EMAC_NCR) | EMAC_TE | EMAC_RE | EMAC_WESTAT);
- EMPRINTF("EmacStart() DONE\n");
- return 0;
- }
- /*! \fn EmacRxThread(void *arg)
- * \brief NIC receiver thread.
- *
- */
- THREAD(EmacRxThread, arg)
- {
- NUTDEVICE *dev = arg;
- IFNET *ifn = (IFNET *) dev->dev_icb;
- EMACINFO *ni = (EMACINFO *) dev->dev_dcb;
- NETBUF *nb;
- EMPRINTF("EmacRxThread() INIT\n");
- /*
- * This is a temporary hack. Due to a change in initialization,
- * we may not have got a MAC address yet. Wait until a valid one
- * has been set.
- */
- while (!ETHER_IS_UNICAST(ifn->if_mac)) {
- NutSleep(10);
- }
- /*
- * Do not continue unless we managed to start the NIC. We are
- * trapped here if the Ethernet link cannot be established.
- * This happens, for example, if no Ethernet cable is plugged
- * in.
- */
- EMPRINTF(" Call EmacStart()\n");
- while (EmacStart(ifn->if_mac)) {
- EmacReset(EMAC_LINK_LOOPS);
- NutSleep(1000);
- }
- /* Initialize the access mutex. */
- NutEventPost(&ni->ni_mutex);
- /* Run at high priority. */
- NutThreadSetPriority(9);
- /* Enable receive and transmit interrupts. */
- outr(EMAC_IER, EMAC_ROVR | EMAC_TCOMP | EMAC_TUND | EMAC_RXUBR | EMAC_RCOMP);
- NutIrqEnable(&sig_EMAC);
- for (;;) {
- /*
- * Wait for the arrival of new packets or poll the receiver every
- * 500 milliseconds. This short timeout helps a bit to deal with
- * the SAM9260 Ethernet problem.
- *
- * Sometimes an interrupt status change doesn't trigger an interrupt.
- * We need to read the status register, so that the flags get cleared
- * and the next change triggers an interrupt again.
- */
- if (NutEventWait(&ni->ni_rx_rdy, 500)) {
- inr(EMAC_ISR);
- }
- /*
- * Fetch all packets from the NIC's internal buffer and pass
- * them to the registered handler.
- */
- while (EmacGetPacket(ni, &nb) == 0) {
- /* Discard short packets. */
- if (nb->nb_dl.sz < 60) {
- NutNetBufFree(nb);
- } else {
- (*ifn->if_recv) (dev, nb);
- }
- }
- outr(EMAC_IER, EMAC_ROVR | EMAC_RXUBR | EMAC_RCOMP);
- /* We got a weird chip, try to restart it. */
- while (ni->ni_insane) {
- EmacReset(EMAC_LINK_LOOPS);
- if (EmacStart(ifn->if_mac) == 0) {
- ni->ni_insane = 0;
- ni->ni_tx_queued = 0;
- ni->ni_tx_quelen = 0;
- NutIrqEnable(&sig_EMAC);
- } else {
- NutSleep(1000);
- }
- }
- }
- }
- /*!
- * \brief Send Ethernet packet.
- *
- * \param dev Identifies the device to use.
- * \param nb Network buffer structure containing the packet to be sent.
- * The structure must have been allocated by a previous
- * call NutNetBufAlloc().
- *
- * \return 0 on success, -1 in case of any errors.
- */
- int EmacOutput(NUTDEVICE * dev, NETBUF * nb)
- {
- static uint32_t mx_wait = 5000;
- int rc = -1;
- EMACINFO *ni = (EMACINFO *) dev->dev_dcb;
- /*
- * After initialization we are waiting for a long time to give
- * the PHY a chance to establish an Ethernet link.
- */
- while (rc) {
- if (ni->ni_insane) {
- break;
- }
- if (NutEventWait(&ni->ni_mutex, mx_wait)) {
- break;
- }
- /* Check for packet queue space. */
- if ((txBufTab[txBufIdx].stat & TXS_USED) == 0) {
- if (NutEventWait(&ni->ni_tx_rdy, 500)) {
- /*
- * We may have a timeout here because the last status change
- * didn't trigger an interrupt. Reading the status register
- * will clear the current status and the next change triggers
- * an interrupt again, hopefully.
- */
- inr(EMAC_ISR);
- if ((txBufTab[txBufIdx].stat & TXS_USED) == 0) {
- /* No queue space. Release the lock and give up. */
- txBufTab[txBufIdx].stat |= TXS_USED;
- txBufIdx++;
- txBufIdx &= 1;
- NutEventPost(&ni->ni_mutex);
- break;
- }
- }
- } else {
- if (inr(EMAC_TSR) & EMAC_UND) {
- txBufIdx = 0;
- outr(EMAC_TSR, EMAC_UND);
- }
- if (inr(EMAC_TSR) & EMAC_COMP) {
- outr(EMAC_TSR, EMAC_COMP);
- }
- if ((rc = EmacPutPacket(txBufIdx, ni, nb)) == 0) {
- txBufIdx++;
- txBufIdx &= 1;
- }
- }
- NutEventPost(&ni->ni_mutex);
- }
- /*
- * Probably no Ethernet link. Significantly reduce the waiting
- * time, so following transmission will soon return an error.
- */
- if (rc) {
- mx_wait = 500;
- } else {
- /* Ethernet works. Set a long waiting time in case we
- temporarily lose the link next time. */
- mx_wait = 5000;
- }
- return rc;
- }
- /*!
- * \brief Initialize Ethernet hardware.
- *
- * Applications should do not directly call this function. It is
- * automatically executed during during device registration by
- * NutRegisterDevice().
- *
- * \param dev Identifies the device to initialize.
- */
- int EmacInit(NUTDEVICE * dev)
- {
- EMACINFO *ni = (EMACINFO *) dev->dev_dcb;
- EMPRINTF("EmacInit()\n");
- /* Reset the controller. */
- if (EmacReset(EMAC_LINK_LOOPS)) {
- if (EmacReset(EMAC_LINK_LOOPS)) {
- return -1;
- }
- }
- /* Clear EMACINFO structure. */
- memset(ni, 0, sizeof(EMACINFO));
- /* Register interrupt handler. */
- if (NutRegisterIrqHandler(&sig_EMAC, EmacInterrupt, dev)) {
- EMPRINTF(" IRQR CRASHED\n");
- return -1;
- }
- EMPRINTF(" IRQR OK\n");
- /* Start the receiver thread. */
- if (NutThreadCreate("emacrx", EmacRxThread, dev,
- (NUT_THREAD_NICRXSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD) == NULL) {
- EMPRINTF(" THREAD CRASHED\n");
- return -1;
- }
- EMPRINTF("EmacInit() DONE\n");
- return 0;
- }
- /*!
- * \brief Update the multicast hash.
- *
- * This function must be called after the multicast list changed.
- *
- * \param mclst Pointer to the first entry of the linked list of
- * multicast entries.
- */
- static void EmacHashUpdate(MCASTENTRY *mclst)
- {
- int i;
- int j;
- int b;
- int idx;
- uint32_t hash[2] = { 0, 0 };
- /* Determine the hash bit for each entry. */
- while (mclst) {
- /* For each bit of the index. */
- for (idx = 0, i = 0; i < 6; i++) {
- /* Xor every 6th bit in the address. */
- for (b = 0, j = i; j < 48; j += 6) {
- b ^= (mclst->mca_ha[j >> 3] & (1 << (j & 0x07))) != 0;
- }
- idx |= b << i;
- }
- /* Set the bit given by the 6 bit index. */
- hash[idx > 31] |= 1 << (idx & 31);
- mclst = mclst->mca_next;
- }
- /* Set result in the hash register. */
- outr(EMAC_HRB, hash[0]);
- outr(EMAC_HRT, hash[1]);
- /* Enable or disable multicast hash. */
- if (hash[0] || hash[1]) {
- outr(EMAC_NCFGR, inr(EMAC_NCFGR) | EMAC_MTI);
- } else {
- outr(EMAC_NCFGR, inr(EMAC_NCFGR) & ~EMAC_MTI);
- }
- }
- /*!
- * \brief Get multicast entry of a given IP address.
- *
- * \todo This function should be shared by all Ethernet drivers.
- *
- * \param ifn Pointer to the network interface structure.
- * \param ip IP address of the entry to retrieve.
- *
- * \return Pointer to the entry or NULL if none exists.
- */
- static MCASTENTRY *McastIpEntry(IFNET *ifn, uint32_t ip)
- {
- MCASTENTRY *mca = ifn->if_mcast;
- while (mca) {
- if (ip == mca->mca_ip) {
- break;
- }
- mca = mca->mca_next;
- }
- return mca;
- }
- /*!
- * \brief Add a given IP address to the multicast list.
- *
- * \todo This function should be shared by all Ethernet drivers.
- *
- * \param ifn Pointer to the network interface structure.
- * \param ip IP address of the new entry.
- *
- * \return Pointer to the requested entry, either a new one or
- * an already existing entry. In case of a failure, NULL
- * is returned.
- */
- static MCASTENTRY *McastAddEntry(IFNET *ifn, uint32_t ip)
- {
- MCASTENTRY *mca;
- mca = McastIpEntry(ifn, ip);
- if (mca == NULL) {
- mca = malloc(sizeof(MCASTENTRY));
- if (mca) {
- mca->mca_ip = ip;
- /* Set the IANA OUI. */
- mca->mca_ha[0] = 0x01;
- mca->mca_ha[1] = 0x00;
- mca->mca_ha[2] = 0x5e;
- /* Map the lower 23 bits of the IP address to the MAC address.
- Note that Nut/Net IP addresses are in network byte order. */
- mca->mca_ha[3] = (ip >> 8) & 0x7f;
- mca->mca_ha[4] = (ip >> 16) & 0xff;
- mca->mca_ha[5] = (ip >> 24) & 0xff;
- /* Add the new entry to the front of the list. */
- mca->mca_next = ifn->if_mcast;
- ifn->if_mcast = mca;
- /* Update the EMAC's multicast hash. */
- EmacHashUpdate(mca);
- }
- }
- return mca;
- }
- /*!
- * \brief Remove multicast entry of a given IP address.
- *
- * \param ifn Pointer to the network interface structure.
- * \param ip IP address of the entry to remove.
- */
- static void McastDelEntry(IFNET *ifn, uint32_t ip)
- {
- MCASTENTRY *mca = ifn->if_mcast;
- MCASTENTRY **lnk = &ifn->if_mcast;
- while (mca) {
- if (mca->mca_ip == ip) {
- *lnk = mca->mca_next;
- free(mca);
- break;
- }
- lnk = &mca->mca_next;
- mca = *lnk;
- }
- /* Update the EMAC's multicast hash. */
- EmacHashUpdate(mca);
- }
- /*!
- * \brief Perform Ethernet control functions.
- *
- * \param dev Identifies the device that receives the device-control
- * function.
- * \param req Requested control function. May be set to one of the
- * following constants:
- * - SIOCSIFADDR sets interface MAC address passed in buffer.
- * - SIOCGIFADDR copies current interface MAC address to buffer.
- * - SIOCADDMULTI adds multicast entry for IP in buffer.
- * - SIOCDELMULTI removes multicast entry of IP in buffer.
- * \param conf Points to a buffer that contains any data required for
- * the given control function or receives data from that
- * function.
- * \return 0 on success, -1 otherwise.
- *
- * \warning Timeout values are given in milliseconds and are limited to
- * the granularity of the system timer.
- *
- * \note For ATmega103, only 8 data bits, 1 stop bit and no parity are allowed.
- *
- */
- static int EmacIoCtl(NUTDEVICE * dev, int req, void *conf)
- {
- int rc = 0;
- IFNET *ifn = (IFNET *) dev->dev_icb;
- uint32_t ip;
- switch (req) {
- case SIOCSIFADDR:
- /* Set interface hardware address. */
- memcpy(ifn->if_mac, conf, sizeof(ifn->if_mac));
- break;
- case SIOCGIFADDR:
- /* Get interface hardware address. */
- memcpy(conf, ifn->if_mac, sizeof(ifn->if_mac));
- break;
- case SIOCADDMULTI:
- /* Add multicast address. */
- memcpy(&ip, conf, sizeof(ip));
- if (McastAddEntry(ifn, ip) == NULL) {
- rc = -1;
- }
- break;
- case SIOCDELMULTI:
- /* Delete multicast address. */
- memcpy(&ip, conf, sizeof(ip));
- McastDelEntry(ifn, ip);
- break;
- default:
- rc = -1;
- break;
- }
- return rc;
- }
- static EMACINFO dcb_eth0;
- /*!
- * \brief Network interface information structure.
- *
- * Used to call.
- */
- static IFNET ifn_eth0 = {
- IFT_ETHER, /*!< \brief Interface type, if_type. */
- 0, /*!< \brief Interface flags, if_flags. */
- {0, 0, 0, 0, 0, 0}, /*!< \brief Hardware net address, if_mac. */
- 0, /*!< \brief IP address, if_local_ip. */
- 0, /*!< \brief Remote IP address for point to point, if_remote_ip. */
- 0, /*!< \brief IP network mask, if_mask. */
- ETHERMTU, /*!< \brief Maximum size of a transmission unit, if_mtu. */
- 0, /*!< \brief Packet identifier, if_pkt_id. */
- 0, /*!< \brief Linked list of arp entries, arpTable. */
- 0, /*!< \brief Linked list of multicast address entries, if_mcast. */
- NutEtherInput, /*!< \brief Routine to pass received data to, if_recv(). */
- EmacOutput, /*!< \brief Driver output routine, if_send(). */
- NutEtherOutput, /*!< \brief Media output routine, if_output(). */
- NULL /*!< \brief Interface specific control function, if_ioctl(). */
- #ifdef NUT_PERFMON
- , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- #endif
- };
- /*!
- * \brief Device information structure.
- *
- * A pointer to this structure must be passed to NutRegisterDevice()
- * to bind this Ethernet device driver to the Nut/OS kernel.
- * An application may then call NutNetIfConfig() with the name \em eth0
- * of this driver to initialize the network interface.
- *
- */
- NUTDEVICE devAt91Emac = {
- 0, /*!< \brief Pointer to next device. */
- {'e', 't', 'h', '0', 0, 0, 0, 0, 0}, /*!< \brief Unique device name. */
- IFTYP_NET, /*!< \brief Type of device. */
- 0, /*!< \brief Base address. */
- 0, /*!< \brief First interrupt number. */
- &ifn_eth0, /*!< \brief Interface control block. */
- &dcb_eth0, /*!< \brief Driver control block. */
- EmacInit, /*!< \brief Driver initialization routine. */
- EmacIoCtl, /*!< \brief Driver specific control function. */
- 0, /*!< \brief Read from device. */
- 0, /*!< \brief Write to device. */
- #ifdef __HARVARD_ARCH__
- 0, /*!< \brief Write from program space data to device. */
- #endif
- 0, /*!< \brief Open a device or file. */
- 0, /*!< \brief Close a device or file. */
- 0, /*!< \brief Request file size. */
- 0, /*!< \brief Select function, optional, not yet implemented */
- };
- /*@}*/
|