2007-12-04 18:11:55 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* arch/arm/src/c5471/c5471_ethernet.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2007 Gregory Nutt. All rights reserved.
|
|
|
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
|
|
|
*
|
|
|
|
* Based one a C5471 Linux driver and released under this BSD license with
|
|
|
|
* special permisson from the copyright holder of the Linux driver:
|
|
|
|
* Todd Fischer, Cadenux, LLC. Other references: "TMS320VC547x CPU and
|
|
|
|
* Peripherals Reference Guide," TI document spru038.pdf.
|
|
|
|
*
|
|
|
|
* 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 <nuttx/config.h>
|
|
|
|
#if defined(CONFIG_NET)
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
#include <stdio.h>
|
2007-12-04 18:11:55 +01:00
|
|
|
#include <time.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <debug.h>
|
|
|
|
#include <wdog.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <nuttx/irq.h>
|
|
|
|
#include <nuttx/arch.h>
|
|
|
|
|
|
|
|
#include <net/uip/uip.h>
|
|
|
|
#include <net/uip/uip-arp.h>
|
|
|
|
#include <net/uip/uip-arch.h>
|
|
|
|
|
|
|
|
#include "chip.h"
|
2007-12-04 21:23:43 +01:00
|
|
|
#include "up_arch.h"
|
2007-12-04 18:11:55 +01:00
|
|
|
#include "up_internal.h"
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Definitions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/* Configuration ************************************************************/
|
|
|
|
/* CONFIG_C5471_NET_NINTERFACES determines the number of physical interfaces
|
|
|
|
* that will be supported.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef CONFIG_C5471_NET_NINTERFACES
|
|
|
|
# define CONFIG_C5471_NET_NINTERFACES 1
|
|
|
|
#endif
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
/* CONFIG_C5471_NET_STATS will enabled collection of driver statistics.
|
|
|
|
* Default is disabled.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* CONFIG_C5471_ETHERNET_PHY may be set to one of the following values to
|
|
|
|
* select the PHY (or left undefined if there is no PHY)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef ETHERNET_PHY_LU3X31T_T64
|
|
|
|
# define ETHERNET_PHY_LU3X31T_T64 1
|
|
|
|
#endif
|
|
|
|
#ifndef ETHERNET_PHY_AC101L
|
|
|
|
# define ETHERNET_PHY_AC101L 2
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Mode of operation defaults to AUTONEGOTIATION */
|
|
|
|
|
|
|
|
#if defined(CONFIG_NET_C5471_AUTONEGOTIATION)
|
|
|
|
# undef CONFIG_NET_C5471_BASET100
|
|
|
|
# undef CONFIG_NET_C5471_BASET10
|
|
|
|
#elif defined(CONFIG_NET_C5471_BASET100)
|
|
|
|
# undef CONFIG_NET_C5471_AUTONEGOTIATION
|
|
|
|
# undef CONFIG_NET_C5471_BASET10
|
|
|
|
#elif defined(CONFIG_NET_C5471_BASET10)
|
|
|
|
# undef CONFIG_NET_C5471_AUTONEGOTIATION
|
|
|
|
# undef CONFIG_NET_C5471_BASET100
|
|
|
|
#else
|
|
|
|
# define CONFIG_NET_C5471_AUTONEGOTIATION 1
|
|
|
|
# undef CONFIG_NET_C5471_BASET100
|
|
|
|
# undef CONFIG_NET_C5471_BASET10
|
|
|
|
#endif
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
/* This should be disabled unless you are performing very low level debug */
|
|
|
|
|
|
|
|
#undef CONFIG_C5471_NET_DUMPBUFFER
|
|
|
|
//#define CONFIG_C5471_NET_DUMPBUFFER 1
|
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
/* Timing values ************************************************************/
|
|
|
|
/* TX poll deley = 1 seconds. CLK_TCK=number of clock ticks per second */
|
|
|
|
|
|
|
|
#define C5471_WDDELAY (1*CLK_TCK)
|
|
|
|
#define C5471_POLLHSEC (1*2)
|
|
|
|
|
|
|
|
/* TX timeout = 1 minute */
|
|
|
|
|
|
|
|
#define C5471_TXTIMEOUT (60*CLK_TCK)
|
|
|
|
|
|
|
|
/* Ethernet GPIO bit settings ***********************************************/
|
|
|
|
|
|
|
|
#define GPIO_CIO_MDIO 0x00004000
|
|
|
|
#define GPIO_IO_MDCLK 0x00008000
|
|
|
|
|
|
|
|
/* Ethernet interface bit settings ******************************************/
|
|
|
|
|
|
|
|
/* TX descriptor, word #0 */
|
|
|
|
|
|
|
|
#define EIM_TXDESC_OWN_HOST 0x80000000 /* Bit 15: Ownership bit */
|
|
|
|
#define EIM_TXDESC_OWN_ENET 0x00000000
|
|
|
|
#define EIM_TXDESC_WRAP_NEXT 0x40000000 /* Bit 14: Descriptor chain wrap */
|
|
|
|
#define EIM_TXDESC_WRAP_FIRST 0x00000000
|
|
|
|
#define EIM_TXDESC_FIF 0x20000000 /* Bit 13: First in frame */
|
|
|
|
#define EIM_TXDESC_LIF 0x10000000 /* Bit 12: Last in frame */
|
|
|
|
/* Bits 8-11: Retry count status */
|
|
|
|
#define EIM_TXDESC_INTRE 0x00800000 /* Bit 7: TX_IRQ int enable */
|
|
|
|
#define EIM_TXDESC_STATUSMASK 0x007f0000 /* Bits 0-6: Status */
|
|
|
|
#define EIM_TXDESC_RETRYERROR 0x00400000 /* Exceed retry error */
|
|
|
|
#define EIM_TXDESC_HEARTBEAT 0x00200000 /* Heartbeat (SQE) */
|
|
|
|
#define EIM_TXDESC_LCOLLISON 0x00100000 /* Late collision error */
|
|
|
|
#define EIM_TXDESC_COLLISION 0x00080000 /* Collision */
|
|
|
|
#define EIM_TXDESC_CRCERROR 0x00040000 /* CRC error */
|
|
|
|
#define EIM_TXDESC_UNDERRUN 0x00020000 /* Underrun error */
|
|
|
|
#define EIM_TXDESC_LOC 0x00010000 /* Loss of carrier */
|
|
|
|
|
|
|
|
/* Packet bytes value used for both TX and RX descriptors */
|
|
|
|
|
|
|
|
#define EIM_PACKET_BYTES 0x00000040
|
|
|
|
|
|
|
|
/* Count of descriptors */
|
|
|
|
|
|
|
|
#define NUM_DESC_TX 32
|
|
|
|
#define NUM_DESC_RX 64
|
|
|
|
|
|
|
|
/* TX descriptor, word #1 */
|
|
|
|
/* Bit 15: reserved */
|
|
|
|
#define EIM_TXDESC_PADCRC 0x00004000 /* Bit 14: Enable padding small frames */
|
|
|
|
/* Bits 11-13: reserved */
|
|
|
|
#define EIM_TXDESC_BYTEMASK 0x000007ff /* Bits 0-10: Descriptor byte count */
|
|
|
|
|
|
|
|
/* RX descriptor, word #0 */
|
|
|
|
|
|
|
|
#define EIM_RXDESC_OWN_HOST 0x80000000 /* Bit 15: Ownership bit */
|
|
|
|
#define EIM_RXDESC_OWN_ENET 0x00000000
|
|
|
|
#define EIM_RXDESC_WRAP_NEXT 0x40000000 /* Bit 14: Descriptor chain wrap */
|
|
|
|
#define EIM_RXDESC_WRAP_FIRST 0x00000000
|
|
|
|
#define EIM_RXDESC_FIF 0x20000000 /* Bit 13: First in frame */
|
|
|
|
#define EIM_RXDESC_LIF 0x10000000 /* Bit 12: Last in frame */
|
|
|
|
/* Bits 8-11: reserved */
|
|
|
|
#define EIM_RXDESC_INTRE 0x00800000 /* Bit 7: RX_IRQ int enable */
|
|
|
|
#define EIM_RXDESC_STATUSMASK 0x007f0000 /* Bits 0-6: Status */
|
|
|
|
#define EIM_RXDESC_MISS 0x00400000 /* Miss */
|
|
|
|
#define EIM_RXDESC_VLAN 0x00200000 /* VLAN */
|
|
|
|
#define EIM_RXDESC_LFRAME 0x00100000 /* Long frame error */
|
|
|
|
#define EIM_RXDESC_SFRAME 0x00080000 /* Short frame error */
|
|
|
|
#define EIM_RXDESC_CRCERROR 0x00040000 /* CRC error */
|
|
|
|
#define EIM_RXDESC_OVERRUN 0x00020000 /* Overrun error */
|
|
|
|
#define EIM_RXDESC_ALIGN 0x00010000 /* Non-octect align error */
|
|
|
|
|
|
|
|
#define EIM_RXDESC_PADCRC 0x00004000 /* Enable padding for small frames */
|
|
|
|
|
|
|
|
/* RX descriptor, word #1 */
|
|
|
|
/* Bits 11-15: reserved */
|
|
|
|
#define EIM_RXDESC_BYTEMASK 0x000007ff /* Bits 0-10: Descriptor byte count */
|
|
|
|
|
|
|
|
/* EIM_CPU_FILTER bit settings */
|
|
|
|
/* Bits 5-31: reserved */
|
|
|
|
#define EIM_FILTER_MACLA 0x00000010 /* Bit 4: Enable logical address+multicast filtering */
|
|
|
|
#define EIM_FILTER_LOGICAL 0x00000008 /* Bit 3: Enable ENET logical filtering */
|
|
|
|
#define EIM_FILTER_MULTICAST 0x00000004 /* Bit 2: Enable multicast filtering */
|
|
|
|
#define EIM_FILTER_BROADCAST 0x00000002 /* Bit 1: Enable broadcast matching */
|
|
|
|
#define EIM_FILTER_UNICAST 0x00000001 /* Bit 0: Enable dest CPU address matching */
|
|
|
|
|
|
|
|
/* EIM_CTRL bit settings */
|
|
|
|
/* Bits 16-31: Reserved */
|
|
|
|
#define EIM_CTRL_ESM_EN 0x00008000 /* Bit 15: Ethernet state machine enable */
|
|
|
|
/* Bits 9-14: reserved */
|
|
|
|
#define EIM_CTRL_ENET0_EN 0x00000100 /* Bit 8: Enable routing of RX packets CPU->ENET0 */
|
|
|
|
/* Bit 7: reserved */
|
|
|
|
#define EIM_CTRL_ENET0_FLW 0x00000040 /* Bit 6: Enable ENET0 flow control RX threshold */
|
|
|
|
#define EIM_CTRL_RXENET0_EN 0x00000020 /* Bit 5: Enable processing of ENET0 RX queue */
|
|
|
|
#define EIM_CTRL_TXENET0_EN 0x00000010 /* Bit 4: Enable processing of ENET0 TX queue */
|
|
|
|
/* Bits 2-3: reserved */
|
|
|
|
#define EIM_CTRL_RXCPU_EN 0x00000002 /* Bit 1: Enable processing of CPU RX queue */
|
|
|
|
#define EIM_CTRL_TXCPU_EN 0x00000001 /* Bit 0: Enable processing of CPU TX queue */
|
|
|
|
|
|
|
|
/* EIM_STATUS bit settings */
|
|
|
|
/* Bits 10-31: reserved */
|
|
|
|
#define EIM_STATUS_CPU_TXLIF 0x00000200 /* Bit 9: Last descriptor of TX packet filled */
|
|
|
|
#define EIM_STATUS_CPU_RXLIF 0x00000100 /* Bit 8: Last descriptor of RX queue processed */
|
|
|
|
#define EIM_STATUS_CPU_TX 0x00000080 /* Bit 7: Descriptor filled in TX queue */
|
|
|
|
#define EIM_STATUS_CPU_RX 0x00000040 /* Bit 6: Descriptor filled in RX queue */
|
|
|
|
/* Bits 3-5: reserved */
|
|
|
|
#define EIM_STATUS_ENET0_ERR 0x00000004 /* Bit 2: ENET0 error interrupt */
|
|
|
|
#define EIM_STATUS_ENET0_TX 0x00000002 /* Bit 1: ENET0 TX interrupt */
|
|
|
|
#define EIM_STATUS_ENET0_RX 0x00000001 /* Bit 0" ENET0 RX interrupt */
|
|
|
|
|
|
|
|
/* EIM_INTEN bit settings */
|
|
|
|
|
|
|
|
#define EIM_INTEN_CPU_TXLIF 0x00000200 /* Bit 9: Last descriptor of TX packet filled */
|
|
|
|
#define EIM_INTEN_CPU_RXLIF 0x00000100 /* Bit 8: Last descriptor of RX queue processed */
|
|
|
|
#define EIM_INTEN_CPU_TX 0x00000080 /* Bit 7: Descriptor filled in TX queue */
|
|
|
|
#define EIM_INTEN_CPU_RX 0x00000040 /* Bit 6: Descriptor filled in RX queue */
|
|
|
|
/* Bits 3-5: reserved */
|
|
|
|
#define EIM_INTEN_ENET0_ERR 0x00000004 /* Bit 2: ENET0 error interrupt */
|
|
|
|
#define EIM_INTEN_ENET0_TX 0x00000002 /* Bit 1: ENET0 TX interrupt */
|
2007-12-06 00:51:41 +01:00
|
|
|
#define EIM_INTEN_ENET0_RX 0x00000001 /* Bit 0: ENET0 RX interrupt */
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* ENET0_ADRMODE_EN bit settings */
|
|
|
|
|
|
|
|
#define ENET_ADR_PROMISCUOUS 0x00000008 /* Bit 3: Enable snoop address comparison */
|
|
|
|
#define ENET_ADR_BROADCAST 0x00000004 /* Bit 2: Enable broadcast address comparison */
|
2007-12-07 16:19:00 +01:00
|
|
|
#define ENET_ADDR_LCOMPARE 0x00000002 /* Bit 1: Enable logical address comparison */
|
|
|
|
#define ENET_ADDR_PCOMPARE 0x00000001 /* Bit 0: Enable physical address comparison */
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* ENET0_MODE bit settings */
|
|
|
|
/* Bits 16-31: reserved */
|
|
|
|
#define ENET_MODO_FIFO_EN 0x00008000 /* Bit 15: Fifo enable */
|
|
|
|
/* Bits 8-14: reserved */
|
|
|
|
#define ENET_MODE_RJCT_SFE 0x00000080 /* Bit 7: Reject short frames durig receive */
|
|
|
|
#define ENET_MODE_DPNET 0x00000040 /* Bit 6: Demand priority networkd vs CSMA/CD */
|
|
|
|
#define ENET_MODE_MWIDTH 0x00000020 /* Bit 5: Select nibble mode MII port */
|
|
|
|
#define ENET_MODE_WRAP 0x00000010 /* Bit 4: Internal MAC loopback */
|
|
|
|
#define ENET_MODE_FDWRAP 0x00000008 /* Bit 3: Full duplex wrap */
|
|
|
|
#define ENET_MODE_FULLDUPLEX 0x00000004 /* Bit 2: 1:Full duplex */
|
|
|
|
#define ENET_MODE_HALFDUPLEX 0x00000000 /* 0:Half duplex */
|
|
|
|
/* Bit 1: reserved */
|
|
|
|
#define ENET_MODE_ENABLE 0x00000001 /* Bit 0: Port enable */
|
|
|
|
|
|
|
|
/* PHY registers */
|
|
|
|
|
|
|
|
#define MD_PHY_CONTROL_REG 0x00
|
|
|
|
#define MD_PHY_MSB_REG 0x02
|
|
|
|
#define MD_PHY_LSB_REG 0x03
|
|
|
|
#define MD_PHY_CTRL_STAT_REG 0x17
|
|
|
|
|
|
|
|
/* Lucent LU3X31T-T64 transeiver ID */
|
|
|
|
|
|
|
|
#define LU3X31_T64_PHYID 0x00437421
|
|
|
|
|
|
|
|
/* PHY control register bit settings */
|
|
|
|
|
|
|
|
#define MODE_AUTONEG 0x1000
|
|
|
|
#define MODE_10MBIT_HALFDUP 0x0000
|
|
|
|
#define MODE_10MBIT_FULLDUP 0x0100
|
|
|
|
#define MODE_100MBIT_FULLDUP 0x2100
|
|
|
|
#define MODE_100MBIT_HALFDUP 0x2000
|
|
|
|
|
|
|
|
/* Inserts an ARM "nop" instruction */
|
|
|
|
|
|
|
|
#define nop() asm(" nop");
|
|
|
|
|
|
|
|
/* This is a helper pointer for accessing the contents of the Ethernet header */
|
|
|
|
|
|
|
|
#define BUF ((struct uip_eth_hdr *)c5471->c_dev.d_buf)
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Types
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/* The c5471_driver_s encapsulates all state information for a single c5471
|
|
|
|
* hardware interface
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct c5471_driver_s
|
|
|
|
{
|
|
|
|
boolean c_bifup; /* TRUE:ifup FALSE:ifdown */
|
|
|
|
WDOG_ID c_txpoll; /* TX poll timer */
|
|
|
|
WDOG_ID c_txtimeout; /* TX timeout timer */
|
|
|
|
|
|
|
|
/* Note: According to the C547x documentation: "The software has to maintain
|
|
|
|
* two pointers to the current RX-CPU and TX-CPU descriptors. At init time,
|
|
|
|
* they have to be set to the first descriptors of each queue, and they have
|
|
|
|
* to be incremented each time a descriptor ownership is give to the SWITCH".
|
|
|
|
*/
|
|
|
|
|
|
|
|
volatile uint32 c_txcpudesc;
|
|
|
|
volatile uint32 c_rxcpudesc;
|
|
|
|
|
|
|
|
/* Last TX descriptor saved for error handling */
|
|
|
|
|
|
|
|
uint32 c_lastdescstart;
|
|
|
|
uint32 c_lastdescend;
|
|
|
|
|
|
|
|
/* Shadowed registers */
|
|
|
|
|
|
|
|
uint32 c_eimstatus;
|
|
|
|
|
|
|
|
#ifdef CONFIG_C5471_NET_STATS
|
|
|
|
/* TX statistics */
|
|
|
|
|
|
|
|
uint32 c_txpackets; /* Number of packets sent */
|
|
|
|
uint32 c_txmiss; /* Miss */
|
|
|
|
uint32 c_txvlan; /* VLAN */
|
|
|
|
uint32 c_txlframe; /* Long frame errors */
|
|
|
|
uint32 c_txsframe; /* Short frame errors */
|
|
|
|
uint32 c_txcrc; /* CRC errors */
|
|
|
|
uint32 c_txoverrun; /* Overrun errors */
|
|
|
|
uint32 c_txalign; /* Non-octect align errors */
|
|
|
|
uint32 c_txtimeouts; /* TX timeouts */
|
|
|
|
|
|
|
|
uint32 c_rxpackets; /* Number of packets received */
|
|
|
|
uint32 c_rxretries; /* Exceed retry errors */
|
|
|
|
uint32 c_rxheartbeat; /* Heartbeat (SQE) */
|
|
|
|
uint32 c_rxlcollision; /* Late collision errors */
|
|
|
|
uint32 c_rxcollision; /* Collision */
|
|
|
|
uint32 c_rxcrc; /* CRC errors */
|
|
|
|
uint32 c_rxunderrun; /* Underrun errors */
|
|
|
|
uint32 c_rxloc; /* Loss of carrier */
|
2007-12-05 00:24:26 +01:00
|
|
|
uint32 c_rxdropped; /* Packets dropped because of size */
|
2007-12-04 18:11:55 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* This holds the information visible to uIP/NuttX */
|
|
|
|
|
|
|
|
struct uip_driver_s c_dev; /* Interface understood by uIP */
|
|
|
|
};
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Data
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static struct c5471_driver_s g_c5471[CONFIG_C5471_NET_NINTERFACES];
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Function Prototypes
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/* Transceiver interface */
|
|
|
|
|
|
|
|
static void c5471_mdtxbit (int bit_state);
|
|
|
|
static int c5471_mdrxbit (void);
|
|
|
|
static void c5471_mdwrite (int adr, int reg, int data);
|
|
|
|
static int c5471_mdread (int adr, int reg);
|
|
|
|
static int c5471_phyinit (void);
|
|
|
|
|
|
|
|
/* Support logic */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
static inline void c5471_inctxcpu(struct c5471_driver_s *c5471);
|
|
|
|
static inline void c5471_incrxcpu(struct c5471_driver_s *c5471);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* Common TX logic */
|
|
|
|
|
|
|
|
static int c5471_transmit(struct c5471_driver_s *c5471);
|
|
|
|
static int c5471_uiptxpoll(struct uip_driver_s *dev);
|
|
|
|
|
|
|
|
/* Interrupt handling */
|
|
|
|
|
2007-12-07 17:13:50 +01:00
|
|
|
#ifdef CONFIG_C5471_NET_STATS
|
|
|
|
static void c5471_rxstatus(struct c5471_driver_s *c5471);
|
|
|
|
#endif
|
2007-12-04 18:11:55 +01:00
|
|
|
static void c5471_receive(struct c5471_driver_s *c5471);
|
2007-12-07 17:13:50 +01:00
|
|
|
#ifdef CONFIG_C5471_NET_STATS
|
|
|
|
static void c5471_txstatus(struct c5471_driver_s *c5471);
|
|
|
|
#endif
|
2007-12-04 18:11:55 +01:00
|
|
|
static void c5471_txdone(struct c5471_driver_s *c5471);
|
|
|
|
static int c5471_interrupt(int irq, FAR void *context);
|
|
|
|
|
|
|
|
/* Watchdog timer expirations */
|
|
|
|
|
|
|
|
static void c5471_polltimer(int argc, uint32 arg, ...);
|
|
|
|
static void c5471_txtimeout(int argc, uint32 arg, ...);
|
|
|
|
|
|
|
|
/* NuttX callback functions */
|
|
|
|
|
|
|
|
static int c5471_ifup(struct uip_driver_s *dev);
|
|
|
|
static int c5471_ifdown(struct uip_driver_s *dev);
|
|
|
|
static int c5471_txavail(struct uip_driver_s *dev);
|
|
|
|
|
|
|
|
/* Initialization functions */
|
|
|
|
|
|
|
|
static void c5471_eimreset (struct c5471_driver_s *c5471);
|
2007-12-04 21:23:43 +01:00
|
|
|
static void c5471_eimconfig(struct c5471_driver_s *c5471);
|
2007-12-04 18:11:55 +01:00
|
|
|
static void c5471_reset(struct c5471_driver_s *c5471);
|
|
|
|
static void c5471_macassign(struct c5471_driver_s *c5471);
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_dumpbuffer
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
* Debug only
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef CONFIG_C5471_NET_DUMPBUFFER
|
|
|
|
static void c5471_dumpbuffer(const char *buffer, ssize_t nbytes)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_NET)
|
|
|
|
char line[128];
|
|
|
|
int ch;
|
|
|
|
int i;
|
|
|
|
int j;
|
|
|
|
|
|
|
|
for (i = 0; i < nbytes; i += 16)
|
|
|
|
{
|
|
|
|
sprintf(line, "%04x: ", i);
|
|
|
|
for (j = 0; j < 16; j++)
|
|
|
|
{
|
|
|
|
if (i + j < nbytes)
|
|
|
|
{
|
|
|
|
sprintf(&line[strlen(line)], "%02x", buffer[i+j] );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(&line[strlen(line)], " ");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j == 7 || j == 15)
|
|
|
|
{
|
|
|
|
strcpy(&line[strlen(line)], " ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( j = 0; j < 16; j++)
|
|
|
|
{
|
|
|
|
if (i + j < nbytes)
|
|
|
|
{
|
|
|
|
ch = buffer[i+j];
|
|
|
|
sprintf(&line[strlen(line)], "%c", ch >= 0x20 && ch <= 0x7e ? ch : '.');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j == 7 || j == 15)
|
|
|
|
{
|
|
|
|
strcpy(&line[strlen(line)], " ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ndbg("%s\n", line);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
# define c5471_dumpbuffer(buffer,nbytes)
|
|
|
|
#endif
|
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_mdtxbit
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
* A helper routine used when serially communicating with the c547X's
|
|
|
|
* external ethernet transeiver device. GPIO pins are connected to the
|
|
|
|
* transeiver's MDCLK and MDIO pins and are used to accomplish the serial
|
|
|
|
* comm.
|
|
|
|
*
|
|
|
|
* protocol:
|
|
|
|
* ___________
|
|
|
|
* MDCLK ________/ \_
|
|
|
|
* ________:____
|
|
|
|
* MDIO <________:____>--------
|
|
|
|
* :
|
|
|
|
* ^
|
|
|
|
* Pin state internalized
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void c5471_mdtxbit (int bit_state)
|
|
|
|
{
|
|
|
|
/* Note: any non-zero "bit_state" supplied by the caller means we should clk a "1"
|
|
|
|
* out the MDIO pin.
|
|
|
|
*/
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
/* Config MDIO as output pin. */
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
putreg32((getreg32(GPIO_CIO) & ~GPIO_CIO_MDIO), GPIO_CIO);
|
2007-12-06 00:51:41 +01:00
|
|
|
|
|
|
|
/* Select the the bit output state */
|
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
if (bit_state)
|
|
|
|
{
|
|
|
|
/* set MDIO state high. */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
putreg32((getreg32(GPIO_IO) | GPIO_CIO_MDIO), GPIO_IO);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* set MDIO state low. */
|
|
|
|
|
|
|
|
putreg32((getreg32(GPIO_IO) & ~GPIO_CIO_MDIO), GPIO_IO);
|
|
|
|
}
|
|
|
|
|
|
|
|
nop();
|
|
|
|
nop();
|
|
|
|
nop();
|
|
|
|
nop();
|
|
|
|
|
|
|
|
/* MDCLK rising edge */
|
|
|
|
|
|
|
|
putreg32((getreg32(GPIO_IO) | GPIO_IO_MDCLK), GPIO_IO);
|
|
|
|
nop();
|
|
|
|
nop();
|
|
|
|
|
|
|
|
/* release MDIO */
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
putreg32((getreg32(GPIO_CIO) | GPIO_CIO_MDIO), GPIO_CIO);
|
2007-12-04 18:11:55 +01:00
|
|
|
nop();
|
|
|
|
nop();
|
|
|
|
|
|
|
|
/* MDCLK falling edge. */
|
|
|
|
|
|
|
|
putreg32((getreg32(GPIO_IO) & ~GPIO_IO_MDCLK), GPIO_IO);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_mdrxbit
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
* A helper routine used when serially communicating with the c547X's
|
|
|
|
* external ethernet transeiver device. GPIO pins are connected to the
|
|
|
|
* transeiver's MDCLK and MDIO pins and are used to accomplish the serial
|
|
|
|
* comm.
|
|
|
|
*
|
|
|
|
* protocol:
|
|
|
|
* ___________
|
|
|
|
* MDCLK ________/ \_
|
|
|
|
* _______:_____
|
|
|
|
* MDIO _______:_____>--------
|
|
|
|
* :
|
|
|
|
* ^
|
|
|
|
* pin state sample point
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int c5471_mdrxbit (void)
|
|
|
|
{
|
|
|
|
register volatile uint32 bit_state;
|
|
|
|
|
|
|
|
/* config MDIO as input pin. */
|
|
|
|
|
|
|
|
putreg32((getreg32(GPIO_CIO) | GPIO_CIO_MDIO), GPIO_CIO);
|
|
|
|
|
|
|
|
/* Make sure the MDCLK is low */
|
|
|
|
|
|
|
|
putreg32((getreg32(GPIO_IO) & ~GPIO_IO_MDCLK), GPIO_IO);
|
|
|
|
nop();
|
|
|
|
nop();
|
|
|
|
nop();
|
|
|
|
nop();
|
|
|
|
|
|
|
|
/* Sample MDIO */
|
|
|
|
|
|
|
|
bit_state = getreg32(GPIO_IO) & GPIO_CIO_MDIO;
|
|
|
|
|
|
|
|
/* MDCLK rising edge */
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
putreg32((getreg32(GPIO_IO) | GPIO_IO_MDCLK), GPIO_IO);
|
2007-12-04 18:11:55 +01:00
|
|
|
nop();
|
|
|
|
nop();
|
|
|
|
nop();
|
|
|
|
nop();
|
|
|
|
|
|
|
|
/* MDCLK falling edge. */
|
|
|
|
|
|
|
|
putreg32((getreg32(GPIO_IO)&~GPIO_IO_MDCLK), GPIO_IO); /* MDCLK falling edge */
|
|
|
|
if (bit_state)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-12-05 00:24:26 +01:00
|
|
|
return OK;
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_mdwrite
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
* A helper routine used when serially communicating with the c547X's
|
|
|
|
* external ethernet transeiver device. GPIO pins are connected to the
|
|
|
|
* transeiver's MDCLK and MDIO pins and are used to accomplish the serial
|
|
|
|
* comm.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void c5471_mdwrite (int adr, int reg, int data)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* preamble: 11111111111111111111111111111111 */
|
|
|
|
|
|
|
|
for (i = 0; i < 32; i++)
|
2007-12-06 00:51:41 +01:00
|
|
|
{
|
|
|
|
c5471_mdtxbit(1);
|
|
|
|
}
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* start of frame: 01 */
|
|
|
|
|
|
|
|
c5471_mdtxbit(0);
|
|
|
|
c5471_mdtxbit(1);
|
|
|
|
|
|
|
|
/* operation code: 01 - write */
|
|
|
|
|
|
|
|
c5471_mdtxbit(0);
|
|
|
|
c5471_mdtxbit(1);
|
|
|
|
|
|
|
|
/* PHY device address: AAAAA, msb first */
|
|
|
|
|
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
{
|
|
|
|
c5471_mdtxbit(adr & 0x10);
|
|
|
|
adr = adr << 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* MII register address: RRRRR, msb first */
|
|
|
|
|
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
{
|
|
|
|
c5471_mdtxbit(reg & 0x10);
|
|
|
|
reg = reg << 1;
|
|
|
|
}
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
/* Turnaround time: ZZ */
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
c5471_mdtxbit(1);
|
|
|
|
c5471_mdtxbit(0);
|
|
|
|
|
|
|
|
/* data: DDDDDDDDDDDDDDDD, msb first */
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
c5471_mdtxbit(data & 0x8000);
|
|
|
|
data = data << 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_mdread
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
* A helper routine used when serially communicating with the c547X's
|
|
|
|
* external ethernet transeiver device. GPIO pins are connected to the
|
|
|
|
* transeiver's MDCLK and MDIO pins and are used to accomplish the serial
|
|
|
|
* comm.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int c5471_mdread (int adr, int reg)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int data = 0;
|
|
|
|
|
|
|
|
/* preamble: 11111111111111111111111111111111 */
|
|
|
|
|
|
|
|
for (i = 0; i < 32; i++)
|
2007-12-06 00:51:41 +01:00
|
|
|
{
|
|
|
|
c5471_mdtxbit(1);
|
|
|
|
}
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* start of frame: 01 */
|
|
|
|
|
|
|
|
c5471_mdtxbit(0);
|
|
|
|
c5471_mdtxbit(1);
|
|
|
|
|
|
|
|
/* operation code: 10 - read */
|
|
|
|
|
|
|
|
c5471_mdtxbit(1);
|
|
|
|
c5471_mdtxbit(0);
|
|
|
|
|
|
|
|
/* PHY device address: AAAAA, msb first */
|
|
|
|
|
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
{
|
|
|
|
c5471_mdtxbit(adr & 0x10);
|
|
|
|
adr = adr << 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* MII register address: RRRRR, msb first */
|
|
|
|
|
|
|
|
for (i = 0; i < 5; i++)
|
|
|
|
{
|
|
|
|
c5471_mdtxbit(reg & 0x10);
|
|
|
|
reg = reg << 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* turnaround time: ZZ */
|
|
|
|
|
|
|
|
c5471_mdrxbit();
|
|
|
|
c5471_mdrxbit(); /* PHY should drive a 0 */
|
|
|
|
|
|
|
|
/* data: DDDDDDDDDDDDDDDD, msb first */
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
data = data << 1;
|
|
|
|
data |= c5471_mdrxbit();
|
|
|
|
}
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_phyinit
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
* The c547X EVM board uses a Lucent LU3X31T-T64 transeiver device to
|
|
|
|
* handle the physical layer (PHY). It's a h/w block that on the one end
|
|
|
|
* offers a Media Independent Interface (MII) which is connected to the
|
|
|
|
* Ethernet Interface Module (EIM) internal to the C547x and on the other
|
|
|
|
* end offers either the 10baseT or 100baseT electrical interface connecting
|
|
|
|
* to an RJ45 onboard network connector. The PHY transeiver has several
|
|
|
|
* internal registers allowing host configuration and status access. These
|
|
|
|
* internal registers are accessable by clocking serial data in/out of the
|
|
|
|
* MDIO pin of the LU3X31T-T64 chip. For c547X, the MDC and the MDIO pins
|
|
|
|
* are connected to the C547x GPIO15 and GPIO14 pins respectivley. Host
|
|
|
|
* software twiddles the GPIO pins appropriately to get data serially into
|
|
|
|
* and out of the chip. This is typically a one time operation at boot and
|
|
|
|
* normal operation of the transeiver involves EIM/Transeiver interaction at
|
|
|
|
* the other pins of the transeiver chip and doesn't require host intervention
|
|
|
|
* at the MDC and MDIO pins.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#if (CONFIG_C5471_ETHERNET_PHY == ETHERNET_PHY_LU3X31T_T64)
|
|
|
|
static int c5471_phyinit (void)
|
|
|
|
{
|
2007-12-05 00:24:26 +01:00
|
|
|
int phyid;
|
2007-12-04 18:11:55 +01:00
|
|
|
int status;
|
|
|
|
|
|
|
|
/* Next, Setup GPIO pins to talk serially to the Lucent transeiver chip */
|
|
|
|
|
|
|
|
/* enable gpio bits 15,14 */
|
|
|
|
|
|
|
|
putreg32((getreg32(GPIO_EN) | 0x0000C000), GPIO_EN);
|
|
|
|
|
|
|
|
/* config gpio(15); out -> MDCLK */
|
|
|
|
|
|
|
|
putreg32((getreg32(GPIO_CIO) & ~0x00008000), GPIO_CIO);
|
|
|
|
|
|
|
|
/* config gpio(14); in <- MDIO */
|
|
|
|
|
|
|
|
putreg32((getreg32(GPIO_CIO) | 0x00004000), GPIO_CIO);
|
|
|
|
|
|
|
|
/* initial pin state; MDCLK = 0 */
|
|
|
|
|
|
|
|
putreg32((getreg32(GPIO_IO) & 0x000F3FFF), GPIO_IO);
|
|
|
|
|
|
|
|
/* Next, request a chip reset */
|
|
|
|
|
|
|
|
c5471_mdwrite(0, MD_PHY_CONTROL_REG, 0x8000);
|
|
|
|
while (c5471_mdread(0, MD_PHY_CONTROL_REG) & 0x8000)
|
|
|
|
{
|
|
|
|
/* wait for chip reset to complete */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next, Read out the chip ID */
|
|
|
|
|
2007-12-05 00:24:26 +01:00
|
|
|
phyid = (c5471_mdread(0, MD_PHY_MSB_REG) << 16) | c5471_mdread(0, MD_PHY_LSB_REG);
|
|
|
|
if (phyid != LU3X31_T64_PHYID)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
2007-12-05 00:24:26 +01:00
|
|
|
ndbg("Unrecognized PHY ID: %08x\n", phyid);
|
|
|
|
return ERROR;
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Next, Set desired network rate, 10BaseT, 100BaseT, or auto. */
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_C5471_AUTONEGOTIATION
|
2007-12-05 00:24:26 +01:00
|
|
|
ndbg("Setting PHY Transceiver for Autonegotiation\n");
|
2007-12-04 18:11:55 +01:00
|
|
|
c5471_mdwrite(0, MD_PHY_CONTROL_REG, MODE_AUTONEG);
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_NET_C5471_BASET100
|
2007-12-05 00:24:26 +01:00
|
|
|
ndbg("Setting PHY Transceiver for 100BaseT FullDuplex\n");
|
2007-12-04 18:11:55 +01:00
|
|
|
c5471_mdwrite(0, MD_PHY_CONTROL_REG, MODE_100MBIT_FULLDUP);
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_NET_C5471_BASET10
|
2007-12-05 00:24:26 +01:00
|
|
|
ndbg("Setting PHY Transceiver for 10BaseT FullDuplex\n");
|
2007-12-04 18:11:55 +01:00
|
|
|
c5471_mdwrite(0, MD_PHY_CONTROL_REG, MODE_10MBIT_FULLDUP);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
status = c5471_mdread(0, MD_PHY_CTRL_STAT_REG);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif (CONFIG_C5471_ETHERNET_PHY == ETHERNET_PHY_AC101L)
|
|
|
|
|
|
|
|
static int c5471_phyinit (void)
|
|
|
|
{
|
2007-12-05 00:24:26 +01:00
|
|
|
int phyid;
|
2007-12-04 18:11:55 +01:00
|
|
|
int status;
|
|
|
|
|
|
|
|
/* Next, Setup GPIO pins to talk serially to the Lucent transeiver chip */
|
|
|
|
|
2007-12-05 00:24:26 +01:00
|
|
|
putreg32((getreg32(GPIO_EN) | 0x0000C000), GPIO_EN); /* enable gpio bits 15,14 */
|
|
|
|
putreg32((getreg32(GPIO_CIO) & ~0x00008000), GPIO_CIO); /* config gpio(15); out -> MDCLK */
|
|
|
|
putreg32((getreg32(GPIO_CIO) | 0x00004000), GPIO_CIO); /* config gpio(14); in <- MDIO */
|
|
|
|
putreg32((getreg32(GPIO_IO) & 0x000F3FFF), GPIO_IO); /* initial pin state; MDCLK = 0 */
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
2007-12-04 21:23:43 +01:00
|
|
|
# define c5471_phyinit()
|
|
|
|
# if defined(CONFIG_C5471_ETHERNET_PHY)
|
|
|
|
# error "CONFIG_C5471_ETHERNET_PHY value not recognized"
|
|
|
|
# else
|
|
|
|
# warning "CONFIG_C5471_ETHERNET_PHY not defined -- assumed NO PHY"
|
|
|
|
# endif
|
2007-12-04 18:11:55 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_inctxcpu
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
static inline void c5471_inctxcpu(struct c5471_driver_s *c5471)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
if (EIM_TXDESC_WRAP_NEXT & getreg32(c5471->c_txcpudesc))
|
|
|
|
{
|
|
|
|
/* Loop back around to base of descriptor queue */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
c5471->c_txcpudesc = getreg32(EIM_CPU_TXBA) + EIM_RAM_START;
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
c5471->c_txcpudesc += 2*sizeof(uint32);
|
|
|
|
}
|
2007-12-05 00:24:26 +01:00
|
|
|
|
|
|
|
nvdbg("TX CPU desc: %08x\n", c5471->c_txcpudesc);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_incrxcpu
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
static inline void c5471_incrxcpu(struct c5471_driver_s *c5471)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
if (EIM_RXDESC_WRAP_NEXT & getreg32(c5471->c_rxcpudesc))
|
|
|
|
{
|
|
|
|
/* Loop back around to base of descriptor queue */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
c5471->c_rxcpudesc = getreg32(EIM_CPU_RXBA) + EIM_RAM_START;
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
c5471->c_rxcpudesc += 2*sizeof(uint32);
|
|
|
|
}
|
2007-12-05 00:24:26 +01:00
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
nvdbg("RX CPU desc: %08x\n", c5471->c_rxcpudesc);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_transmit
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Start hardware transmission. Called either from the txdone interrupt
|
|
|
|
* handling or from watchdog based polling.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* c5471 - Reference to the driver state structure
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* OK on success; a negated errno on failure
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int c5471_transmit(struct c5471_driver_s *c5471)
|
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
struct uip_driver_s *dev = &c5471->c_dev;
|
|
|
|
volatile uint16 *packetmem;
|
|
|
|
uint16 framelen;
|
2007-12-04 18:11:55 +01:00
|
|
|
boolean bfirstframe;
|
2007-12-04 21:23:43 +01:00
|
|
|
int nbytes;
|
2007-12-04 18:11:55 +01:00
|
|
|
int nshorts;
|
|
|
|
unsigned int i;
|
|
|
|
unsigned int j;
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
nbytes = (dev->d_len + 1) & ~1;
|
2007-12-04 18:11:55 +01:00
|
|
|
j = 0;
|
|
|
|
bfirstframe = TRUE;
|
|
|
|
c5471->c_lastdescstart = c5471->c_rxcpudesc;
|
|
|
|
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("Packet size: %d RX CPU desc: %08x\n", nbytes, c5471->c_rxcpudesc);
|
2007-12-06 00:51:41 +01:00
|
|
|
c5471_dumpbuffer(dev->d_buf, dev->d_len);
|
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
while (nbytes)
|
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
/* Verify that the hardware is ready to send another packet */
|
2007-12-04 18:11:55 +01:00
|
|
|
/* Words #0 and #1 of descriptor */
|
|
|
|
|
|
|
|
while (EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc))
|
|
|
|
{
|
|
|
|
/* Loop until the SWITCH lets go of the descriptor giving us access
|
|
|
|
* rights to submit our new ether frame to it.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bfirstframe)
|
|
|
|
{
|
|
|
|
putreg32((getreg32(c5471->c_rxcpudesc) | EIM_RXDESC_FIF), c5471->c_rxcpudesc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
putreg32((getreg32(c5471->c_rxcpudesc) & ~EIM_RXDESC_FIF), c5471->c_rxcpudesc);
|
|
|
|
}
|
|
|
|
|
|
|
|
putreg32((getreg32(c5471->c_rxcpudesc) & ~EIM_RXDESC_PADCRC), c5471->c_rxcpudesc);
|
|
|
|
|
|
|
|
if (bfirstframe)
|
|
|
|
{
|
2007-12-05 00:24:26 +01:00
|
|
|
putreg32((getreg32(c5471->c_rxcpudesc) | EIM_RXDESC_PADCRC), c5471->c_rxcpudesc);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (nbytes >= EIM_PACKET_BYTES)
|
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
framelen = EIM_PACKET_BYTES;
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
framelen = nbytes;
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
/* Submit ether frame bytes to the C5472 Ether Module packet memory space. */
|
|
|
|
/* Get the number of 16-bit values to transfer by dividing by 2 with round up. */
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
nshorts = (framelen + 1) >> 1;
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* Words #2 and #3 of descriptor */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
packetmem = (uint16*)getreg32(c5471->c_rxcpudesc + sizeof(uint32));
|
2007-12-04 18:11:55 +01:00
|
|
|
for (i = 0; i < nshorts; i++, j++)
|
|
|
|
{
|
|
|
|
/* 16-bits at a time. */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
packetmem[i] = htons(((uint16*)dev->d_buf)[j]);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
putreg32(((getreg32(c5471->c_rxcpudesc) & ~EIM_RXDESC_BYTEMASK) | framelen), c5471->c_rxcpudesc);
|
|
|
|
nbytes -= framelen;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("Wrote framelen: %d nbytes: %d nshorts: %d\n", framelen, nbytes, nshorts);
|
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
if (0 == nbytes)
|
|
|
|
{
|
|
|
|
putreg32((getreg32(c5471->c_rxcpudesc) | EIM_RXDESC_LIF), c5471->c_rxcpudesc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
putreg32((getreg32(c5471->c_rxcpudesc) & ~EIM_RXDESC_LIF), c5471->c_rxcpudesc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We're done with that descriptor; give access rights back to h/w */
|
|
|
|
|
|
|
|
putreg32((getreg32(c5471->c_rxcpudesc) | EIM_RXDESC_OWN_HOST), c5471->c_rxcpudesc);
|
|
|
|
|
|
|
|
/* Next, tell Ether Module that those submitted bytes are ready for the wire */
|
|
|
|
|
|
|
|
putreg32(0x00000001, EIM_CPU_RXREADY);
|
|
|
|
c5471->c_lastdescend = c5471->c_rxcpudesc;
|
|
|
|
|
|
|
|
/* Advance to the next free descriptor */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
c5471_incrxcpu(c5471);
|
2007-12-04 18:11:55 +01:00
|
|
|
bfirstframe = FALSE;
|
|
|
|
}
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
/* Packet transferred .. Update statistics */
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
#ifdef CONFIG_C5471_NET_STATS
|
|
|
|
c5471->c_txpackets++;
|
|
|
|
#endif
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
|
|
|
|
|
|
|
|
(void)wd_start(c5471->c_txtimeout, C5471_TXTIMEOUT, c5471_txtimeout, 1, (uint32)c5471);
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_uiptxpoll
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* The transmitter is available, check if uIP has any outgoing packets ready
|
|
|
|
* to send. This is a callback from uip_poll(). uip_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 NuttX driver state structure
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* OK on success; a negated errno on failure
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int c5471_uiptxpoll(struct uip_driver_s *dev)
|
|
|
|
{
|
|
|
|
struct c5471_driver_s *c5471 = (struct c5471_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 (c5471->c_dev.d_len > 0)
|
|
|
|
{
|
|
|
|
uip_arp_out(&c5471->c_dev);
|
|
|
|
c5471_transmit(c5471);
|
|
|
|
|
|
|
|
/* Check if the ESM has let go of the RX descriptor giving us access
|
|
|
|
* rights to submit another Ethernet frame.
|
|
|
|
*/
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
if ((EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) != 0)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
/* No, then return non-zero to terminate the poll */
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If zero is returned, the polling will continue until all connections have
|
|
|
|
* been examined.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_rxstatus
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* An interrupt was received indicating that the last RX packet(s) is done
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* c5471 - Reference to the driver state structure
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef CONFIG_C5471_NET_STATS
|
2007-12-07 17:13:50 +01:00
|
|
|
static void c5471_rxstatus(struct c5471_driver_s *c5471)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
uint32 desc = c5471->c_txcpudesc;
|
2007-12-04 18:11:55 +01:00
|
|
|
uint32 rxstatus;
|
|
|
|
|
|
|
|
/* Walk that last packet we just received to collect xmit status bits. */
|
|
|
|
|
|
|
|
rxstatus = 0;
|
|
|
|
for (;;)
|
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
if (EIM_TXDESC_OWN_HOST & getreg32(desc))
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
2007-12-10 18:15:11 +01:00
|
|
|
/* The incoming packet queue is empty. */
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
rxstatus |= (getreg32(desc) & EIM_TXDESC_STATUSMASK);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
if ((getreg32(desc) & EIM_TXDESC_LIF) != 0)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This packet is made up of several descriptors, find next one in chain. */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
if (EIM_TXDESC_WRAP_NEXT & getreg32(desc))
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
/* Loop back around to base of descriptor queue. */
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
desc = getreg32(EIM_CPU_TXBA) + EIM_RAM_START;
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
desc += 2 * sizeof(uint32);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rxstatus != 0)
|
|
|
|
{
|
|
|
|
if ((rxstatus & EIM_TXDESC_RETRYERROR) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_rxretries++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_rxretries: %d\n", c5471->c_rxretries);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((rxstatus & EIM_TXDESC_HEARTBEAT) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_rxheartbeat++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_rxheartbeat: %d\n", c5471->c_rxheartbeat);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((rxstatus & EIM_TXDESC_LCOLLISON) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_rxlcollision++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_rxlcollision: %d\n", c5471->c_rxlcollision);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((rxstatus & EIM_TXDESC_COLLISION) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_rxcollision++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_rxcollision: %d\n", c5471->c_rxcollision);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((rxstatus & EIM_TXDESC_CRCERROR) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_rxcrc++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_rxcrc: %d\n", c5471->c_rxcrc);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((rxstatus & EIM_TXDESC_UNDERRUN) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_rxunderrun++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_rxunderrun: %d\n", c5471->c_rxunderrun);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((rxstatus & EIM_TXDESC_LOC) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_rxloc++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_rxloc: %d\n", c5471->c_rxloc);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_receive
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* An interrupt was received indicating the availability of a new RX packet
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* c5471 - Reference to the driver state structure
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void c5471_receive(struct c5471_driver_s *c5471)
|
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
struct uip_driver_s *dev = &c5471->c_dev;
|
|
|
|
uint16 *packetmem;
|
2007-12-04 18:11:55 +01:00
|
|
|
boolean bmore = TRUE;
|
2007-12-04 21:23:43 +01:00
|
|
|
int packetlen = 0;
|
|
|
|
int framelen;
|
2007-12-04 18:11:55 +01:00
|
|
|
int nshorts;
|
|
|
|
int i;
|
|
|
|
int j = 0;
|
|
|
|
|
|
|
|
/* Walk the newly received packet contained within the EIM and transfer
|
|
|
|
* its contents to the uIP buffer. This frees up the memory contained within
|
|
|
|
* the EIM for additional packets that might be received later from the network.
|
|
|
|
*/
|
|
|
|
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("Reading TX CPU desc: %08x\n", c5471->c_txcpudesc);
|
2007-12-04 18:11:55 +01:00
|
|
|
while (bmore)
|
|
|
|
{
|
|
|
|
/* Words #0 and #1 of descriptor */
|
|
|
|
|
|
|
|
if (EIM_TXDESC_OWN_HOST & getreg32(c5471->c_txcpudesc))
|
|
|
|
{
|
|
|
|
/* No further packets to receive. */
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
/* Get the size of the frame from words #0 and #1 of the descriptor
|
|
|
|
* and update the accumulated packet size
|
|
|
|
*/
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
framelen = (getreg32(c5471->c_txcpudesc) & EIM_TXDESC_BYTEMASK);
|
|
|
|
packetlen += framelen;
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
/* Check if the received packet will fit within the uIP packet buffer */
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
if (packetlen < (CONFIG_NET_BUFSIZE + 4))
|
|
|
|
{
|
|
|
|
/* Get the packet memory from words #2 and #3 of descriptor */
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-07 16:19:00 +01:00
|
|
|
packetmem = (uint16*)getreg32(c5471->c_txcpudesc + sizeof(uint32));
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
/* Divide by 2 with round up to get the number of 16-bit words. */
|
2007-12-05 00:24:26 +01:00
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
nshorts = (framelen + 1) >> 1;
|
|
|
|
nvdbg("Reading framelen: %d packetlen: %d nshorts: %d packetmen: %p\n",
|
|
|
|
framelen, packetlen, nshorts, packetmem);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
for (i = 0 ; i < nshorts; i++, j++)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
/* Copy the data data from the hardware to c5471->c_dev.d_buf 16-bits at
|
|
|
|
* a time.
|
|
|
|
*/
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
((uint16*)dev->d_buf)[j] = htons(packetmem[i]);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
}
|
2007-12-06 00:51:41 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
nvdbg("Discarding framelen: %d packetlen\n", framelen, packetlen);
|
|
|
|
}
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
if (getreg32(c5471->c_txcpudesc) & EIM_TXDESC_LIF)
|
|
|
|
{
|
|
|
|
bmore = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next, Clear all bits of words0/1 of the emptied descriptor except preserve
|
|
|
|
* the settings of a select few. Can leave descriptor words 2/3 alone.
|
|
|
|
*/
|
|
|
|
|
|
|
|
putreg32((getreg32(c5471->c_txcpudesc) & (EIM_TXDESC_WRAP_NEXT|EIM_TXDESC_INTRE)),
|
|
|
|
c5471->c_txcpudesc);
|
|
|
|
|
|
|
|
/* Next, Give ownership of now emptied descriptor back to the Ether Module's SWITCH */
|
|
|
|
|
|
|
|
putreg32((getreg32(c5471->c_txcpudesc) | EIM_TXDESC_OWN_HOST), c5471->c_txcpudesc);
|
|
|
|
|
|
|
|
/* Advance to the next data buffer */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
c5471_inctxcpu(c5471);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Adjust the packet length to remove the CRC bytes that uIP doesn't care about. */
|
|
|
|
|
|
|
|
packetlen -= 4;
|
|
|
|
|
2007-12-05 00:24:26 +01:00
|
|
|
#ifdef CONFIG_C5471_NET_STATS
|
2007-12-06 00:51:41 +01:00
|
|
|
/* Increment the count of received packets */
|
2007-12-05 00:24:26 +01:00
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
c5471->c_rxpackets++;
|
2007-12-05 00:24:26 +01:00
|
|
|
#endif
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* If we successfully transferred the data into the uIP buffer, then pass it on
|
|
|
|
* to uIP for processing.
|
|
|
|
*/
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
if (packetlen > 0 && packetlen < CONFIG_NET_BUFSIZE)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
/* Set amount of data in c5471->c_dev.d_len. */
|
|
|
|
|
|
|
|
dev->d_len = packetlen;
|
2007-12-10 18:15:11 +01:00
|
|
|
nvdbg("Received packet, packetlen: %d type: %02x\n", packetlen, ntohs(BUF->type));
|
2007-12-06 00:51:41 +01:00
|
|
|
c5471_dumpbuffer(dev->d_buf, dev->d_len);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* We only accept IP packets of the configured type and ARP packets */
|
|
|
|
|
|
|
|
#ifdef CONFIG_NET_IPv6
|
|
|
|
if (BUF->type == HTONS(UIP_ETHTYPE_IP6))
|
|
|
|
#else
|
|
|
|
if (BUF->type == HTONS(UIP_ETHTYPE_IP))
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
uip_arp_ipin();
|
2007-12-10 18:15:11 +01:00
|
|
|
uip_input(dev);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
* Send that data now if ESM has let go of the RX descriptor giving us
|
|
|
|
* access rights to submit another Ethernet frame.
|
|
|
|
*/
|
|
|
|
|
2007-12-10 18:15:11 +01:00
|
|
|
if (dev->d_len > 0 &&
|
2007-12-04 18:11:55 +01:00
|
|
|
(EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0)
|
|
|
|
{
|
2007-12-10 18:15:11 +01:00
|
|
|
uip_arp_out(dev);
|
2007-12-04 18:11:55 +01:00
|
|
|
c5471_transmit(c5471);
|
|
|
|
}
|
|
|
|
}
|
2007-12-10 18:15:11 +01:00
|
|
|
else if (BUF->type == HTONS(UIP_ETHTYPE_ARP))
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
2007-12-10 18:15:11 +01:00
|
|
|
uip_arp_arpin(dev);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
* Send that data now if ESM has let go of the RX descriptor giving us
|
|
|
|
* access rights to submit another Ethernet frame.
|
|
|
|
*/
|
|
|
|
|
2007-12-10 18:15:11 +01:00
|
|
|
if (dev->d_len > 0 &&
|
2007-12-04 18:11:55 +01:00
|
|
|
(EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0)
|
|
|
|
{
|
|
|
|
c5471_transmit(c5471);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-12-05 00:24:26 +01:00
|
|
|
#ifdef CONFIG_C5471_NET_STATS
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Increment the count of dropped packets */
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
ndbg("Too big! packetlen: %d\n", packetlen);
|
2007-12-05 00:24:26 +01:00
|
|
|
c5471->c_rxdropped++;
|
|
|
|
}
|
|
|
|
#endif
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_txstatus
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* An interrupt was received indicating that the last TX packet(s) is done
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* c5471 - Reference to the driver state structure
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef CONFIG_C5471_NET_STATS
|
2007-12-07 17:13:50 +01:00
|
|
|
static void c5471_txstatus(struct c5471_driver_s *c5471)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
uint32 desc = c5471->c_lastdescstart;
|
2007-12-04 18:11:55 +01:00
|
|
|
uint32 txstatus;
|
|
|
|
|
|
|
|
/* Walk that last packet we just sent to collect xmit status bits. */
|
|
|
|
|
|
|
|
txstatus = 0;
|
|
|
|
if (c5471->c_lastdescstart && c5471->c_lastdescend)
|
|
|
|
{
|
|
|
|
for (;;)
|
|
|
|
{
|
2007-12-06 00:51:41 +01:00
|
|
|
txstatus |= (getreg32(desc) & EIM_RXDESC_STATUSMASK);
|
2007-12-04 21:23:43 +01:00
|
|
|
if (desc == c5471->c_lastdescend)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This packet is made up of several descriptors, find next one in chain. */
|
|
|
|
|
|
|
|
if (EIM_RXDESC_WRAP_NEXT & getreg32(c5471->c_rxcpudesc))
|
|
|
|
{
|
|
|
|
/* Loop back around to base of descriptor queue. */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
desc = getreg32(EIM_CPU_RXBA) + EIM_RAM_START;
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
desc += 2 * sizeof(uint32);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (txstatus)
|
|
|
|
{
|
|
|
|
if ((txstatus & EIM_RXDESC_MISS) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_txmiss++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_txmiss: %d\n", c5471->c_txmiss);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((txstatus & EIM_RXDESC_VLAN) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_txvlan++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_txvlan: %d\n", c5471->c_txvlan);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((txstatus & EIM_RXDESC_LFRAME) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_txlframe++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_txlframe: %d\n", c5471->c_txlframe);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((txstatus & EIM_RXDESC_SFRAME) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_txsframe++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_txsframe: %d\n", c5471->c_txsframe);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((txstatus & EIM_RXDESC_CRCERROR) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_txcrc++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_txcrc: %d\n", c5471->c_txcrc);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((txstatus & EIM_RXDESC_OVERRUN) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_txoverrun++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_txoverrun: %d\n", c5471->c_txoverrun);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((txstatus & EIM_RXDESC_OVERRUN) != 0)
|
|
|
|
{
|
|
|
|
c5471->c_txalign++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_txalign: %d\n", c5471->c_txalign);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
2007-12-07 17:13:50 +01:00
|
|
|
}
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_txdone
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* An interrupt was received indicating that the last TX packet(s) is done
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* c5471 - Reference to the driver state structure
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void c5471_txdone(struct c5471_driver_s *c5471)
|
|
|
|
{
|
|
|
|
/* If no further xmits are pending, then cancel the TX timeout */
|
|
|
|
|
|
|
|
wd_cancel(c5471->c_txtimeout);
|
|
|
|
|
|
|
|
/* Then poll uIP for new XMIT data */
|
|
|
|
|
|
|
|
(void)uip_poll(&c5471->c_dev, c5471_uiptxpoll);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_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 c5471_interrupt(int irq, FAR void *context)
|
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
#if CONFIG_C5471_NET_NINTERFACES == 1
|
|
|
|
register struct c5471_driver_s *c5471 = &g_c5471[0];
|
|
|
|
#else
|
|
|
|
# error "Additional logic needed to support multiple interfaces"
|
|
|
|
#endif
|
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
/* Get and clear interrupt status bits */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
c5471->c_eimstatus = getreg32(EIM_STATUS);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
/* Handle interrupts according to status bit settings */
|
2007-12-04 18:11:55 +01:00
|
|
|
/* Check if we received an incoming packet, if so, call c5471_receive() */
|
|
|
|
|
2007-12-07 00:12:48 +01:00
|
|
|
if ((EIM_STATUS_CPU_TX & c5471->c_eimstatus) != 0)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
/* An incoming packet has been received by the EIM from the network and
|
|
|
|
* the interrupt associated with EIM's CPU TX queue has been asserted. It
|
|
|
|
* is the EIM's CPU TX queue that we need to read from to get those
|
|
|
|
* packets. We use this terminology to stay consistent with the Orion
|
|
|
|
* documentation.
|
|
|
|
*/
|
|
|
|
|
2007-12-05 00:24:26 +01:00
|
|
|
#ifdef CONFIG_C5471_NET_STATS
|
2007-12-04 18:11:55 +01:00
|
|
|
/* Check for RX errors */
|
|
|
|
|
|
|
|
c5471_rxstatus(c5471);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Process the received packet */
|
|
|
|
|
|
|
|
c5471_receive(c5471);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check is a packet transmission just completed. If so, call c5471_txdone */
|
|
|
|
|
2007-12-07 00:12:48 +01:00
|
|
|
if ((EIM_STATUS_CPU_RX & c5471->c_eimstatus) != 0)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
/* An outgoing packet has been processed by the EIM and the interrupt
|
|
|
|
* associated with EIM's CPU RX que has been asserted. It is the EIM's
|
|
|
|
* CPU RX queue that we put packets on to send them *out*. TWe use this
|
|
|
|
* terminology to stay consistent with the Orion documentation.
|
|
|
|
*/
|
|
|
|
|
2007-12-07 17:13:50 +01:00
|
|
|
#ifdef CONFIG_C5471_NET_STATS
|
|
|
|
/* Check for TX errors */
|
|
|
|
|
|
|
|
c5471_txstatus(c5471);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Handle the transmission done event */
|
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
c5471_txdone(c5471);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable Ethernet interrupts (perhaps excluding the TX done interrupt if
|
|
|
|
* there are no pending transmissions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_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:
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void c5471_txtimeout(int argc, uint32 arg, ...)
|
|
|
|
{
|
|
|
|
struct c5471_driver_s *c5471 = (struct c5471_driver_s *)arg;
|
|
|
|
|
|
|
|
/* Increment statistics */
|
|
|
|
|
|
|
|
#ifdef CONFIG_C5471_NET_STATS
|
|
|
|
c5471->c_txtimeouts++;
|
2007-12-05 00:24:26 +01:00
|
|
|
nvdbg("c_txtimeouts: %d\n", c5471->c_txtimeouts);
|
2007-12-04 18:11:55 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Then try to restart the hardware */
|
|
|
|
|
|
|
|
c5471_ifdown(&c5471->c_dev);
|
|
|
|
c5471_ifup(&c5471->c_dev);
|
|
|
|
|
|
|
|
/* Then poll uIP for new XMIT data */
|
|
|
|
|
|
|
|
(void)uip_poll(&c5471->c_dev, c5471_uiptxpoll);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_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 c5471_polltimer(int argc, uint32 arg, ...)
|
|
|
|
{
|
|
|
|
struct c5471_driver_s *c5471 = (struct c5471_driver_s *)arg;
|
|
|
|
|
|
|
|
/* Check if the ESM has let go of the RX descriptor giving us access rights
|
|
|
|
* to submit another Ethernet frame.
|
|
|
|
*/
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
if ((EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
/* If so, update TCP timing states and poll uIP for new XMIT data */
|
|
|
|
|
|
|
|
(void)uip_timer(&c5471->c_dev, c5471_uiptxpoll, C5471_POLLHSEC);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup the watchdog poll timer again */
|
|
|
|
|
|
|
|
(void)wd_start(c5471->c_txpoll, C5471_WDDELAY, c5471_polltimer, 1, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_ifup
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* NuttX Callback: Bring up the Ethernet interface when an IP address is
|
|
|
|
* provided
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* dev - Reference to the NuttX driver state structure
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
* The user has assigned a MAC to the driver
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int c5471_ifup(struct uip_driver_s *dev)
|
|
|
|
{
|
|
|
|
struct c5471_driver_s *c5471 = (struct c5471_driver_s *)dev->d_private;
|
|
|
|
volatile uint32 clearbits;
|
|
|
|
|
|
|
|
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 Ethernet interface */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
c5471_reset(c5471);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* Assign the MAC to the device */
|
|
|
|
|
|
|
|
c5471_macassign(c5471);
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
/* Clear pending interrupts by reading the EIM status register */
|
|
|
|
|
|
|
|
clearbits = getreg32(EIM_STATUS);
|
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
/* Enable interrupts going from EIM Module to Interrupt Module. */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
putreg32(((getreg32(EIM_INTEN) | EIM_INTEN_CPU_TX|EIM_INTEN_CPU_RX)), EIM_INTEN);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* Next, go on-line. According to the C547X documentation the enables have to
|
|
|
|
* occur in this order to insure proper operation; ESM first then the ENET.
|
|
|
|
*/
|
|
|
|
|
|
|
|
putreg32((getreg32(EIM_CTRL) | EIM_CTRL_ESM_EN), EIM_CTRL); /* enable ESM */
|
|
|
|
putreg32((getreg32(ENET0_MODE) | ENET_MODE_ENABLE), ENET0_MODE); /* enable ENET */
|
|
|
|
up_mdelay(100);
|
|
|
|
|
|
|
|
/* Set and activate a timer process */
|
|
|
|
|
|
|
|
(void)wd_start(c5471->c_txpoll, C5471_WDDELAY, c5471_polltimer, 1, (uint32)c5471);
|
|
|
|
|
|
|
|
/* Enable the Ethernet interrupt */
|
|
|
|
|
|
|
|
c5471->c_bifup = TRUE;
|
|
|
|
up_enable_irq(C5471_IRQ_ETHER);
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_ifdown
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* NuttX Callback: Stop the interface.
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* dev - Reference to the NuttX driver state structure
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int c5471_ifdown(struct uip_driver_s *dev)
|
|
|
|
{
|
|
|
|
struct c5471_driver_s *c5471 = (struct c5471_driver_s *)dev->d_private;
|
|
|
|
irqstate_t flags;
|
|
|
|
|
2007-12-05 00:24:26 +01:00
|
|
|
ndbg("Stopping\n");
|
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
/* Disable the Ethernet interrupt */
|
|
|
|
|
|
|
|
flags = irqsave();
|
|
|
|
up_disable_irq(C5471_IRQ_ETHER);
|
|
|
|
|
|
|
|
/* Disable interrupts going from EIM Module to Interrupt Module. */
|
|
|
|
|
|
|
|
putreg32((getreg32(EIM_INTEN) & ~(EIM_INTEN_CPU_TX|EIM_INTEN_CPU_RX)), EIM_INTEN);
|
|
|
|
|
|
|
|
/* Disable ENET */
|
|
|
|
|
|
|
|
putreg32((getreg32(ENET0_MODE) & ~ENET_MODE_ENABLE), ENET0_MODE); /* disable ENET */
|
|
|
|
|
|
|
|
/* Disable ESM */
|
|
|
|
|
|
|
|
putreg32((getreg32(EIM_CTRL) & ~EIM_CTRL_ESM_EN), EIM_CTRL); /* disable ESM */
|
|
|
|
|
|
|
|
/* Cancel the TX poll timer and TX timeout timers */
|
|
|
|
|
|
|
|
wd_cancel(c5471->c_txpoll);
|
|
|
|
wd_cancel(c5471->c_txtimeout);
|
|
|
|
|
|
|
|
/* Reset the device */
|
|
|
|
|
|
|
|
c5471->c_bifup = FALSE;
|
|
|
|
irqrestore(flags);
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_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 NuttX driver state structure
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
* Called in normal user mode
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int c5471_txavail(struct uip_driver_s *dev)
|
|
|
|
{
|
|
|
|
struct c5471_driver_s *c5471 = (struct c5471_driver_s *)dev->d_private;
|
|
|
|
irqstate_t flags;
|
|
|
|
|
2007-12-05 00:24:26 +01:00
|
|
|
ndbg("Polling\n");
|
2007-12-04 18:11:55 +01:00
|
|
|
flags = irqsave();
|
|
|
|
|
|
|
|
/* Ignore the notification if the interface is not yet up */
|
|
|
|
|
|
|
|
if (c5471->c_bifup)
|
|
|
|
{
|
|
|
|
/* Check if the ESM has let go of the RX descriptor giving us access
|
|
|
|
* rights to submit another Ethernet frame.
|
|
|
|
*/
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
if ((EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
/* If so, then poll uIP for new XMIT data */
|
|
|
|
|
|
|
|
(void)uip_poll(&c5471->c_dev, c5471_uiptxpoll);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
irqrestore(flags);
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_eimreset
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
* The C547x docs states that a module should generally be reset according
|
|
|
|
* to the following algorithm:
|
|
|
|
*
|
|
|
|
* 1. Put the module in reset.
|
|
|
|
* 2. Switch on the module clock.
|
|
|
|
* 3. Wait for eight clock cycles.
|
|
|
|
* 4. Release the reset.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void c5471_eimreset (struct c5471_driver_s *c5471)
|
|
|
|
{
|
|
|
|
/* Stop the EIM module clock */
|
|
|
|
|
|
|
|
putreg32((getreg32(CLKM) | CLKM_EIM_CLK_STOP), CLKM);
|
|
|
|
|
|
|
|
/* Put EIM module in reset */
|
|
|
|
|
|
|
|
putreg32((getreg32(CLKM_RESET) & ~CLKM_RESET_EIM), CLKM_RESET);
|
|
|
|
|
|
|
|
/* Start the EIM module clock */
|
|
|
|
|
|
|
|
putreg32((getreg32(CLKM) & ~CLKM_EIM_CLK_STOP), CLKM);
|
|
|
|
|
|
|
|
/* Assert nRESET to reset the board's PHY0/1 chips */
|
|
|
|
|
|
|
|
putreg32((CLKM_CTL_RST_EXT_RESET|CLKM_CTL_RST_LEAD_RESET), CLKM_CTL_RST);
|
|
|
|
up_mdelay(2);
|
|
|
|
|
|
|
|
/* Release the peripheral nRESET signal */
|
|
|
|
|
|
|
|
putreg32(CLKM_CTL_RST_LEAD_RESET, CLKM_CTL_RST);
|
|
|
|
|
|
|
|
/* Release EIM module reset */
|
|
|
|
|
|
|
|
putreg32((getreg32(CLKM_RESET) | CLKM_RESET_EIM), CLKM_RESET);
|
|
|
|
|
|
|
|
/* All EIM register should now be in there power-up default states */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
c5471->c_lastdescstart = 0;
|
|
|
|
c5471->c_lastdescend = 0;
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_eimconfig
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
* Assumes that all registers are currently in the power-up reset state.
|
|
|
|
* This routine then modifies that state to provide our specific ethernet
|
|
|
|
* configuration.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
static void c5471_eimconfig(struct c5471_driver_s *c5471)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
volatile uint32 pbuf;
|
|
|
|
volatile uint32 desc;
|
|
|
|
volatile uint32 val;
|
2007-12-04 18:11:55 +01:00
|
|
|
int i;
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
desc = EIM_RAM_START;
|
|
|
|
pbuf = EIM_RAM_START + 0x6C0;
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* TX ENET 0 */
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
ndbg("TX ENET0 desc: %08x pbuf: %08x\n", desc, pbuf);
|
|
|
|
putreg32((desc & 0x0000ffff), ENET0_TDBA); /* 16-bit offset address */
|
2007-12-04 18:11:55 +01:00
|
|
|
for (i = NUM_DESC_TX-1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if (i == 0)
|
|
|
|
val = EIM_TXDESC_WRAP_NEXT;
|
|
|
|
else
|
|
|
|
val = EIM_TXDESC_WRAP_FIRST;
|
2007-12-06 00:51:41 +01:00
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
val |= EIM_TXDESC_OWN_HOST|EIM_TXDESC_INTRE|EIM_TXDESC_PADCRC|EIM_PACKET_BYTES;
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
putreg32(val, desc);
|
|
|
|
desc += sizeof(uint32);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
putreg32(pbuf, desc);
|
|
|
|
desc += sizeof(uint32);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-07 16:19:00 +01:00
|
|
|
putreg32(0, pbuf);
|
2007-12-04 18:11:55 +01:00
|
|
|
pbuf += EIM_PACKET_BYTES;
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
putreg32(0, pbuf);
|
2007-12-04 21:23:43 +01:00
|
|
|
pbuf += sizeof(uint32); /* Ether Module's "Buffer Usage Word" */
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* RX ENET 0 */
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
ndbg("RX ENET0 desc: %08x pbuf: %08x\n", desc, pbuf);
|
|
|
|
putreg32((desc & 0x0000ffff), ENET0_RDBA); /* 16-bit offset address */
|
2007-12-04 18:11:55 +01:00
|
|
|
for (i = NUM_DESC_RX-1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if (i == 0)
|
|
|
|
val = EIM_RXDESC_WRAP_NEXT;
|
|
|
|
else
|
|
|
|
val = EIM_RXDESC_WRAP_FIRST;
|
2007-12-06 00:51:41 +01:00
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
val |= EIM_RXDESC_OWN_ENET|EIM_RXDESC_INTRE|EIM_RXDESC_PADCRC|EIM_PACKET_BYTES;
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
putreg32(val, desc);
|
|
|
|
desc += sizeof(uint32);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
putreg32(pbuf, desc);
|
|
|
|
desc += sizeof(uint32);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-07 16:19:00 +01:00
|
|
|
putreg32(0, pbuf);
|
2007-12-04 18:11:55 +01:00
|
|
|
pbuf += EIM_PACKET_BYTES;
|
|
|
|
|
2007-12-07 16:19:00 +01:00
|
|
|
putreg32(0, pbuf);
|
2007-12-04 21:23:43 +01:00
|
|
|
pbuf += sizeof(uint32); /* Ether Module's "Buffer Usage Word" */
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* TX CPU */
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
ndbg("TX CPU desc: %08x pbuf: %08x\n", desc, pbuf);
|
2007-12-04 21:23:43 +01:00
|
|
|
c5471->c_txcpudesc = desc;
|
2007-12-06 00:51:41 +01:00
|
|
|
putreg32((desc & 0x0000ffff), EIM_CPU_TXBA); /* 16-bit offset address */
|
2007-12-04 18:11:55 +01:00
|
|
|
for (i = NUM_DESC_TX-1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
/* Set words 1+2 of the TXDESC */
|
|
|
|
|
|
|
|
if (i == 0)
|
|
|
|
val = EIM_TXDESC_WRAP_NEXT;
|
|
|
|
else
|
|
|
|
val = EIM_TXDESC_WRAP_FIRST;
|
2007-12-06 00:51:41 +01:00
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
val |= EIM_TXDESC_OWN_HOST|EIM_TXDESC_INTRE|EIM_TXDESC_PADCRC|EIM_PACKET_BYTES;
|
2007-12-06 00:51:41 +01:00
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
putreg32(val, desc);
|
|
|
|
desc += sizeof(uint32);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
putreg32(pbuf, desc);
|
|
|
|
desc += sizeof(uint32);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
putreg(0, pbuf);
|
2007-12-04 18:11:55 +01:00
|
|
|
pbuf += EIM_PACKET_BYTES;
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
putreg(0, pbuf);
|
2007-12-04 21:23:43 +01:00
|
|
|
pbuf += sizeof(uint32); /* Ether Module's "Buffer Usage Word" */
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* RX CPU */
|
|
|
|
|
2007-12-06 00:51:41 +01:00
|
|
|
ndbg("RX CPU desc: %08x pbuf: %08x\n", desc, pbuf);
|
2007-12-04 21:23:43 +01:00
|
|
|
c5471->c_rxcpudesc = desc;
|
2007-12-06 00:51:41 +01:00
|
|
|
putreg32((desc & 0x0000ffff), EIM_CPU_RXBA); /* 16-bit offset address */
|
2007-12-04 18:11:55 +01:00
|
|
|
for (i = NUM_DESC_RX-1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
/* Set words 1+2 of the RXDESC */
|
|
|
|
|
|
|
|
if (i == 0)
|
|
|
|
val = EIM_RXDESC_WRAP_NEXT;
|
|
|
|
else
|
|
|
|
val = EIM_RXDESC_WRAP_FIRST;
|
2007-12-06 00:51:41 +01:00
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
val |= EIM_RXDESC_OWN_ENET|EIM_RXDESC_INTRE|EIM_RXDESC_PADCRC|EIM_PACKET_BYTES;
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
putreg32(val, desc);
|
|
|
|
desc += sizeof(uint32);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
putreg32(pbuf, desc);
|
|
|
|
desc += sizeof(uint32);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
2007-12-07 16:19:00 +01:00
|
|
|
putreg32(0, pbuf);
|
2007-12-04 18:11:55 +01:00
|
|
|
pbuf += EIM_PACKET_BYTES;
|
|
|
|
|
2007-12-07 16:19:00 +01:00
|
|
|
putreg32(0, pbuf);
|
2007-12-04 21:23:43 +01:00
|
|
|
pbuf += sizeof(uint32); /* Ether Module's "Buffer Usage Word" */
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
2007-12-06 00:51:41 +01:00
|
|
|
ndbg("END desc: %08x pbuf: %08x\n", desc, pbuf);
|
2007-12-04 18:11:55 +01:00
|
|
|
|
|
|
|
/* Save the descriptor packet size */
|
|
|
|
|
|
|
|
putreg32(EIM_PACKET_BYTES, EIM_BUFSIZE);
|
|
|
|
|
|
|
|
/* Set the filter mode */
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
putreg32(EIM_FILTER_UNICAST, EIM_CPU_FILTER);
|
|
|
|
#else
|
|
|
|
// putreg32(EIM_FILTER_LOGICAL|EIM_FILTER_UNICAST|EIM_FILTER_MULTICAST|
|
|
|
|
// EIM_FILTER_BROADCAST, EIM_CPU_FILTER);
|
|
|
|
putreg32(EIM_FILTER_UNICAST|EIM_FILTER_MULTICAST|EIM_FILTER_BROADCAST, EIM_CPU_FILTER);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Disable all Ethernet interrupts */
|
|
|
|
|
|
|
|
putreg32(0x00000000, EIM_INTEN);
|
|
|
|
|
|
|
|
/* Setup the EIM control register */
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
putreg32(EIM_CTRL_ENET0_EN|EIM_CTRL_RXENET0_EN|EIM_CTRL_TXENET0_EN|
|
|
|
|
EIM_CTRL_RXCPU_EN|EIM_CTRL_TXCPU_EN, EIM_CTRL);
|
|
|
|
#else
|
|
|
|
putreg32(EIM_CTRL_ENET0_EN|EIM_CTRL_ENET0_FLW|EIM_CTRL_RXENET0_EN|
|
|
|
|
EIM_CTRL_TXENET0_EN|EIM_CTRL_RXCPU_EN|EIM_CTRL_TXCPU_EN, EIM_CTRL);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
putreg32(0x00000000, EIM_MFVHI);
|
|
|
|
#else
|
|
|
|
putreg32(0x0000ff00, EIM_MFVHI);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
putreg32(0x00000000, EIM_MFVLO);
|
|
|
|
putreg32(0x00000000, EIM_MFMHI);
|
|
|
|
putreg32(0x00000000, EIM_MFMLO);
|
|
|
|
putreg32(0x00000018, EIM_RXTH);
|
|
|
|
putreg32(0x00000000, EIM_CPU_RXREADY);
|
|
|
|
|
|
|
|
/* Setup the ENET0 mode register */
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
putreg32(ENET_MODE_RJCT_SFE|ENET_MODE_MWIDTH|ENET_MODE_FULLDUPLEX, ENET0_MODE);
|
|
|
|
#else
|
|
|
|
putreg32(ENET_MODE_RJCT_SFE|ENET_MODE_MWIDTH|ENET_MODE_HALFDUPLEX, ENET0_MODE);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
putreg32(0x00000000, ENET0_BOFFSEED);
|
|
|
|
putreg32(0x00000000, ENET0_FLWPAUSE);
|
|
|
|
putreg32(0x00000000, ENET0_FLWCONTROL);
|
|
|
|
putreg32(0x00000000, ENET0_VTYPE);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
putreg32(ENET_ADR_BROADCAST|ENET_ADR_PROMISCUOUS, ENET0_ADRMODE_EN);
|
|
|
|
#else
|
|
|
|
/* The CPU port is not PROMISCUOUS, it wants a no-promiscuous address
|
|
|
|
* match yet the the SWITCH receives packets from the PROMISCUOUS ENET0
|
|
|
|
* which routes all packets for filter matching at the CPU port which
|
|
|
|
* then allows the s/w to see the new incoming packetes that passed
|
|
|
|
* the filter. Here we are setting the main SWITCH closest the ether
|
|
|
|
* wire.
|
|
|
|
*/
|
|
|
|
|
|
|
|
putreg32(ENET_ADR_PROMISCUOUS, ENET0_ADRMODE_EN);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
putreg32(0x00000000, ENET0_DRP);
|
|
|
|
up_mdelay(500);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_reset
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void c5471_reset(struct c5471_driver_s *c5471)
|
|
|
|
{
|
|
|
|
#if (CONFIG_C5471_ETHERNET_PHY == ETHERNET_PHY_LU3X31T_T64)
|
2007-12-06 00:51:41 +01:00
|
|
|
ndbg("EIM reset\n");
|
2007-12-04 18:11:55 +01:00
|
|
|
c5471_eimreset(c5471);
|
|
|
|
#endif
|
2007-12-06 00:51:41 +01:00
|
|
|
ndbg("PHY init\n");
|
2007-12-04 18:11:55 +01:00
|
|
|
c5471_phyinit();
|
2007-12-06 00:51:41 +01:00
|
|
|
|
|
|
|
ndbg("EIM config\n");
|
2007-12-04 21:23:43 +01:00
|
|
|
c5471_eimconfig(c5471);
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Name: c5471_macassign
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
* Set the mac address of our CPU ether port so that when the SWITCH
|
|
|
|
* receives packets from the PROMISCUOUS ENET0 it will switch them to the
|
|
|
|
* CPU port and cause a packet arrival event on the Switch's CPU TX queue
|
|
|
|
* when an address match occurs. The CPU port is not PROMISCUOUS and wants
|
|
|
|
* to see only packets specifically addressed to this device.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static void c5471_macassign(struct c5471_driver_s *c5471)
|
|
|
|
{
|
2007-12-04 21:23:43 +01:00
|
|
|
struct uip_driver_s *dev = &c5471->c_dev;
|
2007-12-05 00:24:26 +01:00
|
|
|
uint8 *mptr = dev->d_mac.addr;
|
2007-12-04 18:11:55 +01:00
|
|
|
register uint32 tmp;
|
|
|
|
|
2007-12-05 00:24:26 +01:00
|
|
|
ndbg("MAC: %0x:%0x:%0x:%0x:%0x:%0x\n",
|
|
|
|
mptr[0], mptr[1], mptr[2], mptr[3], mptr[4], mptr[5]);
|
|
|
|
|
2007-12-04 18:11:55 +01:00
|
|
|
/* Set CPU port MAC address. S/W will only see incoming packets that match
|
|
|
|
* this destination address.
|
|
|
|
*/
|
|
|
|
|
2007-12-05 00:24:26 +01:00
|
|
|
tmp = (((uint32)mptr[0]) << 8) | ((uint32)mptr[1]);
|
2007-12-04 18:11:55 +01:00
|
|
|
putreg32(tmp, EIM_CPU_DAHI);
|
|
|
|
|
2007-12-05 00:24:26 +01:00
|
|
|
tmp = (((uint32)mptr[2]) << 24) | (((uint32)mptr[3]) << 16) |
|
|
|
|
(((uint32)mptr[4]) << 8) | ((uint32)mptr[5]);
|
2007-12-04 18:11:55 +01:00
|
|
|
putreg32(tmp, EIM_CPU_DALO);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* Set the ENET MAC address */
|
|
|
|
|
|
|
|
putreg32(getreg32(EIM_CPU_DAHI), ENET0_PARHI);
|
|
|
|
putreg32(getreg32(EIM_CPU_DALO), ENET0_PARLO);
|
|
|
|
putreg32(getreg32(EIM_CPU_DAHI), ENET0_LARHI);
|
|
|
|
putreg32(getreg32(EIM_CPU_DALO), ENET0_LARLO);
|
|
|
|
|
|
|
|
#else
|
|
|
|
/* ENET MAC assignment not needed for its PROMISCUOUS mode */
|
|
|
|
|
|
|
|
putreg32(0x00000000, ENET0_PARHI);
|
|
|
|
putreg32(0x00000000, ENET0_PARLO);
|
|
|
|
putreg32(0x00000000, ENET0_LARHI);
|
|
|
|
putreg32(0x00000000, ENET0_LARLO);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Function: c5471_initialize
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Initialize the Ethernet driver
|
|
|
|
*
|
|
|
|
* Parameters:
|
|
|
|
* None
|
|
|
|
*
|
|
|
|
* Returned Value:
|
|
|
|
* OK on success; Negated errno on failure.
|
|
|
|
*
|
|
|
|
* Assumptions:
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/* Initialize the DM90x0 chip and driver */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
void up_netinitialize(void)
|
2007-12-04 18:11:55 +01:00
|
|
|
{
|
|
|
|
/* Attach the IRQ to the driver */
|
|
|
|
|
|
|
|
if (irq_attach(C5471_IRQ_ETHER, c5471_interrupt))
|
|
|
|
{
|
|
|
|
/* We could not attach the ISR to the ISR */
|
|
|
|
|
2007-12-04 21:23:43 +01:00
|
|
|
nlldbg("irq_attach() failed\n");
|
|
|
|
return;
|
2007-12-04 18:11:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the driver structure */
|
|
|
|
|
|
|
|
memset(g_c5471, 0, CONFIG_C5471_NET_NINTERFACES*sizeof(struct c5471_driver_s));
|
|
|
|
g_c5471[0].c_dev.d_ifup = c5471_ifup; /* I/F down callback */
|
|
|
|
g_c5471[0].c_dev.d_ifdown = c5471_ifdown; /* I/F up (new IP address) callback */
|
|
|
|
g_c5471[0].c_dev.d_txavail = c5471_txavail; /* New TX data callback */
|
|
|
|
g_c5471[0].c_dev.d_private = (void*)g_c5471; /* Used to recover private state from dev */
|
|
|
|
|
|
|
|
/* Create a watchdog for timing polling for and timing of transmisstions */
|
|
|
|
|
|
|
|
g_c5471[0].c_txpoll = wd_create(); /* Create periodic poll timer */
|
|
|
|
g_c5471[0].c_txtimeout = wd_create(); /* Create TX timeout timer */
|
|
|
|
|
|
|
|
/* Register the device with the OS so that socket IOCTLs can be performed */
|
|
|
|
|
|
|
|
(void)netdev_register(&g_c5471[0].c_dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_NET */
|
|
|
|
|