⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ks5000_ether.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
//==========================================================================
//
//      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 + -