| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982 |
- /*
- * Copyright (C) 2001-2004 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 EGNITE SOFTWARE GMBH 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 EGNITE
- * SOFTWARE GMBH 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/
- *
- */
- /*
- * $Log$
- * Revision 1.1 2005/07/26 18:02:40 haraldkipp
- * Moved from dev.
- *
- * Revision 1.4 2005/04/30 16:42:41 chaac
- * Fixed bug in handling of NUTDEBUG. Added include for cfg/os.h. If NUTDEBUG
- * is defined in NutConf, it will make effect where it is used.
- *
- * Revision 1.3 2005/01/24 21:11:52 freckle
- * renamed NutEventPostFromIRQ into NutEventPostFromIrq
- *
- * Revision 1.2 2005/01/21 16:49:46 freckle
- * Seperated calls to NutEventPostAsync between Threads and IRQs
- *
- * Revision 1.1 2004/03/16 16:48:27 haraldkipp
- * Added Jan Dubiec's H8/300 port.
- *
- */
- #include <cfg/os.h>
- #include <string.h>
- #include <sys/nutconfig.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/nicrtl.h>
- #include "rtlregs.h"
- #ifdef NUTDEBUG
- #include <sys/osdebug.h>
- #include <net/netdebug.h>
- #endif
- /*!
- * \brief Read word from controller DMA port.
- */
- #define nic_read_dma() *((volatile u_short*) (base + NIC_IOPORT))
- /*!
- * \brief Write word to controller DMA port.
- */
- #define nic_write_dma(data) *((u_short*) (base + NIC_IOPORT)) = data
- /*!
- * \brief Size of a single ring buffer page.
- */
- #define NIC_PAGE_SIZE 0x100
- /*!
- * \brief First ring buffer page address.
- */
- #define NIC_START_PAGE 0x40
- /*!
- * \brief Last ring buffer page address plus 1.
- */
- #define NIC_STOP_PAGE 0x60
- /*!
- * \brief Number of pages in a single transmit buffer.
- *
- * This should be at least the MTU size.
- */
- #define NIC_TX_PAGES 6
- /*!
- * \brief Number of transmit buffers.
- */
- #define NIC_TX_BUFFERS 2
- /*!
- * \brief Controller memory layout:
- *
- * 0x4000 - 0x4bff 3k bytes transmit buffer
- * 0x4c00 - 0x5fff 5k bytes receive buffer
- */
- #define NIC_FIRST_TX_PAGE NIC_START_PAGE
- #define NIC_FIRST_RX_PAGE (NIC_FIRST_TX_PAGE + NIC_TX_PAGES * NIC_TX_BUFFERS)
- /*!
- * \brief Standard sizing information
- */
- #define TX_PAGES 12 /* Allow for 2 back-to-back frames */
- /*!
- * \addtogroup xgNicRtl
- */
- /*@{*/
- /*!
- * Realtek packet header.
- */
- struct nic_pkt_header {
- u_char ph_status; /*!< \brief Status, contents of RSR register */
- u_char ph_nextpg; /*!< \brief Page for next packet */
- u_short ph_size; /*!< \brief Size of header and packet in octets */
- };
- /*!
- * \brief Reset the Ethernet controller.
- *
- */
- static int NicReset(volatile u_char * base)
- {
- u_char i;
- u_char j;
- /*
- * Do the software reset by reading from the reset register followed
- * by writing to the reset register. Wait until the controller enters
- * the reset state.
- */
- for (j = 0; j < 20; j++) {
- i = nic_read(NIC_RESET);
- NutDelay(WAIT5);
- nic_write(NIC_RESET, i);
- for (i = 0; i < 20; i++) {
- NutDelay(WAIT50);
- /*
- * We got the reset bit. However, Ethernut 1.1 may
- * still fail because the NIC hasn't got it's hardware
- * reset and the data lines remain in tristate. So we
- * read noise instead of the register. To solve this
- * problem, we will verify the NIC's id.
- */
- if ((nic_read(NIC_PG0_ISR) & NIC_ISR_RST) != 0 && nic_read(NIC_PG0_RBCR0) == 0x50 && nic_read(NIC_PG0_RBCR1) == 0x70)
- return 0;
- }
- }
- return -1;
- }
- /*
- * Fires up the network interface. NIC interrupts
- * should have been disabled when calling this
- * function.
- */
- static int NicStart(volatile u_char * base, CONST u_char * mac)
- {
- u_char i;
- if (NicReset(base))
- return -1;
- /*
- * Mask all interrupts and clear any interrupt status flag to set the
- * INT pin back to low.
- */
- nic_write(NIC_PG0_IMR, 0);
- nic_write(NIC_PG0_ISR, 0xff);
- /*
- * During reset the nic loaded its initial configuration from an
- * external eeprom. On the ethernut board we do not have any
- * configuration eeprom, but simply tied the eeprom data line to
- * high level. So we have to clear some bits in the configuration
- * register. Switch to register page 3.
- */
- nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1);
- /*
- * The nic configuration registers are write protected unless both
- * EEM bits are set to 1.
- */
- nic_write(NIC_PG3_EECR, NIC_EECR_EEM0 | NIC_EECR_EEM1);
- /*
- * Disable sleep and power down.
- */
- nic_write(NIC_PG3_CONFIG3, 0);
- /*
- * Network media had been set to 10Base2 by the virtual EEPROM and
- * will be set now to auto detect. This will initiate a link test.
- * We don't force 10BaseT, because this would disable the link test.
- */
- nic_write(NIC_PG3_CONFIG2, NIC_CONFIG2_BSELB);
- /*
- * Reenable write protection of the nic configuration registers
- * and wait for link test to complete.
- */
- nic_write(NIC_PG3_EECR, 0);
- NutDelay(255);
- /*
- * Switch to register page 0 and set data configuration register
- * to byte-wide DMA transfers, normal operation (no loopback),
- * send command not executed and 8 byte fifo threshold.
- */
- nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2);
- /* nic_write(NIC_PG0_DCR, NIC_DCR_LS | NIC_DCR_FT1); */
- nic_write(NIC_PG0_DCR, NIC_DCR_WTS | NIC_DCR_LS | NIC_DCR_FT1);
- /*
- * Clear remote dma byte count register.
- */
- nic_write(NIC_PG0_RBCR0, 0);
- nic_write(NIC_PG0_RBCR1, 0);
- /*
- * Temporarily set receiver to monitor mode and transmitter to
- * internal loopback mode. Incoming packets will not be stored
- * in the nic ring buffer and no data will be send to the network.
- */
- nic_write(NIC_PG0_RCR, NIC_RCR_MON);
- nic_write(NIC_PG0_TCR, NIC_TCR_LB0);
- /*
- * Configure the nic's ring buffer page layout.
- * NIC_PG0_BNRY: Last page read.
- * NIC_PG0_PSTART: First page of receiver buffer.
- * NIC_PG0_PSTOP: Last page of receiver buffer.
- */
- nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE);
- nic_write(NIC_PG0_BNRY, NIC_STOP_PAGE - 1);
- nic_write(NIC_PG0_PSTART, NIC_FIRST_RX_PAGE);
- nic_write(NIC_PG0_PSTOP, NIC_STOP_PAGE);
- /*
- * Once again clear interrupt status register.
- */
- nic_write(NIC_PG0_ISR, 0xff);
- /*
- * Switch to register page 1 and copy our MAC address into the nic.
- * We are still in stop mode.
- */
- nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0);
- for (i = 0; i < 6; i++)
- nic_write(NIC_PG1_PAR0 + i, mac[i]);
- /*
- * Clear multicast filter bits to disable all packets.
- */
- for (i = 0; i < 8; i++)
- nic_write(NIC_PG1_MAR0 + i, 0);
- /*
- * Set current page pointer to one page after the boundary pointer.
- */
- nic_write(NIC_PG1_CURR, NIC_START_PAGE + TX_PAGES);
- /*
- * Switch back to register page 0, remaining in stop mode.
- */
- nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2);
- /*
- * Take receiver out of monitor mode and enable it for accepting
- * broadcasts.
- */
- nic_write(NIC_PG0_RCR, NIC_RCR_AB);
- /*
- * Clear all interrupt status flags and enable interrupts.
- */
- nic_write(NIC_PG0_ISR, 0xff);
- nic_write(NIC_PG0_IMR, NIC_IMR_PRXE | NIC_IMR_PTXE | NIC_IMR_RXEE | NIC_IMR_TXEE | NIC_IMR_OVWE);
- /*
- * Fire up the nic by clearing the stop bit and setting the start bit.
- * To activate the local receive dma we must also take the nic out of
- * the local loopback mode.
- */
- nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
- nic_write(NIC_PG0_TCR, 0);
- NutDelay(255);
- return 0;
- }
- /*!
- * Complete remote DMA.
- */
- static void NicCompleteDma(volatile u_char * base)
- {
- u_char i;
- /*
- * Complete remote dma.
- */
- nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
- /*
- * Check that we have a DMA complete flag.
- */
- for (i = 0; i <= 20; i++)
- if (nic_read(NIC_PG0_ISR) & NIC_ISR_RDC)
- break;
- /*
- * Reset remote dma complete flag.
- */
- nic_write(NIC_PG0_ISR, NIC_ISR_RDC);
- }
- /*!
- * \brief Load a packet into the nic's transmit ring buffer.
- *
- * Interupts must have been disabled when calling this function.
- *
- * \param base NIC hardware base address.
- * \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 NicPutPacket(volatile u_char * base, NETBUF * nb)
- {
- u_short sz;
- u_short i;
- u_short *p;
- u_char padding = 0;
- /*
- * Calculate the number of bytes to be send. Do not
- * send packets larger than 1518 bytes.
- */
- sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
- if (sz > 1518)
- return -1;
- /*
- * The controller will not append pad bytes,
- * so we have to do this.
- */
- if (sz < 60) {
- padding = (u_char) (60 - sz);
- sz = 60;
- }
- /*
- * Set remote dma byte count
- * and start address.
- */
- nic_write(NIC_PG0_RBCR0, sz);
- nic_write(NIC_PG0_RBCR1, sz >> 8);
- nic_write(NIC_PG0_RSAR0, 0);
- nic_write(NIC_PG0_RSAR1, NIC_FIRST_TX_PAGE);
- /*
- * Peform the write.
- */
- nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD1);
- /*
- * Switch MCU data bus to 16-bit mode
- */
- NicMcu16bitBus();
- /*
- * Transfer the Ethernet frame.
- */
- p = nb->nb_dl.vp;
- for (i = nb->nb_dl.sz >> 1; i; i--)
- nic_write_dma(*p++);
- p = nb->nb_nw.vp;
- for (i = nb->nb_nw.sz >> 1; i; i--)
- nic_write_dma(*p++);
- p = nb->nb_tp.vp;
- for (i = nb->nb_tp.sz >> 1; i; i--)
- nic_write_dma(*p++);
- p = nb->nb_ap.vp;
- for (i = (nb->nb_ap.sz + 1) >> 1; i; i--)
- nic_write_dma(*p++);
- /*
- * Add pad bytes.
- */
- if ((nb->nb_ap.sz & 0x0001) != 0)
- padding--;
- for (i = 0; i < (padding + 1) >> 1; i++)
- nic_write_dma(0);
- /*
- * Switch MCU data bus to 8-bit mode
- */
- NicMcu8bitBus();
- /*
- * Complete remote dma.
- */
- NicCompleteDma(base);
- /*
- * Number of bytes to be transmitted.
- */
- nic_write(NIC_PG0_TBCR0, (sz & 0xff));
- nic_write(NIC_PG0_TBCR1, ((sz >> 8) & 0xff));
- /*
- * First page of packet to be transmitted.
- */
- nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE);
- /*
- * Start transmission.
- */
- nic_write(NIC_CR, NIC_CR_STA | NIC_CR_TXP | NIC_CR_RD2);
- return 0;
- }
- /*!
- * \brief Fetch the next packet out of the receive ring buffer.
- *
- * Nic interrupts must be disabled when calling this funtion.
- *
- * \return Pointer to an allocated ::NETBUF. If there is no
- * no data available, then the function returns a
- * null pointer. If the NIC's buffer seems to be
- * corrupted, a pointer to 0xFFFF is returned.
- */
- static NETBUF *NicGetPacket(volatile u_char * base, u_char dflg)
- {
- NETBUF *nb = 0;
- struct nic_pkt_header hdr;
- u_short count;
- u_char nextpg;
- u_char bnry;
- u_char curr;
- u_short i;
- u_short *buf;
- /*
- * Get the current page pointer. It points to the page where the NIC
- * will start saving the next incoming packet.
- */
- nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2 | NIC_CR_PS0);
- curr = nic_read(NIC_PG1_CURR);
- nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
- /*
- * Get the pointer to the last page we read from. The following page
- * is the one where we start reading. If it's equal to the current
- * page pointer, then there's nothing to read. In this case we return
- * a null pointer.
- */
- if ((bnry = nic_read(NIC_PG0_BNRY) + 1) >= NIC_STOP_PAGE)
- bnry = NIC_FIRST_RX_PAGE;
- if (bnry == curr)
- return 0;
- /*
- * Read the NIC specific packet header.
- */
- nic_write(NIC_PG0_RBCR0, sizeof(struct nic_pkt_header));
- nic_write(NIC_PG0_RBCR1, 0);
- nic_write(NIC_PG0_RSAR0, 0);
- nic_write(NIC_PG0_RSAR1, bnry);
- nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD0);
- buf = (u_short *) & hdr;
- NicMcu16bitBus(); /* Switch MCU data bus to 16-bit mode */
- *buf++ = nic_read_dma(); /* Read status byte and next page pointer */
- *buf = nic_read_dma(); /* Read frame length */
- NicMcu8bitBus(); /* Switch MCU data bus to 8-bit mode */
- NicCompleteDma(base);
- #ifdef __BIG_ENDIAN__
- hdr.ph_size = __byte_swap2(hdr.ph_size);
- #endif
- /*
- * Check packet length.
- */
- if (hdr.ph_size < 60 + sizeof(struct nic_pkt_header) || hdr.ph_size > 1518 + sizeof(struct nic_pkt_header)) {
- return dflg ? 0 : (NETBUF *) - 1;
- }
- /*
- * Calculate the page of the next packet. If it differs from the
- * pointer in the packet header, we discard the whole buffer
- * and return a null pointer.
- */
- nextpg = bnry + (hdr.ph_size >> 8) + ((hdr.ph_size & 0xFF) != 0);
- if (nextpg >= NIC_STOP_PAGE) {
- nextpg -= NIC_STOP_PAGE;
- nextpg += NIC_FIRST_RX_PAGE;
- }
- if (nextpg != hdr.ph_nextpg) {
- u_char nextpg1 = nextpg + 1;
- if (nextpg1 >= NIC_STOP_PAGE) {
- nextpg1 -= NIC_STOP_PAGE;
- nextpg1 += NIC_FIRST_RX_PAGE;
- }
- if (nextpg1 != hdr.ph_nextpg) {
- return dflg ? 0 : (NETBUF *) - 1;
- }
- nextpg = nextpg1;
- }
- /*
- * Check packet status. It should have set bit 0, but
- * even without this bit packets seem to be OK.
- */
- if ((hdr.ph_status & 0x0E) == 0) {
- /*
- * Allocate a NETBUF.
- */
- count = hdr.ph_size - sizeof(struct nic_pkt_header);
- if (dflg == 0) {
- nb = NutNetBufAlloc(0, NBAF_DATALINK, count);
- }
- /*
- * Set remote dma byte count and
- * start address. Don't read the
- * header again.
- */
- nic_write(NIC_PG0_RBCR0, count);
- nic_write(NIC_PG0_RBCR1, count >> 8);
- nic_write(NIC_PG0_RSAR0, sizeof(struct nic_pkt_header));
- nic_write(NIC_PG0_RSAR1, bnry);
- /*
- * Perform the read.
- */
- nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD0);
- /*
- * Switch MCU data bus to 16-bit mode
- */
- NicMcu16bitBus();
- count = (count + 1) >> 1;
- if (nb) {
- buf = nb->nb_dl.vp;
- for (i = 0; i < count; i++)
- *buf++ = nic_read_dma();
- } else {
- for (i = 0; i < count; i++)
- nic_read_dma();
- }
- /*
- * Switch MCU data bus to 8-bit mode
- */
- NicMcu8bitBus();
- /*
- * Complete remote dma.
- */
- NicCompleteDma(base);
- }
- /*
- * Set boundary register to the last page we read.
- */
- if (--nextpg < NIC_FIRST_RX_PAGE)
- nextpg = NIC_STOP_PAGE - 1;
- nic_write(NIC_PG0_BNRY, nextpg);
- return dflg ? (NETBUF *) ((uptr_t) dflg) : nb;
- }
- /*
- * When a receiver buffer overflow occurs, the NIC will defer any
- * subsequent action until properly restarted.
- */
- static int NicOverflow(volatile u_char * base)
- {
- u_char cr;
- u_char resend;
- /*
- * Save the command register, so we can later determine, if NIC
- * transmitter has been interrupted. Then stop the NIC and wait
- * 5 ms for any transmission or reception in progress.
- */
- cr = nic_read(NIC_CR);
- nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2);
- NutDelay(WAIT5);
- /*
- * Clear remote byte count register.
- */
- nic_write(NIC_PG0_RBCR0, 0);
- nic_write(NIC_PG0_RBCR1, 0);
- /*
- * Check for any incomplete transmission.
- */
- resend = 0;
- if (cr & NIC_CR_TXP) {
- if ((nic_read(NIC_PG0_ISR) & (NIC_ISR_PTX | NIC_ISR_TXE)) == 0)
- resend = 1;
- }
- /*
- * Enter loopback mode and restart the NIC.
- */
- nic_write(NIC_PG0_TCR, NIC_TCR_LB0);
- nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2);
- /*
- * Discard all packets from the receiver buffer.
- */
- while (NicGetPacket(base, 1));
- /*
- * Switch from loopback to normal mode mode.
- */
- nic_write(NIC_PG0_TCR, 0);
- /*
- * Re-invoke any interrupted transmission.
- */
- if (resend) {
- nic_write(NIC_CR, NIC_CR_STA | NIC_CR_TXP | NIC_CR_RD2);
- }
- /* Finally clear the overflow flag. */
- nic_write(NIC_PG0_ISR, NIC_ISR_OVW);
- return resend;
- }
- /*
- * NIC interrupt entry.
- */
- static void NicInterrupt(void *arg)
- {
- u_char isr;
- volatile u_char *base = (u_char *) (((NUTDEVICE *) arg)->dev_base);
- NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
- ni->ni_interrupts++;
- isr = nic_read(NIC_PG0_ISR);
- nic_write(NIC_PG0_ISR, isr);
- /*
- * Recover from receive buffer overflow. This may take some
- * time, so we enable global interrupts but keep NIC
- * interrupts disabled.
- */
- if (isr & NIC_ISR_OVW) {
- NicDisableInt();
- NutEnableInt();
- ni->ni_rx_pending++;
- if (NicOverflow(base))
- ni->ni_tx_bsy++;
- else {
- NutEventPostFromIrq(&ni->ni_tx_rdy);
- }
- ni->ni_overruns++;
- NutDisableInt();
- NicEnableInt();
- } else {
- /*
- * If this is a transmit interrupt, then a packet has been sent.
- * So we can clear the transmitter busy flag and wake up the
- * transmitter thread.
- */
- if (isr & (NIC_ISR_PTX | NIC_ISR_TXE)) {
- ni->ni_tx_bsy = 0;
- NutEventPostFromIrq(&ni->ni_tx_rdy);
- }
- /*
- * If this is a receive interrupt, then wake up the receiver
- * thread.
- */
- if (isr & NIC_ISR_PRX) {
- ni->ni_rx_pending++;
- NutEventPostFromIrq(&ni->ni_rx_rdy);
- }
- if (isr & NIC_ISR_RXE) {
- ni->ni_rx_frame_errors += nic_read(NIC_PG0_CNTR0);
- ni->ni_rx_crc_errors += nic_read(NIC_PG0_CNTR1);
- ni->ni_rx_missed_errors += nic_read(NIC_PG0_CNTR2);
- }
- }
- }
- /*! \fn NicRx(void *arg)
- * \brief NIC receiver thread.
- *
- *
- * It runs with high priority.
- */
- THREAD(NicRx, arg)
- {
- NUTDEVICE *dev;
- IFNET *ifn;
- NICINFO *ni;
- NETBUF *nb;
- u_char rlcnt;
- dev = arg;
- ifn = (IFNET *) dev->dev_icb;
- ni = (NICINFO *) dev->dev_dcb;
- NutThreadSetPriority(9);
- /*
- * This is a temporary hack. Due to a change in initialization,
- * we may not have got a MAC address yet. Wait until one has been
- * set.
- */
- if ((ifn->if_mac[0] & ifn->if_mac[1] & ifn->if_mac[2]) == 0xFF) {
- while ((ifn->if_mac[0] & ifn->if_mac[1] & ifn->if_mac[2]) == 0xFF)
- NutSleep(125);
- NicDisableInt();
- NicStart((u_char *) (dev->dev_base), ifn->if_mac);
- ni->ni_curr_page = NIC_START_PAGE + TX_PAGES;
- NicEnableInt();
- }
- for (;;) {
- /*
- * Wait for the arrival of new packets or check
- * the receiver every two second.
- */
- if (ni->ni_rx_pending > 10) {
- NicDisableInt();
- if (NicStart((u_char *) (dev->dev_base), ifn->if_mac) == 0)
- ni->ni_rx_pending = 0;
- ni->ni_curr_page = NIC_START_PAGE + TX_PAGES;
- NicEnableInt();
- }
- NutEventWait(&ni->ni_rx_rdy, 2000);
- /*
- * Fetch all packets from the NIC's internal
- * buffer and pass them to the registered handler.
- */
- rlcnt = 0;
- NicDisableInt();
- while (rlcnt++ < 10) {
- if ((nb = NicGetPacket((u_char *) (dev->dev_base), 0)) == 0)
- break;
- /* The sanity check may fail because the controller is too busy.
- try another read before giving up and restarting the NIC. */
- if (nb == (void *) -1) {
- if ((nb = NicGetPacket((u_char *) (dev->dev_base), 0)) == 0)
- break;
- }
- if (nb == (void *) -1) {
- if (NicStart((u_char *) (dev->dev_base), ifn->if_mac) == 0)
- ni->ni_rx_pending = 0;
- ni->ni_curr_page = NIC_START_PAGE + TX_PAGES;
- ni->ni_rx_pending = 0;
- } else {
- ni->ni_rx_pending = 0;
- ni->ni_rx_packets++;
- NicEnableInt();
- (*ifn->if_recv) (dev, nb);
- NicDisableInt();
- }
- }
- NicEnableInt();
- }
- }
- /*!
- * \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 NicOutput(NUTDEVICE * dev, NETBUF * nb)
- {
- int rc = -1;
- NICINFO *ni;
- u_char retries = 10;
- u_char sigmod = 0;
- ni = (NICINFO *) dev->dev_dcb;
- while (ni->ni_tx_bsy && retries--) {
- if (NutEventWait(&ni->ni_tx_rdy, 200)) {
- volatile u_char *base = (u_char *) (dev->dev_base);
- /*
- * If hanging around here too long, there's something wrong
- * with the transmit interrupt. Force sending the packet,
- * if the transmitter has become inactive.
- */
- if (NicIntIsEnabled()) {
- NicDisableInt();
- sigmod = 1;
- }
- if ((nic_read(NIC_CR) & NIC_CR_TXP) == 0)
- ni->ni_tx_bsy = 0;
- if (sigmod) {
- NicEnableInt();
- sigmod = 0;
- }
- }
- }
- if (NicIntIsEnabled()) {
- NicDisableInt();
- sigmod = 1;
- }
- if (ni->ni_tx_bsy == 0) {
- ni->ni_tx_bsy++;
- if (NicPutPacket((u_char *) (dev->dev_base), nb) == 0) {
- ni->ni_tx_packets++;
- rc = 0;
- }
- }
- if (sigmod)
- NicEnableInt();
- return rc;
- }
- /*!
- * \brief Initialize Ethernet hardware.
- *
- * Resets RTL8019AS Ethernet controller, initializes all required
- * hardware registers and starts a background thread for incoming
- * Ethernet traffic.
- *
- * Applications should do not directly call this function. It is
- * automatically executed during during device registration by
- * NutRegisterDevice().
- *
- * If the network configuration hasn't been set by the application
- * before registering the specified device, this function will
- * call NutNetLoadConfig() to get the MAC address.
- *
- * \param dev Identifies the device to initialize.
- */
- int NicInit(NUTDEVICE * dev)
- {
- volatile u_char *base;
- IFNET *ifn;
- NICINFO *ni;
- /*
- * We need to know our MAC address. If no configuration is
- * available, load it now.
- */
- if (confnet.cd_size == 0)
- NutNetLoadConfig(dev->dev_name);
- ifn = dev->dev_icb;
- memcpy(ifn->if_mac, confnet.cdn_mac, 6);
- ni = (NICINFO *) dev->dev_dcb;
- memset(ni, 0, sizeof(NICINFO));
- base = (u_char *) (dev->dev_base);
- NicDisableInt();
- NutInitSysIrq();
- if (ifn->if_mac[0] | ifn->if_mac[1] | ifn->if_mac[2])
- if (NicStart(base, ifn->if_mac))
- return -1;
- ni->ni_curr_page = NIC_START_PAGE + TX_PAGES;
- /*
- * Start the receiver thread.
- */
- NutThreadCreate("rxi0", NicRx, dev, 640);
- NutSleep(WAIT500);
- /*
- * Register interrupt handler and enable interrupts.
- */
- if (NutRegisterIrqHandler(&RTL_SIGNAL, NicInterrupt, dev))
- return -1;
- NicEnableInt();
- return 0;
- }
- /*!
- * \brief Network interface device control block structure.
- *
- * Used to call.
- */
- static NICINFO dcb_eth0rtl;
- /*!
- * \brief Network interface information structure.
- *
- * Used to call.
- */
- static IFNET ifn_eth0rtl = {
- IFT_ETHER, /*!< \brief Interface type. */
- {0, 0, 0, 0, 0, 0}, /*!< \brief Hardware net address. */
- 0, /*!< \brief IP address. */
- 0, /*!< \brief Remote IP address for point to point. */
- 0, /*!< \brief IP network mask. */
- ETHERMTU, /*!< \brief Maximum size of a transmission unit. */
- 0, /*!< \brief Packet identifier. */
- 0, /*!< \brief Linked list of arp entries. */
- NutEtherInput, /*!< \brief Routine to pass received data to, if_recv(). */
- NicOutput, /*!< \brief Driver output routine, if_send(). */
- NutEtherOutput /*!< \brief Media output routine, if_output(). */
- };
- /*!
- * \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 devEth0 = {
- 0, /* Pointer to next device. */
- {'e', 't', 'h', '0', 0, 0, 0, 0, 0}, /* Unique device name. */
- IFTYP_NET, /* Type of device. */
- 0, /* Base address. */
- 0, /* First interrupt number. */
- &ifn_eth0rtl, /* Interface control block. */
- &dcb_eth0rtl, /* Driver control block. */
- NicInit, /* Driver initialization routine. */
- 0, /* Driver specific control function. */
- 0, /* Read from device. */
- 0, /* Write to device. */
- /* Write from program space data to device. */
- 0, /* Open a device or file. */
- 0, /* Close a device or file. */
- 0, /* Request file size. */
- 0, /* Select function, optional, not yet implemented */
- };
- /*@}*/
|