📄 ks5000_ether.c
字号:
//==========================================================================
//
// ks5000_ether.c
//
//
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas, jskov
// Grant Edwards <grante@visi.com>
// Date: 2001-07-31
// Purpose:
// Description:
//
//####DESCRIPTIONEND####
//
//========================================================================*/
#include <pkgconf/system.h>
#include <pkgconf/devs_eth_arm_ks32c5000.h>
#include <pkgconf/io_eth_drivers.h>
#include <errno.h>
#if defined(CYGPKG_IO)
#include <pkgconf/io.h>
#include <cyg/io/io.h>
#include <cyg/io/devtab.h>
#endif
// need to provide fake values for errno?
#ifndef EIO
# define EIO 1
#endif
#ifndef EINVAL
# define EINVAL 2
#endif
#include <cyg/infra/cyg_type.h> // Common type definitions and support
// including endian-ness
#include <cyg/infra/diag.h>
#include <cyg/io/eth/netdev.h>
#include <cyg/io/eth/eth_drv.h>
#include <cyg/io/eth/eth_drv_stats.h>
#include <cyg/hal/hal_intr.h>
#if defined(CYGPKG_REDBOOT)
#include <pkgconf/redboot.h>
#endif
#ifndef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
#define cyg_drv_interrupt_unmask(v) /* noop */
#define cyg_drv_interrupt_mask(v) /* noop */
#define cyg_drv_isr_lock() /* noop */
#define cyg_drv_isr_unlock() /* noop */
#define cyg_drv_mutex_init(m) /* noop */
#define cyg_drv_mutex_lock(m) /* noop */
#define cyg_drv_mutex_unlock(m) /* noop */
#define cyg_drv_dsr_lock() /* noop */
#define cyg_drv_dsr_unlock() /* noop */
#endif
#define HavePHYinterrupt 0
#include "std.h"
#include "ks5000_regs.h"
#include "ks5000_ether.h"
#if CYGINT_DEVS_ETH_ARM_KS32C5000_PHY
#include "phy.h"
#endif
// Set up the level of debug output
#if CYGPKG_DEVS_ETH_ARM_KS32C5000_DEBUG_LEVEL > 0
#define debug1_printf(args...) diag_printf(args)
#else
#define debug1_printf(args...) /* noop */
#endif
#if CYGPKG_DEVS_ETH_ARM_KS32C5000_DEBUG_LEVEL > 1
#define debug2_printf(args...) diag_printf(args)
#else
#define debug2_printf(args...) /* noop */
#endif
#define Bit(n) (1<<(n))
// enable/disable software verification of rx CRC
// should be moved to user-controlled valud in CDL file
#if defined(CYG_HAL_CPUTYPE_KS32C5000A)
#define SoftwareCRC 1
#include <cyg/crc/crc.h>
#else
#define SoftwareCRC 0
#endif
// --------------------------------------------------------------
// RedBoot configuration options for managing ESAs for us
// Decide whether to have redboot config vars for it...
#if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGPKG_REDBOOT_NETWORKING)
#include <redboot.h>
#include <flash_config.h>
#ifdef CYGSEM_DEVS_ETH_ARM_KS32C5000_REDBOOT_HOLDS_ESA_ETH0
RedBoot_config_option("Network hardware address [MAC] for eth0",
eth0_esa_data,
ALWAYS_ENABLED, true,
CONFIG_ESA, 0);
#endif
#endif // CYGPKG_REDBOOT_NETWORKING && CYGSEM_REDBOOT_FLASH_CONFIG
// and initialization code to read them
// - independent of whether we are building RedBoot right now:
#ifdef CYGPKG_DEVS_ETH_ARM_KS32C5000_REDBOOT_HOLDS_ESA
#include <cyg/hal/hal_if.h>
#ifndef CONFIG_ESA
#define CONFIG_ESA (6)
#endif
#define CYGHWR_DEVS_ETH_ARM_KS32C5000_GET_ESA( mac_address, ok ) \CYG_MACRO_START \ ok = CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET, \ "eth0_esa_data", mac_address, CONFIG_ESA); \CYG_MACRO_END
#endif // CYGPKG_DEVS_ETH_I82559_ETH_REDBOOT_HOLDS_ESA
#if CYGINT_DEVS_ETH_ARM_KS32C5000_PHY
// functions to read/write Phy chip registers via MII interface
// on 32c5000. These need to be non-static since they're used
// by PHY-specific routines in a different file.
#define PHYREGWRITE 0x0400
#define MiiStart 0x0800
void MiiStationWrite(U32 RegAddr, U32 PhyAddr, U32 PhyWrData)
{
STADATA = PhyWrData ;
STACON = RegAddr | (PhyAddr<<5) | MiiStart | PHYREGWRITE ;
while (STACON & MiiStart)
;
//debug1_printf("PHY Wr %x:%02x := %04x\n",PhyAddr, RegAddr, PhyWrData) ;
}
U32 MiiStationRead(U32 RegAddr, U32 PhyAddr)
{
U32 PhyRdData;
STACON = RegAddr | (PhyAddr<<5) | MiiStart;
while (STACON & MiiStart)
;
PhyRdData = STADATA;
//debug1_printf("PHY Rd %x:%02x %04x\n",PhyAddr,RegAddr,PhyRdData) ;
return PhyRdData ;
}
#endif
// miscellaneous data structures
typedef BYTE ETH_ADDR[6] __attribute__((packed));
typedef struct tagETH_HEADER
{
ETH_ADDR daddr __attribute__((packed));
ETH_ADDR saddr __attribute__((packed));
WORD type __attribute__((packed));
} ETH_HEADER __attribute__((packed));
#define ETH_HEADER_SIZE 14
// Tx/Rx common descriptor structure
typedef struct tagFRAME_DESCRIPTOR
{
LWORD FrameDataPtr;
LWORD Reserved; /* cf: RX-reserved, TX-Reserved(25bits) + Control bits(7bits) */
LWORD StatusAndFrameLength;
struct tagFRAME_DESCRIPTOR *NextFD;
} FRAME_DESCRIPTOR;
typedef struct
{
U8 DestinationAddr[6];
U8 SourceAddr[6];
U8 LengthOrType[2];
U8 LLCData[1506];
} MAC_FRAME;
#if defined(CYGPKG_NET)
struct ether_drv_stats ifStats;
#endif
#if defined(CYGINT_IO_ETH_INT_SUPPORT_REQUIRED)
static cyg_drv_mutex_t txMutex;
#endif
typedef struct
{
LWORD BTxNLErr;
LWORD BTxNOErr;
LWORD BTxEmptyErr;
} BDMA_TX_ERR;
typedef struct
{
LWORD BRxNLErr;
LWORD BRxNOErr;
LWORD BRxMSOErr;
LWORD BRxEmptyErr;
LWORD sBRxSEarly;
LWORD noBufferAvail;
LWORD queueOverflow;
LWORD bad;
} BDMA_RX_ERR;
// interrupt entry counters
U32 ks5000_MAC_Rx_Cnt;
U32 ks5000_MAC_Tx_Cnt;
U32 ks5000_MAC_Phy_Cnt;
U32 ks5000_BDMA_Tx_Isr_Cnt;
U32 ks5000_BDMA_Tx_Dsr_Cnt;
U32 ks5000_BDMA_Rx_Isr_Cnt;
U32 ks5000_BDMA_Rx_Dsr_Cnt;
// packet and byte counters
static U32 MAC_Tx_Pkts;
static U32 MAC_Tx_Octets;
// static U32 BDMA_Rx_Pkts;
// static U32 BDMA_Rx_Octets;
// configuration values
static volatile U32 MACConfigVar;
static volatile U32 CAMConfigVar = CAMCON_COMP_EN | CAMCON_BROAD_ACC;
static volatile U32 MACTxConfigVar =
/* MACTXCON_EN_UNDER | */
MACTXCON_EN_DEFER |
MACTXCON_EN_NCARR |
MACTXCON_EN_EXCOLL |
MACTXCON_EN_LATE_COLL |
MACTXCON_ENTX_PAR |
MACTXCON_EN_COMP;
static volatile U32 MACRxConfigVar =
MACRXCON_RX_EN |
MACRXCON_EN_ALIGN |
MACRXCON_EN_CRC_ERR |
MACRXCON_EN_OVER |
MACRXCON_EN_LONG_ERR |
MACRXCON_EN_RX_PAR;
static volatile U32 BDMATxConfigVar =
BDMATXCON_MSL111 |
BDMATXCON_STP_SKP |
3; /* burst size - 1 */
#define EtherFramePadding 2
#if EtherFramePadding == 0
#define BDMARXCON_ALIGN BDMARXCON_WA00
#elif EtherFramePadding == 1
#define BDMARXCON_ALIGN BDMARXCON_WA01
#elif EtherFramePadding == 2
#define BDMARXCON_ALIGN BDMARXCON_WA10
#elif EtherFramePadding == 3
#define BDMARXCON_ALIGN BDMARXCON_WA11
#else
#error "EtherFramePadding must be 0,1,2 or 3"
#endif
#if (CYG_BYTEORDER == CYG_MSBFIRST) // Big endian
static volatile U32 BDMARxConfigVar =
BDMARXCON_DIE |
BDMARXCON_EN |
BDMARXCON_BIG |
BDMARXCON_MA_INC |
BDMARXCON_NOIE |
BDMARXCON_ALIGN |
BDMARXCON_STP_SKP |
15; /* burst size - 1 */
#else // Little endian
static volatile U32 BDMARxConfigVar =
BDMARXCON_DIE |
BDMARXCON_EN |
BDMARXCON_LITTLE |
BDMARXCON_MA_INC |
BDMARXCON_NOIE |
BDMARXCON_ALIGN |
BDMARXCON_STP_SKP |
15; /* burst size - 1 */
#endif
/* Global variables For BDMA Error Report */
static BDMA_TX_ERR BDMATxErrCnt = {0,0,0};
static BDMA_RX_ERR BDMARxErrCnt = {0,0,0,0,0};
static void Init_TxFrameDescriptorArray(void);
static void Init_RxFrameDescriptorArray(void);
// number of ethernet buffers should be enough to keep both rx
// and tx queues full plus some extras for in-process packets
#if defined(CYGPKG_REDBOOT)
#define NUM_ETH_BUFFERS 10
#define MAX_RX_FRAME_DESCRIPTORS 4 // Max number of Rx Frame Descriptors
#define MAX_TX_FRAME_DESCRIPTORS 4 // Max number of Tx Frame Descriptors
#else
#define NUM_ETH_BUFFERS 80
#define MAX_RX_FRAME_DESCRIPTORS 32 // Max number of Rx Frame Descriptors
#define MAX_TX_FRAME_DESCRIPTORS 32 // Max number of Tx Frame Descriptors
#endif
static FRAME_DESCRIPTOR _rxFrameDescrArray[MAX_RX_FRAME_DESCRIPTORS] __attribute__((aligned(16)));
static FRAME_DESCRIPTOR _txFrameDescrArray[MAX_TX_FRAME_DESCRIPTORS] __attribute__((aligned(16)));
/* define aliases that will set the no-cache bit */
#define rxFrameDescrArray ((FRAME_DESCRIPTOR*)(((unsigned)_rxFrameDescrArray)|0x4000000))
#define txFrameDescrArray ((FRAME_DESCRIPTOR*)(((unsigned)_txFrameDescrArray)|0x4000000))
static volatile FRAME_DESCRIPTOR *rxReadPointer;
static volatile FRAME_DESCRIPTOR *txDonePointer;
static volatile FRAME_DESCRIPTOR *txWritePointer;
static cyg_drv_mutex_t oldRxMutex;
static cyg_drv_cond_t oldRxCond;
static bool configDone;
/*----------------------------------------------------------------------
* Data structures used to manage ethernet buffers
*/
#define MAX_ETH_FRAME_SIZE 1520
typedef struct tEthBufferTag
{
unsigned char data[MAX_ETH_FRAME_SIZE+8];
unsigned length;
unsigned userData;
struct tEthBufferTag *next;
struct tEthBufferTag *prev;
}tEthBuffer;
typedef struct
{
tEthBuffer *head;
tEthBuffer *tail;
}tEthBufQueue;
#define EmptyQueue {NULL,NULL}
static void ethBufQueueClear(tEthBufQueue *q)
{
q->head = NULL;
q->tail = NULL;
}
static tEthBuffer *ethBufQueueGet(tEthBufQueue *q)
{
tEthBuffer *r;
r = q->head;
if (r)
q->head = r->next;
return r;
}
static void ethBufQueuePut(tEthBufQueue *q, tEthBuffer *b)
{
b->next = NULL;
if (!q->head)
{
q->head = b;
q->tail = b;
}
else
{
q->tail->next = b;
q->tail = b;
}
}
#if 0
// not used at the moment
static bool ethBufQueueEmpty(tEthBufQueue *q)
{
return q->head != NULL;
}
#endif
/*----------------------------------------------------------------------
* Free pool and routines to manipulate it.
*/
static tEthBuffer __bufferPool[NUM_ETH_BUFFERS] __attribute__((aligned(16)));
#define bufferPool ((tEthBuffer*)((unsigned)__bufferPool|0x4000000))
static tEthBufQueue freeList;
static int freeCount;
// do not call from ISR routine
static void freeBuffer(tEthBuffer *b)
{
cyg_drv_isr_lock();
++freeCount;
ethBufQueuePut(&freeList,b);
cyg_drv_isr_unlock();
}
static int allocFail;
void bufferListError(void)
{
while (1)
;
}
// do not call from ISR routine
static tEthBuffer *allocBuffer(void)
{
tEthBuffer *r;
cyg_drv_isr_lock();
r = ethBufQueueGet(&freeList);
cyg_drv_isr_unlock();
if (r)
--freeCount;
else
{
++allocFail;
if (freeCount)
bufferListError();
}
return r;
}
// call only from ISR routine or init
static void isrFreeBuffer(tEthBuffer *b)
{
++freeCount;
ethBufQueuePut(&freeList,b);
}
#if 0
// not used at the moment
// call only from ISR routine or init
static tEthBuffer *isrAllocBuffer(void)
{
tEthBuffer *r;
r = ethBufQueueGet(&freeList);
if (r)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -