| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600 |
- /*
- * Copyright (C) 2001-2007 by egnite Software GmbH
- * Copyright (C) 2010 by egnite 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: ether.c 4115 2012-04-12 21:06:13Z olereinhardt $
- */
- #include "dialog.h"
- #include "arp.h"
- #include "ether.h"
- #include "bootmon.h"
- #define PIO_BASE 0xFFFF0000 /*!< \brief PIO base address. */
- #define PIO_OER (PIO_BASE + 0x10) /*!< \brief Output enable register. */
- #define PIO_ODR (PIO_BASE + 0x14) /*!< \brief Output disable register. */
- #define PIO_SODR (PIO_BASE + 0x30) /*!< \brief Set output data register. */
- #define PIO_CODR (PIO_BASE + 0x34) /*!< \brief Clear output data register. */
- #ifndef NIC_BASE_ADDR
- #define NIC_BASE_ADDR 0x20000000
- #endif
- #ifndef NIC_DATA_ADDR
- #define NIC_DATA_ADDR (NIC_BASE_ADDR + 4)
- #endif
- #define NIC_NCR 0x00 /* Network control register (0x00). */
- #define NIC_NCR_LBM 0x06 /* Loopback mode. */
- #define NIC_NCR_LBNORM 0x00 /* Normal mode. */
- #define NIC_NCR_LBMAC 0x02 /* MAC loopback. */
- #define NIC_NCR_LBPHY 0x04 /* PHY loopback. */
- #define NIC_NCR_RST 0x01 /* Software reset, auto clear. */
- #define NIC_NSR 0x01 /* Network status register (0x00). */
- #define NIC_NSR_SPEED 0x80
- #define NIC_NSR_LINKST 0x40
- #define NIC_NSR_WAKEST 0x20
- #define NIC_NSR_TX2END 0x08
- #define NIC_NSR_TX1END 0x04
- #define NIC_NSR_RXOV 0x02
- #define NIC_TCR 0x02 /* TX control register (0x00). */
- #define NIC_TCR_TXREQ 0x01 /* TX request */
- #define NIC_TSR1 0x03 /* TX status register I (0x00). */
- #define NIC_TSR2 0x04 /* TX status register II (0x00). */
- #define NIC_RCR 0x05 /* RX control register (0x00). */
- #define NIC_RCR_DIS_LONG 0x20 /* Discard long packets. */
- #define NIC_RCR_DIS_CRC 0x10 /* Discard CRC error packets. */
- #define NIC_RCR_PRMSC 0x02 /* Enable promiscuous mode. */
- #define NIC_RCR_RXEN 0x01 /* Enable receiver. */
- #define NIC_RSR 0x06 /* RX status register (0x00). */
- #define NIC_RSR_ERRORS 0xBF /* Error bit mask. */
- #define NIC_RSR_RF 0x80 /* Runt frame. */
- #define NIC_RSR_MF 0x40 /* Multicast frame. */
- #define NIC_RSR_LCS 0x20 /* Late collision. */
- #define NIC_RSR_RWTO 0x10 /* Receiver watchdog time out. */
- #define NIC_RSR_PLE 0x08 /* Physical layer error. */
- #define NIC_RSR_AE 0x04 /* Alignment error. */
- #define NIC_RSR_CE 0x02 /* CRC error. */
- #define NIC_RSR_FOE 0x01 /* FIFO overflow error. */
- #define NIC_ROCR 0x07 /* Receive overflow counter register (0x00). */
- #define NIC_BPTR 0x08 /* Back pressure threshold register (0x37). */
- #define NIC_FCTR 0x09 /* Flow control threshold register (0x38). */
- #define NIC_FCR 0x0A /* RX flow control register (0x00). */
- #define NIC_EPCR 0x0B /* EEPROM and PHY control register. */
- #define NIC_EPAR 0x0C /* EEPROM and PHY address register. */
- #define NIC_EPDRL 0x0D /* EEPROM and PHY low byte data register. */
- #define NIC_EPDRH 0x0E /* EEPROM and PHY high byte data register. */
- #define NIC_WCR 0x0F /* Wake up control register (0x00). */
- #define NIC_PAR 0x10 /* 6 byte physical address register. */
- #define NIC_MAR 0x16 /* 8 byte multicast address register. */
- #define NIC_GPCR 0x1E /* General purpose control register (?). */
- #define NIC_GPR 0x1F /* General purpose register (?). */
- #define NIC_TRPA 0x22 /* 2 byte TX SRAM read pointer address, low/high (0x0000). */
- #define NIC_RWPA 0x24 /* 2 byte RX SRAM write pointer address, low/high (0x0000). */
- #define NIC_VID 0x28 /* 2 byte vendor ID (0x0A46). */
- #define NIC_PID 0x2A /* 2 byte product ID (0x0900). */
- #define NIC_CHIPR 0x2C /* Chip revision (0x00). */
- #define NIC_SMCR 0x2F /* Special mode register (0x00). */
- #define NIC_MRCMDX 0xF0 /* Memory data read command w/o increment (?). */
- #define NIC_MRCMD 0xF2 /* Memory data read command with increment (?). */
- #define NIC_MRR 0xF4 /* 2 byte memory data read register, low/high (?). */
- #define NIC_MWCMDX 0xF6 /* Memory data write command register w/o increment (?). */
- #define NIC_MWCMD 0xF8 /* Memory data write command register with increment (?). */
- #define NIC_MWR 0xFA /* Memory data write command register with increment (?). */
- #define NIC_TXPL 0xFC /* 2 byte TX packet length register. (?). */
- #define NIC_ISR 0xFE /* Interrupt status register (0x00). */
- #define NIC_ISR_IOM 0xC0 /* I/O mode mask */
- #define NIC_ISR_M16 0x00 /* 16-bit I/O mode */
- #define NIC_ISR_M32 0x40 /* 32-bit I/O mode */
- #define NIC_ISR_M8 0x80 /* 8-bit I/O mode */
- #define NIC_ISR_ROOS 0x08 /* Receiver overflow counter interrupt. */
- #define NIC_ISR_ROS 0x04 /* Receiver overflow interrupt. */
- #define NIC_ISR_PTS 0x02 /* Transmitter interrupt. */
- #define NIC_ISR_PRS 0x01 /* Receiver interrupt. */
- #define NIC_IMR 0xFF /* Interrupt mask register (0x00). */
- #define NIC_IMR_PAR 0x80 /* Enable read/write pointer wrap around. */
- #define NIC_IMR_ROOM 0x08 /* Enable receiver overflow counter interrupts. */
- #define NIC_IMR_ROM 0x04 /* Enable receiver overflow interrupts. */
- #define NIC_IMR_PTM 0x02 /* Enable transmitter interrupts. */
- #define NIC_IMR_PRM 0x01 /* Enable receiver interrupts. */
- #define NIC_PHY_BMCR 0x00 /* Basic mode control register. */
- #define NIC_PHY_BMSR 0x01 /* Basic mode status register. */
- #define NIC_PHY_BMSR_ANCOMPL 0x0020 /* Auto negotiation complete. */
- #define NIC_PHY_BMSR_LINKSTAT 0x0004 /* Link status. */
- #define NIC_PHY_ID1 0x02 /* PHY identifier register 1. */
- #define NIC_PHY_ID2 0x03 /* PHY identifier register 2. */
- #define NIC_PHY_ANAR 0x04 /* Auto negotiation advertisement register. */
- #define NIC_PHY_ANLPAR 0x05 /* Auto negotiation link partner availability register. */
- #define NIC_PHY_ANER 0x06 /* Auto negotiation expansion register. */
- #define NIC_PHY_DSCR 0x10 /* Davicom specified configuration register. */
- #define NIC_PHY_DSCSR 0x11 /* Davicom specified configuration and status register. */
- #define NIC_PHY_10BTCSR 0x12 /* 10BASE-T configuration and status register. */
- #define outb(_reg, _val) (*((volatile unsigned char *)(_reg)) = (_val))
- #define outw(_reg, _val) (*((volatile unsigned short *)(_reg)) = (_val))
- #define outr(_reg, _val) (*((volatile unsigned int *)(_reg)) = (_val))
- #define inb(_reg) (*((volatile unsigned char *)(_reg)))
- #define inw(_reg) (*((volatile unsigned short *)(_reg)))
- #define inr(_reg) (*((volatile unsigned int *)(_reg)))
- #define _BV(bit) (1 << bit)
- static inline void nic_outb(unsigned char reg, unsigned char val)
- {
- outb(NIC_BASE_ADDR, reg);
- outb(NIC_DATA_ADDR, val);
- }
- static inline void nic_outw(unsigned char reg, unsigned short val)
- {
- outb(NIC_BASE_ADDR, reg);
- outb(NIC_DATA_ADDR, (unsigned char)val);
- outb(NIC_BASE_ADDR, reg + 1);
- outb(NIC_DATA_ADDR, (unsigned char)(val >> 8));
- }
- static inline unsigned char nic_inb(unsigned short reg)
- {
- outb(NIC_BASE_ADDR, reg);
- return inb(NIC_DATA_ADDR);
- }
- static inline unsigned short nic_inw(unsigned short reg)
- {
- unsigned short val;
- outb(NIC_BASE_ADDR, reg);
- val = inb(NIC_DATA_ADDR);
- outb(NIC_BASE_ADDR, reg + 1);
- val |= inb(NIC_DATA_ADDR) << 8;
- return val;
- }
- /*!
- * \brief Read contents of PHY register.
- *
- * \param reg PHY register number.
- *
- * \return Contents of the specified register.
- */
- static unsigned short phy_inw(unsigned char reg)
- {
- /* Select PHY register */
- nic_outb(NIC_EPAR, 0x40 | reg);
- /* PHY read command. */
- nic_outb(NIC_EPCR, 0x0C);
- MicroDelay(100);
- nic_outb(NIC_EPCR, 0x00);
- /* Get data from PHY data register. */
- return nic_inw(NIC_EPDRL);
- }
- /*!
- * \brief Write value to PHY register.
- *
- * \note NIC interrupts must have been disabled before calling this routine.
- *
- * \param reg PHY register number.
- * \param val Value to write.
- */
- static void phy_outw(unsigned char reg, unsigned short val)
- {
- /* Select PHY register */
- nic_outb(NIC_EPAR, 0x40 | reg);
- /* Store value in PHY data register. */
- nic_outw(NIC_EPDRL, val);
- /* PHY write command. */
- nic_outb(NIC_EPCR, 0x0A);
- MicroDelay(100);
- nic_outb(NIC_EPCR, 0x00);
- }
- static int NicPhyInit(void)
- {
- /* Restart auto negotiation. */
- phy_outw(NIC_PHY_ANAR, 0x01E1);
- phy_outw(NIC_PHY_BMCR, 0x1200);
- nic_outb(NIC_GPCR, 1);
- nic_outb(NIC_GPR, 0);
- return 0;
- }
- /*!
- * \brief Write data block to the NIC.
- *
- * NIC interrupts must be disabled when calling this function.
- */
- static void NicWrite16(unsigned char *buf, unsigned int len)
- {
- unsigned short val;
- /* Make sure that the total size is an even value. */
- len = (len + 1) / 2;
- while (len--) {
- val = *buf++;
- val |= *buf++ << 8;
- outw(NIC_DATA_ADDR, val);
- }
- }
- /*!
- * \brief Read data block from the NIC.
- *
- * NIC interrupts must be disabled when calling this function.
- */
- static void NicRead16(unsigned char *buf, unsigned short len)
- {
- unsigned short val;
- /* Make sure that the total size is an even value. */
- len = (len + 1) / 2;
- while (len--) {
- val = inw(NIC_DATA_ADDR);
- *buf++ = (unsigned char) val;
- *buf++ = (unsigned char) (val >> 8);
- }
- }
- /*!
- * \brief Reset the Ethernet controller.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int NicReset(void)
- {
- /* Software reset. */
- nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
- MicroDelay(10000);
- return NicPhyInit();
- }
- /*!
- * \brief Initialize the NIC.
- *
- * \return 0 on success, -1 otherwise.
- */
- int EtherInit(void)
- {
- unsigned long id;
- int link_wait;
- int i;
- unsigned char val;
- /* Software reset. */
- nic_outb(NIC_NCR, NIC_NCR_RST);
- MicroDelay(10000);
- /* Probe chip by verifying the identifier registers. */
- id = (unsigned long) nic_inw(NIC_VID);
- id |= ((unsigned long) nic_inw(NIC_PID)) << 16;
- DEBUG("[ID=");
- DEBUGULONG(id);
- DEBUG("]");
- if (id != 0x90000A46) {
- return -1;
- }
- /* NIC reset. */
- if (NicReset()) {
- DEBUG("[RESET-ERR]");
- return -1;
- }
- /* Determine bus mode. We do not support 32 bit access. */
- val = nic_inb(NIC_ISR);
- if ((val & NIC_ISR_IOM) != NIC_ISR_M16) {
- DEBUG("[BUS-ERR ISR=0x");
- DEBUGUCHAR(val);
- DEBUG("]");
- return -1;
- }
- /* Power up the PHY. */
- nic_outb(NIC_GPR, 0);
- MicroDelay(5000);
- /* Software reset with MAC loopback. */
- nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
- MicroDelay(5000);
- nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
- MicroDelay(5000);
- /*
- * PHY power down followed by PHY power up. This should activate
- * the auto sense link.
- */
- nic_outb(NIC_GPR, 1);
- nic_outb(NIC_GPR, 0);
- /* Set MAC address. */
- DEBUG("[MAC=");
- for (i = 0; i < 6; i++) {
- DEBUGUCHAR(confnet.cdn_mac[i]);
- nic_outb(NIC_PAR + i, confnet.cdn_mac[i]);
- }
- DEBUG("]");
- /* Enable broadcast receive. */
- for (i = 0; i < 7; i++) {
- nic_outb(NIC_MAR + i, 0);
- }
- nic_outb(NIC_MAR + 7, 0x80);
- /* Clear interrupts. */
- nic_outb(NIC_ISR, NIC_ISR_ROOS | NIC_ISR_ROS | NIC_ISR_PTS | NIC_ISR_PRS);
- /* Enable late collision retries on the DM9000A. */
- if (nic_inb(NIC_CHIPR) == 0x19) {
- nic_outb(0x2D, 0x40);
- }
- /* Enable receiver. */
- nic_outb(NIC_RCR, NIC_RCR_DIS_LONG | NIC_RCR_DIS_CRC | NIC_RCR_RXEN);
- /* Wait for link. */
- for (link_wait = 50;; link_wait--) {
- unsigned short bmsr;
- bmsr = phy_inw(NIC_PHY_BMSR);
- DEBUG("[BMSR=");
- DEBUGUSHORT(bmsr);
- DEBUG("]");
- if (bmsr & NIC_PHY_BMSR_ANCOMPL) {
- break;
- }
- if (link_wait == 0) {
- DEBUG("[LINK-ERR]");
- return -1;
- }
- MicroDelay(100000);
- }
- /* Enable interrupts. */
- nic_outb(NIC_IMR, NIC_IMR_PAR | NIC_IMR_PTM | NIC_IMR_PRM);
- DEBUG("[OK]");
- return 0;
- }
- /*!
- * \brief Send an Ethernet frame.
- *
- * \param dmac Destination MAC address, NULL for broadcast.
- * \param type Frame type.
- * \param len Frame size.
- *
- * \return 0 on success, -1 otherwise.
- */
- int EtherOutput(const unsigned char *dmac, unsigned int type, unsigned int len)
- {
- ETHERHDR *eh;
- unsigned char *ed;
- /*
- * Set the Ethernet header.
- */
- if (type == ETHERTYPE_ARP) {
- eh = &arpheader;
- ed = (unsigned char *) &arpframe;
- } else {
- eh = &sheader;
- ed = (unsigned char *) &sframe;
- }
- memcpy_(eh->ether_shost, confnet.cdn_mac, 6);
- if (dmac) {
- memcpy_(eh->ether_dhost, dmac, 6);
- } else {
- memset_(eh->ether_dhost, 0xFF, 6);
- }
- eh->ether_type = (unsigned short)type;
- DEBUG("\nTx(");
- DEBUGUSHORT(len);
- DEBUG(")");
- /* Enable data write. */
- outb(NIC_BASE_ADDR, NIC_MWCMD);
- /* Transfer the Ethernet frame. */
- NicWrite16((unsigned char *)eh, sizeof(ETHERHDR));
- NicWrite16(ed, len);
- /* Start the transmission. */
- nic_outw(NIC_TXPL, len + sizeof(ETHERHDR));
- nic_outb(NIC_TCR, NIC_TCR_TXREQ);
- return 0;
- }
- /*!
- * \brief Receive an Ethernet frame.
- *
- * \param type Unused?
- * \param tms Return with timeout after the specified number of polling loops.
- *
- * \return The number of bytes received, 0 on timeout or -1 in case of
- * a failure.
- */
- int EtherInput(unsigned short type, unsigned int tms)
- {
- unsigned short fsw;
- unsigned short fbc;
- unsigned char isr;
- for (;;) {
- /* Read the status word w/o auto increment. */
- nic_inb(NIC_MRCMDX);
- fsw = inb(NIC_DATA_ADDR);
- if (fsw != 1) {
- DEBUG("[ETH-POLL]");
- DEBUGUSHORT(tms);
- while (tms) {
- tms--;
- random_id++;
- DEBUG(".");
- isr = nic_inb(NIC_ISR);
- nic_outb(NIC_ISR, isr);
- /* Receiver interrupt. */
- if (isr & NIC_ISR_PRS) {
- nic_inb(NIC_MRCMDX);
- fsw = inb(NIC_DATA_ADDR);
- if (fsw == 1) {
- break;
- }
- }
- MicroDelay(10000);
- }
- }
- if (fsw != 1) {
- return 0;
- }
- /* Now read status word and byte count with auto increment. */
- outb(NIC_BASE_ADDR, NIC_MRCMD);
- fsw = inw(NIC_DATA_ADDR);
- fbc = inw(NIC_DATA_ADDR);
- /*
- * Receiving long packets is unexpected, because we disabled
- * this during initialization. Let's declare the chip insane.
- * Short packets will be handled by the caller.
- */
- if (fbc > 1536) {
- //ni->ni_insane = 1;
- DEBUG("[FBC ");
- DEBUGUSHORT(fbc);
- DEBUG("]");
- return -1;
- }
- /*
- * The high byte of the status word contains a copy of the
- * receiver status register.
- */
- fsw >>= 8;
- fsw &= NIC_RSR_ERRORS;
- /* Discard error packets. */
- if (fsw) {
- DEBUG(" RxError(");
- DEBUGUSHORT(fbc);
- DEBUG(")");
- fbc = (fbc + 1) / 2;
- while (fbc--) {
- fsw = inw(NIC_DATA_ADDR);
- }
- return -1;
- }
- DEBUG(" Rx(");
- DEBUGUSHORT(fbc);
- DEBUG(")");
- /* Read packet data from 16 bit bus. */
- fbc -= 4;
- NicRead16((unsigned char *) &rheader, sizeof(ETHERHDR));
- NicRead16((unsigned char *) &rframe, fbc - sizeof(ETHERHDR));
- /* Read packet CRC. */
- fsw = inw(NIC_DATA_ADDR);
- fsw = inw(NIC_DATA_ADDR);
- if (rheader.ether_type == type) {
- break;
- }
- /*
- * Handle incoming ARP requests.
- */
- if (rheader.ether_type == ETHERTYPE_ARP)
- ArpRespond();
- }
- return fbc;
- }
|