📄 dm642.c
字号:
//--------------------------------------------------------------------------
// IP Stack
//--------------------------------------------------------------------------
// dm642.c
//
// DM642 EMAC Packet Driver
//
// Author: Michael A. Denio
// Copyright 2000, 2003 by Texas Instruments Inc.
//-------------------------------------------------------------------------
#include <std.h>
#include <sys.h>
#include <hwi.h>
#include <c62.h>
#include <stkmain.h>
#include <csl.h>
#include <csl_cache.h>
#include "llpacket.h"
#include "csl_emachal.h"
#include "csl_mdio.h"
//
// This single global can be checked via CCS if there's trouble
//
uint DM642EMAC_FatalError = 0;
extern cregister volatile uint ICR;
//
// Configuration (Obtained via callback)
//
extern void DM642EMAC_getConfig( UINT8 *pMacAddr, uint *pIntVector );
extern void DM642EMAC_linkStatus( uint phy, uint linkStatus );
static UINT8 bMacAddr[6]; // MAC Address
static uint IntVector = 5; // Interrupt vector to use
static uint IntFlag; // Interrupt flag (1<<IntVector)
// Transmit/Receive Descriptor Channel Structure
// (One receive and one transmit in this driver)
typedef struct _EMAC_DescCh {
PBMQ DescQueue; // Packets queued as desc
uint DescMax; // Max number of desc (buffs)
uint DescCount; // Current number of desc
EMAC_Desc *pDescFirst; // First desc location
EMAC_Desc *pDescLast; // Last desc location
EMAC_Desc *pDescRead; // Location to read next desc
EMAC_Desc *pDescWrite; // Location to write nest desc
} EMAC_DescCh;
static EMAC_DescCh chTx;
static EMAC_DescCh chRx;
static uint FlashActiveLED = 0;
#define EMAC_NUMSTATS 36 // The number of statistics regs
//
// RX Buffer Depth
//
// We set this to 12 by default. This is the max (typical) number
// of free buffers ready for rx packets.
//
// Note that this driver always assumes it can enqueue a new TX
// packet to the EMAC. It justifies this by assuming that the size of
// its transmit descriptor chain (256 - EMAC_MAX_RX) is greater than
// or equal to the size of the free packet buffer pool (defined by
// PKT_NUM_FRAMEBUF in pbm.c). Thus the value of EMAC_MAX_RX
// plus the size of PKT_NUM_FRAMEBUF (defaults to 48) must be less
// than or equal to 256 for the driver work properly.
//
#define EMAC_MAX_RX 16
// Local instance information pointer for our single device instance
static PDINFO *pPDI = 0;
static Handle hMDIO = 0;
// Local Functions
static void HwInt();
static uint emacInit();
static void emacDequeueTx( EMAC_Desc *pDescAck );
static void emacEnqueueRx( uint fRestart );
static void emacDequeueRx( EMAC_Desc *pDescAck );
//--------------------------------------------------------------------
// HwPktInit()
//
// Initialize Device environment and return instance count
//--------------------------------------------------------------------
uint HwPktInit()
{
//
// Get our MAC address and interrupt to use
//
DM642EMAC_getConfig( bMacAddr, &IntVector );
IntFlag = 1<<IntVector;
return(1);
}
//--------------------------------------------------------------------
// HwPktShutdown()
//
// Shutdown Device Environment
//--------------------------------------------------------------------
void HwPktShutdown()
{
}
//--------------------------------------------------------------------
// HwPktOpen()
//
// Open Device Instance
//--------------------------------------------------------------------
uint HwPktOpen( PDINFO *pi )
{
uint ReturnCode = 1;
// We only have one device, so store off the PDINFO pointer as
// global to this module. Otherwise; we'd pick an unclaimed device
// and associate it with the PDINFO.
// Disable our general purpose interrupt
C62_disableIER( IntFlag );
// IF pPDI is aleady set, this is a restart.
if( !pPDI )
{
//
// Now initialize the EMAC device
//
pPDI = pi;
// Map the EMAC interrupt to DSP interrupt
IRQ_map( 0x18, IntVector );
// Hook our interrupt
HWI_dispatchPlug( IntVector, (Fxn)HwInt, -1, 0 );
CACHE_invalidate( CACHE_L1PALL, 0, 0 );
}
// Use the new PDINFO
pPDI = pi;
// Copy in the MAC address from the configuration
mmCopy( pPDI->bMacAddr, bMacAddr, 6 );
// Initialize the EMAC
ReturnCode = emacInit();
// Enable our general purpose interrupt
C62_enableIER( IntFlag );
// Say not ready to send (we wait for link)
pi->TxFree = 0;
return(ReturnCode);
}
//--------------------------------------------------------------------
// HwPktClose()
//
// Close Device Instance
//--------------------------------------------------------------------
void HwPktClose( PDINFO *pi )
{
PBM_Handle hPkt;
(void)pi;
// Disable the DSP interrupt
C62_disableIER( IntFlag );
// Disable EMAC/MDIO interrupts in wrapper
EMAC_FSETS( EWCTL, INTEN, DISABLE );
// Teardown RX
EMAC_RSET( RXTEARDOWN, 0 );
// Teardown TX
EMAC_RSET( TXTEARDOWN, 0 );
// Disable RX, TX, and Clear MACCONTROL
EMAC_FSETS( TXCONTROL, TXEN, DISABLE );
EMAC_FSETS( RXCONTROL, RXEN, DISABLE );
EMAC_RSET( MACCONTROL, 0 );
// Free all RX buffers
while( hPkt = PBMQ_deq( &chRx.DescQueue ) )
PBM_free( hPkt );
// Free all TX buffers
while( hPkt = PBMQ_deq( &chTx.DescQueue ) )
PBM_free( hPkt );
// Close the MDIO Module
MDIO_close( hMDIO );
}
//--------------------------------------------------------------------
// HwPktSetRx()
//
// Update Rx Mode (Rx filter and multicast hash table)
//--------------------------------------------------------------------
void HwPktSetRx( PDINFO *pi )
{
uint tmp1,tmp2;
Uint8 HashVal,tmpval,*pMCastList;
UINT32 MacHash1,MacHash2;
// Clear the hash bits
MacHash1 = 0;
MacHash2 = 0;
// For each address in the list, hash and set the bit
pMCastList = pi->bMCast;
for( tmp1=0; tmp1<pi->MCastCnt; tmp1++ )
{
HashVal=0;
for( tmp2=0; tmp2<2; tmp2++ )
{
tmpval = *pMCastList++;
HashVal ^= (tmpval>>2)^(tmpval<<4);
tmpval = *pMCastList++;
HashVal ^= (tmpval>>4)^(tmpval<<2);
tmpval = *pMCastList++;
HashVal ^= (tmpval>>6)^(tmpval);
}
if( HashVal & 0x20 )
MacHash2 |= (1<<(HashVal&0x1f));
else
MacHash1 |= (1<<(HashVal&0x1f));
}
// The following code relies on the numberic relation of the filter
// value such that the higher filter values receive more types of
// packets.
// Disable Section
if( pi->Filter < ETH_PKTFLT_ALL )
EMAC_FSETS( RXMBPENABLE, RXCAFEN, DISABLE );
if( pi->Filter < ETH_PKTFLT_ALLMULTICAST )
{
EMAC_RSET( MACHASH1, MacHash1 );
EMAC_RSET( MACHASH2, MacHash2 );
}
if( pi->Filter < ETH_PKTFLT_MULTICAST )
EMAC_FSETS( RXMBPENABLE, MULTEN, DISABLE );
if( pi->Filter < ETH_PKTFLT_BROADCAST )
EMAC_FSETS( RXMBPENABLE, BROADEN, DISABLE );
if( pi->Filter < ETH_PKTFLT_DIRECT )
EMAC_RSET( RXUNICASTCLEAR, 1 );
// Enable Section
if( pi->Filter >= ETH_PKTFLT_DIRECT )
EMAC_RSET( RXUNICASTSET, 1 );
if( pi->Filter >= ETH_PKTFLT_BROADCAST )
EMAC_FSETS( RXMBPENABLE, BROADEN, ENABLE );
if( pi->Filter >= ETH_PKTFLT_MULTICAST )
EMAC_FSETS( RXMBPENABLE, MULTEN, ENABLE );
if( pi->Filter >= ETH_PKTFLT_ALLMULTICAST )
{
EMAC_RSET( MACHASH1, 0xffffffff );
EMAC_RSET( MACHASH1, 0xffffffff );
}
if( pi->Filter == ETH_PKTFLT_ALL )
EMAC_FSETS( RXMBPENABLE, RXCAFEN, ENABLE );
}
//--------------------------------------------------------------------
// HwPktTxNext()
//
// Transmit Next Packet on Tx Queue
//--------------------------------------------------------------------
void HwPktTxNext( PDINFO *pi )
{
register EMAC_Desc *pDescThis;
register UINT8 *buffer;
register uint length;
PBM_Handle hPkt;
uint intmask;
// Make sure we have a packet to send
if( !(hPkt = PBMQ_deq(&pi->PBMQ_tx)) )
{
pi->TxFree = 1;
return;
}
buffer = PBM_getDataBuffer(hPkt) + PBM_getDataOffset(hPkt);
length = PBM_getValidLen(hPkt);
// Clean the cache for external addesses
if( (UINT32)buffer & 0x80000000 )
OEMCacheClean( (void *)buffer, length );
// Disable our device interrupt
intmask = C62_disableIER( IntFlag );
// This can't happen, but check anyway
if( chTx.DescCount == chTx.DescMax )
{
PBM_free( hPkt );
goto send_exit;
}
// Assign the pointer to "this" desc
pDescThis = chTx.pDescWrite;
// Move the write pointer and bump count
if( pDescThis == chTx.pDescLast )
chTx.pDescWrite = chTx.pDescFirst;
else
chTx.pDescWrite++;
chTx.DescCount++;
// Fill out the descriptor
pDescThis->pNext = 0;
pDescThis->pBuffer = buffer;
pDescThis->BufOffLen = length;
pDescThis->PktFlgLen = EMAC_DSC_FLAG_SOP | EMAC_DSC_FLAG_EOP |
length | EMAC_DSC_FLAG_OWNER;
// Enqueue this packet onto the desc queue
PBMQ_enq( &chTx.DescQueue, hPkt );
// Synch the cache
if( (UINT32)buffer & 0x80000000 )
OEMCacheCleanSynch();
// Start it sending
if( chTx.DescCount > 1 )
{
// Transmitter is already running.
// Make the previous buffer point to us
if( pDescThis == chTx.pDescFirst )
chTx.pDescLast->pNext = pDescThis;
else
(pDescThis-1)->pNext = pDescThis;
}
else
{
// Transmitter is not running, start it up
EMAC_RSET( TX0HDP, (Uint32)pDescThis );
}
send_exit:
C62_enableIER( intmask );
}
//--------------------------------------------------------------------
// _HwPktPoll()
//
// Poll routine - CALLED OUTSIDE OF KERNEL MODE
//
// This function is called at least every 100ms, faster in a
// polling environment. The fTimerTick flag is set only when
// called on a 100ms event.
//--------------------------------------------------------------------
void _HwPktPoll( PDINFO *pi, uint fTimerTick )
{
uint intmask;
uint mdioStatus,phy,linkStatus;
(void)pi;
if( fTimerTick && hMDIO )
{
LED_TOGGLE( USER_LED2 );
if( FlashActiveLED )
{
FlashActiveLED = 0;
LED_TOGGLE( USER_LED3 );
}
llEnter();
intmask = C62_disableIER( IntFlag );
// Signal the MDIO
mdioStatus = MDIO_timerTick( hMDIO );
// Track new or lost link
if( mdioStatus == MDIO_EVENT_LINKDOWN ||
mdioStatus == MDIO_EVENT_LINKUP )
{
MDIO_getStatus( hMDIO, &phy, &linkStatus );
// On a new link, set the EMAC duplex
if( mdioStatus == MDIO_EVENT_LINKUP )
{
if( linkStatus == MDIO_LINKSTATUS_FD10 ||
linkStatus == MDIO_LINKSTATUS_FD100 )
{
EMAC_FSETS( MACCONTROL, FULLDUPLEX, ENABLE );
}
else
{
EMAC_FSETS( MACCONTROL, FULLDUPLEX, DISABLE );
}
// Now that we have a link, send any queued packets
while( !pi->TxFree )
HwPktTxNext( pi );
}
// Tell application
DM642EMAC_linkStatus( phy, linkStatus );
}
// Re-fill Rx buffer queue if needed
if( chRx.DescCount != chRx.DescMax )
emacEnqueueRx( 1 );
C62_enableIER( intmask );
llExit();
}
}
//--------------------------------------------------------------------
// HwInt()
//
// EMAC Hardware Interrupt
//--------------------------------------------------------------------
void HwInt(void)
{
Uint32 intflags,Desc;
uint tmp;
// Disable EMAC/MDIO interrupts in wrapper
EMAC_FSETS( EWCTL, INTEN, DISABLE );
// Read the interrupt cause
intflags = EMAC_RGET( MACINVECTOR );
// Look for fatal errors first
if( intflags & EMAC_FMK( MACINVECTOR, HOSTPEND, 1 ) )
{
// A fatal error can only be caused by a software
// logic error. We'll read the fatal error code
// and exit with the EMAC interrupt still disabled.
// This will halt all network functionality. The
// application programmer can manually check the
// status of DM642EMAC_FatalError. If the network
// stops working.
DM642EMAC_FatalError = EMAC_RGET( MACSTATUS );
return;
}
// Look for statistics interrupt
if( intflags & EMAC_FMK( MACINVECTOR, STATPEND, 1 ) )
{
volatile Uint32 *pRegAddr;
Uint32 statval;
pRegAddr = EMAC_ADDR(RXGOODFRAMES);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -