From: EunBong Song Date: Wed, 15 Mar 2017 04:09:09 +0000 (+0900) Subject: drivers/net: remove legacy NuttX uIP based network device drivers X-Git-Tag: 1.1_Public_Release~614^2~354 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=89c7c6dcbf6ee3d2c1aab1607973ce95774bb151;p=rtos%2Ftinyara.git drivers/net: remove legacy NuttX uIP based network device drivers This patch removes all network device drivers which is based on NuttX uIP. These drivers are not integrated with LwIP and does not work. Change-Id: Ia7334ffc56ebd6aed83623ce928ed5a49565eeb6 Signed-off-by: EunBong Song --- diff --git a/os/drivers/net/Make.defs b/os/drivers/net/Make.defs index 3472bb5..7176dea 100644 --- a/os/drivers/net/Make.defs +++ b/os/drivers/net/Make.defs @@ -60,30 +60,10 @@ ifeq ($(CONFIG_NETDEV_TELNET),y) CSRCS += telnet.c endif -ifeq ($(CONFIG_NET_DM90x0),y) - CSRCS += dm90x0.c -endif - -ifeq ($(CONFIG_NET_CS89x0),y) - CSRCS += cs89x0.c -endif - ifeq ($(CONFIG_ENC28J60),y) CSRCS += enc28j60.c endif -ifeq ($(CONFIG_ENCX24J600),y) - CSRCS += encx24j600.c -endif - -ifeq ($(CONFIG_NET_VNET),y) - CSRCS += vnet.c -endif - -ifeq ($(CONFIG_NET_E1000),y) - CSRCS += e1000.c -endif - ifeq ($(CONFIG_NET_SLIP),y) CSRCS += slip.c endif diff --git a/os/drivers/net/dm90x0.c b/os/drivers/net/dm90x0.c deleted file mode 100644 index 608fb60..0000000 --- a/os/drivers/net/dm90x0.c +++ /dev/null @@ -1,1840 +0,0 @@ -/**************************************************************************** - * - * Copyright 2016 Samsung Electronics All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the License. - * - ****************************************************************************/ -/**************************************************************************** - * drivers/net/dm9x.c - * - * Copyright (C) 2007-2010, 2014 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * References: Davicom data sheets (DM9000-DS-F03-041906.pdf, - * DM9010-DS-F01-103006.pdf) and looking at lots of other DM90x0 - * drivers. - * - * 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 NuttX nor the names of its 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. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#if defined(CONFIG_NET) && defined(CONFIG_NET_DM90x0) - -/* Only one hardware interface supported at present (although there are - * hooks throughout the design to that extending the support to multiple - * interfaces should not be that difficult) - */ - -#undef CONFIG_DM9X_NINTERFACES -#define CONFIG_DM9X_NINTERFACES 1 - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#ifdef CONFIG_NET_PKT -#include -#endif - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/* DM90000 and DM9010 register offets */ - -#define DM9X_NETC 0x00 /* Network control register */ -#define DM9X_NETS 0x01 /* Network Status register */ -#define DM9X_TXC 0x02 /* TX control register */ -#define DM9X_TXS1 0x03 /* TX status register 1 */ -#define DM9X_TXS2 0x03 /* TX status register 2 */ -#define DM9X_RXC 0x05 /* RX control register */ -#define DM9X_RXS 0x06 /* RX status register */ -#define DM9X_RXOVF 0x07 /* Receive overflow counter register */ -#define DM9X_BPTHRES 0x08 /* Back pressure threshold register */ -#define DM9X_FCTHRES 0x09 /* Flow control threshold register */ -#define DM9X_FC 0x0a /* RX/TX flow control register */ -#define DM9X_EEPHYC 0x0b /* EEPROM & PHY control register */ -#define DM9X_EEPHYA 0x0c /* EEPROM & PHY address register */ -#define DM9X_EEPHYDL 0x0d /* EEPROM & PHY data register (lo) */ -#define DM9X_EEPHYDH 0x0e /* EEPROM & PHY data register (hi) */ -#define DM9X_WAKEUP 0x0f /* Wake-up control register */ -#define DM9X_PAB0 0x10 /* Physical address register (byte 0) */ -#define DM9X_PAB1 0x11 /* Physical address register (byte 1) */ -#define DM9X_PAB2 0x12 /* Physical address register (byte 2) */ -#define DM9X_PAB3 0x13 /* Physical address register (byte 3) */ -#define DM9X_PAB4 0x14 /* Physical address register (byte 4) */ -#define DM9X_PAB5 0x15 /* Physical address register (byte 5) */ -#define DM9X_MAB0 0x16 /* Multicast address register (byte 0) */ -#define DM9X_MAB1 0x17 /* Multicast address register (byte 1) */ -#define DM9X_MAB2 0x18 /* Multicast address register (byte 2) */ -#define DM9X_MAB3 0x19 /* Multicast address register (byte 3) */ -#define DM9X_MAB4 0x1a /* Multicast address register (byte 4) */ -#define DM9X_MAB5 0x1b /* Multicast address register (byte 5) */ -#define DM9X_MAB6 0x1c /* Multicast address register (byte 6) */ -#define DM9X_MAB7 0x1d /* Multicast address register (byte 7) */ -#define DM9X_GPC 0x1e /* General purpose control register */ -#define DM9X_GPD 0x1f /* General purpose register */ - -#define DM9X_TRPAL 0x22 /* TX read pointer address (lo) */ -#define DM9X_TRPAH 0x23 /* TX read pointer address (hi) */ -#define DM9X_RWPAL 0x24 /* RX write pointer address (lo) */ -#define DM9X_RWPAH 0x25 /* RX write pointer address (hi) */ - -#define DM9X_VIDL 0x28 /* Vendor ID (lo) */ -#define DM9X_VIDH 0x29 /* Vendor ID (hi) */ -#define DM9X_PIDL 0x2a /* Product ID (lo) */ -#define DM9X_PIDH 0x2b /* Product ID (hi) */ -#define DM9X_CHIPR 0x2c /* Product ID (lo) */ -#define DM9X_TXC2 0x2d /* Transmit control register 2 (dm9010) */ -#define DM9X_OTC 0x2e /* Operation test control register (dm9010) */ -#define DM9X_SMODEC 0x2f /* Special mode control register */ -#define DM9X_ETXCSR 0x30 /* Early transmit control/status register (dm9010) */ -#define DM9X_TCCR 0x31 /* Transmit checksum control register (dm9010) */ -#define DM9X_RCSR 0x32 /* Receive checksum control/status register (dm9010) */ -#define DM9X_EPHYA 0x33 /* External PHY address register (dm9010) */ -#define DM9X_GPC2 0x34 /* General purpose control register 2 (dm9010) */ -#define DM9X_GPD2 0x35 /* General purpose register 2 */ -#define DM9X_GPC3 0x36 /* General purpose control register 3 (dm9010) */ -#define DM9X_GPD3 0x37 /* General purpose register 3 */ -#define DM9X_PBUSC 0x38 /* Processor bus control register (dm9010) */ -#define DM9X_IPINC 0x39 /* INT pin control register (dm9010) */ - -#define DM9X_MON1 0x40 /* Monitor register 1 (dm9010) */ -#define DM9X_MON2 0x41 /* Monitor register 2 (dm9010) */ - -#define DM9X_SCLKC 0x50 /* System clock turn ON control register (dm9010) */ -#define DM9X_SCLKR 0x51 /* Resume system clock control register (dm9010) */ - -#define DM9X_MRCMDX 0xf0 /* Memory data pre-fetch read command without address increment */ -#define DM9X_MRCMDX1 0xf1 /* memory data read command without address increment (dm9010) */ -#define DM9X_MRCMD 0xf2 /* Memory data read command with address increment */ -#define DM9X_MDRAL 0xf4 /* Memory data read address register (lo) */ -#define DM9X_MDRAH 0xf5 /* Memory data read address register (hi) */ -#define DM9X_MWCMDX 0xf6 /* Memory data write command without address increment */ -#define DM9X_MWCMD 0xf8 /* Memory data write command with address increment */ -#define DM9X_MDWAL 0xfa /* Memory data write address register (lo) */ -#define DM9X_MDWAH 0xfb /* Memory data write address register (lo) */ -#define DM9X_TXPLL 0xfc /* Memory data write address register (lo) */ -#define DM9X_TXPLH 0xfd /* Memory data write address register (hi) */ -#define DM9X_ISR 0xfe /* Interrupt status register */ -#define DM9X_IMR 0xff /* Interrupt mask register */ - -/* Network control register bit definitions */ - -#define DM9X_NETC_RST (1 << 0) /* Software reset */ -#define DM9X_NETC_LBKM (3 << 1) /* Loopback mode mask */ -#define DM9X_NETC_LBK0 (0 << 1) /* 0: Normal */ -#define DM9X_NETC_LBK1 (1 << 1) /* 1: MAC internal loopback */ -#define DM9X_NETC_LBK2 (2 << 1) /* 2: Internal PHY 100M mode loopback */ -#define DM9X_NETC_FDX (1 << 3) /* Full dupliex mode */ -#define DM9X_NETC_FCOL (1 << 4) /* Force collision mode */ -#define DM9X_NETC_WAKEEN (1 << 6) /* Wakeup event enable */ -#define DM9X_NETC_EXTPHY (1 << 7) /* Select external PHY */ - -/* Network status bit definitions */ - -#define DM9X_NETS_RXOV (1 << 1) /* RX Fifo overflow */ -#define DM9X_NETS_TX1END (1 << 2) /* TX packet 1 complete status */ -#define DM9X_NETS_TX2END (1 << 3) /* TX packet 2 complete status */ -#define DM9X_NETS_WAKEST (1 << 5) /* Wakeup event status */ -#define DM9X_NETS_LINKST (1 << 6) /* Link status */ -#define DM9X_NETS_SPEED (1 << 7) /* Media speed */ - -/* IMR/ISR bit definitions */ - -#define DM9X_INT_PR (1 << 0) /* Packet received interrupt */ -#define DM9X_INT_PT (1 << 1) /* Packet transmitted interrupt */ -#define DM9X_INT_RO (1 << 2) /* Receive overflow interrupt */ -#define DM9X_INT_ROO (1 << 3) /* Receive overflow counter overflow int */ -#define DM9X_INT_UDRUN (1 << 4) /* Transmit underrun interrupt */ -#define DM9X_INT_LNKCHG (1 << 5) /* Link status change interrupt */ -#define DM9X_INT_ALL (0x3f) - -#define DM9X_IMR_UNUSED (1 << 6) /* (not used) */ -#define DM9X_IMR_PAR (1 << 7) /* Enable auto R/W pointer reset */ - -#define DM9X_ISR_IOMODEM (3 << 6) /* IO mode mask */ -#define DM9X_ISR_IOMODE8 (2 << 6) /* IO mode = 8 bit */ -#define DM9X_ISR_IOMODE16 (0 << 6) /* IO mode = 16 bit */ -#define DM9X_ISR_IOMODE32 (1 << 6) /* IO mode = 32 bit */ - -#define DM9X_IMRENABLE (DM9X_INT_PR|DM9X_INT_PT|DM9X_INT_LNKCHG|DM9X_IMR_PAR) -#define DM9X_IMRRXDISABLE (DM9X_INT_PT|DM9X_INT_LNKCHG|DM9X_IMR_PAR) -#define DM9X_IMRDISABLE (DM9X_IMR_PAR) - -/* EEPROM/PHY control regiser bits */ - -#define DM9X_EEPHYC_ERRE (1 << 0) /* EEPROM (vs PHY) access status */ -#define DM9X_EEPHYC_ERPRW (1 << 1) /* EEPROM/PHY write access */ -#define DM9X_EEPHYC_ERPRR (1 << 2) /* EEPROM/PHY read access */ -#define DM9X_EEPHYC_EPOS (1 << 3) /* EEPROM/PHY operation select */ -#define DM9X_EEPHYC_WEP (1 << 4) /* Write EEPROM enable */ -#define DM9X_EEPHYC_REEP (1 << 5) /* Reload EEPROM */ - -/* Supported values from the vendor and product ID register */ - -#define DM9X_DAVICOMVID 0x0a46 -#define DM9X_DM9000PID 0x9000 -#define DM9X_DM9010PID 0x9010 - -/* RX control register bit settings */ - -#define DM9X_RXC_RXEN (1 << 0) /* RX enable */ -#define DM9X_RXC_PRMSC (1 << 1) /* Promiscuous mode */ -#define DM9X_RXC_RUNT (1 << 2) /* Pass runt packet */ -#define DM9X_RXC_ALL (1 << 3) /* Pass all multicast */ -#define DM9X_RXC_DISCRC (1 << 4) /* Discard CRC error packets */ -#define DM9X_RXC_DISLONG (1 << 5) /* Discard long packets */ -#define DM9X_RXC_WTDIS (1 << 6) /* Disable watchdog timer */ -#define DM9X_RXC_HASHALL (1 << 7) /* Filter all addresses in hash table */ - -#define DM9X_RXCSETUP (DM9X_RXC_DISCRC|DM9X_RXC_DISLONG) - -/* EEPHY bit settings */ - -#define DM9X_EEPHYA_EROA 0x40 /* PHY register address 0x01 */ - -#define DM9X_PKTRDY 0x01 /* Packet ready to receive */ - -/* The RX interrupt will be disabled if more than the following RX - * interrupts are received back-to-back. - */ - -#define DM9X_CRXTHRES 10 - -/* All access is via an index register and a data regist. Select accecss - * according to user supplied base address and bus width. - */ - -#if defined(CONFIG_DM9X_BUSWIDTH8) -#define DM9X_INDEX *(volatile uint8_t*)(CONFIG_DM9X_BASE) -#define DM9X_DATA *(volatile uint8_t*)(CONFIG_DM9X_BASE + 2) -#elif defined(CONFIG_DM9X_BUSWIDTH16) -#define DM9X_INDEX *(volatile uint16_t*)(CONFIG_DM9X_BASE) -#define DM9X_DATA *(volatile uint16_t*)(CONFIG_DM9X_BASE + 2) -#elif defined(CONFIG_DM9X_BUSWIDTH32) -#define DM9X_INDEX *(volatile uint32_t*)(CONFIG_DM9X_BASE) -#define DM9X_DATA *(volatile uint32_t*)(CONFIG_DM9X_BASE + 2) -#endif - -/* Phy operating mode. Default is AUTO, but this setting can be overridden - * in the TinyAra configuration file. - */ - -#if !defined(CONFIG_DM9X_MODE_AUTO) && !defined(CONFIG_DM9X_MODE_10MHD) && \ - !defined(CONFIG_DM9X_MODE_100MHD) && !defined(CONFIG_DM9X_MODE_10MFD) && \ - !defined(CONFIG_DM9X_MODE_100MFD) -#define CONFIG_DM9X_MODE_AUTO 1 -#endif - -/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */ - -#define DM6X_WDDELAY (1*CLK_TCK) -#define DM6X_POLLHSEC (1*2) - -/* TX timeout = 1 minute */ - -#define DM6X_TXTIMEOUT (60*CLK_TCK) - -/* This is a helper pointer for accessing the contents of the Ethernet header */ - -#define BUF ((struct eth_hdr_s *)dm9x->dm_dev.d_buf) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -union rx_desc_u { - uint8_t rx_buf[4]; - struct { - uint8_t rx_byte; - uint8_t rx_status; - uint16_t rx_len; - } desc; -}; - -/* The dm9x_driver_s encapsulates all DM90x0 state information for a single - * DM90x0 hardware interface - */ - -struct dm9x_driver_s { - bool dm_bifup; /* true:ifup false:ifdown */ - bool dm_b100M; /* true:speed == 100M; false:speed == 10M */ - WDOG_ID dm_txpoll; /* TX poll timer */ - WDOG_ID dm_txtimeout; /* TX timeout timer */ - uint8_t dm_ntxpending; /* Count of packets pending transmission */ - uint8_t ncrxpackets; /* Number of continuous rx packets */ - - /* Mode-dependent function to move data in 8/16/32 I/O modes */ - - void (*dm_read)(uint8_t *ptr, int len); - void (*dm_write)(const uint8_t *ptr, int len); - void (*dm_discard)(int len); - -#if defined(CONFIG_DM9X_STATS) - uint32_t dm_ntxpackets; /* Count of packets sent */ - uint32_t dm_ntxbytes; /* Count of bytes sent */ - uint32_t dm_ntxerrors; /* Count of TX errors */ - uint32_t dm_nrxpackets; /* Count of packets received */ - uint32_t dm_nrxbytes; /* Count of bytes received */ - uint32_t dm_nrxfifoerrors; /* Count of RX FIFO overflow errors */ - uint32_t dm_nrxcrcerrors; /* Count of RX CRC errors */ - uint32_t dm_nrxlengtherrors; /* Count of RX length errors */ - uint32_t dm_nphyserrors; /* Count of physical layer errors */ - uint32_t dm_nresets; /* Counts number of resets */ - uint32_t dm_ntxtimeouts; /* Counts resets caused by TX timeouts */ -#endif - - /* This holds the information visible to uIP/TinyAra */ - - struct net_driver_s dm_dev; -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* At present, only a single DM90x0 device is supported. */ - -static struct dm9x_driver_s g_dm9x[CONFIG_DM9X_NINTERFACES]; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Utility functions */ - -static uint8_t getreg(int reg); -static void putreg(int reg, uint8_t value); -static void read8(uint8_t *ptr, int len); -static void read16(uint8_t *ptr, int len); -static void read32(uint8_t *ptr, int len); -static void discard8(int len); -static void discard16(int len); -static void discard32(int len); -static void write8(const uint8_t *ptr, int len); -static void write16(const uint8_t *ptr, int len); -static void write32(const uint8_t *ptr, int len); - -/* static uint16_t dm9x_readsrom(struct dm9x_driver_s *dm9x, int offset); */ -static uint16_t dm9x_phyread(struct dm9x_driver_s *dm9x, int reg); -static void dm9x_phywrite(struct dm9x_driver_s *dm9x, int reg, uint16_t value); - -#if defined(CONFIG_DM9X_STATS) -static void dm9x_resetstatistics(struct dm9x_driver_s *dm9x); -#else -#define dm9x_resetstatistics(dm9x) -#endif - -#if defined(CONFIG_DM9X_STATS) && defined(CONFIG_DEBUG) -static void dm9x_dumpstatistics(struct dm9x_driver_s *dm9x); -#else -#define dm9x_dumpstatistics(dm9x) -#endif - -#if defined(CONFIG_DM9X_CHECKSUM) -static bool dm9x_rxchecksumready(uint8_t); -#else -#define dm9x_rxchecksumready(a) ((a) == 0x01) -#endif - -/* Common TX logic */ - -static int dm9x_transmit(struct dm9x_driver_s *dm9x); -static int dm9x_txpoll(struct net_driver_s *dev); - -/* Interrupt handling */ - -static void dm9x_receive(struct dm9x_driver_s *dm9x); -static void dm9x_txdone(struct dm9x_driver_s *dm9x); -static int dm9x_interrupt(int irq, FAR void *context); - -/* Watchdog timer expirations */ - -static void dm9x_polltimer(int argc, uint32_t arg, ...); -static void dm9x_txtimeout(int argc, uint32_t arg, ...); - -/* TinyAra callback functions */ - -static int dm9x_ifup(struct net_driver_s *dev); -static int dm9x_ifdown(struct net_driver_s *dev); -static int dm9x_txavail(struct net_driver_s *dev); -#ifdef CONFIG_NET_IGMP -static int dm9x_addmac(struct net_driver_s *dev, FAR const uint8_t *mac); -static int dm9x_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac); -#endif - -/* Initialization functions */ - -static void dm9x_bringup(struct dm9x_driver_s *dm9x); -static void dm9x_reset(struct dm9x_driver_s *dm9x); - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: getreg and setreg - * - * Description: - * Access to memory-mapped DM90x0 8-bit registers - * - * Parameters: - * reg - Register number - * value - Value to write to the register (setreg only) - * - * Returned Value: - * Value read from the register (getreg only) - * - * Assumptions: - * - ****************************************************************************/ - -static uint8_t getreg(int reg) -{ - DM9X_INDEX = reg; - return DM9X_DATA & 0xff; -} - -static void putreg(int reg, uint8_t value) -{ - DM9X_INDEX = reg; - DM9X_DATA = value & 0xff; -} - -/**************************************************************************** - * Function: read8, read16, read32 - * - * Description: - * Read packet data from the DM90x0 SRAM based on its current I/O mode - * - * Parameters: - * ptr - Location to write the packet data - * len - The number of bytes to read - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void read8(uint8_t *ptr, int len) -{ - nvdbg("Read %d bytes (8-bit mode)\n", len); - for (; len > 0; len--) { - *ptr++ = DM9X_DATA; - } -} - -static void read16(uint8_t *ptr, int len) -{ - register uint16_t *ptr16 = (uint16_t *) ptr; - nvdbg("Read %d bytes (16-bit mode)\n", len); - for (; len > 0; len -= sizeof(uint16_t)) { - *ptr16++ = DM9X_DATA; - } -} - -static void read32(uint8_t *ptr, int len) -{ - register uint32_t *ptr32 = (uint32_t *) ptr; - nvdbg("Read %d bytes (32-bit mode)\n", len); - for (; len > 0; len -= sizeof(uint32_t)) { - *ptr32++ = DM9X_DATA; - } -} - -/**************************************************************************** - * Function: discard8, discard16, discard32 - * - * Description: - * Read and discard packet data in the DM90x0 SRAM based on its current - * I/O mode - * - * Parameters: - * len - The number of bytes to discard - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void discard8(int len) -{ - nvdbg("Discard %d bytes (8-bit mode)\n", len); - for (; len > 0; len--) { - DM9X_DATA; - } -} - -static void discard16(int len) -{ - nvdbg("Discard %d bytes (16-bit mode)\n", len); - for (; len > 0; len -= sizeof(uint16_t)) { - DM9X_DATA; - } -} - -static void discard32(int len) -{ - nvdbg("Discard %d bytes (32-bit mode)\n", len); - for (; len > 0; len -= sizeof(uint32_t)) { - DM9X_DATA; - } -} - -/**************************************************************************** - * Function: write8, write16, write32 - * - * Description: - * Write packet data into the DM90x0 SRAM based on its current I/O mode - * - * Parameters: - * ptr - Location to write the packet data - * len - The number of bytes to read - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void write8(const uint8_t *ptr, int len) -{ - nvdbg("Write %d bytes (8-bit mode)\n", len); - for (; len > 0; len--) { - DM9X_DATA = (*ptr++ & 0xff); - } -} - -static void write16(const uint8_t *ptr, int len) -{ - register uint16_t *ptr16 = (uint16_t *) ptr; - nvdbg("Write %d bytes (16-bit mode)\n", len); - - for (; len > 0; len -= sizeof(uint16_t)) { - DM9X_DATA = *ptr16++; - } -} - -static void write32(const uint8_t *ptr, int len) -{ - register uint32_t *ptr32 = (uint32_t *) ptr; - nvdbg("Write %d bytes (32-bit mode)\n", len); - for (; len > 0; len -= sizeof(uint32_t)) { - DM9X_DATA = *ptr32++; - } -} - -/**************************************************************************** - * Function: dm9x_readsrom - * - * Description: - * Read a word from SROM - * - * Parameters: - * dm9x - Reference to the driver state structure - * offset - SROM offset to read from - * - * Returned Value: - * SROM content at that offset - * - * Assumptions: - * - ****************************************************************************/ - -#if 0 /* Not used */ -static uint16_t dm9x_readsrom(struct dm9x_driver_s *dm9x, int offset) -{ - putreg(DM9X_EEPHYA, offset); - putreg(DM9X_EEPHYC, DM9X_EEPHYC_ERPRR); - up_udelay(200); - putreg(DM9X_EEPHYC, 0x00); - return (getreg(DM9X_EEPHYDL) + (getreg(DM9X_EEPHYDH) << 8)); -} -#endif - -/**************************************************************************** - * Function: dm9x_phyread and dm9x_phywrite - * - * Description: - * Read/write data from/to the PHY - * - * Parameters: - * dm9x - Reference to the driver state structure - * reg - PHY register offset - * value - The value to write to the PHY register (dm9x_write only) - * - * Returned Value: - * The value read from the PHY (dm9x_read only) - * - * Assumptions: - * - ****************************************************************************/ - -static uint16_t dm9x_phyread(struct dm9x_driver_s *dm9x, int reg) -{ - /* Setup DM9X_EEPHYA, the EEPROM/PHY address register */ - - putreg(DM9X_EEPHYA, DM9X_EEPHYA_EROA | reg); - - /* Issue PHY read command pulse in the EEPROM/PHY control register */ - - putreg(DM9X_EEPHYC, (DM9X_EEPHYC_ERPRR | DM9X_EEPHYC_EPOS)); - up_udelay(100); - putreg(DM9X_EEPHYC, 0x00); - - /* Return the data from the EEPROM/PHY data register pair */ - - return (((uint16_t)getreg(DM9X_EEPHYDH)) << 8) | (uint16_t)getreg(DM9X_EEPHYDL); -} - -static void dm9x_phywrite(struct dm9x_driver_s *dm9x, int reg, uint16_t value) -{ - /* Setup DM9X_EEPHYA, the EEPROM/PHY address register */ - - putreg(DM9X_EEPHYA, DM9X_EEPHYA_EROA | reg); - - /* Put the data to write in the EEPROM/PHY data register pair */ - - putreg(DM9X_EEPHYDL, (value & 0xff)); - putreg(DM9X_EEPHYDH, ((value >> 8) & 0xff)); - - /* Issue PHY write command pulse in the EEPROM/PHY control register */ - - putreg(DM9X_EEPHYC, (DM9X_EEPHYC_ERPRW | DM9X_EEPHYC_EPOS)); - up_udelay(500); - putreg(DM9X_EEPHYC, 0x0); -} - -/**************************************************************************** - * Function: dm9x_resetstatistics - * - * Description: - * Reset all DM90x0 statistics - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#if defined(CONFIG_DM9X_STATS) -static void dm9x_resetstatistics(struct dm9x_driver_s *dm9x) -{ - dm9x->dm_ntxpackets = 0; /* Count of packets sent */ - dm9x->dm_ntxbytes = 0; /* Count of bytes sent */ - dm9x->dm_ntxerrors = 0; /* Count of TX errors */ - dm9x->dm_nrxpackets = 0; /* Count of packets received */ - dm9x->dm_nrxbytes = 0; /* Count of bytes received */ - dm9x->dm_nrxfifoerrors = 0; /* Count of RX FIFO overflow errors */ - dm9x->dm_nrxcrcerrors = 0; /* Count of RX CRC errors */ - dm9x->dm_nrxlengtherrors = 0; /* Count of RX length errors */ - dm9x->dm_nphyserrors = 0; /* Count of physical layer errors */ - dm9x->dm_nresets = 0; /* Counts number of resets */ - dm9x->dm_ntxtimeouts = 0; /* Counts resets caused by TX timeouts */ -} -#endif - -/**************************************************************************** - * Function: dm9x_dumpstatistics - * - * Description: - * Print the current value of all DM90x0 statistics - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#if defined(CONFIG_DM9X_STATS) && defined(CONFIG_DEBUG) -static void dm9x_dumpstatistics(struct dm9x_driver_s *dm9x) -{ - ndbg("TX packets: %d\n", dm9x->dm_ntxpackets); - ndbg(" bytes: %d\n", dm9x->dm_ntxbytes); - ndbg(" errors: %d\n", dm9x->dm_ntxerrors); - ndbg("RX packets: %d\n", dm9x->dm_nrxpackets); - ndbg(" bytes: %d\n", dm9x->dm_nrxbytes); - ndbg(" FIFO overflows: %d\n", dm9x->dm_nrxfifoerrors); - ndbg(" CRC errors: %d\n", dm9x->dm_nrxcrcerrors); - ndbg(" length errors: %d\n", dm9x->dm_nrxlengtherrors); - ndbg("Physical layer errors: %d\n", dm9x->dm_nphyserrors); - ndbg("Resets: %d\n", dm9x->dm_nresets); - ndbg("TX timeout resets: %d\n", dm9x->dm_ntxtimeouts); -} -#endif - -/**************************************************************************** - * Function: dm9x_rxchecksumready - * - * Description: - * Return true if the RX checksum is available - * - * Parameters: - * rxbyte - * - * Returned Value: - * true: checksum is ready - * - * Assumptions: - * - ****************************************************************************/ - -#if defined(CONFIG_DM9X_CHECKSUM) -static inline bool dm9x_rxchecksumready(uint8_t rxbyte) -{ - if ((rxbyte & 0x01) == 0) { - return false; - } - - return ((rxbyte >> 4) | 0x01) != 0; -} -#endif - -/**************************************************************************** - * Function: dm9x_transmit - * - * Description: - * Start hardware transmission. Called either from the txdone interrupt - * handling or from watchdog based polling. - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * - ****************************************************************************/ - -static int dm9x_transmit(struct dm9x_driver_s *dm9x) -{ - /* Check if there is room in the DM90x0 to hold another packet. In 100M mode, - * that can be 2 packets, otherwise it is a single packet. - */ - - if (dm9x->dm_ntxpending < 1 || (dm9x->dm_b100M && dm9x->dm_ntxpending < 2)) { - /* Increment count of packets transmitted */ - - dm9x->dm_ntxpending++; -#if defined(CONFIG_DM9X_STATS) - dm9x->dm_ntxpackets++; - dm9x->dm_ntxbytes += dm9x->dm_dev.d_len; -#endif - - /* Disable all DM90x0 interrupts */ - - putreg(DM9X_IMR, DM9X_IMRDISABLE); - - /* Set the TX length */ - - putreg(DM9X_TXPLL, (dm9x->dm_dev.d_len & 0xff)); - putreg(DM9X_TXPLH, (dm9x->dm_dev.d_len >> 8) & 0xff); - - /* Move the data to be sent into TX SRAM */ - - DM9X_INDEX = DM9X_MWCMD; - dm9x->dm_write(dm9x->dm_dev.d_buf, dm9x->dm_dev.d_len); - -#if !defined(CONFIG_DM9X_ETRANS) - /* Issue TX polling command */ - - putreg(DM9X_TXC, 0x1); /* Cleared after TX complete */ -#endif - - /* Clear count of back-to-back RX packet transfers */ - - dm9x->ncrxpackets = 0; - - /* Re-enable DM90x0 interrupts */ - - putreg(DM9X_IMR, DM9X_IMRENABLE); - - /* Setup the TX timeout watchdog (perhaps restarting the timer) */ - - (void)wd_start(dm9x->dm_txtimeout, DM6X_TXTIMEOUT, dm9x_txtimeout, 1, (uint32_t)dm9x); - return OK; - } - return -EBUSY; -} - -/**************************************************************************** - * Function: dm9x_txpoll - * - * Description: - * The transmitter is available, check if uIP has any outgoing packets ready - * to send. This is a callback from netif_poll(). netif_poll() may be called: - * - * 1. When the preceding TX packet send is complete, - * 2. When the preceding TX packet send timesout and the DM90x0 is reset - * 3. During normal TX polling - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * - ****************************************************************************/ - -static int dm9x_txpoll(struct net_driver_s *dev) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)dev->d_private; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - if (dm9x->dm_dev.d_len > 0) { - /* Look up the destination MAC address and add it to the Ethernet - * header. - */ - -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - if (IFF_IS_IPv4(dm9x->dm_dev.d_flags)) -#endif - { - arp_out(&dm9x->dm_dev); - } -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else -#endif - { - neighbor_out(&dm9x->dm_dev); - } -#endif /* CONFIG_NET_IPv6 */ - - /* Send the packet */ - - dm9x_transmit(dm9x); - - /* Check if there is room in the DM90x0 to hold another packet. In 100M mode, - * that can be 2 packets, otherwise it is a single packet. - */ - - if (dm9x->dm_ntxpending > 1 || !dm9x->dm_b100M) { - /* Returning a non-zero value will terminate the poll operation */ - - return 1; - } - } - - /* If zero is returned, the polling will continue until all connections have - * been examined. - */ - - return 0; -} - -/**************************************************************************** - * Function: dm9x_receive - * - * Description: - * An interrupt was received indicating the availability of a new RX packet - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_receive(struct dm9x_driver_s *dm9x) -{ - union rx_desc_u rx; - bool bchecksumready; - uint8_t rxbyte; - - nvdbg("Packet received\n"); - - do { - /* Store the value of memory data read address register */ - - (void)getreg(DM9X_MDRAH); - (void)getreg(DM9X_MDRAL); - - getreg(DM9X_MRCMDX); /* Dummy read */ - rxbyte = (uint8_t)DM9X_DATA; /* Get the most up-to-date data */ - - /* Packet ready for receive check */ - - bchecksumready = dm9x_rxchecksumready(rxbyte); - if (!bchecksumready) { - break; - } - - /* A packet is ready now. Get status/length */ - - DM9X_INDEX = DM9X_MRCMD; /* set read ptr ++ */ - - /* Read packet status & length */ - - dm9x->dm_read((uint8_t *)&rx, 4); - - /* Check if any errors were reported by the hardware */ - - if (rx.desc.rx_status & 0xbf) { - /* Bad RX packet... update statistics */ - -#if defined(CONFIG_DM9X_STATS) - if (rx.desc.rx_status & 0x01) { - dm9x->dm_nrxfifoerrors++; - ndbg("RX FIFO error: %d\n", dm9x->dm_nrxfifoerrors); - } - - if (rx.desc.rx_status & 0x02) { - dm9x->dm_nrxcrcerrors++; - ndbg("RX CRC error: %d\n", dm9x->dm_nrxcrcerrors); - } - - if (rx.desc.rx_status & 0x80) { - dm9x->dm_nrxlengtherrors++; - ndbg("RX length error: %d\n", dm9x->dm_nrxlengtherrors); - } - - if (rx.desc.rx_status & 0x08) { - dm9x->dm_nphyserrors++; - ndbg("Physical Layer error: %d\n", dm9x->dm_nphyserrors); - } -#else - ndbg("Received packet with errors: %02x\n", rx.desc.rx_status); -#endif - /* Drop this packet and continue to check the next packet */ - - dm9x->dm_discard(rx.desc.rx_len); - } - - /* Also check if the packet is a valid size for the uIP configuration */ - - else if (rx.desc.rx_len < ETH_HDRLEN || rx.desc.rx_len > (CONFIG_NET_ETH_MTU + 2)) { -#if defined(CONFIG_DM9X_STATS) - dm9x->dm_nrxlengtherrors++; - ndbg("RX length error: %d\n", dm9x->dm_nrxlengtherrors); -#endif - /* Drop this packet and continue to check the next packet */ - - dm9x->dm_discard(rx.desc.rx_len); - } else { - /* Good packet... Copy the packet data out of SRAM and pass it one to uIP */ - - dm9x->dm_dev.d_len = rx.desc.rx_len; - dm9x->dm_read(dm9x->dm_dev.d_buf, rx.desc.rx_len); - -#ifdef CONFIG_NET_PKT - /* When packet sockets are enabled, feed the frame into the packet tap */ - - pkt_input(&dm9x->dm_dev); -#endif - - /* We only accept IP packets of the configured type and ARP packets */ - -#ifdef CONFIG_NET_IPv4 - if (BUF->type == HTONS(ETHTYPE_IP)) { - nllvdbg("IPv4 frame\n"); - - /* Handle ARP on input then give the IPv4 packet to the network - * layer - */ - - arp_ipin(&dm9x->dm_dev); - ipv4_input(&dm9x->dm_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (dm9x->dm_dev.d_len > 0) { - /* Update the Ethernet header with the correct MAC address */ - -#ifdef CONFIG_NET_IPv6 - if (IFF_IS_IPv4(dm9x->dm_dev.d_flags)) -#endif - { - arp_out(&dm9x->dm_dev); - } -#ifdef CONFIG_NET_IPv6 - else { - neighbor_out(&dm9x->dm_dev); - } -#endif - - /* And send the packet */ - - dm9x_transmit(dm9x); - } - } else -#endif -#ifdef CONFIG_NET_IPv6 - if (BUF->type == HTONS(ETHTYPE_IP6)) { - nllvdbg("Iv6 frame\n"); - - /* Give the IPv6 packet to the network layer */ - - ipv6_input(&dm9x->dm_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (dm9x->dm_dev.d_len > 0) { - /* Update the Ethernet header with the correct MAC address */ - -#ifdef CONFIG_NET_IPv4 - if (IFF_IS_IPv4(dm9x->dm_dev.d_flags)) { - arp_out(&dm9x->dm_dev); - } else -#endif -#ifdef CONFIG_NET_IPv6 - { - neighbor_out(&dm9x->dm_dev); - } -#endif - - /* And send the packet */ - - dm9x_transmit(dm9x); - } - } else -#endif -#ifdef CONFIG_NET_ARP - if (BUF->type == htons(ETHTYPE_ARP)) { - arp_arpin(&dm9x->dm_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (dm9x->dm_dev.d_len > 0) { - dm9x_transmit(dm9x); - } - } -#endif - } - -#if defined(CONFIG_DM9X_STATS) - dm9x->dm_nrxpackets++; - dm9x->dm_nrxbytes += rx.desc.rx_len; -#endif - dm9x->ncrxpackets++; - } while ((rxbyte & 0x01) == DM9X_PKTRDY && dm9x->ncrxpackets < DM9X_CRXTHRES); - nvdbg("All RX packets processed\n"); -} - -/**************************************************************************** - * Function: dm9x_txdone - * - * Description: - * An interrupt was received indicating that the last TX packet(s) is done - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_txdone(struct dm9x_driver_s *dm9x) -{ - int nsr; - - nvdbg("TX done\n"); - - /* Another packet has completed transmission. Decrement the count of - * of pending TX transmissions. - */ - - nsr = getreg(DM9X_NETS); - if (nsr & DM9X_NETS_TX1END) { - if (dm9x->dm_ntxpending) { - dm9x->dm_ntxpending--; - } else { - ndbg("Bad TX count (TX1END)\n"); - } - } - - if (nsr & DM9X_NETS_TX2END) { - if (dm9x->dm_ntxpending) { - dm9x->dm_ntxpending--; - } else { - ndbg("Bad TX count (TX2END)\n"); - } - } - - /* Cancel the TX timeout */ - - if (dm9x->dm_ntxpending == 0) { - wd_cancel(dm9x->dm_txtimeout); - } - - /* Then poll uIP for new XMIT data */ - - (void)netif_poll(&dm9x->dm_dev, dm9x_txpoll); -} - -/**************************************************************************** - * Function: dm9x_interrupt - * - * Description: - * DM90x0 interrupt handler - * - * Parameters: - * irq - Number of the IRQ that generated the interrupt - * context - Interrupt register state save info (architecture-specific) - * - * Returned Value: - * OK on success - * - * Assumptions: - * - ****************************************************************************/ - -static int dm9x_interrupt(int irq, FAR void *context) -{ -#if CONFIG_DM9X_NINTERFACES == 1 - register struct dm9x_driver_s *dm9x = &g_dm9x[0]; -#else -#error "Additional logic needed to support multiple interfaces" -#endif - uint8_t isr; - uint8_t save; - int i; - - /* Save previous register address */ - - save = (uint8_t)DM9X_INDEX; - - /* Disable all DM90x0 interrupts */ - - putreg(DM9X_IMR, DM9X_IMRDISABLE); - - /* Get and clear the DM90x0 interrupt status bits */ - - isr = getreg(DM9X_ISR); - putreg(DM9X_ISR, isr); - nvdbg("Interrupt status: %02x\n", isr); - - /* Check for link status change */ - - if (isr & DM9X_INT_LNKCHG) { - /* Wait up to 0.5s for link OK */ - - for (i = 0; i < 500; i++) { - dm9x_phyread(dm9x, 0x1); - if (dm9x_phyread(dm9x, 0x1) & 0x4) { /*Link OK */ - /* Wait to get detected speed */ - - for (i = 0; i < 200; i++) { - up_mdelay(1); - } - - /* Set the new network speed */ - - if (dm9x_phyread(dm9x, 0) & 0x2000) { - dm9x->dm_b100M = true; - } else { - dm9x->dm_b100M = false; - } - break; - } - up_mdelay(1); - } - ndbg("delay: %dmS speed: %s\n", i, dm9x->dm_b100M ? "100M" : "10M"); - } - - /* Check if we received an incoming packet */ - - if (isr & DM9X_INT_PR) { - dm9x_receive(dm9x); - } - - /* Check if we are able to transmit a packet */ - - if (isr & DM9X_INT_PT) { - dm9x_txdone(dm9x); - } - - /* If the number of consecutive receive packets exceeds a threshold, - * then disable the RX interrupt. - */ - - if (dm9x->ncrxpackets >= DM9X_CRXTHRES) { - /* Eanble all DM90x0 interrupts EXCEPT for RX */ - - putreg(DM9X_IMR, DM9X_IMRRXDISABLE); - } else { - /* Enable all DM90x0 interrupts */ - - putreg(DM9X_IMR, DM9X_IMRENABLE); - } - - /* Restore previous register address */ - - DM9X_INDEX = save; - return OK; -} - -/**************************************************************************** - * Function: dm9x_txtimeout - * - * Description: - * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Reset the DM90x0 and start again. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_txtimeout(int argc, uint32_t arg, ...) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)arg; - - ndbg("TX timeout\n"); - - /* Increment statistics and dump debug info */ - -#if defined(CONFIG_DM9X_STATS) - dm9x->dm_ntxtimeouts++; - dm9x->dm_ntxerrors++; -#endif - - ndbg(" TX packet count: %d\n", dm9x->dm_ntxpending); -#if defined(CONFIG_DM9X_STATS) - ndbg(" TX timeouts: %d\n", dm9x->dm_ntxtimeouts); -#endif - ndbg(" TX read pointer address: 0x%02x:%02x\n", getreg(DM9X_TRPAH), getreg(DM9X_TRPAL)); - ndbg(" Memory data write address: 0x%02x:%02x (DM9010)\n", getreg(DM9X_MDWAH), getreg(DM9X_MDWAL)); - - /* Then reset the DM90x0 */ - - dm9x_reset(dm9x); - - /* Then poll uIP for new XMIT data */ - - (void)netif_poll(&dm9x->dm_dev, dm9x_txpoll); -} - -/**************************************************************************** - * Function: dm9x_polltimer - * - * Description: - * Periodic timer handler. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_polltimer(int argc, uint32_t arg, ...) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)arg; - - /* If the number of contiguous RX packets exceeds a threshold, reset the counter and - * re-enable RX interrupts - */ - - if (dm9x->ncrxpackets >= DM9X_CRXTHRES) { - dm9x->ncrxpackets = 0; - putreg(DM9X_IMR, DM9X_IMRENABLE); - } - - /* Check if there is room in the DM90x0 to hold another packet. In 100M mode, - * that can be 2 packets, otherwise it is a single packet. - */ - - if (dm9x->dm_ntxpending < 1 || (dm9x->dm_b100M && dm9x->dm_ntxpending < 2)) { - /* If so, update TCP timing states and poll uIP for new XMIT data */ - - (void)netif_timer(&dm9x->dm_dev, dm9x_txpoll, DM6X_POLLHSEC); - } - - /* Setup the watchdog poll timer again */ - - (void)wd_start(dm9x->dm_txpoll, DM6X_WDDELAY, dm9x_polltimer, 1, arg); -} - -/**************************************************************************** - * Function: dm9x_phymode - * - * Description: - * Configure the PHY operating mode - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static inline void dm9x_phymode(struct dm9x_driver_s *dm9x) -{ - uint16_t phyreg0; - uint16_t phyreg4; - -#if defined(CONFIG_DM9X_MODE_AUTO) - phyreg0 = 0x1200; /* Auto-negotiation & Restart Auto-negotiation */ - phyreg4 = 0x01e1; /* Default flow control disable */ -#elif defined(CONFIG_DM9X_MODE_10MHD) - phyreg4 = 0x21; - phyreg0 = 0x1000; -#elif defined(CONFIG_DM9X_MODE_10MFD) - phyreg4 = 0x41; - phyreg0 = 0x1100; -#elif defined(CONFIG_DM9X_MODE_100MHD) - phyreg4 = 0x81; - phyreg0 = 0x3000; -#elif defined(CONFIG_DM9X_MODE_100MFD) - phyreg4 = 0x101; - phyreg0 = 0x3100; -#else -#error "Recognized PHY mode" -#endif - - dm9x_phywrite(dm9x, 0, phyreg0); - dm9x_phywrite(dm9x, 4, phyreg4); -} - -/**************************************************************************** - * Function: dm9x_ifup - * - * Description: - * TinyAra Callback: Bring up the DM90x0 interface when an IP address is - * provided - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int dm9x_ifup(struct net_driver_s *dev) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)dev->d_private; - uint8_t netstatus; - int i; - - ndbg("Bringing up: %d.%d.%d.%d\n", dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24); - - /* Initilize DM90x0 chip */ - - dm9x_bringup(dm9x); - - /* Check link state and media speed (waiting up to 3s for link OK) */ - - dm9x->dm_b100M = false; - for (i = 0; i < 3000; i++) { - netstatus = getreg(DM9X_NETS); - if (netstatus & DM9X_NETS_LINKST) { - /* Link OK... Wait a bit before getting the detected speed */ - - up_mdelay(200); - netstatus = getreg(DM9X_NETS); - if ((netstatus & DM9X_NETS_SPEED) == 0) { - dm9x->dm_b100M = true; - } - break; - } - i++; - up_mdelay(1); - } - - ndbg("delay: %dmS speed: %s\n", i, dm9x->dm_b100M ? "100M" : "10M"); - - /* Set and activate a timer process */ - - (void)wd_start(dm9x->dm_txpoll, DM6X_WDDELAY, dm9x_polltimer, 1, (uint32_t)dm9x); - - /* Enable the DM9X interrupt */ - - dm9x->dm_bifup = true; - up_enable_irq(CONFIG_DM9X_IRQ); - return OK; -} - -/**************************************************************************** - * Function: dm9x_ifdown - * - * Description: - * TinyAra Callback: Stop the interface. - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int dm9x_ifdown(struct net_driver_s *dev) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)dev->d_private; - irqstate_t flags; - - ndbg("Stopping\n"); - - /* Disable the DM9X interrupt */ - - flags = irqsave(); - up_disable_irq(CONFIG_DM9X_IRQ); - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(dm9x->dm_txpoll); - wd_cancel(dm9x->dm_txtimeout); - - /* Reset the device */ - - dm9x_phywrite(dm9x, 0x00, 0x8000); /* PHY reset */ - putreg(DM9X_GPD, 0x01); /* Power-down PHY (GEPIO0=1) */ - putreg(DM9X_IMR, DM9X_IMRDISABLE); /* Disable all interrupts */ - putreg(DM9X_RXC, 0x00); /* Disable RX */ - putreg(DM9X_ISR, DM9X_INT_ALL); /* Clear interrupt status */ - - dm9x->dm_bifup = false; - irqrestore(flags); - - /* Dump statistics */ - - dm9x_dumpstatistics(dm9x); - return OK; -} - -/**************************************************************************** - * Function: dm9x_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int dm9x_txavail(struct net_driver_s *dev) -{ - struct dm9x_driver_s *dm9x = (struct dm9x_driver_s *)dev->d_private; - irqstate_t flags; - - ndbg("Polling\n"); - flags = irqsave(); - - /* Ignore the notification if the interface is not yet up */ - - if (dm9x->dm_bifup) { - - /* Check if there is room in the DM90x0 to hold another packet. In 100M - * mode, that can be 2 packets, otherwise it is a single packet. - */ - - if (dm9x->dm_ntxpending < 1 || (dm9x->dm_b100M && dm9x->dm_ntxpending < 2)) { - /* If so, then poll uIP for new XMIT data */ - - (void)netif_poll(&dm9x->dm_dev, dm9x_txpoll); - } - } - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: dm9x_addmac - * - * Description: - * TinyAra Callback: Add the specified MAC address to the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * mac - The MAC address to be added - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int dm9x_addmac(struct net_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - -#warning "Multicast MAC support not implemented" - return OK; -} -#endif - -/**************************************************************************** - * Function: dm9x_rmmac - * - * Description: - * TinyAra Callback: Remove the specified MAC address from the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * mac - The MAC address to be removed - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int dm9x_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct dm9x_driver_s *priv = (FAR struct dm9x_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - -#warning "Multicast MAC support not implemented" - return OK; -} -#endif - -/**************************************************************************** - * Function: dm9x_bringup - * - * Description: - * Initialize the dm90x0 chip - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_bringup(struct dm9x_driver_s *dm9x) -{ - ndbg("Initializing\n"); - - /* Set the internal PHY power-on, GPIOs normal, and wait 2ms */ - - putreg(DM9X_GPD, 0x01); /* Power-down the PHY (GEPIO0=1) */ - up_udelay(500); - putreg(DM9X_GPD, 0x00); /* Preactivate PHY (GPIO0=0 */ - up_udelay(20); /* Wait 20us for PHY power-on ready */ - - /* Do a software reset and wait 20us (twice). The reset autoclears - * in 10us; 20us guarantees completion of the reset - */ - - putreg(DM9X_NETC, (DM9X_NETC_RST | DM9X_NETC_LBK1)); - up_udelay(20); - putreg(DM9X_NETC, (DM9X_NETC_RST | DM9X_NETC_LBK1)); - up_udelay(20); - - /* Configure I/O mode */ - - switch (getreg(DM9X_ISR) & DM9X_ISR_IOMODEM) { - case DM9X_ISR_IOMODE8: - dm9x->dm_read = read8; - dm9x->dm_write = write8; - dm9x->dm_discard = discard8; - break; - - case DM9X_ISR_IOMODE16: - dm9x->dm_read = read16; - dm9x->dm_write = write16; - dm9x->dm_discard = discard16; - break; - - case DM9X_ISR_IOMODE32: - dm9x->dm_read = read32; - dm9x->dm_write = write32; - dm9x->dm_discard = discard32; - break; - - default: - break; - } - - /* Program PHY operating mode */ - - dm9x_phymode(dm9x); - - /* Program operating mode */ - - putreg(DM9X_NETC, 0x00); /* Network control */ - putreg(DM9X_TXC, 0x00); /* Clear TX Polling */ - putreg(DM9X_BPTHRES, 0x3f); /* Less 3kb, 600us */ - putreg(DM9X_SMODEC, 0x00); /* Special mode */ - putreg(DM9X_NETS, (DM9X_NETS_WAKEST | DM9X_NETS_TX1END | DM9X_NETS_TX2END)); /* Clear TX status */ - putreg(DM9X_ISR, DM9X_INT_ALL); /* Clear interrupt status */ - -#if defined(CONFIG_DM9X_CHECKSUM) - putreg(DM9X_TCCR, 0x07); /* TX UDP/TCP/IP checksum enable */ - putreg(DM9X_RCSR, 0x02); /* Receive checksum enable */ -#endif - -#if defined(CONFIG_DM9X_ETRANS) - putreg(DM9X_ETXCSR, 0x83); -#endif - - /* Initialize statistics */ - - dm9x->ncrxpackets = 0; /* Number of continuous RX packets */ - dm9x->dm_ntxpending = 0; /* Number of pending TX packets */ - dm9x_resetstatistics(dm9x); - - /* Activate DM9000A/DM9010 */ - - putreg(DM9X_RXC, DM9X_RXCSETUP | 1); /* RX enable */ - putreg(DM9X_IMR, DM9X_IMRENABLE); /* Enable TX/RX interrupts */ -} - -/**************************************************************************** - * Function: dm9x_reset - * - * Description: - * Stop, reset, re-initialize, and restart the DM90x0 chip and driver. At - * present, the chip is only reset after a TX timeout. - * - * Parameters: - * dm9x - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void dm9x_reset(struct dm9x_driver_s *dm9x) -{ - uint8_t save; - int i; - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(dm9x->dm_txpoll); - wd_cancel(dm9x->dm_txtimeout); - - /* Save previous register address */ - - save = (uint8_t)DM9X_INDEX; - -#if defined(CONFIG_DM9X_STATS) - dm9x->dm_nresets++; -#endif - dm9x_bringup(dm9x); - - /* Wait up to 1 second for the link to be OK */ - - dm9x->dm_b100M = false; - for (i = 0; i < 1000; i++) { - if (dm9x_phyread(dm9x, 0x1) & 0x4) { - if (dm9x_phyread(dm9x, 0) & 0x2000) { - dm9x->dm_b100M = true; - } - break; - } - up_mdelay(1); - } - - /* Restore previous register address */ - - DM9X_INDEX = save; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: dm9x_initialize - * - * Description: - * Initialize the DM90x0 driver - * - * Parameters: - * None - * - * Returned Value: - * OK on success; Negated errno on failure. - * - * Assumptions: - * - ****************************************************************************/ - -/* Initialize the DM90x0 chip and driver */ - -int dm9x_initialize(void) -{ - uint8_t *mptr; - uint16_t vid; - uint16_t pid; - int i; - int j; - - /* Get the chip vendor ID and product ID */ - - vid = (((uint16_t)getreg(DM9X_VIDH)) << 8) | (uint16_t)getreg(DM9X_VIDL); - pid = (((uint16_t)getreg(DM9X_PIDH)) << 8) | (uint16_t)getreg(DM9X_PIDL); - nlldbg("I/O base: %08x VID: %04x PID: %04x\n", CONFIG_DM9X_BASE, vid, pid); - - /* Check if a DM90x0 chip is recognized at this I/O base */ - - if (vid != DM9X_DAVICOMVID || (pid != DM9X_DM9000PID && pid != DM9X_DM9010PID)) { - nlldbg("DM90x0 vendor/product ID not found at this base address\n"); - return -ENODEV; - } - - /* Attach the IRQ to the driver */ - - if (irq_attach(CONFIG_DM9X_IRQ, dm9x_interrupt)) { - /* We could not attach the ISR to the ISR */ - - nlldbg("irq_attach() failed\n"); - return -EAGAIN; - } - - /* Initialize the driver structure */ - - memset(g_dm9x, 0, CONFIG_DM9X_NINTERFACES * sizeof(struct dm9x_driver_s)); - g_dm9x[0].dm_dev.d_ifup = dm9x_ifup; /* I/F down callback */ - g_dm9x[0].dm_dev.d_ifdown = dm9x_ifdown; /* I/F up (new IP address) callback */ - g_dm9x[0].dm_dev.d_txavail = dm9x_txavail; /* New TX data callback */ -#ifdef CONFIG_NET_IGMP - g_dm9x[0].dm_dev.d_addmac = dm9x_addmac; /* Add multicast MAC address */ - g_dm9x[0].dm_dev.d_rmmac = dm9x_rmmac; /* Remove multicast MAC address */ -#endif - g_dm9x[0].dm_dev.d_private = (void *)g_dm9x; /* Used to recover private state from dev */ - - /* Create a watchdog for timing polling for and timing of transmisstions */ - - g_dm9x[0].dm_txpoll = wd_create(); /* Create periodic poll timer */ - g_dm9x[0].dm_txtimeout = wd_create(); /* Create TX timeout timer */ - - /* Read the MAC address */ - - mptr = g_dm9x[0].dm_dev.d_mac.ether_addr_octet; - for (i = 0, j = DM9X_PAB0; i < ETHER_ADDR_LEN; i++, j++) { - mptr[i] = getreg(j); - } - - nlldbg("MAC: %0x:%0x:%0x:%0x:%0x:%0x\n", mptr[0], mptr[1], mptr[2], mptr[3], mptr[4], mptr[5]); - - /* Register the device with the OS so that socket IOCTLs can be performed */ - - (void)netdev_register(&g_dm9x[0].dm_dev, NET_LL_ETHERNET); - return OK; -} - -#endif /* CONFIG_NET && CONFIG_NET_DM90x0 */ diff --git a/os/drivers/net/e1000.c b/os/drivers/net/e1000.c deleted file mode 100644 index 8b55de0..0000000 --- a/os/drivers/net/e1000.c +++ /dev/null @@ -1,1214 +0,0 @@ -/**************************************************************************** - * - * Copyright 2016 Samsung Electronics All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the License. - * - ****************************************************************************/ -/**************************************************************************** - * drivers/net/e1000.c - * - * Copyright (C) 2011 Yu Qiang. All rights reserved. - * Author: Yu Qiang - * - * This file is a part of NuttX: - * - * Copyright (C) 2011, 2014 Gregory Nutt. 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 NuttX nor the names of its 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. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_NET_PKT -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "e1000.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */ - -#define E1000_WDDELAY (1*CLK_TCK) -#define E1000_POLLHSEC (1*2) - -/* TX timeout = 1 minute */ - -#define E1000_TXTIMEOUT (60*CLK_TCK) - -/* This is a helper pointer for accessing the contents of the Ethernet header */ - -#define BUF ((struct eth_hdr_s *)e1000->netdev.d_buf) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct tx_ring { - struct tx_desc *desc; - char *buf; - int tail; /* where to write desc */ -}; - -struct rx_ring { - struct rx_desc *desc; - char *buf; - int head; /* where to read */ - int tail; /* where to release free desc */ - int free; /* number of freed desc */ -}; - -struct e1000_dev { - uint32_t phy_mem_base; - uint32_t io_mem_base; - uint32_t mem_size; - int pci_dev_id; - uint16_t pci_addr; - unsigned char src_mac[6]; - unsigned char dst_mac[6]; - struct irq_action int_desc; - struct tx_ring tx_ring; - struct rx_ring rx_ring; - struct e1000_dev *next; - - /* TinyAra net data */ - - bool bifup; /* true:ifup false:ifdown */ - WDOG_ID txpoll; /* TX poll timer */ - WDOG_ID txtimeout; /* TX timeout timer */ - - /* This holds the information visible to uIP/TinyAra */ - - struct net_driver_s netdev; /* Interface understood by networking layer */ -}; - -struct e1000_dev_head { - struct e1000_dev *next; -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static struct e1000_dev_head e1000_list = { 0 }; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Common TX logic */ - -static int e1000_transmit(struct e1000_dev *e1000); -static int e1000_txpoll(struct net_driver_s *dev); - -/* Interrupt handling */ - -static void e1000_receive(struct e1000_dev *e1000); - -/* Watchdog timer expirations */ - -static void e1000_polltimer(int argc, uint32_t arg, ...); -static void e1000_txtimeout(int argc, uint32_t arg, ...); - -/* TinyAra callback functions */ - -static int e1000_ifup(struct net_driver_s *dev); -static int e1000_ifdown(struct net_driver_s *dev); -static int e1000_txavail(struct net_driver_s *dev); -#ifdef CONFIG_NET_IGMP -static int e1000_addmac(struct net_driver_s *dev, const uint8_t *mac); -static int e1000_rmmac(struct net_driver_s *dev, const uint8_t *mac); -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -static inline void e1000_outl(struct e1000_dev *dev, int reg, uint32_t val) -{ - writel(dev->io_mem_base + reg, val); -} - -static inline uint32_t e1000_inl(struct e1000_dev *dev, int reg) -{ - return readl(dev->io_mem_base + reg); -} - -/****************************** e1000 driver ********************************/ - -void e1000_reset(struct e1000_dev *dev) -{ - uint32_t dev_control; - - /* Reset the network controller hardware */ - - dev_control = 0; - dev_control |= (1 << 0); /* FD-bit (Full Duplex) */ - dev_control |= (0 << 2); /* GIOMD-bit (GIO Master Disable) */ - dev_control |= (1 << 3); /* LRST-bit (Link Reset) */ - dev_control |= (1 << 6); /* SLU-bit (Set Link Up) */ - dev_control |= (2 << 8); /* SPEED=2 (1000Mbps) */ - dev_control |= (0 << 11); /* FRCSPD-bit (Force Speed) */ - dev_control |= (0 << 12); /* FRCDPLX-bit (Force Duplex) */ - dev_control |= (0 << 20); /* ADVD3WUC-bit (Advertise D3 Wake Up Cap) */ - dev_control |= (1 << 26); /* RST-bit (Device Reset) */ - dev_control |= (1 << 27); /* RFCE-bit (Receive Flow Control Enable) */ - dev_control |= (1 << 28); /* TFCE-bit (Transmit Flow Control Enable) */ - dev_control |= (0 << 30); /* VME-bit (VLAN Mode Enable) */ - dev_control |= (0 << 31); /* PHY_RST-bit (PHY Reset) */ - - e1000_outl(dev, E1000_IMC, 0xFFFFFFFF); - e1000_outl(dev, E1000_STATUS, 0x00000000); - e1000_outl(dev, E1000_CTRL, dev_control); - dev_control &= ~(1 << 26); /* clear RST-bit (Device Reset) */ - e1000_outl(dev, E1000_CTRL, dev_control); - up_mdelay(10); - e1000_outl(dev, E1000_CTRL_EXT, 0x001401C0); - e1000_outl(dev, E1000_IMC, 0xFFFFFFFF); -} - -void e1000_turn_on(struct e1000_dev *dev) -{ - int tx_control; - int rx_control; - uint32_t ims = 0; - - /* turn on the controller's receive engine */ - - rx_control = e1000_inl(dev, E1000_RCTL); - rx_control |= (1 << 1); - e1000_outl(dev, E1000_RCTL, rx_control); - - /* turn on the controller's transmit engine */ - - tx_control = e1000_inl(dev, E1000_TCTL); - tx_control |= (1 << 1); - e1000_outl(dev, E1000_TCTL, tx_control); - - /* enable the controller's interrupts */ - - e1000_outl(dev, E1000_ICR, 0xFFFFFFFF); - e1000_outl(dev, E1000_IMC, 0xFFFFFFFF); - - ims |= 1 << 0; /* TXDW */ - ims |= 1 << 1; /* TXQE */ - ims |= 1 << 2; /* LSC */ - ims |= 1 << 4; /* RXDMT0 */ - ims |= 1 << 7; /* RXT0 */ - e1000_outl(dev, E1000_IMS, ims); -} - -void e1000_turn_off(struct e1000_dev *dev) -{ - int tx_control; - int rx_control; - - /* turn off the controller's receive engine */ - - rx_control = e1000_inl(dev, E1000_RCTL); - rx_control &= ~(1 << 1); - e1000_outl(dev, E1000_RCTL, rx_control); - - /* turn off the controller's transmit engine */ - - tx_control = e1000_inl(dev, E1000_TCTL); - tx_control &= ~(1 << 1); - e1000_outl(dev, E1000_TCTL, tx_control); - - /* turn off the controller's interrupts */ - - e1000_outl(dev, E1000_IMC, 0xFFFFFFFF); -} - -void e1000_init(struct e1000_dev *dev) -{ - uint32_t rxd_phys; - uint32_t txd_phys; - uint32_t kmem_phys; - uint32_t rx_control; - uint32_t tx_control; - uint32_t pba; - int i; - - e1000_reset(dev); - - /* configure the controller's 'receive' engine */ - - rx_control = 0; - rx_control |= (0 << 1); /* EN-bit (Enable) */ - rx_control |= (0 << 2); /* SPB-bit (Store Bad Packets) */ - rx_control |= (0 << 3); /* UPE-bit (Unicast Promiscuous Mode) */ - rx_control |= (1 << 4); /* MPE-bit (Multicast Promiscuous Mode) */ - rx_control |= (0 << 5); /* LPE-bit (Long Packet Enable) */ - rx_control |= (0 << 6); /* LBM=0 (Loop-Back Mode) */ - rx_control |= (0 << 8); /* RDMTS=0 (Rx Descriptor Min Threshold Size) */ - rx_control |= (0 << 10); /* DTYPE=0 (Descriptor Type) */ - rx_control |= (0 << 12); /* MO=0 (Multicast Offset) */ - rx_control |= (1 << 15); /* BAM-bit (Broadcast Address Mode) */ - rx_control |= (0 << 16); /* BSIZE=0 (Buffer Size = 2048) */ - rx_control |= (0 << 18); /* VLE-bit (VLAN filter Enable) */ - rx_control |= (0 << 19); /* CFIEN-bit (Canonical Form Indicator Enable) */ - rx_control |= (0 << 20); /* CFI-bit (Canonical Form Indicator) */ - rx_control |= (1 << 22); /* DPF-bit (Discard Pause Frames) */ - rx_control |= (0 << 23); /* PMCF-bit (Pass MAC Control Frames) */ - rx_control |= (0 << 25); /* BSEX=0 (Buffer Size EXtension) */ - rx_control |= (1 << 26); /* SECRC-bit (Strip Ethernet CRC) */ - rx_control |= (0 << 27); /* FLEXBUF=0 (Flexible Buffer size) */ - e1000_outl(dev, E1000_RCTL, rx_control); - - /* configure the controller's 'transmit' engine */ - - tx_control = 0; - tx_control |= (0 << 1); /* EN-bit (Enable) */ - tx_control |= (1 << 3); /* PSP-bit (Pad Short Packets) */ - tx_control |= (15 << 4); /* CT=15 (Collision Threshold) */ - tx_control |= (63 << 12); /* COLD=63 (Collision Distance) */ - tx_control |= (0 << 22); /* SWXOFF-bit (Software XOFF) */ - tx_control |= (1 << 24); /* RTLC-bit (Re-Transmit on Late Collision) */ - tx_control |= (0 << 25); /* UNORTX-bit (Underrun No Re-Transmit) */ - tx_control |= (0 << 26); /* TXCSCMT=0 (TxDesc Mininum Threshold) */ - tx_control |= (0 << 28); /* MULR-bit (Multiple Request Support) */ - e1000_outl(dev, E1000_TCTL, tx_control); - - /* hardware flow control */ - - pba = e1000_inl(dev, E1000_PBA); - - /* get receive FIFO size */ - - pba = (pba & 0x000000ff) << 10; - e1000_outl(dev, E1000_FCAL, 0x00C28001); - e1000_outl(dev, E1000_FCAH, 0x00000100); - e1000_outl(dev, E1000_FCT, 0x00008808); - e1000_outl(dev, E1000_FCTTV, 0x00000680); - e1000_outl(dev, E1000_FCRTL, (pba * 8 / 10) | 0x80000000); - e1000_outl(dev, E1000_FCRTH, pba * 9 / 10); - - /* setup tx rings */ - - txd_phys = PADDR((uintptr_t)dev->tx_ring.desc); - kmem_phys = PADDR((uintptr_t)dev->tx_ring.buf); - for (i = 0; i < CONFIG_E1000_N_TX_DESC; i++, kmem_phys += CONFIG_E1000_BUFF_SIZE) { - dev->tx_ring.desc[i].base_address = kmem_phys; - dev->tx_ring.desc[i].packet_length = 0; - dev->tx_ring.desc[i].cksum_offset = 0; - dev->tx_ring.desc[i].cksum_origin = 0; - dev->tx_ring.desc[i].desc_status = 1; - dev->tx_ring.desc[i].desc_command = (1 << 0) | (1 << 1) | (1 << 3); - dev->tx_ring.desc[i].special_info = 0; - } - - dev->tx_ring.tail = 0; - e1000_outl(dev, E1000_TDT, 0); - e1000_outl(dev, E1000_TDH, 0); - - /* tell controller the location, size, and fetch-policy for Tx queue */ - - e1000_outl(dev, E1000_TDBAL, txd_phys); - e1000_outl(dev, E1000_TDBAH, 0x00000000); - e1000_outl(dev, E1000_TDLEN, CONFIG_E1000_N_TX_DESC * 16); - e1000_outl(dev, E1000_TXDCTL, 0x01010000); - - /* setup rx rings */ - - rxd_phys = PADDR((uintptr_t)dev->rx_ring.desc); - kmem_phys = PADDR((uintptr_t)dev->rx_ring.buf); - for (i = 0; i < CONFIG_E1000_N_RX_DESC; i++, kmem_phys += CONFIG_E1000_BUFF_SIZE) { - dev->rx_ring.desc[i].base_address = kmem_phys; - dev->rx_ring.desc[i].packet_length = 0; - dev->rx_ring.desc[i].packet_cksum = 0; - dev->rx_ring.desc[i].desc_status = 0; - dev->rx_ring.desc[i].desc_errors = 0; - dev->rx_ring.desc[i].vlan_tag = 0; - } - - dev->rx_ring.head = 0; - dev->rx_ring.tail = CONFIG_E1000_N_RX_DESC - 1; - dev->rx_ring.free = 0; - - /* give the controller ownership of all receive descriptors */ - - e1000_outl(dev, E1000_RDH, 0); - e1000_outl(dev, E1000_RDT, CONFIG_E1000_N_RX_DESC - 1); - - /* tell controller the location, size, and fetch-policy for RX queue */ - - e1000_outl(dev, E1000_RDBAL, rxd_phys); - e1000_outl(dev, E1000_RDBAH, 0x00000000); - e1000_outl(dev, E1000_RDLEN, CONFIG_E1000_N_RX_DESC * 16); - e1000_outl(dev, E1000_RXDCTL, 0x01010000); - - e1000_turn_on(dev); -} - -/**************************************************************************** - * Function: e1000_transmit - * - * Description: - * Start hardware transmission. Called either from the txdone interrupt - * handling or from watchdog based polling. - * - * Parameters: - * e1000 - Reference to the driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. - * - ****************************************************************************/ - -static int e1000_transmit(struct e1000_dev *e1000) -{ - int tail = e1000->tx_ring.tail; - unsigned char *cp = (unsigned char *) - (e1000->tx_ring.buf + tail * CONFIG_E1000_BUFF_SIZE); - int count = e1000->netdev.d_len; - - /* Verify that the hardware is ready to send another packet. If we get - * here, then we are committed to sending a packet; Higher level logic - * must have assured that there is not transmission in progress. - */ - - if (!e1000->tx_ring.desc[tail].desc_status) { - return -1; - } - - /* Increment statistics */ - - /* Send the packet: address=skel->sk_dev.d_buf, length=skel->sk_dev.d_len */ - - memcpy(cp, e1000->netdev.d_buf, e1000->netdev.d_len); - - /* prepare the transmit-descriptor */ - - e1000->tx_ring.desc[tail].packet_length = count < 60 ? 60 : count; - e1000->tx_ring.desc[tail].desc_status = 0; - - /* give ownership of this descriptor to the network controller */ - - tail = (tail + 1) % CONFIG_E1000_N_TX_DESC; - e1000->tx_ring.tail = tail; - e1000_outl(e1000, E1000_TDT, tail); - - /* Enable Tx interrupts */ - - /* Setup the TX timeout watchdog (perhaps restarting the timer) */ - - wd_start(e1000->txtimeout, E1000_TXTIMEOUT, e1000_txtimeout, 1, (uint32_t)e1000); - return OK; -} - -/**************************************************************************** - * Function: e1000_txpoll - * - * Description: - * The transmitter is available, check if uIP has any outgoing packets ready - * to send. This is a callback from netif_poll(). netif_poll() may be called: - * - * 1. When the preceding TX packet send is complete, - * 2. When the preceding TX packet send timesout and the interface is reset - * 3. During normal TX polling - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. - * - ****************************************************************************/ - -static int e1000_txpoll(struct net_driver_s *dev) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private; - int tail = e1000->tx_ring.tail; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - if (e1000->netdev.d_len > 0) { - /* Look up the destination MAC address and add it to the Ethernet - * header. - */ - -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - if (IFF_IS_IPv4(e1000->netdev.d_flags)) -#endif - { - arp_out(&e1000->netdev); - } -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else -#endif - { - neighbor_out(&e1000->netdev); - } -#endif /* CONFIG_NET_IPv6 */ - - /* Send the packet */ - - e1000_transmit(e1000); - - /* Check if there is room in the device to hold another packet. If not, - * return a non-zero value to terminate the poll. - */ - - if (!e1000->tx_ring.desc[tail].desc_status) { - return -1; - } - } - - /* If zero is returned, the polling will continue until all connections have - * been examined. - */ - - return 0; -} - -/**************************************************************************** - * Function: e1000_receive - * - * Description: - * An interrupt was received indicating the availability of a new RX packet - * - * Parameters: - * e1000 - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by interrupt handling logic. - * - ****************************************************************************/ - -static void e1000_receive(struct e1000_dev *e1000) -{ - int head = e1000->rx_ring.head; - unsigned char *cp = (unsigned char *) - (e1000->rx_ring.buf + head * CONFIG_E1000_BUFF_SIZE); - int cnt; - - while (e1000->rx_ring.desc[head].desc_status) { - /* Check for errors and update statistics */ - - /* Here we do not handle packets that exceed packet-buffer size */ - - if ((e1000->rx_ring.desc[head].desc_status & 3) == 1) { - cprintf("NIC READ: Oversized packet\n"); - goto next; - } - - /* Check if the packet is a valid size for the uIP buffer configuration */ - - /* get the number of actual data-bytes in this packet */ - - cnt = e1000->rx_ring.desc[head].packet_length; - - if (cnt > CONFIG_NET_ETH_MTU || cnt < 14) { - cprintf("NIC READ: invalid package size\n"); - goto next; - } - - /* Copy the data data from the hardware to e1000->netdev.d_buf. Set - * amount of data in e1000->netdev.d_len - */ - - /* now we try to copy these data-bytes to the UIP buffer */ - - memcpy(e1000->netdev.d_buf, cp, cnt); - e1000->netdev.d_len = cnt; - -#ifdef CONFIG_NET_PKT - /* When packet sockets are enabled, feed the frame into the packet tap */ - - pkt_input(&e1000->netdev); -#endif - - /* We only accept IP packets of the configured type and ARP packets */ - -#ifdef CONFIG_NET_IPv4 - if (BUF->type == HTONS(ETHTYPE_IP)) { - nllvdbg("IPv4 frame\n"); - - /* Handle ARP on input then give the IPv4 packet to the network - * layer - */ - - arp_ipin(&e1000->netdev); - ipv4_input(&e1000->netdev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (e1000->netdev.d_len > 0) { - /* Update the Ethernet header with the correct MAC address */ - -#ifdef CONFIG_NET_IPv6 - if (IFF_IS_IPv4(e1000->netdev.d_flags)) -#endif - { - arp_out(&e1000->netdev); - } -#ifdef CONFIG_NET_IPv6 - else { - neighbor_out(&e1000->netdev); - } -#endif - - /* And send the packet */ - - e1000_transmit(e1000); - } - } else -#endif -#ifdef CONFIG_NET_IPv6 - if (BUF->type == HTONS(ETHTYPE_IP6)) { - nllvdbg("Iv6 frame\n"); - - /* Give the IPv6 packet to the network layer */ - - ipv6_input(&e1000->netdev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (e1000->netdev.d_len > 0) { - /* Update the Ethernet header with the correct MAC address */ - -#ifdef CONFIG_NET_IPv4 - if (IFF_IS_IPv4(e1000->netdev.d_flags)) { - arp_out(&e1000->netdev); - } else -#endif -#ifdef CONFIG_NET_IPv6 - { - neighbor_out(&e1000->netdev); - } -#endif - - /* And send the packet */ - - e1000_transmit(e1000); - } - } else -#endif -#ifdef CONFIG_NET_ARP - if (BUF->type == htons(ETHTYPE_ARP)) { - arp_arpin(&e1000->netdev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (e1000->netdev.d_len > 0) { - e1000_transmit(e1000); - } -#endif - } - -next: - e1000->rx_ring.desc[head].desc_status = 0; - e1000->rx_ring.head = (head + 1) % CONFIG_E1000_N_RX_DESC; - e1000->rx_ring.free++; - head = e1000->rx_ring.head; - cp = (unsigned char *)(e1000->rx_ring.buf + head * CONFIG_E1000_BUFF_SIZE); - } -} - -/**************************************************************************** - * Function: e1000_txtimeout - * - * Description: - * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Reset the hardware and start again. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void e1000_txtimeout(int argc, uint32_t arg, ...) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)arg; - - /* Increment statistics and dump debug info */ - - /* Then reset the hardware */ - - e1000_init(e1000); - - /* Then poll uIP for new XMIT data */ - - (void)netif_poll(&e1000->netdev, e1000_txpoll); -} - -/**************************************************************************** - * Function: e1000_polltimer - * - * Description: - * Periodic timer handler. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void e1000_polltimer(int argc, uint32_t arg, ...) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)arg; - int tail = e1000->tx_ring.tail; - - /* Check if there is room in the send another TX packet. We cannot perform - * the TX poll if he are unable to accept another packet for transmission. - */ - - if (!e1000->tx_ring.desc[tail].desc_status) { - return; - } - - /* If so, update TCP timing states and poll uIP for new XMIT data. Hmmm.. - * might be bug here. Does this mean if there is a transmit in progress, - * we will missing TCP time state updates? - */ - - (void)netif_timer(&e1000->netdev, e1000_txpoll, E1000_POLLHSEC); - - /* Setup the watchdog poll timer again */ - - (void)wd_start(e1000->txpoll, E1000_WDDELAY, e1000_polltimer, 1, arg); -} - -/**************************************************************************** - * Function: e1000_ifup - * - * Description: - * TinyAra Callback: Bring up the Ethernet interface when an IP address is - * provided - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int e1000_ifup(struct net_driver_s *dev) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private; - - ndbg("Bringing up: %d.%d.%d.%d\n", dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24); - - /* Initialize PHYs, the Ethernet interface, and setup up Ethernet interrupts */ - - e1000_init(e1000); - - /* Set and activate a timer process */ - - (void)wd_start(e1000->txpoll, E1000_WDDELAY, e1000_polltimer, 1, (uint32_t)e1000); - - if (e1000_inl(e1000, E1000_STATUS) & 2) { - e1000->bifup = true; - } else { - e1000->bifup = false; - } - - return OK; -} - -/**************************************************************************** - * Function: e1000_ifdown - * - * Description: - * TinyAra Callback: Stop the interface. - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int e1000_ifdown(struct net_driver_s *dev) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private; - irqstate_t flags; - - /* Disable the Ethernet interrupt */ - - flags = irqsave(); - - e1000_turn_off(e1000); - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(e1000->txpoll); - wd_cancel(e1000->txtimeout); - - /* Put the EMAC is its reset, non-operational state. This should be - * a known configuration that will guarantee the skel_ifup() always - * successfully brings the interface back up. - */ - - //e1000_reset(e1000); - - /* Mark the device "down" */ - - e1000->bifup = false; - irqrestore(flags); - - return OK; -} - -/**************************************************************************** - * Function: e1000_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int e1000_txavail(struct net_driver_s *dev) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev->d_private; - int tail = e1000->tx_ring.tail; - irqstate_t flags; - - /* Disable interrupts because this function may be called from interrupt - * level processing. - */ - - flags = irqsave(); - - /* Ignore the notification if the interface is not yet up */ - - if (e1000->bifup) { - /* Check if there is room in the hardware to hold another outgoing packet. */ - - if (e1000->tx_ring.desc[tail].desc_status) { - (void)netif_poll(&e1000->netdev, e1000_txpoll); - } - } - - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: e1000_addmac - * - * Description: - * TinyAra Callback: Add the specified MAC address to the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * mac - The MAC address to be added - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int e1000_addmac(struct net_driver_s *dev, const uint8_t *mac) -{ - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -/**************************************************************************** - * Function: e1000_rmmac - * - * Description: - * TinyAra Callback: Remove the specified MAC address from the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * mac - The MAC address to be removed - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int e1000_rmmac(struct net_driver_s *dev, const uint8_t *mac) -{ - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -static irqreturn_t e1000_interrupt_handler(int irq, void *dev_id) -{ - struct e1000_dev *e1000 = (struct e1000_dev *)dev_id; - - /* Get and clear interrupt status bits */ - - int intr_cause = e1000_inl(e1000, E1000_ICR); - e1000_outl(e1000, E1000_ICR, intr_cause); - - /* not for me */ - - if (intr_cause == 0) { - return IRQ_NONE; - } - - /* Handle interrupts according to status bit settings */ - - /* Link status change */ - - if (intr_cause & (1 << 2)) { - if (e1000_inl(e1000, E1000_STATUS) & 2) { - e1000->bifup = true; - } else { - e1000->bifup = false; - } - } - - /* Check if we received an incoming packet, if so, call skel_receive() */ - - /* Rx-descriptor Timer expired */ - - if (intr_cause & (1 << 7)) { - e1000_receive(e1000); - } - - /* Tx queue empty */ - - if (intr_cause & (1 << 1)) { - wd_cancel(e1000->txtimeout); - } - - /* Check is a packet transmission just completed. If so, call skel_txdone. - * This may disable further Tx interrupts if there are no pending - * tansmissions. - */ - - /* Tx-descriptor Written back */ - - if (intr_cause & (1 << 0)) { - netif_poll(&e1000->netdev, e1000_txpoll); - } - - /* Rx-Descriptors Low */ - - if (intr_cause & (1 << 4)) { - int tail; - - tail = e1000->rx_ring.tail + e1000->rx_ring.free; - tail %= CONFIG_E1000_N_RX_DESC; - e1000->rx_ring.tail = tail; - e1000->rx_ring.free = 0; - e1000_outl(e1000, E1000_RDT, tail); - } - - return IRQ_HANDLED; -} - -/******************************* PCI driver *********************************/ - -static pci_id_t e1000_id_table[] = { - {.sep = {INTEL_VENDERID, E1000_82573L} }, - {.sep = {INTEL_VENDERID, E1000_82540EM} }, - {.sep = {INTEL_VENDERID, E1000_82574L} }, - {.sep = {INTEL_VENDERID, E1000_82567LM} }, - {.sep = {INTEL_VENDERID, E1000_82541PI} }, - {.sep = {0, 0} } -}; - -static int e1000_probe(uint16_t addr, pci_id_t id) -{ - uint32_t mmio_base, mmio_size; - uint32_t size; - int err; - void *kmem; - void *omem; - struct e1000_dev *dev; - - /* alloc e1000_dev memory */ - - if ((dev = kmm_zalloc(sizeof(struct e1000_dev))) == NULL) { - return -1; - } - - /* save pci addr */ - - dev->pci_addr = addr; - - /* enable device */ - - if ((err = pci_enable_device(addr, PCI_BUS_MASTER)) < 0) { - goto error; - } - - /* get e1000 device type */ - - dev->pci_dev_id = id.join; - - /* remap the controller's i/o-memory into kernel's address-space */ - - mmio_base = pci_resource_start(addr, 0); - mmio_size = pci_resource_len(addr, 0); - err = rgmp_memmap_nocache(mmio_base, mmio_size, mmio_base); - if (err) { - goto error; - } - - dev->phy_mem_base = mmio_base; - dev->io_mem_base = mmio_base; - dev->mem_size = mmio_size; - - /* MAC address */ - - memset(dev->dst_mac, 0xFF, 6); - memcpy(dev->src_mac, (void *)(dev->io_mem_base + E1000_RA), 6); - - /* IRQ setup */ - - dev->int_desc.handler = e1000_interrupt_handler; - dev->int_desc.dev_id = dev; - if ((err = pci_request_irq(addr, &dev->int_desc, 0)) < 0) { - goto err0; - } - - /* Here we alloc a big block of memory once and make it - * aligned to page boundary and multiple of page size. This - * is because the memory can be modified by E1000 DMA and - * should be mapped no-cache which will hugely reduce memory - * access performance. The page size alloc will restrict - * this bad effect only within the memory we alloc here. - * - * NEED FIX: the memalign may alloc memory continous in - * virtual address but dis-continous in physical address - * due to RGMP memory setup. - */ - - size = CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc) + CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE + CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc) + CONFIG_E1000_N_RX_DESC * CONFIG_E1000_BUFF_SIZE; - size = ROUNDUP(size, PGSIZE); - omem = kmem = memalign(PGSIZE, size); - if (kmem == NULL) { - err = -ENOMEM; - goto err1; - } - - rgmp_memremap_nocache((uintptr_t)kmem, size); - - /* alloc memory for tx ring */ - - dev->tx_ring.desc = (struct tx_desc *)kmem; - kmem += CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc); - dev->tx_ring.buf = kmem; - kmem += CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE; - - /* alloc memory for rx rings */ - - dev->rx_ring.desc = (struct rx_desc *)kmem; - kmem += CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc); - dev->rx_ring.buf = kmem; - - /* Initialize the driver structure */ - - dev->netdev.d_ifup = e1000_ifup; /* I/F up (new IP address) callback */ - dev->netdev.d_ifdown = e1000_ifdown; /* I/F down callback */ - dev->netdev.d_txavail = e1000_txavail; /* New TX data callback */ -#ifdef CONFIG_NET_IGMP - dev->netdev.d_addmac = e1000_addmac; /* Add multicast MAC address */ - dev->netdev.d_rmmac = e1000_rmmac; /* Remove multicast MAC address */ -#endif - dev->netdev.d_private = dev; /* Used to recover private state from dev */ - - /* Create a watchdog for timing polling for and timing of transmisstions */ - - dev->txpoll = wd_create(); /* Create periodic poll timer */ - dev->txtimeout = wd_create(); /* Create TX timeout timer */ - - /* Put the interface in the down state. - * e1000 reset - */ - - e1000_reset(dev); - - /* Read the MAC address from the hardware */ - - memcpy(dev->netdev.d_mac.ether_addr_octet, (void *)(dev->io_mem_base + E1000_RA), 6); - - /* Register the device with the OS so that socket IOCTLs can be performed */ - - err = netdev_register(&dev->netdev, NET_LL_ETHERNET); - if (err) { - goto err2; - } - - /* insert into e1000_list */ - - dev->next = e1000_list.next; - e1000_list.next = dev; - cprintf("bring up e1000 device: %04x %08x\n", addr, id.join); - - return 0; - -err2: - rgmp_memremap((uintptr_t)omem, size); - free(omem); -err1: - pci_free_irq(addr); -err0: - rgmp_memunmap(mmio_base, mmio_size); -error: - kmm_free(dev); - cprintf("e1000 device probe fail: %d\n", err); - return err; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -void e1000_mod_init(void) -{ - pci_probe_device(e1000_id_table, e1000_probe); -} - -void e1000_mod_exit(void) -{ - uint32_t size; - struct e1000_dev *dev; - - size = CONFIG_E1000_N_TX_DESC * sizeof(struct tx_desc) + CONFIG_E1000_N_TX_DESC * CONFIG_E1000_BUFF_SIZE + CONFIG_E1000_N_RX_DESC * sizeof(struct rx_desc) + CONFIG_E1000_N_RX_DESC * CONFIG_E1000_BUFF_SIZE; - size = ROUNDUP(size, PGSIZE); - - for (dev = e1000_list.next; dev != NULL; dev = dev->next) { - netdev_unregister(&dev->netdev); - e1000_reset(dev); - wd_delete(dev->txpoll); - wd_delete(dev->txtimeout); - rgmp_memremap((uintptr_t)dev->tx_ring.desc, size); - free(dev->tx_ring.desc); - pci_free_irq(dev->pci_addr); - rgmp_memunmap((uintptr_t)dev->io_mem_base, dev->mem_size); - kmm_free(dev); - } - - e1000_list.next = NULL; -} diff --git a/os/drivers/net/e1000.h b/os/drivers/net/e1000.h deleted file mode 100644 index e04a215..0000000 --- a/os/drivers/net/e1000.h +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************** - * - * Copyright 2016 Samsung Electronics All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the License. - * - ****************************************************************************/ -/**************************************************************************** - * drivers/net/e1000.h - * - * Copyright (C) 2011 Yu Qiang. All rights reserved. - * Author: Yu Qiang - * - * This file is a part of NuttX: - * - * Copyright (C) 2011 Gregory Nutt. 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 NuttX nor the names of its 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. - * - ****************************************************************************/ - -#ifndef __DRIVERS_NET_E1000_H -#define __DRIVERS_NET_E1000_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/************** PCI ID ***************/ - -#define INTEL_VENDERID 0x8086 -#define E1000_82573L 0x109a -#define E1000_82540EM 0x100e -#define E1000_82574L 0x10d3 -#define E1000_82567LM 0x10f5 -#define E1000_82541PI 0x107c - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -enum e1000_registers { - E1000_CTRL = 0x0000, // Device Control - E1000_STATUS = 0x0008, // Device Status - E1000_CTRL_EXT = 0x0018, // Device Control Extension - E1000_FCAL = 0x0028, // Flow Control Address Low - E1000_FCAH = 0x002C, // Flow Control Address High - E1000_FCT = 0x0030, // Flow Control Type - E1000_ICR = 0x00C0, // Interrupt Cause Read - E1000_ICS = 0x00C8, // Interrupt Cause Set - E1000_IMS = 0x00D0, // Interrupt Mask Set - E1000_IMC = 0x00D8, // Interrupt Mask Clear - E1000_RCTL = 0x0100, // Receive Control - E1000_FCTTV = 0x0170, // Flow Control Transmit Timer Value - E1000_TCTL = 0x0400, // Transmit Control - E1000_PBA = 0x1000, // Packet Buffer Allocation - E1000_FCRTL = 0x2160, // Flow Control Receive Threshold Low - E1000_FCRTH = 0x2168, // Flow Control Receive Threshold High - E1000_RDBAL = 0x2800, // Rx Descriptor Base Address Low - E1000_RDBAH = 0x2804, // Rx Descriptor Base Address High - E1000_RDLEN = 0x2808, // Rx Descriptor Length - E1000_RDH = 0x2810, // Rx Descriptor Head - E1000_RDT = 0x2818, // Rx Descriptor Tail - E1000_RXDCTL = 0x2828, // Rx Descriptor Control - E1000_TDBAL = 0x3800, // Tx Descriptor Base Address Low - E1000_TDBAH = 0x3804, // Tx Descriptor Base Address High - E1000_TDLEN = 0x3808, // Tx Descriptor Length - E1000_TDH = 0x3810, // Tx Descriptor Head - E1000_TDT = 0x3818, // Tx Descriptor Tail - E1000_TXDCTL = 0x3828, // Tx Descriptor Control - E1000_TPR = 0x40D0, // Total Packets Received - E1000_TPT = 0x40D4, // Total Packets Transmitted - E1000_RA = 0x5400, // Receive-filter Array -}; - -/***************** e1000 device structure *****************/ - -struct tx_desc { - uint64_t base_address; - uint16_t packet_length; - uint8_t cksum_offset; - uint8_t desc_command; - uint8_t desc_status; - uint8_t cksum_origin; - uint16_t special_info; -}; - -struct rx_desc { - uint64_t base_address; - uint16_t packet_length; - uint16_t packet_cksum; - uint8_t desc_status; - uint8_t desc_errors; - uint16_t vlan_tag; -}; - -#endif diff --git a/os/drivers/net/encx24j600.c b/os/drivers/net/encx24j600.c deleted file mode 100644 index 008aa20..0000000 --- a/os/drivers/net/encx24j600.c +++ /dev/null @@ -1,2889 +0,0 @@ -/**************************************************************************** - * - * Copyright 2016 Samsung Electronics All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the License. - * - ****************************************************************************/ -/**************************************************************************** - * drivers/net/encx24j600.c - * - * Copyright (C) 2013-2014 UVC Ingenieure. All rights reserved. - * Author: Max Holtzberg - * - * References: - * - ENC424J600/624J600 Data Sheet, Stand-Alone 10/100 Ethernet Controller - * with SPI or Parallel Interface, DS39935C, 2010 Microchip Technology Inc. - * - * Derived from enc28j60 driver written by: - * - * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * 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 NuttX nor the names of its 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. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#if defined(CONFIG_NET) && defined(CONFIG_ENCX24J600) - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_NET_PKT -#include -#endif - -#include "encx24j600.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* Configuration ************************************************************/ - -/* ENCX24J600 Configuration Settings: - * - * CONFIG_ENCX24J600 - Enabled ENCX24J600 support - * CONFIG_ENCX24J600_SPIMODE - Controls the SPI mode - * CONFIG_ENCX24J600_FREQUENCY - Define to use a different bus frequency - * CONFIG_ENCX24J600_NINTERFACES - Specifies the number of physical ENCX24J600 - * devices that will be supported. - * CONFIG_ENCX24J600_STATS - Collect network statistics - */ - -/* The ENCX24J600 spec says that it supports SPI mode 0,0 only: "The - * implementation used on this device supports SPI mode 0,0 only. In - * addition, the SPI port requires that SCK be at Idle in a low state; - * selectable clock polarity is not supported." However, sometimes you - * need to tinker with these things. - */ - -#ifndef CONFIG_ENCX24J600_SPIMODE -#define CONFIG_ENCX24J600_SPIMODE SPIDEV_MODE0 -#endif - -/* CONFIG_ENCX24J600_NINTERFACES determines the number of physical interfaces - * that will be supported. - */ - -#ifndef CONFIG_ENCX24J600_NINTERFACES -#define CONFIG_ENCX24J600_NINTERFACES 1 -#endif - -/* CONFIG_NET_ETH_MTU must always be defined */ - -#if !defined(CONFIG_NET_ETH_MTU) && (CONFIG_NET_ETH_MTU <= MAX_FRAMELEN) -#error "CONFIG_NET_ETH_MTU is not valid for the ENCX24J600" -#endif - -/* We need to have the work queue to handle SPI interrupts */ - -#ifndef CONFIG_SCHED_WORKQUEUE -#error "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)" -#endif - -/* CONFIG_ENCX24J600_DUMPPACKET will dump the contents of each packet to the console. */ - -#ifdef CONFIG_ENCX24J600_DUMPPACKET -#define enc_dumppacket(m, a, n) lib_dumpbuffer(m, a, n) -#else -#define enc_dumppacket(m, a, n) -#endif - -/* The ENCX24J600 will not do interrupt level processing */ - -#ifndef CONFIG_NET_NOINTS -#warning "CONFIG_NET_NOINTS should be set" -#endif - -/* Low-level register debug */ - -#if !defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_NET) -#undef CONFIG_ENCX24J600_REGDEBUG -#endif - -/* Timing *******************************************************************/ - -/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */ - -#define ENC_WDDELAY (1*CLK_TCK) -#define ENC_POLLHSEC (1*2) - -/* TX timeout = 1 minute */ - -#define ENC_TXTIMEOUT (60*CLK_TCK) - -/* RX timeout (Time packets are held in the RX queue until they are dropped) */ - -#define ENC_RXTIMEOUT MSEC2TICK(2000) - -/* Poll timeout */ - -#define ENC_POLLTIMEOUT MSEC2TICK(50) - -/* Register poll timeout */ - -#define ENC_REGPOLLTIMEOUT MSEC2TICK(5000) - -/* Packet Memory ************************************************************/ - -/* Packet memory layout */ - -#define PKTMEM_ALIGNED_BUFSIZE ((CONFIG_NET_ETH_MTU + 1) & ~1) -#define PKTMEM_RX_START (PKTMEM_START + PKTMEM_SIZE / 2) /* Followed by RX buffer */ -#define PKTMEM_RX_SIZE (PKTMEM_SIZE - PKTMEM_RX_START) -#define PKTMEM_RX_END (PKTMEM_START + PKTMEM_SIZE) /* RX buffer goes to the end of SRAM */ - -/* We use preinitialized TX descriptors */ - -#define ENC_NTXDESCR ((PKTMEM_RX_START - PKTMEM_START) / PKTMEM_ALIGNED_BUFSIZE) - -/* This is a helper pointer for accessing the contents of the Ethernet header */ - -#define BUF ((struct eth_hdr_s *)priv->dev.d_buf) - -/* Debug ********************************************************************/ - -#ifdef CONFIG_ENCX24J600_REGDEBUG -#define enc_wrdump(a, v) \ - lowsyslog(LOG_DEBUG, "ENCX24J600: %02x<-%04x\n", a, v); -#define enc_rddump(a, v) \ - lowsyslog(LOG_DEBUG, "ENCX24J600: %02x->%04x\n", a, v); -#define enc_bfsdump(a, m) \ - lowsyslog(LOG_DEBUG, "ENCX24J600: %02x|=%04x\n", a, m); -#define enc_bfcdump(a, m) \ - lowsyslog(LOG_DEBUG, "ENCX24J600: %02x&=~%04x\n", a, m); -#define enc_cmddump(c) \ - lowsyslog(LOG_DEBUG, "ENCX24J600: CMD: %02x\n", c); -#define enc_bmdump(c, b, s) \ - lowsyslog(LOG_DEBUG, "ENCX24J600: CMD: %02x buffer: %p length: %d\n", c, b, s); -#else -#define enc_wrdump(a, v) -#define enc_rddump(a, v) -#define enc_bfsdump(a, m) -#define enc_bfcdump(a, m) -#define enc_cmddump(c) -#define enc_bmdump(c, b, s) -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* The state of the interface */ - -enum enc_state_e { - ENCSTATE_UNINIT = 0, /* The interface is in an uninitialized state */ - ENCSTATE_DOWN, /* The interface is down */ - ENCSTATE_UP, /* The interface is up */ - ENCSTATE_RUNNING /* The interface is has a cable plugged in and is ready to use */ -}; - -struct enc_descr_s { - struct enc_descr_next *flink; - uint16_t addr; - uint16_t len; - systime_t ts; /* Timestamp of reception for timeout */ -}; - -/* The enc_driver_s encapsulates all state information for a single hardware - * interface - */ - -struct enc_driver_s { - /* Device control */ - - uint8_t ifstate; /* Interface state: See ENCSTATE_* */ - uint8_t bank; /* Currently selected bank command */ - uint16_t nextpkt; /* Next packet address */ - FAR const struct enc_lower_s *lower; /* Low-level MCU-specific support */ - - /* Timing */ - - WDOG_ID txpoll; /* TX poll timer */ - WDOG_ID txtimeout; /* TX timeout timer */ - - /* If we don't own the SPI bus, then we cannot do SPI accesses from the - * interrupt handler. - */ - - struct work_s irqwork; /* Interrupt continuation work queue support */ - struct work_s towork; /* Tx timeout work queue support */ - struct work_s pollwork; /* Poll timeout work queue support */ - - struct enc_descr_s txdescralloc[ENC_NTXDESCR]; - struct enc_descr_s rxdescralloc[CONFIG_ENCX24J600_NRXDESCR]; - - sq_queue_t txfreedescr; /* Free inititialized TX descriptors */ - sq_queue_t rxfreedescr; /* Free RX descriptors */ - sq_queue_t txqueue; /* Enqueued descriptors waiting for transmition */ - sq_queue_t rxqueue; /* Unhandled incoming packets waiting for reception */ - - /* This is the contained SPI driver intstance */ - - FAR struct spi_dev_s *spi; - - /* This holds the information visible to uIP/NuttX */ - - struct net_driver_s dev; /* Interface understood by uIP */ - - /* Statistics */ - -#ifdef CONFIG_ENCX24J600_STATS - struct enc_stats_s stats; -#endif -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static struct enc_driver_s g_encx24j600[CONFIG_ENCX24J600_NINTERFACES]; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Low-level SPI helpers */ - -#ifdef CONFIG_SPI_OWNBUS -static inline void enc_configspi(FAR struct spi_dev_s *spi); -#define enc_lock(priv); -#define enc_unlock(priv); -#else -#define enc_configspi(spi) -static void enc_lock(FAR struct enc_driver_s *priv); -static inline void enc_unlock(FAR struct enc_driver_s *priv); -#endif - -/* SPI control register access */ - -static inline void enc_setethrst(FAR struct enc_driver_s *priv); -static void enc_setbank(FAR struct enc_driver_s *priv, uint8_t bank); -static uint16_t enc_rdreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg); -static void enc_wrreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg, uint16_t wrdata); -static int enc_waitreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg, uint16_t bits, uint16_t value); -static void enc_bfs(FAR struct enc_driver_s *priv, uint16_t ctrlreg, uint16_t bits); -static void enc_bfc(FAR struct enc_driver_s *priv, uint16_t ctrlreg, uint16_t bits); -static void enc_cmd(FAR struct enc_driver_s *priv, uint8_t cmd, uint16_t arg); - -#if 0 /* Sometimes useful */ -static void enc_rxdump(FAR struct enc_driver_s *priv); -static void enc_txdump(FAR struct enc_driver_s *priv); -#endif - -/* SPI buffer transfers */ - -static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer, size_t buflen); -static inline void enc_wrbuffer(FAR struct enc_driver_s *priv, FAR const uint8_t *buffer, size_t buflen); - -/* PHY register access */ - -static uint16_t enc_rdphy(FAR struct enc_driver_s *priv, uint8_t phyaddr); -static void enc_wrphy(FAR struct enc_driver_s *priv, uint8_t phyaddr, uint16_t phydata); - -/* Common TX logic */ - -static int enc_txenqueue(FAR struct enc_driver_s *priv); -static int enc_transmit(FAR struct enc_driver_s *priv); -static int enc_txpoll(struct net_driver_s *dev); - -/* Common RX logic */ - -static struct enc_descr_s *enc_rxgetdescr(FAR struct enc_driver_s *priv); -static void enc_rxldpkt(FAR struct enc_driver_s *priv, struct enc_descr_s *descr); -static void enc_rxrmpkt(FAR struct enc_driver_s *priv, struct enc_descr_s *descr); -static void enc_rxdispatch(FAR struct enc_driver_s *priv); - -/* Interrupt handling */ - -static void enc_linkstatus(FAR struct enc_driver_s *priv); -static void enc_txif(FAR struct enc_driver_s *priv); -static void enc_pktif(FAR struct enc_driver_s *priv); -static void enc_rxabtif(FAR struct enc_driver_s *priv); -static void enc_irqworker(FAR void *arg); -static int enc_interrupt(int irq, FAR void *context); - -/* Watchdog timer expirations */ - -static void enc_toworker(FAR void *arg); -static void enc_txtimeout(int argc, uint32_t arg, ...); -static void enc_pollworker(FAR void *arg); -static void enc_polltimer(int argc, uint32_t arg, ...); - -/* TinyAra callback functions */ - -static int enc_ifup(struct net_driver_s *dev); -static int enc_ifdown(struct net_driver_s *dev); -static int enc_txavail(struct net_driver_s *dev); -static int enc_rxavail(struct net_driver_s *dev); -#ifdef CONFIG_NET_IGMP -static int enc_addmac(struct net_driver_s *dev, FAR const uint8_t *mac); -static int enc_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac); -#endif - -/* Initialization */ - -static void enc_pwrsave(FAR struct enc_driver_s *priv); -static void enc_setmacaddr(FAR struct enc_driver_s *priv); -static void enc_resetbuffers(FAR struct enc_driver_s *priv); -static int enc_reset(FAR struct enc_driver_s *priv); - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: enc_configspi - * - * Description: - * Configure the SPI for use with the ENCX24J600 - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void enc_configspi(FAR struct spi_dev_s *spi) -{ - /* Configure SPI for the ENCX24J600. But only if we own the SPI bus. - * Otherwise, don't bother because it might change. - */ - - SPI_SETMODE(spi, CONFIG_ENCX24J600_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_ENCX24J600_FREQUENCY); -} -#endif - -/**************************************************************************** - * Function: enc_lock - * - * Description: - * Select the SPI, locking and re-configuring if necessary - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static void enc_lock(FAR struct enc_driver_s *priv) -{ - /* Lock the SPI bus in case there are multiple devices competing for the SPI - * bus. - */ - - SPI_LOCK(priv->spi, true); - - /* Now make sure that the SPI bus is configured for the ENCX24J600 (it - * might have gotten configured for a different device while unlocked) - */ - - SPI_SETMODE(priv->spi, CONFIG_ENCX24J600_SPIMODE); - SPI_SETBITS(priv->spi, 8); - SPI_SETFREQUENCY(priv->spi, CONFIG_ENCX24J600_FREQUENCY); -} -#endif - -/**************************************************************************** - * Function: enc_unlock - * - * Description: - * De-select the SPI - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static inline void enc_unlock(FAR struct enc_driver_s *priv) -{ - /* Relinquish the lock on the bus. */ - - SPI_LOCK(priv->spi, false); -} -#endif - -/**************************************************************************** - * Function: enc_cmd - * - * Description: - * Execute two byte command. - * - * Parameters: - * priv - Reference to the driver state structure - * cmd - ENCX24J600 two-byte command - * arg - Two byte argument to the command - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_cmd(FAR struct enc_driver_s *priv, uint8_t cmd, uint16_t arg) -{ - DEBUGASSERT(priv && priv->spi); - - /* Select ENCX24J600 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - (void)SPI_SEND(priv->spi, cmd); /* Clock out the command */ - (void)SPI_SEND(priv->spi, arg & 0xff); /* Clock out the low byte */ - (void)SPI_SEND(priv->spi, arg >> 8); /* Clock out the high byte */ - - /* De-select ENCX24J600 chip. */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_wrdump(cmd, arg); -} - -/**************************************************************************** - * Function: enc_setethrst - * - * Description: - * Issues System Reset by setting ETHRST (ECON2<4>) - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static inline void enc_setethrst(FAR struct enc_driver_s *priv) -{ - DEBUGASSERT(priv && priv->spi); - - /* Select ENC28J60 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - /* Send the system reset command. */ - - (void)SPI_SEND(priv->spi, ENC_SETETHRST); - - up_udelay(25); - - /* De-select ENC28J60 chip. */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_cmddump(ENC_SETETHRST); -} - -/**************************************************************************** - * Function: enc_setbank - * - * Description: - * Set the bank for the next control register access. - * - * Assumption: - * The caller has exclusive access to the SPI bus - * - * Parameters: - * priv - Reference to the driver state structure - * bank - SPI command to select the bank with - * - * Returned Value: - * None - * - * Assumptions: - * The chip is selected and SPI is ready for communication. - * - ****************************************************************************/ - -static void enc_setbank(FAR struct enc_driver_s *priv, uint8_t bank) -{ - - /* Check if a bank has to be set and if the bank setting has changed. - * For registers that are available on all banks, the bank command is set to 0. - */ - - if (bank != 0 && bank != priv->bank) { - /* Select bank with supplied command */ - - SPI_SEND(priv->spi, bank); - - /* Then remember the bank setting */ - - priv->bank = bank; - } -} - -/**************************************************************************** - * Function: enc_rdreg - * - * Description: - * Read one word from a control register using the RCR command. - * - * Parameters: - * priv - Reference to the driver state structure - * ctrlreg - Bit encoded address of banked register to read - * - * Returned Value: - * The byte read from the banked register - * - * Assumptions: - * - ****************************************************************************/ - -static uint16_t enc_rdreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg) -{ - uint16_t rddata; - - DEBUGASSERT(priv && priv->spi); - DEBUGASSERT((ctrlreg & 0xe0) == 0); /* banked regeitsers only */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true); - - enc_setbank(priv, GETBANK(ctrlreg)); - - SPI_SEND(priv->spi, ENC_RCR | GETADDR(ctrlreg)); - - rddata = SPI_SEND(priv->spi, 0); /* Clock in the low byte */ - rddata |= SPI_SEND(priv->spi, 0) << 8; /* Clock in the high byte */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_rddump(GETADDR(ctrlreg), rddata); - - return rddata; -} - -/**************************************************************************** - * Function: enc_wrreg - * - * Description: - * Write one word to a control register using the WCR command. - * - * Parameters: - * priv - Reference to the driver state structure - * ctrlreg - Bit encoded address of banked register to write - * wrdata - The data to send - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_wrreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg, uint16_t wrdata) -{ - DEBUGASSERT(priv && priv->spi); - DEBUGASSERT((ctrlreg & 0xe0) == 0); /* banked regeitsers only */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - enc_setbank(priv, GETBANK(ctrlreg)); - - SPI_SEND(priv->spi, ENC_WCR | GETADDR(ctrlreg)); - SPI_SEND(priv->spi, wrdata & 0xff); /* Clock out the low byte */ - SPI_SEND(priv->spi, wrdata >> 8); /* Clock out the high byte */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_wrdump(GETADDR(ctrlreg), wrdata); -} - -/**************************************************************************** - * Function: enc_waitbreg - * - * Description: - * Wait until banked register bit(s) take a specific value (or a timeout - * occurs). - * - * Parameters: - * priv - Reference to the driver state structure - * ctrlreg - Bit encoded address of banked register to check - * bits - The bits to check (a mask) - * value - The value of the bits to return (value under mask) - * - * Returned Value: - * OK on success, negated errno on failure - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_waitreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg, uint16_t bits, uint16_t value) -{ - systime_t start = clock_systimer(); - systime_t elapsed; - uint16_t rddata; - - /* Loop until the exit condition is met */ - - do { - /* Read the byte from the requested banked register */ - - rddata = enc_rdreg(priv, ctrlreg); - elapsed = clock_systimer() - start; - } while ((rddata & bits) != value && elapsed < ENC_REGPOLLTIMEOUT); - - return (rddata & bits) == value ? OK : -ETIMEDOUT; -} - -/**************************************************************************** - * Function: enc_bfs - * - * Description: - * Bit Field Set. - * - * Parameters: - * priv - Reference to the driver state structure - * ctrlreg - Bit encoded address of banked register to set bits in - * bits - The bits to set (a mask) - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_bfs(FAR struct enc_driver_s *priv, uint16_t ctrlreg, uint16_t bits) -{ - DEBUGASSERT(priv && priv->spi); - - /* Select ENCX24J600 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - /* Set the bank */ - - enc_setbank(priv, GETBANK(ctrlreg)); - - /* Send the BFS command and data. The sequence requires 24-clocks: - * 8 to clock out the cmd + 16 to clock out the data. - */ - - (void)SPI_SEND(priv->spi, ENC_BFS | GETADDR(ctrlreg)); /* Clock out the command */ - (void)SPI_SEND(priv->spi, bits & 0xff); /* Clock out the low byte */ - (void)SPI_SEND(priv->spi, bits >> 8); /* Clock out the high byte */ - - /* De-select ENCX24J600 chip. */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_bfsdump(GETADDR(ctrlreg), bits); -} - -/**************************************************************************** - * Function: enc_bfc - * - * Description: - * Bit Field Clear. - * - * Parameters: - * priv - Reference to the driver state structure - * ctrlreg - Bit encoded address of banked register to clear bits in - * bits - The bits to clear (a mask) - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_bfc(FAR struct enc_driver_s *priv, uint16_t ctrlreg, uint16_t bits) -{ - DEBUGASSERT(priv && priv->spi); - - /* Select ENCX24J600 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - /* Set the bank */ - - enc_setbank(priv, GETBANK(ctrlreg)); - - /* Send the BFC command and data. The sequence requires 24-clocks: - * 8 to clock out the cmd + 16 to clock out the data. - */ - - (void)SPI_SEND(priv->spi, ENC_BFC | GETADDR(ctrlreg)); /* Clock out the command */ - (void)SPI_SEND(priv->spi, bits & 0xff); /* Clock out the low byte */ - (void)SPI_SEND(priv->spi, bits >> 8); /* Clock out the high byte */ - - /* De-select ENCX24J600 chip. */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_bfcdump(GETADDR(ctrlreg), bits); -} - -/**************************************************************************** - * Function: enc_txdump enc_rxdump - * - * Description: - * Dump registers associated with receiving or sending packets. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#if 0 /* Sometimes useful */ -static void enc_rxdump(FAR struct enc_driver_s *priv) -{ - lowsyslog(LOG_DEBUG, "Rx Registers:\n"); - lowsyslog(LOG_DEBUG, " EIE: %02x EIR: %02x\n", enc_rdgreg(priv, ENC_EIE), enc_rdgreg(priv, ENC_EIR)); - lowsyslog(LOG_DEBUG, " ESTAT: %02x ECON1: %02x ECON2: %02x\n", enc_rdgreg(priv, ENC_ESTAT), enc_rdgreg(priv, ENC_ECON1), enc_rdgreg(priv, ENC_ECON2)); - lowsyslog(LOG_DEBUG, " ERXST: %02x %02x\n", enc_rdbreg(priv, ENC_ERXSTH), enc_rdbreg(priv, ENC_ERXSTL)); - lowsyslog(LOG_DEBUG, " ERXND: %02x %02x\n", enc_rdbreg(priv, ENC_ERXNDH), enc_rdbreg(priv, ENC_ERXNDL)); - lowsyslog(LOG_DEBUG, " ERXRDPT: %02x %02x\n", enc_rdbreg(priv, ENC_ERXRDPTH), enc_rdbreg(priv, ENC_ERXRDPTL)); - lowsyslog(LOG_DEBUG, " ERXFCON: %02x EPKTCNT: %02x\n", enc_rdbreg(priv, ENC_ERXFCON), enc_rdbreg(priv, ENC_EPKTCNT)); - lowsyslog(LOG_DEBUG, " MACON1: %02x MACON3: %02x\n", enc_rdbreg(priv, ENC_MACON1), enc_rdbreg(priv, ENC_MACON3)); - lowsyslog(LOG_DEBUG, " MAMXFL: %02x %02x\n", enc_rdbreg(priv, ENC_MAMXFLH), enc_rdbreg(priv, ENC_MAMXFLL)); - lowsyslog(LOG_DEBUG, " MAADR: %02x:%02x:%02x:%02x:%02x:%02x\n", enc_rdbreg(priv, ENC_MAADR1), enc_rdbreg(priv, ENC_MAADR2), enc_rdbreg(priv, ENC_MAADR3), enc_rdbreg(priv, ENC_MAADR4), enc_rdbreg(priv, ENC_MAADR5), enc_rdbreg(priv, ENC_MAADR6)); -} -#endif - -#if 0 /* Sometimes useful */ -static void enc_txdump(FAR struct enc_driver_s *priv) -{ - lowsyslog(LOG_DEBUG, "Tx Registers:\n"); - lowsyslog(LOG_DEBUG, " EIE: %02x EIR: %02x ESTAT: %02x\n", enc_rdgreg(priv, ENC_EIE), enc_rdgreg(priv, ENC_EIR)); - lowsyslog(LOG_DEBUG, " ESTAT: %02x ECON1: %02x\n", enc_rdgreg(priv, ENC_ESTAT), enc_rdgreg(priv, ENC_ECON1)); - lowsyslog(LOG_DEBUG, " ETXST: %02x %02x\n", enc_rdbreg(priv, ENC_ETXSTH), enc_rdbreg(priv, ENC_ETXSTL)); - lowsyslog(LOG_DEBUG, " ETXND: %02x %02x\n", enc_rdbreg(priv, ENC_ETXNDH), enc_rdbreg(priv, ENC_ETXNDL)); - lowsyslog(LOG_DEBUG, " MACON1: %02x MACON3: %02x MACON4: %02x\n", enc_rdbreg(priv, ENC_MACON1), enc_rdbreg(priv, ENC_MACON3), enc_rdbreg(priv, ENC_MACON4)); - lowsyslog(LOG_DEBUG, " MACON1: %02x MACON3: %02x MACON4: %02x\n", enc_rdbreg(priv, ENC_MACON1), enc_rdbreg(priv, ENC_MACON3), enc_rdbreg(priv, ENC_MACON4)); - lowsyslog(LOG_DEBUG, " MABBIPG: %02x MAIPG %02x %02x\n", enc_rdbreg(priv, ENC_MABBIPG), enc_rdbreg(priv, ENC_MAIPGH), enc_rdbreg(priv, ENC_MAIPGL)); - lowsyslog(LOG_DEBUG, " MACLCON1: %02x MACLCON2: %02x\n", enc_rdbreg(priv, ENC_MACLCON1), enc_rdbreg(priv, ENC_MACLCON2)); - lowsyslog(LOG_DEBUG, " MAMXFL: %02x %02x\n", enc_rdbreg(priv, ENC_MAMXFLH), enc_rdbreg(priv, ENC_MAMXFLL)); -} -#endif - -/**************************************************************************** - * Function: enc_rdbuffer - * - * Description: - * Read a buffer of data from RX Data Buffer. - * - * Parameters: - * priv - Reference to the driver state structure - * buffer - A pointer to the buffer to read into - * buflen - The number of bytes to read - * - * Returned Value: - * None - * - * Assumptions: - * RX Data pointer is set to the correct address - * - ****************************************************************************/ - -static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer, size_t buflen) -{ - DEBUGASSERT(priv && priv->spi); - - /* Select ENCX24J600 chip */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true); - - /* Send the read buffer memory command (ignoring the response) */ - - (void)SPI_SEND(priv->spi, ENC_RRXDATA); - - /* Then read the buffer data */ - - SPI_RECVBLOCK(priv->spi, buffer, buflen); - - /* De-select ENCX24J600 chip. */ - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_bmdump(ENC_RRXDATA, buffer, buflen); -} - -/**************************************************************************** - * Function: enc_wrbuffer - * - * Description: - * Write a buffer of data. - * - * Parameters: - * priv - Reference to the driver state structure - * buffer - A pointer to the buffer to write from - * buflen - The number of bytes to write - * - * Returned Value: - * None - * - * Assumptions: - * General Purpose Write pointer is set to the correct address - * - ****************************************************************************/ - -static inline void enc_wrbuffer(FAR struct enc_driver_s *priv, FAR const uint8_t *buffer, size_t buflen) -{ - DEBUGASSERT(priv && priv->spi); - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);; - - SPI_SEND(priv->spi, ENC_WGPDATA); - SPI_SNDBLOCK(priv->spi, buffer, buflen); - - SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false); - enc_bmdump(ENC_WGPDATA, buffer, buflen); -} - -/**************************************************************************** - * Function: enc_rdphy - * - * Description: - * Read 16-bits of PHY data. - * - * Parameters: - * priv - Reference to the driver state structure - * phyaddr - The PHY register address - * - * Returned Value: - * 16-bit value read from the PHY - * - * Assumptions: - * - ****************************************************************************/ - -static uint16_t enc_rdphy(FAR struct enc_driver_s *priv, uint8_t phyaddr) -{ - uint16_t data = 0; - - /* "To read from a PHY register: - * 1. Write the address of the PHY register to read from into the MIREGADR - * register (Register 3-1). Make sure to also set reserved bit 8 of this - * register. - */ - - enc_wrreg(priv, ENC_MIREGADR, phyaddr); - - /* 2. Set the MIIRD bit (MICMD<0>, Register 3-2). The read operation begins - * and the BUSY bit (MISTAT<0>, Register 3-3) is automatically set by - * hardware. - */ - - enc_bfs(priv, ENC_MICMD, MICMD_MIIRD); - - /* 3. Wait 25.6 μs. Poll the BUSY (MISTAT<0>) bit to be certain that the - * operation is complete. While busy, the host controller should not - * start any MIISCAN operations or write to the MIWR register. When the - * MAC has obtained the register contents, the BUSY bit will clear - * itself. - */ - - up_udelay(26); - if (enc_waitreg(priv, ENC_MISTAT, MISTAT_BUSY, 0x00) == OK) { - /* 4. Clear the MIIRD (MICMD<0>) bit. */ - - enc_bfc(priv, ENC_MICMD, MICMD_MIIRD); - - /* 5. Read the desired data from the MIRD register. For 8-bit interfaces, - * the order that these bytes are read is unimportant." - */ - - data = enc_rdreg(priv, ENC_MIRD); - } - - return data; -} - -/**************************************************************************** - * Function: enc_wrphy - * - * Description: - * write 16-bits of PHY data. - * - * Parameters: - * priv - Reference to the driver state structure - * phyaddr - The PHY register address - * phydata - 16-bit data to write to the PHY - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_wrphy(FAR struct enc_driver_s *priv, uint8_t phyaddr, uint16_t phydata) -{ - /* "To write to a PHY register: - * - * 1. Write the address of the PHY register to write to into the MIREGADR - * register. Make sure to also set reserved bit 8 of this register. - */ - - enc_wrreg(priv, ENC_MIREGADR, 0x0100 | phyaddr); - - /* 2. Write the 16 bits of data into the MIWR register. The low byte must - * be written first, followed by the high byte. - */ - - enc_wrreg(priv, ENC_MIWR, phydata); - - /* 3. Writing to the high byte of MIWR begins the MIIM transaction and the - * BUSY (MISTAT<0>) bit is automatically set by hardware. - * - * The PHY register is written after the MIIM operation completes, which takes - * 25.6 μs. When the write operation has completed, the BUSY bit clears - * itself. The host controller should not start any MIISCAN, MIWR or MIIRD - * operations while the BUSY bit is set. - */ - - up_udelay(26); - enc_waitreg(priv, ENC_MISTAT, MISTAT_BUSY, 0); -} - -/**************************************************************************** - * Function: enc_transmit - * - * Description: - * Start hardware transmission. Called either from: - * - * - pkif interrupt when an application responds to the receipt of data - * by trying to send something, or - * - From watchdog based polling. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_transmit(FAR struct enc_driver_s *priv) -{ - struct enc_descr_s *descr; - - /* dequeue next packet to transmit */ - - descr = (struct enc_descr_s *)sq_remfirst(&priv->txqueue); - - DEBUGASSERT(descr != NULL); - - /* Verify that the hardware is ready to send another packet. The driver - * starts a transmission process by setting ECON1.TXRTS. When the packet is - * finished transmitting or is aborted due to an error/cancellation, the - * ECON1.TXRTS bit will be cleared. - * - * NOTE: If we got here, then we have committed to sending a packet. - * higher level logic must have assured that (1) there is no transmission - * in progress, and that (2) TX-related interrupts are disabled. - */ - - DEBUGASSERT((enc_rdreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0); - - /* Set TXStart and TXLen registers. */ - - enc_wrreg(priv, ENC_ETXST, descr->addr); - enc_wrreg(priv, ENC_ETXLEN, descr->len); - - /* Set TXRTS to send the packet in the transmit buffer */ - - enc_bfs(priv, ENC_ECON1, ECON1_TXRTS); - - /* Setup the TX timeout watchdog (perhaps restarting the timer). Note: - * Is there a race condition. Could the TXIF interrupt occur before - * the timer is started? - */ - - (void)wd_start(priv->txtimeout, ENC_TXTIMEOUT, enc_txtimeout, 1, (uint32_t)priv); - - /* free the descriptor */ - - sq_addlast((sq_entry_t *) descr, &priv->txfreedescr); - - return OK; -} - -/**************************************************************************** - * Function: enc_txenqueue - * - * Description: - * Write packet from d_buf to the enc's SRAM if a free descriptor is available. - * The filled descriptor is enqueued for transmission. - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * A packet is available in d_buf. - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static int enc_txenqueue(FAR struct enc_driver_s *priv) -{ - int ret = OK; - struct enc_descr_s *descr; - - DEBUGASSERT(priv->dev.d_len > 0); - - /* Increment statistics */ - -#ifdef CONFIG_ENCX24J600_STATS - priv->stats.txrequests++; -#endif - - descr = (struct enc_descr_s *)sq_remfirst(&priv->txfreedescr); - - if (descr != NULL) { - enc_dumppacket("Write packet to enc SRAM", priv->dev.d_buf, priv->dev.d_len); - - /* Copy the packet into the transmit buffer described by the current - * tx descriptor - */ - - enc_cmd(priv, ENC_WGPWRPT, descr->addr); - enc_wrbuffer(priv, priv->dev.d_buf, priv->dev.d_len); - - /* store packet length */ - - descr->len = priv->dev.d_len; - - /* enqueue packet */ - - sq_addlast((sq_entry_t *) descr, &priv->txqueue); - - /* if currently no transmission is active, trigger the transmission */ - - if ((enc_rdreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0) { - enc_transmit(priv); - } - } else { - nlldbg("no free descriptors\n"); - ret = -ENOMEM; - } - - return ret; -} - -/**************************************************************************** - * Function: enc_txpoll - * - * Description: - * Enqueues uIP packets if available. - * This is a callback from netif_poll(). netif_poll() may be called: - * - * 1. When the preceding TX packet send is complete, - * 2. When the preceding TX packet send timedout and the interface is reset - * 3. During normal TX polling - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static int enc_txpoll(struct net_driver_s *dev) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - int ret = OK; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - nllvdbg("Poll result: d_len=%d\n", priv->dev.d_len); - - if (priv->dev.d_len > 0) { - /* Look up the destination MAC address and add it to the Ethernet - * header. - */ - -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - if (IFF_IS_IPv4(priv->dev.d_flags)) -#endif - { - arp_out(&priv->dev); - } -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else -#endif - { - neighbor_out(&priv->dev); - } -#endif /* CONFIG_NET_IPv6 */ - - /* Send the packet */ - - ret = enc_txenqueue(priv); - } - - /* If zero is returned, the polling will continue until all connections have - * been examined. - */ - - return ret; -} - -/**************************************************************************** - * Function: enc_linkstatus - * - * Description: - * The current link status can be obtained from the PHSTAT1.LLSTAT or - * PHSTAT2.LSTAT. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_linkstatus(FAR struct enc_driver_s *priv) -{ - uint16_t regval; - - /* Before transmitting the first packet after link establishment or - * auto-negotiation, the MAC duplex configuration must be manually set to - * match the duplex configuration of the PHY. To do this, configure - * FULDPX (MACON2<0>) to match PHYDPX (ESTAT<10>). - */ - - regval = enc_rdreg(priv, ENC_ESTAT); - - if (regval & ESTAT_PHYLNK) { - if (regval & ESTAT_PHYDPX) { - /* Configure full-duplex */ - - enc_wrreg(priv, ENC_MABBIPG, 0x15); - enc_bfs(priv, ENC_MACON2, MACON2_FULDPX); - } else { - /* Configure half-duplex */ - - enc_wrreg(priv, ENC_MABBIPG, 0x12); - enc_bfc(priv, ENC_MACON2, MACON2_FULDPX); - } - - netdev_carrier_on(&priv->dev); - priv->ifstate = ENCSTATE_RUNNING; - } else { - netdev_carrier_off(&priv->dev); - priv->ifstate = ENCSTATE_UP; - } -} - -/**************************************************************************** - * Function: enc_txif - * - * Description: - * An TXIF interrupt was received indicating that the last TX packet(s) is - * done - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static void enc_txif(FAR struct enc_driver_s *priv) -{ - if (sq_empty(&priv->txqueue)) { - /* If no further xmits are pending, then cancel the TX timeout */ - - wd_cancel(priv->txtimeout); - - /* Poll for TX packets from the networking layer */ - - netif_poll(&priv->dev, enc_txpoll); - } else { - /* process txqueue */ - - enc_transmit(priv); - } -} - -/**************************************************************************** - * Function: enc_rxldpkt - * - * Description: - * Load packet from the enc's RX buffer to the driver d_buf. - * - * Parameters: - * priv - Reference to the driver state structure - * descr - Reference to the descriptor that should be loaded - * - * Returned Value: - * None - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static void enc_rxldpkt(FAR struct enc_driver_s *priv, struct enc_descr_s *descr) -{ - DEBUGASSERT(priv != NULL && descr != NULL); - - nllvdbg("load packet @%04x len: %d\n", descr->addr, descr->len); - - /* Set the rx data pointer to the start of the received packet (ERXRDPT) */ - - enc_cmd(priv, ENC_WRXRDPT, descr->addr); - - /* Save the packet length (without the 4 byte CRC) in priv->dev.d_len */ - - priv->dev.d_len = descr->len - 4; - - /* Copy the data data from the receive buffer to priv->dev.d_buf */ - - enc_rdbuffer(priv, priv->dev.d_buf, priv->dev.d_len); - - enc_dumppacket("loaded RX packet", priv->dev.d_buf, priv->dev.d_len); -} - -/**************************************************************************** - * Function: enc_rxgetdescr - * - * Description: - * Check for a free descriptor in the free list. If no free descriptor is - * available a pending descriptor will be freed and returned - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * A free rx descriptor - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static struct enc_descr_s *enc_rxgetdescr(FAR struct enc_driver_s *priv) -{ - if (sq_empty(&priv->rxfreedescr)) { - DEBUGASSERT(sq_peek(&priv->rxqueue) != NULL); - - /* Packets are held in the enc's SRAM until the space is needed */ - - enc_rxrmpkt(priv, (struct enc_descr_s *)sq_peek(&priv->rxqueue)); - } - - return (struct enc_descr_s *)sq_remfirst(&priv->rxfreedescr); -} - -/**************************************************************************** - * Function: enc_rxrmpkt - * - * Description: - * Remove packet from the RX queue and free the block of memory in the enc's - * SRAM. - * - * Parameters: - * priv - Reference to the driver state structure - * descr - Reference to the descriptor that should be freed - * - * Returned Value: - * None - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static void enc_rxrmpkt(FAR struct enc_driver_s *priv, struct enc_descr_s *descr) -{ - uint16_t addr; - - nllvdbg("free descr: %p\n", descr); - - /* If it is the last descriptor in the queue, advance ERXTAIL. - * This way it is possible that gaps occcur. Maybe pending packets - * can be reordered th enc's DMA to free RX space? - */ - - if (descr != NULL) { - if (descr == (struct enc_descr_s *)sq_peek(&priv->rxqueue)) { - /* Wrap address properly around */ - addr = (descr->addr - PKTMEM_RX_START + descr->len - 2 + PKTMEM_RX_SIZE) - % PKTMEM_RX_SIZE + PKTMEM_RX_START; - - DEBUGASSERT(addr >= PKTMEM_RX_START && addr < PKTMEM_RX_END); - - nllvdbg("ERXTAIL %04x\n", addr); - - enc_wrreg(priv, ENC_ERXTAIL, addr); - - /* Remove packet from RX queue */ - - sq_remfirst(&priv->rxqueue); - } else { - /* Remove packet from RX queue */ - - sq_rem((sq_entry_t *) descr, &priv->rxqueue); - } - - sq_addlast((sq_entry_t *) descr, &priv->rxfreedescr); - } -} - -/**************************************************************************** - * Function: enc_rxdispatch - * - * Description: - * Give the newly received packet to uIP. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static void enc_rxdispatch(FAR struct enc_driver_s *priv) -{ - struct enc_descr_s *descr; - struct enc_descr_s *next; - - int ret = ERROR; - - /* Process the RX queue */ - - descr = (struct enc_descr_s *)sq_peek(&priv->rxqueue); - - while (descr != NULL) { - /* Store the next pointer, because removing the item from list will set - * flink to NULL - */ - - next = (struct enc_descr_s *)sq_next(descr); - - /* Load the packet from the enc's SRAM */ - - enc_rxldpkt(priv, descr); - -#ifdef CONFIG_NET_PKT - /* When packet sockets are enabled, feed the frame into the packet tap */ - - pkt_input(&priv->dev); -#endif - - /* We only accept IP packets of the configured type and ARP packets */ - -#ifdef CONFIG_NET_IPv4 - if (BUF->type == HTONS(ETHTYPE_IP)) { - nllvdbg("IPv4 frame\n"); - - /* Handle ARP on input then give the IPv4 packet to the network - * layer - */ - - arp_ipin(&priv->dev); - ret = ipv4_input(&priv->dev); - - if (ret == OK || (clock_systimer() - descr->ts) > ENC_RXTIMEOUT) { - /* If packet has been successfully processed or has timed out, - * free it. - */ - - enc_rxrmpkt(priv, descr); - } - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (priv->dev.d_len > 0) { - /* Update the Ethernet header with the correct MAC address */ - -#ifdef CONFIG_NET_IPv6 - if (IFF_IS_IPv4(priv->dev.d_flags)) -#endif - { - arp_out(&priv->dev); - } -#ifdef CONFIG_NET_IPv6 - else { - neighbor_out(&priv->dev); - } -#endif - - /* And send the packet */ - - enc_txenqueue(priv); - } - } else -#endif -#ifdef CONFIG_NET_IPv6 - if (BUF->type == HTONS(ETHTYPE_IP6)) { - nllvdbg("Iv6 frame\n"); - - /* Give the IPv6 packet to the network layer */ - - ret = ipv6_input(&priv->dev); - - if (ret == OK || (clock_systimer() - descr->ts) > ENC_RXTIMEOUT) { - /* If packet has been successfully processed or has timed out, - * free it. - */ - - enc_rxrmpkt(priv, descr); - } - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (priv->dev.d_len > 0) { - /* Update the Ethernet header with the correct MAC address */ - -#ifdef CONFIG_NET_IPv4 - if (IFF_IS_IPv4(priv->dev.d_flags)) { - arp_out(&priv->dev); - } else -#endif -#ifdef CONFIG_NET_IPv6 - { - neighbor_out(&priv->dev); - } -#endif - - /* And send the packet */ - - enc_txenqueue(priv); - } - } else -#endif -#ifdef CONFIG_NET_ARP - if (BUF->type == htons(ETHTYPE_ARP)) { - nllvdbg("ARP packet received (%02x)\n", BUF->type); - arp_arpin(&priv->dev); - - /* ARP packets are freed immediately */ - - enc_rxrmpkt(priv, descr); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (priv->dev.d_len > 0) { - enc_txenqueue(priv); - } - } else -#endif - { - /* free unsupported packet */ - - enc_rxrmpkt(priv, descr); - - nlldbg("Unsupported packet type dropped (%02x)\n", htons(BUF->type)); - } - - descr = next; - } -} - -/**************************************************************************** - * Function: enc_pktif - * - * Description: - * An interrupt was received indicating the availability of a new RX packet - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static void enc_pktif(FAR struct enc_driver_s *priv) -{ - struct enc_descr_s *descr; - uint8_t rsv[8]; - uint16_t pktlen; - uint32_t rxstat; - uint16_t curpkt; - int pktcnt; - - DEBUGASSERT(priv->nextpkt >= PKTMEM_RX_START && priv->nextpkt < PKTMEM_RX_END); - - /* Enqueue all pending packets to the RX queue until PKTCNT == 0 or - * no more descriptors are available. - */ - - pktcnt = (enc_rdreg(priv, ENC_ESTAT) & ESTAT_PKTCNT_MASK) >> ESTAT_PKTCNT_SHIFT; - - while (pktcnt > 0) { - curpkt = priv->nextpkt; - - /* Set the rx data pointer to the start of the received packet (ERXRDPT) */ - - enc_cmd(priv, ENC_WRXRDPT, curpkt); - - /* Read the next packet pointer and the 6 byte read status vector (RSV) - * at the beginning of the received packet. (ERXRDPT should auto-increment - * and wrap to the beginning of the read buffer as necessary) - */ - - enc_rdbuffer(priv, rsv, 8); - - /* Decode the new next packet pointer, and the RSV. The - * RSV is encoded as: - * - * Bits 0-15: Indicates length of the received frame. This includes the - * destination address, source address, type/length, data, - * padding and CRC fields. This field is stored in little- - * endian format. - * Bits 16-47: Bit encoded RX status. - */ - - priv->nextpkt = (uint16_t)rsv[1] << 8 | (uint16_t)rsv[0]; - pktlen = (uint16_t)rsv[3] << 8 | (uint16_t)rsv[2]; - rxstat = (uint32_t)rsv[7] << 24 | (uint32_t)rsv[6] << 16 | (uint32_t)rsv[5] << 8 | (uint32_t)rsv[4]; - - nllvdbg("Receiving packet, nextpkt: %04x pktlen: %d rxstat: %08x pktcnt: %d\n", priv->nextpkt, pktlen, rxstat, pktcnt); - - /* We enqueue the packet first and remove it later if its faulty. - * This way we avoid freeing packets that are not processed yet. - */ - - descr = enc_rxgetdescr(priv); - - /* Set current timestamp */ - - descr->ts = clock_systimer(); - - /* Store the start address of the frame without the enc's header */ - - descr->addr = curpkt + 8; - descr->len = pktlen; - sq_addlast((sq_entry_t *) descr, &priv->rxqueue); - - /* Check if the packet was received OK */ - - if ((rxstat & RXSTAT_OK) == 0) { - nlldbg("ERROR: RXSTAT: %08x\n", rxstat); - - /* Discard packet */ - - enc_rxrmpkt(priv, descr); - -#ifdef CONFIG_ENCX24J600_STATS - priv->stats.rxnotok++; -#endif - } - - /* Check for a usable packet length (4 added for the CRC) */ - - else if (pktlen > (CONFIG_NET_ETH_MTU + 4) || pktlen <= (ETH_HDRLEN + 4)) { - nlldbg("Bad packet size dropped (%d)\n", pktlen); - - /* Discard packet */ - - enc_rxrmpkt(priv, descr); - -#ifdef CONFIG_ENCX24J600_STATS - priv->stats.rxpktlen++; -#endif - } - - /* Decrement PKTCNT */ - - enc_bfs(priv, ENC_ECON1, ECON1_PKTDEC); - - /* Try to process the packet */ - - enc_rxdispatch(priv); - - /* Read out again, maybe there has another packet arrived */ - - pktcnt = (enc_rdreg(priv, ENC_ESTAT) & ESTAT_PKTCNT_MASK) >> ESTAT_PKTCNT_SHIFT; - } -} - -/**************************************************************************** - * Function: enc_rxabtif - * - * Description: - * An interrupt was received indicating the abortion of an RX packet - * - * "The receive abort interrupt occurs when the reception of a frame has been - * aborted. A frame being received is aborted when the Head Pointer attempts - * to overrun the Tail Pointer, or when the packet counter has reached FFh. - * In either case, the receive buffer is full and cannot fit the incoming - * frame, so the packet has been dropped. - * This interrupt does not occur when packets are dropped due to the receive - * filters rejecting a packet. The interrupt should be cleared by software - * once it has been serviced." - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Interrupts are enabled but the caller holds the uIP lock. - * - ****************************************************************************/ - -static void enc_rxabtif(FAR struct enc_driver_s *priv) -{ - struct enc_descr_s *descr; - -#if 0 - /* Free the last received packet from the RX queue */ - - nlldbg("rx abort\n"); - nlldbg("ESTAT: %04x\n", enc_rdreg(priv, ENC_ESTAT)); - nlldbg("EIR: %04x\n", enc_rdreg(priv, ENC_EIR)); - nlldbg("ERXTAIL: %04x\n", enc_rdreg(priv, ENC_ERXTAIL)); - nlldbg("ERXHAED: %04x\n", enc_rdreg(priv, ENC_ERXHEAD)); - - descr = (struct enc_descr_s *)sq_peek(&priv->rxqueue); - - while (descr != NULL) { - nlldbg("addr: %04x len: %d\n", descr->addr, descr->len); - descr = (struct enc_descr_s *)sq_next(descr); - } - - DEBUGASSERT(false); -#endif - - descr = (struct enc_descr_s *)sq_peek(&priv->rxqueue); - - if (descr != NULL) { - enc_rxrmpkt(priv, descr); - - nlldbg("pending packet freed\n"); - } else { - /* If no pending packet blocks the reception, reset all buffers */ - - enc_resetbuffers(priv); - } -} - -/**************************************************************************** - * Function: enc_irqworker - * - * Description: - * Perform interrupt handling logic outside of the interrupt handler (on - * the work queue thread). - * - * Parameters: - * arg - The reference to the driver structure (case to void*) - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_irqworker(FAR void *arg) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg; - net_lock_t lock; - uint16_t eir; - - DEBUGASSERT(priv); - - /* Get exclusive access to both uIP and the SPI bus. */ - - lock = net_lock(); - enc_lock(priv); - - /* A good practice is for the host controller to clear the Global Interrupt - * Enable bit, INTIE (EIE<15>), immediately after an interrupt event. This - * causes the interrupt pin to return to the non-asserted (high) state. Once - * the interrupt has been serviced, the INTIE bit is set again to re-enable - * interrupts. If a new interrupt occurs while servicing another, the act of - * resetting the global enable bit will cause a new falling edge to occur on - * the interrupt pin and ensure that the host does not miss any events - */ - - enc_bfc(priv, ENC_EIE, EIE_INTIE); - - /* Loop until all interrupts have been processed (EIR==0). Note that - * there is no infinite loop check... if there are always pending interrupts, - * we are just broken. - */ - - while ((eir = enc_rdreg(priv, ENC_EIR) & EIR_ALLINTS) != 0) { - /* Handle interrupts according to interrupt register register bit - * settings. - */ - - nllvdbg("EIR: %04x\n", eir); - - if ((eir & EIR_DMAIF) != 0) { /* DMA interrupt */ - /* Not used by this driver. Just clear the interrupt request. */ - - enc_bfc(priv, ENC_EIR, EIR_DMAIF); - } - - /* LINKIF: The link change interrupt occurs when the PHY link status - * changes. This flag is set by hardware when a link has either been - * established or broken between the device and a remote Ethernet partner. - * The current link status can be read from PHYLNK (ESTAT<8>). The - * interrupt should be cleared by software once it has been serviced. - * - * To enable the link change interrupt, set LINKIE (EIE<11>). - */ - - if ((eir & EIR_LINKIF) != 0) { /* PHY Link Status Change */ - enc_linkstatus(priv); /* Get current link status */ - enc_bfc(priv, ENC_EIR, EIR_LINKIF); /* Clear the LINKIF interrupt */ - } - - /* The transmit complete interrupt occurs when the transmission of a - * frame has ended (whether or not it was successful). This flag is set - * when TXRTS (ECON1<1>) is cleared. The interrupt should be cleared by - * software once it has been serviced. - */ - - if ((eir & EIR_TXIF) != 0) { /* Transmit Done */ - enc_txif(priv); - enc_bfc(priv, ENC_EIR, EIR_TXIF); - } - - /* The receive abort interrupt occurs when the reception of a frame has - * been aborted. A frame being received is aborted when the Head Pointer - * attempts to overrun the Tail Pointer, or when the packet counter has - * reached FFh. In either case, the receive buffer is full and cannot fit - * the incoming frame, so the packet has been dropped. This interrupt does - * not occur when packets are dropped due to the receive filters rejecting - * a packet. The interrupt should be cleared by software once it has been - * serviced. - * - * To enable the receive abort interrupt, set RXABTIE (EIE<1>). - * The corresponding interrupt flag is RXABTIF (EIR<1>). - */ - - if ((eir & EIR_RXABTIF) != 0) { /* Receive Abort */ -#ifdef CONFIG_ENCX24J600_STATS - priv->stats.rxerifs++; -#endif - enc_rxabtif(priv); - enc_bfc(priv, ENC_EIR, EIR_RXABTIF); /* Clear the RXABTIF interrupt */ - } - - /* The received packet pending interrupt occurs when one or more frames - * have been received and are ready for software processing. This flag is - * set when the PKTCNT<7:0> (ESTAT<7:0>) bits are non-zero. This interrupt - * flag is read-only and will automatically clear when the PKTCNT bits are - * decremented to zero. For more details about receiving and processing - * incoming frames, refer to Section 9.0 "Transmitting and Receiving - * Packets". - * - * To enable the received packet pending interrupt, set PKTIE (EIE<6>). - * The corresponding interrupt flag is PKTIF (EIR<6>). - */ - - if ((eir & EIR_PKTIF) != 0 /* RX Packet Pending */ - && (enc_rdreg(priv, ENC_ESTAT) & ESTAT_PKTCNT_MASK) != 0) { - enc_pktif(priv); /* Handle packet receipt */ - - /* No clearing necessary, after PKTCNT == 0 the bit is automatically - * cleared. This means we will loop until all packets are processed. - */ - } -#ifdef CONFIG_ENCX24J600_STATS - /* The transmit abort interrupt occurs when the transmission of a frame - * has been aborted. An abort can occur for any of the following reasons: - * - * * Excessive collisions occurred as defined by the Retransmission - * Maximum, MAXRET<3:0> bits (MACLCON<3:0>), setting. If this occurs, - * the COLCNT bits (ETXSTAT<3:0>) will indicate the number of collisions - * that occurred. - * - * * A late collision occurred after 63 bytes were transmitted. If this - * occurs, LATECOL (ETXSTAT<10>) will be set. - * - * * The medium was busy and the packet was deferred. If this occurs, - * EXDEFER (ETXSTAT<8>) will be set. - * - * * The application aborted the transmission by clearing TXRTS - * (ECON1<1>). - * - * The interrupt should be cleared by software once it has been serviced. - * To enable the transmit abort interrupt, set TXABTIE (EIE<2>). - */ - - if ((eir & EIR_TXABTIF) != 0) { /* Transmit Abort */ - priv->stats.txerifs++; - enc_bfc(priv, ENC_EIR, EIR_TXABTIF); /* Clear the TXABTIF interrupt */ - } -#endif - } - - /* Enable GPIO interrupts */ - - priv->lower->enable(priv->lower); - - /* Enable Ethernet interrupts */ - - enc_bfs(priv, ENC_EIE, EIE_INTIE); - - /* Release lock on the SPI bus and uIP */ - - enc_unlock(priv); - net_unlock(lock); -} - -/**************************************************************************** - * Function: enc_interrupt - * - * Description: - * Hardware interrupt handler - * - * Parameters: - * irq - Number of the IRQ that generated the interrupt - * context - Interrupt register state save info (architecture-specific) - * - * Returned Value: - * OK on success - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_interrupt(int irq, FAR void *context) -{ - register FAR struct enc_driver_s *priv = &g_encx24j600[0]; - - /* In complex environments, we cannot do SPI transfers from the interrupt - * handler because semaphores are probably used to lock the SPI bus. In - * this case, we will defer processing to the worker thread. This is also - * much kinder in the use of system resources and is, therefore, probably - * a good thing to do in any event. - */ - - DEBUGASSERT(work_available(&priv->irqwork)); - - /* Notice that further GPIO interrupts are disabled until the work is - * actually performed. This is to prevent overrun of the worker thread. - * Interrupts are re-enabled in enc_irqworker() when the work is completed. - */ - - priv->lower->disable(priv->lower); - return work_queue(HPWORK, &priv->irqwork, enc_irqworker, (FAR void *)priv, 0); -} - -/**************************************************************************** - * Function: enc_toworker - * - * Description: - * Our TX watchdog timed out. This is the worker thread continuation of - * the watchdog timer interrupt. Reset the hardware and start again. - * - * Parameters: - * arg - The reference to the driver structure (case to void*) - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_toworker(FAR void *arg) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg; - net_lock_t lock; - int ret; - - nlldbg("Tx timeout\n"); - DEBUGASSERT(priv); - - /* Get exclusive access to uIP. */ - - lock = net_lock(); - - /* Increment statistics and dump debug info */ - -#ifdef CONFIG_ENCX24J600_STATS - priv->stats.txtimeouts++; -#endif - - /* Then reset the hardware: Take the interface down, then bring it - * back up - */ - - ret = enc_ifdown(&priv->dev); - DEBUGASSERT(ret == OK); - ret = enc_ifup(&priv->dev); - DEBUGASSERT(ret == OK); - (void)ret; - - /* Then poll uIP for new XMIT data */ - - (void)netif_poll(&priv->dev, enc_txpoll); - - /* Release uIP */ - - net_unlock(lock); -} - -/**************************************************************************** - * Function: enc_txtimeout - * - * Description: - * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Perform work on the worker thread. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_txtimeout(int argc, uint32_t arg, ...) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg; - int ret; - - /* In complex environments, we cannot do SPI transfers from the timout - * handler because semaphores are probably used to lock the SPI bus. In - * this case, we will defer processing to the worker thread. This is also - * much kinder in the use of system resources and is, therefore, probably - * a good thing to do in any event. - */ - - DEBUGASSERT(priv && work_available(&priv->towork)); - - /* Notice that Tx timeout watchdog is not active so further Tx timeouts - * can occur until we restart the Tx timeout watchdog. - */ - - ret = work_queue(HPWORK, &priv->towork, enc_toworker, (FAR void *)priv, 0); - (void)ret; - DEBUGASSERT(ret == OK); -} - -/**************************************************************************** - * Function: enc_pollworker - * - * Description: - * Periodic timer handler continuation. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_pollworker(FAR void *arg) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg; - net_lock_t lock; - - DEBUGASSERT(priv); - - /* Get exclusive access to both uIP and the SPI bus. */ - - lock = net_lock(); - enc_lock(priv); - - /* Verify that the hardware is ready to send another packet. The driver - * start a transmission process by setting ECON1.TXRTS. When the packet is - * finished transmitting or is aborted due to an error/cancellation, the - * ECON1.TXRTS bit will be cleared. - */ - - if ((enc_rdreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0) { - /* Yes.. update TCP timing states and poll uIP for new XMIT data. Hmmm.. - * looks like a bug here to me. Does this mean if there is a transmit - * in progress, we will missing TCP time state updates? - */ - - (void)netif_timer(&priv->dev, enc_txpoll, ENC_POLLHSEC); - } - - /* Release lock on the SPI bus and uIP */ - - enc_unlock(priv); - net_unlock(lock); - - /* Setup the watchdog poll timer again */ - - (void)wd_start(priv->txpoll, ENC_WDDELAY, enc_polltimer, 1, arg); -} - -/**************************************************************************** - * Function: enc_polltimer - * - * Description: - * Periodic timer handler. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_polltimer(int argc, uint32_t arg, ...) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg; - int ret; - - /* In complex environments, we cannot do SPI transfers from the timout - * handler because semaphores are probably used to lock the SPI bus. In - * this case, we will defer processing to the worker thread. This is also - * much kinder in the use of system resources and is, therefore, probably - * a good thing to do in any event. - */ - - DEBUGASSERT(priv && work_available(&priv->pollwork)); - - /* Notice that poll watchdog is not active so further poll timeouts can - * occur until we restart the poll timeout watchdog. - */ - - ret = work_queue(HPWORK, &priv->pollwork, enc_pollworker, (FAR void *)priv, 0); - (void)ret; - DEBUGASSERT(ret == OK); -} - -/**************************************************************************** - * Function: enc_ifup - * - * Description: - * TinyAra Callback: Bring up the Ethernet interface when an IP address is - * provided - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_ifup(struct net_driver_s *dev) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - int ret; - - nlldbg("Bringing up: %d.%d.%d.%d\n", dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24); - - /* Lock the SPI bus so that we have exclusive access */ - - enc_lock(priv); - - /* Initialize Ethernet interface, set the MAC address, and make sure that - * the ENC28J80 is not in power save mode. - */ - - ret = enc_reset(priv); - if (ret == OK) { - enc_setmacaddr(priv); - - /* Enable interrupts at the ENCX24J600. Interrupts are still disabled - * at the interrupt controller. - */ - - enc_bfc(priv, ENC_EIR, EIR_ALLINTS); - enc_bfs(priv, ENC_EIE, EIE_INTIE | EIE_LINKIE | EIE_PKTIE | EIE_RXABTIE | EIE_TXIE); - -#ifdef CONFIG_ENCX24J600_STATS - enc_bfs(priv, ENC_EIE, EIE_TXABTIE); -#endif - - /* Enable the receiver */ - - enc_bfs(priv, ENC_ECON1, ECON1_RXEN); - - /* Set and activate a timer process */ - - (void)wd_start(priv->txpoll, ENC_WDDELAY, enc_polltimer, 1, (uint32_t)priv); - - /* Mark the interface up and enable the Ethernet interrupt at the - * controller - */ - - priv->ifstate = ENCSTATE_UP; - priv->lower->enable(priv->lower); - } - - /* Un-lock the SPI bus */ - - enc_unlock(priv); - - return ret; -} - -/**************************************************************************** - * Function: enc_ifdown - * - * Description: - * TinyAra Callback: Stop the interface. - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_ifdown(struct net_driver_s *dev) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - irqstate_t flags; - int ret; - - nlldbg("Taking down: %d.%d.%d.%d\n", dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24); - - /* Lock the SPI bus so that we have exclusive access */ - - enc_lock(priv); - - /* Disable the Ethernet interrupt */ - - flags = irqsave(); - priv->lower->disable(priv->lower); - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(priv->txpoll); - wd_cancel(priv->txtimeout); - - /* Reset the device and leave in the power save state */ - - ret = enc_reset(priv); - enc_pwrsave(priv); - - priv->ifstate = ENCSTATE_DOWN; - irqrestore(flags); - - /* Un-lock the SPI bus */ - - enc_unlock(priv); - - return ret; -} - -/**************************************************************************** - * Function: enc_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int enc_txavail(struct net_driver_s *dev) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - irqstate_t flags; - - /* Lock the SPI bus so that we have exclusive access */ - - enc_lock(priv); - - /* Ignore the notification if the interface is not yet up */ - - flags = irqsave(); - if (priv->ifstate == ENCSTATE_RUNNING) { - /* Check if the hardware is ready to send another packet. The driver - * starts a transmission process by setting ECON1.TXRTS. When the packet is - * finished transmitting or is aborted due to an error/cancellation, the - * ECON1.TXRTS bit will be cleared. - */ - - if ((enc_rdreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0) { - /* The interface is up and TX is idle; poll uIP for new XMIT data */ - - (void)netif_poll(&priv->dev, enc_txpoll); - } - } - - /* Un-lock the SPI bus */ - - irqrestore(flags); - enc_unlock(priv); - - return OK; -} - -/**************************************************************************** - * Function: enc_rxavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int enc_rxavail(struct net_driver_s *dev) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - - if (!sq_empty(&priv->rxqueue)) { - nllvdbg("RX queue not empty, trying to dispatch\n"); - enc_rxdispatch(priv); - } - - return OK; -} - -/**************************************************************************** - * Function: enc_addmac - * - * Description: - * TinyAra Callback: Add the specified MAC address to the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * mac - The MAC address to be added - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int enc_addmac(struct net_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - - /* Lock the SPI bus so that we have exclusive access */ - - enc_lock(priv); - - /* Add the MAC address to the hardware multicast routing table */ - -#warning "Multicast MAC support not implemented" - - /* Un-lock the SPI bus */ - - enc_unlock(priv); - return OK; -} -#endif - -/**************************************************************************** - * Function: enc_rmmac - * - * Description: - * TinyAra Callback: Remove the specified MAC address from the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * mac - The MAC address to be removed - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int enc_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private; - - /* Lock the SPI bus so that we have exclusive access */ - - enc_lock(priv); - - /* Add the MAC address to the hardware multicast routing table */ - -#warning "Multicast MAC support not implemented" - - /* Un-lock the SPI bus */ - - enc_unlock(priv); - return OK; -} -#endif - -/**************************************************************************** - * Function: enc_pwrsave - * - * Description: - * The ENCX24J600 may be placed in Power-Down mode through the command - * interface. In this mode, the device will no longer be able to transmit or - * receive any packets or perform DMA operations. However, most registers, and - * all buffer memories, retain their states and remain accessible by the host - * controller. The clock driver also remains operational, leaving the CLKOUT - * function unaffected. However, the MAC/MII and PHY registers all become - * inaccessible, and the PHY registers lose their current states. - * - * 1. Turn off the Modular Exponentiation and AES engines by clearing - * CRYPTEN (EIR<15>). - * 2. Turn off packet reception by clearing RXEN (ECON1<0>). - * 3. Wait for any in-progress receptions to complete by polling - * RXBUSY (ESTAT<13>) until it is clear. - * 4. Wait for any current transmission operation to complete by verifying - * that TXRTS (ECON1<1>) is clear. - * 5. Power-down the PHY by setting the PSLEEP bit (PHCON1<11>). - * 6. Power-down the Ethernet interface by clearing - * ETHEN and STRCH (ECON2<15,14>). Disabling the LED stretching behavior is - * necessary to ensure no LEDs get trapped in a perpetually illuminated - * state in the event they are being stretched on when ETHEN is cleared. - * - * Note: - * Instead of providing a powerup function, the job is done by enc_reset. - * enc_ifup calls it anyway. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_pwrsave(FAR struct enc_driver_s *priv) -{ - uint16_t regval; - - nllvdbg("Set PWRSV\n"); - - /* 1. Turn off AES */ - - enc_bfc(priv, ENC_EIR, EIR_CRYPTEN); - - /* 2. Turn off packet reception */ - - enc_bfc(priv, ENC_ECON1, ECON1_RXEN); - - /* 3. Wait for pending reception to complete */ - - enc_waitreg(priv, ENC_ESTAT, ESTAT_RXBUSY, 0); - - /* 4. Wait for any current transmissions to complete */ - - enc_waitreg(priv, ENC_ECON1, ECON1_TXRTS, 0); - - /* 5. Power down the PHY */ - - regval = enc_rdphy(priv, ENC_PHCON1); - regval |= PHCON1_PSLEEP; - enc_wrphy(priv, ENC_PHCON1, regval); - - /* 6. Power down the Ethernet interface */ - - enc_bfc(priv, ENC_ECON2, ECON2_ETHEN | ECON2_STRCH); -} - -/**************************************************************************** - * Function: enc_ldmacaddr - * - * Description: - * Load the MAC address from the ENCX24j600 and write it to the device - * structure. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_ldmacaddr(FAR struct enc_driver_s *priv) -{ - uint16_t regval; - uint8_t *mac = priv->dev.d_mac.ether_addr_octet; - - nvdbg("Using ENCX24J600's built in MAC address\n"); - - regval = enc_rdreg(priv, ENC_MAADR1); - mac[0] = regval & 0xff; - mac[1] = regval >> 8; - - regval = enc_rdreg(priv, ENC_MAADR2); - mac[2] = regval & 0xff; - mac[3] = regval >> 8; - - regval = enc_rdreg(priv, ENC_MAADR3); - mac[4] = regval & 0xff; - mac[5] = regval >> 8; -} - -/**************************************************************************** - * Function: enc_setmacaddr - * - * Description: - * Set the MAC address to the configured value. This is done after ifup - * or after a TX timeout. Note that this means that the interface must - * be down before configuring the MAC addr. - * If the MAC address is 0 in all digits, the ENCX24J600's MAC is read out. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_setmacaddr(FAR struct enc_driver_s *priv) -{ - uint8_t *mac = priv->dev.d_mac.ether_addr_octet; - struct ether_addr zmac; - - memset(&zmac, 0, sizeof(zmac)); - - if (memcmp(&priv->dev.d_mac, &zmac, sizeof(zmac)) == 0) { - /* No user defined MAC address. Read it from the device. */ - - enc_ldmacaddr(priv); - } else { - /* There is a user defined mac address. Write it to the ENCXJ600 */ - - nvdbg("Using an user defined MAC address\n"); - - enc_wrreg(priv, ENC_MAADR1, (uint16_t)mac[1] << 8 | (uint16_t)mac[0]); - enc_wrreg(priv, ENC_MAADR2, (uint16_t)mac[3] << 8 | (uint16_t)mac[2]); - enc_wrreg(priv, ENC_MAADR3, (uint16_t)mac[5] << 8 | (uint16_t)mac[4]); - } -} - -/**************************************************************************** - * Function: enc_resetbuffers - * - * Description: - * Initializes the RX/TX queues and configures the enc's RX/TX buffers. - * Called on general reset and on rxabt interrupt. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static void enc_resetbuffers(FAR struct enc_driver_s *priv) -{ - int i; - /* Initialize receive and transmit buffers */ - - priv->nextpkt = PKTMEM_RX_START; - enc_wrreg(priv, ENC_ERXST, PKTMEM_RX_START); - - /* Program the Tail Pointer, ERXTAIL, to the last even address of the buffer */ - - enc_wrreg(priv, ENC_ERXTAIL, PKTMEM_RX_END - 2); - - sq_init(&priv->txfreedescr); - sq_init(&priv->rxfreedescr); - sq_init(&priv->txqueue); - sq_init(&priv->rxqueue); - - /* For transmition we preinitialize the descriptors to aligned NET_BUFFSIZE */ - - for (i = 0; i < ENC_NTXDESCR; i++) { - priv->txdescralloc[i].addr = PKTMEM_START + PKTMEM_ALIGNED_BUFSIZE * i; - sq_addlast((sq_entry_t *)&priv->txdescralloc[i], &priv->txfreedescr); - } - - /* Receive descriptors addresses are set on reception */ - - for (i = 0; i < CONFIG_ENCX24J600_NRXDESCR; i++) { - sq_addlast((sq_entry_t *)&priv->rxdescralloc[i], &priv->rxfreedescr); - } -} - -/**************************************************************************** - * Function: enc_reset - * - * Description: - * Stop, reset, re-initialize, and restart the ENCX24J600. This is done - * initially, on ifup, and after a TX timeout. - * - * Parameters: - * priv - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int enc_reset(FAR struct enc_driver_s *priv) -{ - int ret; - uint16_t regval; - - nllvdbg("Reset\n"); - - do { - enc_wrreg(priv, ENC_EUDAST, 0x1234); - } while (enc_rdreg(priv, ENC_EUDAST) != 0x1234); - - /* Wait for clock to become ready */ - - ret = enc_waitreg(priv, ENC_ESTAT, ESTAT_CLKRDY, ESTAT_CLKRDY); - - if (ret != OK) { - nlldbg("ERROR: encx24j600 clock failed to become ready\n"); - return -ENODEV; - } - - /* Reset the ENCX24J600 */ - - enc_setethrst(priv); - - /* Check if EUDAST has been reset to 0 */ - - regval = enc_rdreg(priv, ENC_EUDAST); - - if (regval != 0x0000) { - nlldbg("ERROR: encx24j600 seems not to be reset properly\n"); - return -ENODEV; - } - - /** - * Wait at least 256 μs for the PHY registers and PHY status bits to become - * available. - */ - up_udelay(256); - - /* Initialize RX/TX buffers */ - - enc_resetbuffers(priv); - -#if 0 - /* When restarting auto-negotiation, the ESTAT_PHYLINK gets set but the link - * seems not to be ready. Because auto-negotiation is enabled by default - * (but with different PHANA_* settings) I did not investigate that further. - */ - - /* "Typically, when using auto-negotiation, users should write 0x05E1 to PHANA - * to advertise flow control capability." - */ - - enc_wrphy(priv, ENC_PHANA, PHANA_ADPAUS0 | PHANA_AD10FD | PHANA_AD10 | PHANA_AD100FD | PHANA_AD100 | PHANA_ADIEEE0); - - /* Restart auto-negotiation */ - - enc_wrphy(priv, ENC_PHCON1, PHCON1_RENEG); - - do { - regval = enc_rdphy(priv, ENC_PHSTAT1); - } while ((regval & PHSTAT1_ANDONE) != 0); - - nllvdbg("Auto-negotation completed\n"); - -#endif - - enc_linkstatus(priv); - - /* Set the maximum packet size which the controller will accept */ - - enc_wrreg(priv, ENC_MAMXFL, CONFIG_NET_ETH_MTU + 4); - - ret = enc_waitreg(priv, ENC_ESTAT, ESTAT_PHYLNK, ESTAT_PHYLNK); - - if (ret == OK) { - enc_linkstatus(priv); - } -#if 0 - if (ret != OK) { - nlldbg("ERROR: encx24j600 failed to establish link\n"); - return -ENODEV; - } -#endif - - return OK; -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: enc_initialize - * - * Description: - * Initialize the Ethernet driver. The ENCX24J600 device is assumed to be - * in the post-reset state upon entry to this function. - * - * Parameters: - * spi - A reference to the platform's SPI driver for the ENCX24J600 - * lower - The MCU-specific interrupt used to control low-level MCU - * functions (i.e., ENCX24J600 GPIO interrupts). - * devno - If more than one ENCX24J600 is supported, then this is the - * zero based number that identifies the ENCX24J600; - * - * Returned Value: - * OK on success; Negated errno on failure. - * - * Assumptions: - * - ****************************************************************************/ - -int enc_initialize(FAR struct spi_dev_s *spi, FAR const struct enc_lower_s *lower, unsigned int devno) -{ - FAR struct enc_driver_s *priv; - - DEBUGASSERT(devno < CONFIG_ENCX24J600_NINTERFACES); - priv = &g_encx24j600[devno]; - - /* Initialize the driver structure */ - - memset(g_encx24j600, 0, CONFIG_ENCX24J600_NINTERFACES * sizeof(struct enc_driver_s)); - priv->dev.d_ifup = enc_ifup; /* I/F up (new IP address) callback */ - priv->dev.d_ifdown = enc_ifdown; /* I/F down callback */ - priv->dev.d_txavail = enc_txavail; /* New TX data callback */ - priv->dev.d_rxavail = enc_rxavail; /* RX wating callback */ -#ifdef CONFIG_NET_IGMP - priv->dev.d_addmac = enc_addmac; /* Add multicast MAC address */ - priv->dev.d_rmmac = enc_rmmac; /* Remove multicast MAC address */ -#endif - priv->dev.d_private = priv; /* Used to recover private state from dev */ - - /* Create a watchdog for timing polling for and timing of transmisstions */ - - priv->txpoll = wd_create(); /* Create periodic poll timer */ - priv->txtimeout = wd_create(); /* Create TX timeout timer */ - priv->spi = spi; /* Save the SPI instance */ - priv->lower = lower; /* Save the low-level MCU interface */ - - /* The interface should be in the down state. However, this function is called - * too early in initalization to perform the ENCX24J600 reset in enc_ifdown. We - * are depending upon the fact that the application level logic will call enc_ifdown - * later to reset the ENCX24J600. - */ - - priv->ifstate = ENCSTATE_UNINIT; - - /* Attach the interrupt to the driver (but don't enable it yet) */ - - if (lower->attach(lower, enc_interrupt)) { - /* We could not attach the ISR to the interrupt */ - - return -EAGAIN; - } - - /* Configure SPI for the ENCX24J600 */ - - enc_configspi(priv->spi); - - /* Lock the SPI bus so that we have exclusive access */ - - enc_lock(priv); - - /* Load the MAC address */ - - enc_ldmacaddr(priv); - - /* Power down the device */ - - enc_pwrsave(priv); - - /* Unlock the SPI bus */ - - enc_unlock(priv); - - /* Register the device with the OS so that socket IOCTLs can be performed */ - - return netdev_register(&priv->dev, NET_LL_ETHERNET); -} - -/**************************************************************************** - * Function: enc_stats - * - * Description: - * Return accumulated ENCX24J600 statistics. Statistics are cleared after - * being returned. - * - * Parameters: - * devno - If more than one ENCX24J600 is supported, then this is the - * zero based number that identifies the ENCX24J600; - * stats - The user-provided location to return the statistics. - * - * Returned Value: - * OK on success; Negated errno on failure. - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_ENCX24J600_STATS -int enc_stats(unsigned int devno, struct enc_stats_s *stats) -{ - FAR struct enc_driver_s *priv; - irqstate_t flags; - - DEBUGASSERT(devno < CONFIG_ENCX24J600_NINTERFACES); - priv = &g_encx24j600[devno]; - - /* Disable the Ethernet interrupt */ - - flags = irqsave(); - memcpy(stats, &priv->stats, sizeof(struct enc_stats_s)); - memset(&priv->stats, 0, sizeof(struct enc_stats_s)); - irqrestore(flags); - return OK; -} -#endif -#endif /* CONFIG_NET && CONFIG_ENCX24J600_NET */ diff --git a/os/drivers/net/encx24j600.h b/os/drivers/net/encx24j600.h deleted file mode 100644 index 0364c79..0000000 --- a/os/drivers/net/encx24j600.h +++ /dev/null @@ -1,422 +0,0 @@ -/**************************************************************************** - * drivers/net/encx24j600.h - * - * Copyright (C) 2013 UVC Ingenieure. All rights reserved. - * Author: Max Holtberg - * - * References: - * - ENC424J600/624J600 Data Sheet, Stand-Alone 10/100 Ethernet Controller - * with SPI or Parallel Interface, DS39935C, 2010 Microchip Technology Inc. - * - * 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 NuttX nor the names of its 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. - * - ****************************************************************************/ - -#ifndef __DRIVERS_NET_ENCX24J600_H -#define __DRIVERS_NET_ENCX24J600_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* ENCX24J600 Commands ********************************************************/ - -/* The SPI opcodes are divided into four families: - * - * Single Byte: Direct opcode instructions; designed for task-oriented SFR - * operations with no data returned - * - * Two-Byte: Direct opcode instruction; designed for SFR operation with byte - * data returned - * - * Three-Byte: Opcode with word length argument; includes read and write - * operations, designed for pointer manipulation with word length data returned - * - * N-Byte: Opcode with one or more bytes of argument; includes read and write - * operations designed for general memory space access with one or more bytes of - * data returned - */ - -/* Single-Byte Instructions */ - -/* Because all single byte instructions are fixed length with no optional - * parameters, it is possible to execute any instruction immediately following - * the execution of any single byte instruction without deasserting the chip - * select line in between. - */ - -#define ENC_B0SEL (0xc0) /* Selects SFR Bank 0 */ -#define ENC_B1SEL (0xc2) /* Selects SFR Bank 1 */ -#define ENC_B2SEL (0xc4) /* Selects SFR Bank 2 */ -#define ENC_B3SEL (0xc6) /* Selects SFR Bank 3 */ -#define ENC_SETETHRST (0xca) /* Issues System Reset by setting ETHRST (ECON2<4>) */ -#define ENC_FCDISABLE (0xe0) /* Disables flow control (sets ECON1<7:6> = 00) */ -#define ENC_FCSINGLE (0xe2) /* Transmits a single pause frame (sets ECON1<7:6> = 01) */ -#define ENC_FCMULTIPLE (0xe4) /* Enables flow control with periodic pause frames (sets ECON1<7:6> = 10) */ -#define ENC_FCCLEAR (0xe6) /* Terminates flow control with a final pause frame (sets ECON1<7:6> = 11) */ -#define ENC_SETPKTDEC (0xcc) /* Decrements PKTCNT by setting PKTDEC (ECON1<8>) */ -#define ENC_DMASTOP (0xd2) /* Stops current DMA operation by clearing DMAST (ECON1<5>) */ -#define ENC_DMACKSUM (0xd8) /* Starts DMA and checksum operation (sets ECON1<5:2> = 1000) */ -#define ENC_DMACKSUMS (0xda) /* Starts DMA checksum operation with seed (sets ECON1<5:2> = 1010) */ -#define ENC_DMACOPY (0xdc) /* Starts DMA copy and checksum operation (sets ECON1<5:2> = 1100) */ -#define ENC_DMACOPYS (0xde) /* Starts DMA copy and checksum operation with seed (sets ECON1<5:2> = 1110) */ -#define ENC_SETTXRTS (0xd4) /* Sets TXRTS (ECON1<1>), sends an Ethernet packet */ -#define ENC_ENABLERX (0xe8) /* Enables packet reception by setting RXEN (ECON1<0>) */ -#define ENC_DISABLERX (0xea) /* Disables packet reception by clearing RXEN (ECON1<0>) */ -#define ENC_SETEIE (0xec) /* Enable Ethernet Interrupts by setting INT (ESTAT<15>) */ -#define ENC_CLREIE (0xee) /* Disable Ethernet Interrupts by clearing INT (ESTAT<15>) */ - -/* Two-Byte Instructions */ - -/* There is only one instruction in the ENCX24J600 command set which uses two - * SPI bytes. The Read Bank Select opcode, RBSEL, reads the internal SFR bank - * select state and returns the value to the host controller. - */ - -#define ENC_RBSEL (0xc8) - -/* Three-Byte Instructions */ - -#define ENC_WGPRDPT (0x60) /* Write General Purpose Buffer Read Pointer (EGPRDPT) */ -#define ENC_RGPRDPT (0x62) /* Read General Purpose Buffer Read Pointer (EGPRDPT) */ -#define ENC_WRXRDPT (0x64) /* Write Receive Buffer Read Pointer (ERXRDPT) */ -#define ENC_RRXRDPT (0x66) /* Read Receive Buffer Read Pointer (ERXRDPT) */ -#define ENC_WUDARDPT (0x68) /* Write User-Defined Area Read Pointer (EUDARDPT) */ -#define ENC_RUDARDPT (0x6a) /* Read User-Defined Area Read Pointer (EUDARDPT) */ -#define ENC_WGPWRPT (0x6c) /* Write General Purpose Buffer Write Pointer (EGPWRPT) */ -#define ENC_RGPWRPT (0x6e) /* Read General Purpose Buffer Write Pointer (EGPWRPT) */ -#define ENC_WRXWRPT (0x70) /* Write Receive Buffer Write Pointer (ERXWRPT) */ -#define ENC_RRXWRPT (0x72) /* Read Receive Buffer Write Pointer (ERXWRPT) */ -#define ENC_WUDAWRPT (0x78) /* Write User-Defined Area Write Pointer (EUDAWRPT) */ -#define ENC_RUDAWRPT (0x76) /* Read User-Defined Area Write Pointer (EUDAWRPT) */ - -/* Banked N-Byte Instructions */ - -#define ENC_RCR (0x00) /* Read Control Register - 000 | aaaaa | (Register value returned)) */ -#define ENC_WCR (0x40) /* Write Control Register - 010 | aaaaa | dddddddd */ -#define ENC_BFS (0x80) /* Bit Field Set - 100 | aaaaa | dddddddd */ -#define ENC_BFC (0xa0) /* Bit Field Clear - 101 | aaaaa | dddddddd */ - -/* Unbanked N-Byte Instructions */ - -#define ENC_RCRU (0x20) /* Read Control Register(s), Unbanked */ -#define ENC_WCRU (0x22) /* Write Control Register(s), Unbanked */ -#define ENC_BFSU (0x24) /* Bit Field(s) Set, Unbanked */ -#define ENC_BFCU (0x26) /* Bit Field(s) Clear, Unbanked */ - -/* SRAM Access Instructions */ - -#define ENC_RGPDATA (0x28) /* Read Data from EGPDATA */ -#define ENC_WGPDATA (0x2a) /* Write Data from EGPDATA */ -#define ENC_RRXDATA (0x2c) /* Read Data from ERXDATA */ -#define ENC_WRXDATA (0x2e) /* Write Data from ERXDATA */ -#define ENC_RUDADATA (0x30) /* Read Data from EUDADATA */ -#define ENC_WUDADATA (0x32) /* Write Data from EUDADATA */ - -/* Banked Control Registers *************************************************/ -/* Registers are described by 16 bit values. The high byte describes the bank - * by the appropiate bank selection command. - * For registers which are available on all banks the comnmand is set to 0. - * Unbanked registers are identified by 0x01. - */ - -#define ENC_ADDR_SHIFT (0) -#define ENC_ADDR_MASK (0xff << ENC_ADDR_SHIFT) -#define ENC_BANK_SHIFT (8) -#define ENC_BANK_MASK (0xff << ENC_BANK_SHIFT) - -#define REGADDR(a, b) ((b) << ENC_BANK_SHIFT | (a) << ENC_ADDR_SHIFT) -#define GETADDR(a) (((a) & ENC_ADDR_MASK) >> ENC_ADDR_SHIFT) -#define GETBANK(a) (((a) & ENC_BANK_MASK) >> ENC_BANK_SHIFT) - -/* Bank 0 Control Register Addresses */ - -#define ENC_ETXST REGADDR(0x00, ENC_B0SEL) -#define ENC_ETXLEN REGADDR(0x02, ENC_B0SEL) -#define ENC_ERXST REGADDR(0x04, ENC_B0SEL) -#define ENC_ERXTAIL REGADDR(0x06, ENC_B0SEL) -#define ENC_ERXHEAD REGADDR(0x08, ENC_B0SEL) -#define ENC_EDMAST REGADDR(0x0a, ENC_B0SEL) -#define ENC_EDMALEN REGADDR(0x0c, ENC_B0SEL) -#define ENC_EDMADST REGADDR(0x0e, ENC_B0SEL) -#define ENC_EDMACS REGADDR(0x10, ENC_B0SEL) -#define ENC_ETXSTAT REGADDR(0x12, ENC_B0SEL) -#define ENC_ETXWIRE REGADDR(0x14, ENC_B0SEL) - -/* Bank 1 Contro Register Addresses */ - -#define ENC_EHT1 REGADDR(0x00, ENC_B1SEL) -#define ENC_EHT2 REGADDR(0x02, ENC_B1SEL) -#define ENC_EHT3 REGADDR(0x04, ENC_B1SEL) -#define ENC_EHT4 REGADDR(0x06, ENC_B1SEL) -#define ENC_EPMM1 REGADDR(0x08, ENC_B1SEL) -#define ENC_EPMM2 REGADDR(0x0a, ENC_B1SEL) -#define ENC_EPMM3 REGADDR(0x0c, ENC_B1SEL) -#define ENC_EPMM4 REGADDR(0x0e, ENC_B1SEL) -#define ENC_EPMCS REGADDR(0x10, ENC_B1SEL) -#define ENC_EPMO REGADDR(0x12, ENC_B1SEL) -#define ENC_ERXFCON REGADDR(0x14, ENC_B1SEL) - -/* Bank 2 Control Register Addresses */ - -#define ENC_MACON1 REGADDR(0x00, ENC_B2SEL) -#define ENC_MACON2 REGADDR(0x02, ENC_B2SEL) -#define ENC_MABBIPG REGADDR(0x04, ENC_B2SEL) -#define ENC_MAIPG REGADDR(0x06, ENC_B2SEL) -#define ENC_MACLCON REGADDR(0x08, ENC_B2SEL) -#define ENC_MAMXFL REGADDR(0x0a, ENC_B2SEL) -/* 0x0c - 0x11 reserved */ -#define ENC_MICMD REGADDR(0x12, ENC_B2SEL) -#define ENC_MIREGADR REGADDR(0x14, ENC_B2SEL) - -/* MAC Control Register 1 Bit Definitions */ - -#define MACON1_PASSALL (1 << 1) -#define MACON1_RXPAUS (1 << 2) -#define MACON1_LOOPBK (1 << 4) - -/* MAC Control Register 2 Bit Definitions */ - -#define MACON2_FULDPX (1 << 0) /* MAC Full-Duplex Enable bit */ -#define MACON2_HFRMEN (1 << 2) /* Huge Frame Enable bit */ -#define MACON2_PHDREN (1 << 3) /* Proprietary Header Enable bit */ -#define MACON2_TXCRCEN (1 << 4) /* Transmit CRC Enable bit */ -#define MACON2_PADCFG0 (1 << 5) /* Automatic Pad and CRC Configuration bits */ -#define MACON2_PADCFG1 (1 << 6) -#define MACON2_PADCFG2 (1 << 7) -#define MACON2_NOBKOFF (1 << 12) /* No Backoff Enable bit (applies to half duplex only) */ -#define MACON2_BPEN (1 << 13) /* No Backoff During Back Pressure Enable bit (applies to half duplex only) */ -#define MACON2_DEFER (1 << 14) /* Defer Transmission Enable bit (applies to half duplex only) */ - -/* MII Management Command Register Bit Definitions */ - -#define MICMD_MIIRD (1 << 0) /* MII Read Enable bit */ -#define MICMD_MIISCAN (1 << 1) /* MII Scan Enable bit */ - -/* MII Management Status Register Bit Definitions */ - -#define MISTAT_BUSY (1 << 0) /* MII Management Busy Status bit */ -#define MISTAT_SCAN (1 << 1) /* MII Management Scan Status bit */ -#define MISTAT_NVALID (1 << 2) /* MII Management Read Data Not Valid Status bit */ - -/* Bank 3 Control Register Addresses */ - -#define ENC_MAADR3 REGADDR(0x00, ENC_B3SEL) -#define ENC_MAADR2 REGADDR(0x02, ENC_B3SEL) -#define ENC_MAADR1 REGADDR(0x04, ENC_B3SEL) -#define ENC_MIWR REGADDR(0x06, ENC_B3SEL) -#define ENC_MIRD REGADDR(0x08, ENC_B3SEL) -#define ENC_MISTAT REGADDR(0x0a, ENC_B3SEL) -#define ENC_EPAUS REGADDR(0x0c, ENC_B3SEL) -#define ENC_ECON2 REGADDR(0x0e, ENC_B3SEL) -#define ENC_ERXWM REGADDR(0x10, ENC_B3SEL) -#define ENC_EIE REGADDR(0x12, ENC_B3SEL) -#define ENC_EIDLED REGADDR(0x14, ENC_B3SEL) - -/* Ethernet Control Register Bit Definitions */ - -#define ECON2_AESLEN0 (1 << 0) /* AES Key Length Control bits */ -#define ECON2_AESLEN1 (1 << 1) /* Modular Exponentiation Length Control bits */ -#define ECON2_MODLEN0 (1 << 2) -#define ECON2_MODLEN1 (1 << 3) -#define ECON2_ETHRST (1 << 4) /* Master Ethernet Reset bit */ -#define ECON2_RXRST (1 << 5) /* Receive Logic Reset bit */ -#define ECON2_TXRST (1 << 6) /* Transmit Logic Reset bit */ -#define ECON2_AUTOFC (1 << 7) /* Automatic Flow Control Enable bit */ -#define ECON2_COCON_SHIFT (8) /* CLKOUT Frequency Control bits */ -#define ECON2_COCON_MASK (0x0f << ECON2_COCON_SHIFT) -#define ECON2_SHA1MD5 (1 << 12) /* SHA-1/MD5 Hash Control bit */ -#define ECON2_TXMAC (1 << 13) /* Automatically Transmit MAC Address Enable bit */ -#define ECON2_STRCH (1 << 14) /* LED Stretching Enable bit */ -#define ECON2_ETHEN (1 << 15) /* Ethernet Enable bit */ - -/* Ethernet Interrupt Enable Register Bit Definitions */ - -#define EIE_PCFULIE (1 << 0) /* Packet Counter Full Interrupt Enable bit */ -#define EIE_RXABTIE (1 << 1) /* Receive Abort Interrupt Enable bit */ -#define EIE_TXABTIE (1 << 2) /* Transmit Abort Interrupt Enable bit */ -#define EIE_TXIE (1 << 3) /* Transmit Done Interrupt Enable bit */ -#define EIE_DMAIE (1 << 5) /* DMA Interrupt Enable bit */ -#define EIE_PKTIE (1 << 6) /* RX Packet Pending Interrupt Enable bit */ -#define EIE_LINKIE (1 << 11) /* PHY Link Status Change Interrupt Enable bit */ -#define EIE_AESIE (1 << 12) /* AES Encrypt/Decrypt Interrupt Enable bit */ -#define EIE_HASHIE (1 << 13) /* MD5/SHA-1 Hash Interrupt Enable bit */ -#define EIE_MODEXIE (1 << 14) /* Modular Exponentiation Interrupt Enable bit */ -#define EIE_INTIE (1 << 15) /* INT Global Interrupt Enable bit */ - -/** - * The last 10 bytes (16h to 1Fh) of all SPI banks point to a common set of five - * registers: EUDAST, EUDAND, ESTAT, EIR and ECON1. These are key registers used - * in controlling and monitoring the operation of the device. Their common - * banked addresses allow easy access without switching the bank. - */ - -/* Common Register Addresses */ - -#define ENC_EUDAST REGADDR(0x16, 0x00) /* User-Defined Area Start Pointer (EUDAST<7:0>) */ -#define ENC_EUDAND REGADDR(0x18, 0x00) /* User-Defined Area End Pointer (EUDAND<7:0>) */ -#define ENC_ESTAT REGADDR(0x1a, 0x00) -#define ENC_EIR REGADDR(0x1c, 0x00) -#define ENC_ECON1 REGADDR(0x1e, 0x00) - -/* Ethernet Status Register Bit Definitions */ - -#define ESTAT_PKTCNT_SHIFT (0) /* Receive Packet Count bits */ -#define ESTAT_PKTCNT_MASK (0xff) -#define ESTAT_PHYLNK (1 << 8) /* PHY Linked Status bit */ -#define ESTAT_PHYDPX (1 << 10) /* PHY Full Duplex Status bit */ -#define ESTAT_CLKRDY (1 << 12) /* Clock Ready Status bit */ -#define ESTAT_RXBUSY (1 << 13) /* Receive Logic Active Status bit */ -#define ESTAT_FCIDLE (1 << 14) /* Flow Control Idle Status bit */ -#define ESTAT_INT (1 << 15) /* Interrupt Pending Status bit */ - -/* Ethernet Interrupt Flag Register Bit Definitions */ - -#define EIR_PCFULIF (1 << 0) /* Packet Counter Full Interrupt Flag bit */ -#define EIR_RXABTIF (1 << 1) /* Receive Abort Interrupt Flag bit */ -#define EIR_TXABTIF (1 << 2) /* Transmit Abort Interrupt Flag bit */ -#define EIR_TXIF (1 << 3) /* Transmit Done Interrupt Flag bit */ -#define EIR_DMAIF (1 << 5) /* DMA Interrupt Flag bit */ -#define EIR_PKTIF (1 << 6) /* RX Packet Pending Interrupt Flag bit */ -#define EIR_LINKIF (1 << 11) /* PHY Link Status Change Interrupt Flag bit */ -#define EIR_AESIF (1 << 12) /* AES Encrypt/Decrypt Interrupt Flag bit */ -#define EIR_HASHIF (1 << 13) /* MD5/SHA-1 Hash Interrupt Flag bit */ -#define EIR_MODEXIF (1 << 14) /* Modular Exponentiation Interrupt Flag bit */ -#define EIR_CRYPTEN (1 << 15) /* Modular Exponentiation and AES Cryptographic Modules Enable bit */ -#define EIR_ALLINTS (0xf86f) - -/* Ethernet Control Register 1 Bit Definitions */ - -#define ECON1_RXEN (1 << 0) /* Receive Enable bit */ -#define ECON1_TXRTS (1 << 1) /* Transmit Request to Send Status/Control bit */ -#define ECON1_DMANOCS (1 << 2) /* DMA No Checksum Control bit */ -#define ECON1_DMACSSD (1 << 3) /* DMA Checksum Seed Control bit */ -#define ECON1_DMACPY (1 << 4) /* DMA Copy Control bit */ -#define ECON1_DMAST (1 << 5) /* DMA Start bit */ -#define ECON1_FCOP0 (1 << 6) /* Flow Control Operation Control/Status bits */ -#define ECON1_FCOP1 (1 << 7) /* Flow Control Operation Control/Status bits */ -#define ECON1_PKTDEC (1 << 8) /* RX Packet Counter Decrement Control bit */ -#define ECON1_AESOP0 (1 << 9) /* AES Operation Control bits */ -#define ECON1_AESOP1 (1 << 10) /* AES Operation Control bits */ -#define ECON1_AESST (1 << 11) /* AES Encrypt/Decrypt Start bit */ -#define ECON1_HASHLST (1 << 12) /* MD5/SHA-1 Hash Last Block Control bit */ -#define ECON1_HASHOP (1 << 13) /* MD5/SHA-1 Hash Operation Control bit */ -#define ECON1_HASHEN (1 << 14) /* MD5/SHA-1 Hash Enable bit */ -#define ECON1_MODEXST (1 << 15) /* Modular Exponentiation Start bit */ - -/* Unbanked Register Addresses */ - -#if 0 -/* Disabled to prevent accidental use. All unbanked operations are implemented - * using the specific manipulation commands. - */ -#define ENC_EGPDATA 0x80 -#define ENC_ERXDATA 0x82 -#define ENC_EUDADATA 0x84 -#define ENC_EGPRDPT 0x86 -#define ENC_EGPWRPT 0x88 -#define ENC_ERXRDPT 0x8a -#define ENC_ERXWRPT 0x8c -#define ENC_EUDARDPT 0x8e -#define ENC_EUDAWRPT 0x90 -#endif - -/* PHY Registers ************************************************************/ - -#define ENC_PHCON1 0x00 -#define ENC_PHSTAT1 0x01 -#define ENC_PHANA 0x04 -#define ENC_PHANLPA 0x05 -#define ENC_PHANE 0x06 -#define ENC_PHCON2 0x11 -#define ENC_PHSTAT2 0x1b -#define ENC_PHSTAT3 0x1f - -/* PHY Control Register 1 Bit Definitions */ - -#define PHCON1_PFULDPX (1 << 8) /* PHY Duplex Select Control bit */ -#define PHCON1_RENEG (1 << 9) /* Restart Auto-Negotiation Control bit */ -#define PHCON1_PSLEEP (1 << 11) /* PHY Sleep Enable bit */ -#define PHCON1_ANEN (1 << 12) /* PHY Auto-Negotiation Enable bit */ -#define PHCON1_SPD100 (1 << 13) /* PHY Speed Select Control bit */ -#define PHCON1_PLOOPBK (1 << 14) /* PHY Loopback Enable bit */ -#define PHCON1_PRST (1 << 15) /* PHY Reset bit */ - -/* PHY Status Register 1 Bit Definitions */ - -#define PHSTAT1_EXTREGS (1 << 0) /* Extended Capabilities Registers Present Status bit */ -#define PHSTAT1_LLSTAT (1 << 2) /* Latching Link Status bit */ -#define PHSTAT1_ANABLE (1 << 3) /* Auto-Negotiation Ability Status bit */ -#define PHSTAT1_LRFAULT (1 << 4) /* Latching Remote Fault Condition Status bit */ -#define PHSTAT1_ANDONE (1 << 5) /* Auto-Negotiation Done Status bit */ -#define PHSTAT1_HALF10 (1 << 11) /* 10Base-T Half-Duplex Ability Status bit */ -#define PHSTAT1_FULL10 (1 << 12) /* 10Base-T Full-Duplex Ability Status bit */ -#define PHSTAT1_HALF100 (1 << 13) /* 100Base-TX Half-Duplex Ability Status bit */ -#define PHSTAT1_FULL100 (1 << 13) /* 100Base-TX Full-Duplex Ability Status bit */ - -/* PHY Auto-Negotiation Advertisement Register Bit Definitions */ - -#define PHANA_ADIEEE0 (1 << 0) -#define PHANA_ADIEEE1 (1 << 1) -#define PHANA_ADIEEE2 (1 << 2) -#define PHANA_ADIEEE3 (1 << 3) -#define PHANA_ADIEEE4 (1 << 4) -#define PHANA_AD10 (1 << 5) /* Advertise 10Base-T Half-Duplex Ability bit */ -#define PHANA_AD10FD (1 << 6) /* Advertise 10Base-T Full-Duplex Ability bit */ -#define PHANA_AD100 (1 << 7) /* Advertise 100Base-TX Half-Duplex Ability bit */ -#define PHANA_AD100FD (1 << 8) /* Advertise 100Base-TX Full-Duplex Ability bit */ -/* Advertise PAUSE Flow Control Ability bits */ -/* 11 = Local device supports both symmetric PAUSE and asymmetric PAUSE toward local device */ -/* 10 = Local device supports asymmetric PAUSE toward link partner only */ -/* 01 = Local device supports symmetric PAUSE only (Normal Flow Control mode) */ -/* 00 = Local device does not support PAUSE flow control */ -#define PHANA_ADPAUS0 (1 << 10) -#define PHANA_ADPAUS1 (1 << 11) -#define PHANA_ADFAULT (1 << 13) /* Advertise Remote Fault Condition bit */ -#define PHANA_ADNP (1 << 15) /* Advertise Next Page Ability bit */ - -/* Packet Memory ************************************************************/ - -/* 24-Kbyte Transmit/Receive Packet Dual Port SRAM */ - -#define PKTMEM_START 0x0000 -#define PKTMEM_SIZE 0x6000 - -/* RX Status Bit Definitions ************************************************/ - -#define RXSTAT_OK (1 << 7) - -#endif /* __DRIVERS_NET_ENCX24J600_H */ diff --git a/os/drivers/net/vnet.c b/os/drivers/net/vnet.c deleted file mode 100644 index 66a11ef..0000000 --- a/os/drivers/net/vnet.c +++ /dev/null @@ -1,785 +0,0 @@ -/**************************************************************************** - * - * Copyright 2016 Samsung Electronics All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific - * language governing permissions and limitations under the License. - * - ****************************************************************************/ -/**************************************************************************** - * drivers/net/vnet.c - * - * Copyright (C) 2011 Yu Qiang. All rights reserved. - * Author: Yu Qiang - * - * This file is a part of NuttX: - * - * Copyright (C) 2011, 2014 Gregory Nutt. 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 NuttX nor the names of its 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. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#if defined(CONFIG_NET) && defined(CONFIG_NET_VNET) - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#ifdef CONFIG_NET_PKT -#include -#endif - -#include -#include - -/**************************************************************************** - * Definitions - ****************************************************************************/ - -/* CONFIG_VNET_NINTERFACES determines the number of physical interfaces - * that will be supported. - */ - -#ifndef CONFIG_VNET_NINTERFACES -#define CONFIG_VNET_NINTERFACES 1 -#endif - -/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */ - -#define VNET_WDDELAY (1*CLK_TCK) -#define VNET_POLLHSEC (1*2) - -/* TX timeout = 1 minute */ - -#define VNET_TXTIMEOUT (60*CLK_TCK) - -/* This is a helper pointer for accessing the contents of the Ethernet header */ - -#define BUF ((struct eth_hdr_s *)vnet->sk_dev.d_buf) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* The vnet_driver_s encapsulates all state information for a single hardware - * interface - */ - -struct vnet_driver_s { - bool sk_bifup; /* true:ifup false:ifdown */ - WDOG_ID sk_txpoll; /* TX poll timer */ - //WDOG_ID sk_txtimeout; /* TX timeout timer */ - - /* This holds the information visible to uIP/TinyAra */ - - struct rgmp_vnet *vnet; - struct net_driver_s sk_dev; /* Interface understood by uIP */ -}; - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static struct vnet_driver_s g_vnet[CONFIG_VNET_NINTERFACES]; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Common TX logic */ - -static int vnet_transmit(FAR struct vnet_driver_s *vnet); -static int vnet_txpoll(struct net_driver_s *dev); - -/* Interrupt handling */ - -static void vnet_txdone(FAR struct vnet_driver_s *vnet); - -/* Watchdog timer expirations */ - -static void vnet_polltimer(int argc, uint32_t arg, ...); -static void vnet_txtimeout(int argc, uint32_t arg, ...); - -/* TinyAra callback functions */ - -static int vnet_ifup(struct net_driver_s *dev); -static int vnet_ifdown(struct net_driver_s *dev); -static int vnet_txavail(struct net_driver_s *dev); -#ifdef CONFIG_NET_IGMP -static int vnet_addmac(struct net_driver_s *dev, FAR const uint8_t *mac); -static int vnet_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac); -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: vnet_transmit - * - * Description: - * Start hardware transmission. Called either from the txdone interrupt - * handling or from watchdog based polling. - * - * Parameters: - * vnet - Reference to the driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. - * - ****************************************************************************/ - -static int vnet_transmit(FAR struct vnet_driver_s *vnet) -{ - int err; - - /* Verify that the hardware is ready to send another packet. If we get - * here, then we are committed to sending a packet; Higher level logic - * must have assured that there is not transmission in progress. - */ - - /* Increment statistics */ - - /* Send the packet: address=vnet->sk_dev.d_buf, length=vnet->sk_dev.d_len */ - - err = vnet_xmit(vnet->vnet, (char *)vnet->sk_dev.d_buf, vnet->sk_dev.d_len); - if (err) { - /* Setup the TX timeout watchdog (perhaps restarting the timer) */ - - //(void)wd_start(vnet->sk_txtimeout, VNET_TXTIMEOUT, vnet_txtimeout, 1, (uint32_t)vnet); - - /* When vnet_xmit fail, it means TX buffer is full. Watchdog - * is of no use here because no TX done INT will happen. So - * we reset the TX buffer directly. - */ - -#ifdef CONFIG_DEBUG - cprintf("VNET: TX buffer is full\n"); -#endif - return ERROR; - } else { - /* This step may be unnecessary here */ - - vnet_txdone(vnet); - } - - return OK; -} - -/**************************************************************************** - * Function: vnet_txpoll - * - * Description: - * The transmitter is available, check if uIP has any outgoing packets ready - * to send. This is a callback from netif_poll(). netif_poll() may be called: - * - * 1. When the preceding TX packet send is complete, - * 2. When the preceding TX packet send timesout and the interface is reset - * 3. During normal TX polling - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * OK on success; a negated errno on failure - * - * Assumptions: - * May or may not be called from an interrupt handler. In either case, - * global interrupts are disabled, either explicitly or indirectly through - * interrupt handling logic. - * - ****************************************************************************/ - -static int vnet_txpoll(struct net_driver_s *dev) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - - /* If the polling resulted in data that should be sent out on the network, - * the field d_len is set to a value > 0. - */ - - if (vnet->sk_dev.d_len > 0) { - /* Look up the destination MAC address and add it to the Ethernet - * header. - */ - -#ifdef CONFIG_NET_IPv4 -#ifdef CONFIG_NET_IPv6 - if (IFF_IS_IPv4(vnet->sk_dev.d_flags)) -#endif - { - arp_out(&vnet->sk_dev); - } -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -#ifdef CONFIG_NET_IPv4 - else -#endif - { - neighbor_out(&vnet->sk_dev); - } -#endif /* CONFIG_NET_IPv6 */ - - /* Send the packet */ - - vnet_transmit(vnet); - - /* Check if there is room in the device to hold another packet. If not, - * return a non-zero value to terminate the poll. - */ - - if (vnet_is_txbuff_full(vnet->vnet)) { - return 1; - } - } - - /* If zero is returned, the polling will continue until all connections have - * been examined. - */ - - return 0; -} - -/**************************************************************************** - * Function: rtos_vnet_recv - * - * Description: - * An interrupt was received indicating the availability of a new RX packet - * - * Parameters: - * vnet - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by interrupt handling logic. - * - ****************************************************************************/ - -void rtos_vnet_recv(struct rgmp_vnet *rgmp_vnet, char *data, int len) -{ - struct vnet_driver_s *vnet = rgmp_vnet->priv; - - do { - /* Check for errors and update statistics */ - - /* Check if the packet is a valid size for the uIP buffer configuration */ - - if (len > CONFIG_NET_ETH_MTU || len < 14) { -#ifdef CONFIG_DEBUG - cprintf("VNET: receive invalid packet of size %d\n", len); -#endif - return; - } - - /* Copy the data data from the hardware to vnet->sk_dev.d_buf. Set - * amount of data in vnet->sk_dev.d_len - */ - - memcpy(vnet->sk_dev.d_buf, data, len); - vnet->sk_dev.d_len = len; - -#ifdef CONFIG_NET_PKT - /* When packet sockets are enabled, feed the frame into the packet tap */ - - pkt_input(&vnet->sk_dev); -#endif - - /* We only accept IP packets of the configured type and ARP packets */ - -#ifdef CONFIG_NET_IPv4 - if (BUF->type == HTONS(ETHTYPE_IP)) { - nllvdbg("IPv4 frame\n"); - - /* Handle ARP on input then give the IPv4 packet to the network - * layer - */ - - arp_ipin(&vnet->sk_dev); - ipv4_input(&vnet->sk_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (vnet->sk_dev.d_len > 0) { - /* Update the Ethernet header with the correct MAC address */ - -#ifdef CONFIG_NET_IPv6 - if (IFF_IS_IPv4(vnet->sk_dev.d_flags)) -#endif - { - arp_out(&vnet->sk_dev); - } -#ifdef CONFIG_NET_IPv6 - else { - neighbor_out(&vnet->sk_dev); - } -#endif - - /* And send the packet */ - - vnet_transmit(vnet); - } - } else -#endif -#ifdef CONFIG_NET_IPv6 - if (BUF->type == HTONS(ETHTYPE_IP6)) { - nllvdbg("Iv6 frame\n"); - - /* Give the IPv6 packet to the network layer */ - - ipv6_input(&vnet->sk_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (vnet->sk_dev.d_len > 0) { - /* Update the Ethernet header with the correct MAC address */ - -#ifdef CONFIG_NET_IPv4 - if (IFF_IS_IPv4(vnet->sk_dev.d_flags)) { - arp_out(&vnet->sk_dev); - } else -#endif -#ifdef CONFIG_NET_IPv6 - { - neighbor_out(&vnet->sk_dev); - } -#endif - - /* And send the packet */ - - vnet_transmit(vnet); - } - } else -#endif -#ifdef CONFIG_NET_ARP - if (BUF->type == htons(ETHTYPE_ARP)) { - arp_arpin(&vnet->sk_dev); - - /* If the above function invocation resulted in data that should be - * sent out on the network, the field d_len will set to a value > 0. - */ - - if (vnet->sk_dev.d_len > 0) { - vnet_transmit(vnet); - } - } -#endif - } while (0); /* While there are more packets to be processed */ -} - -/**************************************************************************** - * Function: vnet_txdone - * - * Description: - * An interrupt was received indicating that the last TX packet(s) is done - * - * Parameters: - * vnet - Reference to the driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void vnet_txdone(FAR struct vnet_driver_s *vnet) -{ - /* Check for errors and update statistics */ - - /* If no further xmits are pending, then cancel the TX timeout and - * disable further Tx interrupts. - */ - - //wd_cancel(vnet->sk_txtimeout); - - /* Then poll uIP for new XMIT data */ - - (void)netif_poll(&vnet->sk_dev, vnet_txpoll); -} - -/**************************************************************************** - * Function: vnet_txtimeout - * - * Description: - * Our TX watchdog timed out. Called from the timer interrupt handler. - * The last TX never completed. Reset the hardware and start again. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void vnet_txtimeout(int argc, uint32_t arg, ...) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)arg; - - /* Increment statistics and dump debug info */ - - /* Then reset the hardware */ - - /* Then poll uIP for new XMIT data */ - - (void)netif_poll(&vnet->sk_dev, vnet_txpoll); -} - -/**************************************************************************** - * Function: vnet_polltimer - * - * Description: - * Periodic timer handler. Called from the timer interrupt handler. - * - * Parameters: - * argc - The number of available arguments - * arg - The first argument - * - * Returned Value: - * None - * - * Assumptions: - * Global interrupts are disabled by the watchdog logic. - * - ****************************************************************************/ - -static void vnet_polltimer(int argc, uint32_t arg, ...) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)arg; - - /* Check if there is room in the send another TX packet. We cannot perform - * the TX poll if he are unable to accept another packet for transmission. - */ - - if (vnet_is_txbuff_full(vnet->vnet)) { -#ifdef CONFIG_DEBUG - cprintf("VNET: TX buffer is full\n"); -#endif - return; - } - - /* If so, update TCP timing states and poll uIP for new XMIT data. Hmmm.. - * might be bug here. Does this mean if there is a transmit in progress, - * we will missing TCP time state updates? - */ - - (void)netif_timer(&vnet->sk_dev, vnet_txpoll, VNET_POLLHSEC); - - /* Setup the watchdog poll timer again */ - - (void)wd_start(vnet->sk_txpoll, VNET_WDDELAY, vnet_polltimer, 1, arg); -} - -/**************************************************************************** - * Function: vnet_ifup - * - * Description: - * TinyAra Callback: Bring up the Ethernet interface when an IP address is - * provided - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int vnet_ifup(struct net_driver_s *dev) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - - ndbg("Bringing up: %d.%d.%d.%d\n", dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff, (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24); - - /* Initialize PHYs, the Ethernet interface, and setup up Ethernet interrupts */ - - /* Set and activate a timer process */ - - (void)wd_start(vnet->sk_txpoll, VNET_WDDELAY, vnet_polltimer, 1, (uint32_t)vnet); - - vnet->sk_bifup = true; - return OK; -} - -/**************************************************************************** - * Function: vnet_ifdown - * - * Description: - * TinyAra Callback: Stop the interface. - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -static int vnet_ifdown(struct net_driver_s *dev) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - irqstate_t flags; - - /* Disable the Ethernet interrupt */ - - flags = irqsave(); - - /* Cancel the TX poll timer and TX timeout timers */ - - wd_cancel(vnet->sk_txpoll); - //wd_cancel(vnet->sk_txtimeout); - - /* Put the EMAC is its reset, non-operational state. This should be - * a known configuration that will guarantee the vnet_ifup() always - * successfully brings the interface back up. - */ - - /* Mark the device "down" */ - - vnet->sk_bifup = false; - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: vnet_txavail - * - * Description: - * Driver callback invoked when new TX data is available. This is a - * stimulus perform an out-of-cycle poll and, thereby, reduce the TX - * latency. - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * - * Returned Value: - * None - * - * Assumptions: - * Called in normal user mode - * - ****************************************************************************/ - -static int vnet_txavail(struct net_driver_s *dev) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - irqstate_t flags; - - /* Disable interrupts because this function may be called from interrupt - * level processing. - */ - - flags = irqsave(); - - /* Ignore the notification if the interface is not yet up */ - - if (vnet->sk_bifup) { - /* Check if there is room in the hardware to hold another outgoing packet. */ - - if (vnet_is_txbuff_full(vnet->vnet)) { -#ifdef CONFIG_DEBUG - cprintf("VNET: TX buffer is full\n"); -#endif - goto out; - } - - /* If so, then poll uIP for new XMIT data */ - - (void)netif_poll(&vnet->sk_dev, vnet_txpoll); - } - -out: - irqrestore(flags); - return OK; -} - -/**************************************************************************** - * Function: vnet_addmac - * - * Description: - * TinyAra Callback: Add the specified MAC address to the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * mac - The MAC address to be added - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int vnet_addmac(struct net_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -/**************************************************************************** - * Function: vnet_rmmac - * - * Description: - * TinyAra Callback: Remove the specified MAC address from the hardware multicast - * address filtering - * - * Parameters: - * dev - Reference to the TinyAra driver state structure - * mac - The MAC address to be removed - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_NET_IGMP -static int vnet_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac) -{ - FAR struct vnet_driver_s *vnet = (FAR struct vnet_driver_s *)dev->d_private; - - /* Add the MAC address to the hardware multicast routing table */ - - return OK; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: vnet_initialize - * - * Description: - * Initialize the Ethernet controller and driver - * - * Parameters: - * intf - In the case where there are multiple EMACs, this value - * identifies which EMAC is to be initialized. - * - * Returned Value: - * OK on success; Negated errno on failure. - * - * Assumptions: - * - ****************************************************************************/ - -int vnet_init(struct rgmp_vnet *vnet) -{ - struct vnet_driver_s *priv; - static int i = 0; - - if (i >= CONFIG_VNET_NINTERFACES) { - return -1; - } - - priv = &g_vnet[i++]; - - /* Initialize the driver structure */ - - memset(priv, 0, sizeof(struct vnet_driver_s)); - priv->sk_dev.d_ifup = vnet_ifup; /* I/F down callback */ - priv->sk_dev.d_ifdown = vnet_ifdown; /* I/F up (new IP address) callback */ - priv->sk_dev.d_txavail = vnet_txavail; /* New TX data callback */ -#ifdef CONFIG_NET_IGMP - priv->sk_dev.d_addmac = vnet_addmac; /* Add multicast MAC address */ - priv->sk_dev.d_rmmac = vnet_rmmac; /* Remove multicast MAC address */ -#endif - priv->sk_dev.d_private = (void *)priv; /* Used to recover private state from dev */ - - /* Create a watchdog for timing polling for and timing of transmisstions */ - - priv->sk_txpoll = wd_create(); /* Create periodic poll timer */ - //priv->sk_txtimeout = wd_create(); /* Create TX timeout timer */ - - priv->vnet = vnet; - vnet->priv = priv; - - /* Register the device with the OS */ - - (void)netdev_register(&priv->sk_dev), NET_LL_ETHERNET; - - return 0; -} - -#endif /* CONFIG_NET && CONFIG_NET_VNET */