?? smsce.c
字號:
TxState = STATE_ALLOC_PEND;
// Allocate a transmit buffer
// Assume ALLOC_INT is already masked
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,2);
// Make sure busy bit is low
while( SMSC_READ16(SBA,SMSC_MMU_COMMAND) & BUSY_BIT );
// Send the allocate command
SMSC_WRITE16(SBA,SMSC_MMU_COMMAND,CMD_ALLOCATE_MEMORY);
// Make sure busy bit is low
while( SMSC_READ16(SBA,SMSC_MMU_COMMAND) & BUSY_BIT );
// Check results. If packet has been allocated, we can fill
// the TX FIFO and send now.
tempbyte = SMSC_READ8(SBA,SMSC_ALLOC_RESULT);
if( !(tempbyte & FAILED) )
{
// Send the packet (this function will free hFrag and set the
// TxState back to IDLE). The value of "tempbyte" is the SMSC
// packet number.
smscSendPacket( tempbyte );
goto tx_exit;
}
// If we get here, the allocation is pending and we remain in the
// TX_STATE_ALLOC_PEND state. If called from an ISR, we just return
// since the ISR will handle the INT mask stuff. If not in an ISR,
// we need to enable the ALLOC_INT interrupt.
if( IsrState == ISR_STATE_IDLE )
{
tempbyte = SMSC_READ8(SBA,SMSC_INT_MASK) | ALLOC_INT;
SMSC_WRITE8(SBA,SMSC_INT_MASK,tempbyte);
}
tx_exit:
// (Potentially) re-enable SMSC device interrupts on the DSP
gmEnableIER( mask );
}
//--------------------------------------------------------------------
// _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 mask;
(void)pi;
if( fTimerTick )
{
LED_TOGGLE( USER_LED2 );
if( FlashActiveLED )
{
FlashActiveLED = 0;
LED_TOGGLE( USER_LED3 );
}
}
// Get into kernel mode to be safe
llEnter();
// Make sure our int is disabled
mask = gmDisableIER( HW_IFLAG );
// Check for missed interrupt
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,2);
if( SMSC_READ8(SBA,SMSC_INT_MASK) & SMSC_READ8(SBA,SMSC_INT_STATUS) )
{
IntSave++;
ICR = HW_IFLAG;
smscIsr(0);
}
// (Potentially) re-enable SMSC device interrupts on the DSP
gmEnableIER( mask );
// Leave kernel mode
llExit();
}
//--------------------------------------------------------------------
// smscReset()
//
// Reset MAC, initialize, and prepare to start
//--------------------------------------------------------------------
static void smscReset()
{
UINT16 tmpword;
UINT8 tmpbyte;
// Set the default configuration
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,1);
SMSC_WRITE16(SBA,SMSC_CONFIGURATION,CONFIGURATION_DEFAULT);
// Soft reset
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,0);
SMSC_WRITE16(SBA,SMSC_RECEIVE_CONTROL,SOFT_RST);
Delay(10000);
SMSC_WRITE16(SBA,SMSC_RECEIVE_CONTROL,0);
Delay(10000);
// Setup Auto-negotiation on the PHY and program the LEDs to
// be tx/rx indicator on 2 and 10/100 link indicator on 1
SMSC_WRITE16(SBA,SMSC_PHY_CONTROL,ANEG|LS1A|LS0A);
// Setup auto-release on the conrol reg
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,1);
tmpword = SMSC_READ16(SBA,SMSC_CONTROL) | AUTO_RELEASE;
SMSC_WRITE16(SBA,SMSC_CONTROL,tmpword);
// Reset the MMU
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,2);
// Make sure busy bit is low
while( SMSC_READ16(SBA,SMSC_MMU_COMMAND) & BUSY_BIT );
SMSC_WRITE16(SBA,SMSC_MMU_COMMAND,CMD_RESET_MMU);
// Make sure busy bit is low
while( SMSC_READ16(SBA,SMSC_MMU_COMMAND) & BUSY_BIT );
// Setup interrupt mask
SMSC_WRITE8(SBA,SMSC_INT_MASK,0);
// Ack any pending interrupts
tmpbyte = SMSC_READ8(SBA,SMSC_INT_STATUS);
SMSC_WRITE8(SBA,SMSC_INT_STATUS,tmpbyte);
// Setup interrupt mask
SMSC_WRITE8(SBA,SMSC_INT_MASK,TX_INT|RCV_INT);
// Enable Transmitter
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,0);
SMSC_WRITE16(SBA,SMSC_TRANSMIT_CONTROL,TransmitControl);
// Reset the PHY negotiation
smscWritePHY( 0, 0x3200 );
// Tansmitter is not free until we start
pPDI->TxFree = 0;
// Delay for a bit
Delay(3000000);
}
//--------------------------------------------------------------------
// smscStart()
//
// Start MAC Rx and Tx state machines
//--------------------------------------------------------------------
static void smscStart()
{
// Initialize states
TxState = STATE_IDLE;
pPDI->TxFree = 1;
// Setup Rx Filter Mode
HwPktSetRx( pPDI );
// Start receive
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,0);
SMSC_WRITE16(SBA,SMSC_RECEIVE_CONTROL,RXEN);
}
//--------------------------------------------------------------------
// smscStop()
//
// Stop GMAC, abort current Rx and Tx
//--------------------------------------------------------------------
static void smscStop()
{
uint mask;
// Disable interrupts from device
mask = gmDisableIER( HW_IFLAG );
// Stop anyone from entering HwPktTxNext()
pPDI->TxFree = 0;
// Reset the part
smscReset();
// Clean up any waiting TX frag
if( TxState != STATE_IDLE && TxState != STATE_SEND )
PBM_free( tx_hPkt );
TxState = STATE_IDLE;
// Re-enable the part
gmEnableIER( mask );
// Flush the Tx Queue
while( PBMQ_count(&pPDI->PBMQ_tx) )
PBM_free( PBMQ_deq(&pPDI->PBMQ_tx) );
}
//--------------------------------------------------------------------
// smscIsr()
//
// General purpose ISR function.
//
// The calling arg "fTrueInt" is set to "1" if called at
// interrupt time, "0" otherwise.
//--------------------------------------------------------------------
static void smscIsr( UINT32 fTrueInt )
{
UINT8 pktnum;
uint IsrFlags;
uint IsrMask;
uint needevent = 0;
IsrState = ISR_STATE_ACTIVE;
// Mask all interrupts while in the ISR. This will also drive
// the SMSC interrupt low, allowing the DSP to catch the rising
// edge of the line if interrupts are still pending when we try
// to exit the ISR.
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,2);
SMSC_WRITE8(SBA,SMSC_INT_MASK,0);
do
{
// Now process all pending interrupts
IsrFlags = SMSC_READ8(SBA,SMSC_INT_STATUS);
if( RxState == STATE_IDLE )
IsrMask = TX_INT|RCV_INT;
else
IsrMask = TX_INT;
if( TxState == STATE_ALLOC_PEND )
IsrMask |= ALLOC_INT;
else if( TxState == STATE_SEND )
IsrMask |= TX_EMPTY_INT;
IsrFlags &= ( IsrMask | RX_OVRN_INT );
// Count overruns for debug
if( IsrFlags & RX_OVRN_INT )
RxOver++;
if( IsrFlags & TX_INT )
{
TxBad++;
// Get the packet number of the failed packet
pktnum = SMSC_READ8(SBA,SMSC_TX_FIFO_PACKET);
// Make sure busy bit is low
while( SMSC_READ16(SBA,SMSC_MMU_COMMAND) & BUSY_BIT );
// Free this packet
SMSC_WRITE8(SBA,SMSC_PACKET_NUMBER,pktnum);
SMSC_WRITE16(SBA,SMSC_MMU_COMMAND,CMD_RELEASE_PACKET);
// Make sure busy bit is low
while( SMSC_READ16(SBA,SMSC_MMU_COMMAND) & BUSY_BIT );
// Start the transmitter
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,0);
SMSC_WRITE16(SBA,SMSC_TRANSMIT_CONTROL,TransmitControl);
}
if( IsrFlags & RCV_INT )
{
// Handle packet receive
needevent |= smscReceivePacket();
}
if( IsrFlags & TX_EMPTY_INT )
{
TxState = STATE_IDLE;
// See if there is another packet pending
HwPktTxNext( pPDI );
}
if( IsrFlags & ALLOC_INT )
{
// Make sure we're on bank 2
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,2);
// Get packet number (we now know the alloc is OK)
// We can fill the TX FIFO and send now.
pktnum = SMSC_READ8(SBA,SMSC_ALLOC_RESULT);
// Send the packet (this function will free hPkt and set the
// TxState back to IDLE). The value of "pktnum" is the SMSC
// packet number.
smscSendPacket( pktnum );
}
// Make sure we're on bank 2
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,2);
// Ack the interrupt
SMSC_WRITE8(SBA,SMSC_INT_STATUS,IsrFlags);
} while( IsrFlags );
// Reset the ISR state
IsrState = ISR_STATE_IDLE;
// Renable SMSC interrupts.
SMSC_WRITE8(SBA,SMSC_INT_MASK,IsrMask);
// Post the NETCTRL event semaphore when needed
if( needevent )
{
FlashActiveLED = 1;
STKEVENT_signal( pPDI->hEvent, STKEVENT_ETHERNET, fTrueInt );
}
}
//--------------------------------------------------------------------
// smscSendPacket
//
// Send the packet (this function will free hPkt and set the
// TxState back to IDLE). The SMSC packet number is passed as
// the calling parameter
//
// If the packet is not properly aligned, it will align it
//--------------------------------------------------------------------
static void smscSendPacket( UINT8 smscPacketNumber )
{
UINT16 *buffer16;
UINT16 tempword;
UINT8 tempbyte;
// First, set the current TX state
TxState = STATE_DMA;
// Load the transmit data
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,2);
SMSC_WRITE8(SBA,SMSC_PACKET_NUMBER,smscPacketNumber);
// Setup pointer (write and TX are default)
while( NOT_EMPTY & SMSC_READ16( SBA, SMSC_POINTER ) ) {
; // wait for write FIFO to become empty
}
SMSC_WRITE16(SBA,SMSC_POINTER,AUTO_INCR);
// Write the status word
SMSC_WRITE16(SBA,SMSC_DATA,0);
// Write the packet size (byte count)
SMSC_WRITE16(SBA,SMSC_DATA,(tx_Size & ~1)+6 );
tempword = tx_Size>>2;
// Setup EDMA
EDMA_RSETH(hEDMA,OPT,EdmaOptTx);
EDMA_RSETH(hEDMA,SRC,(UINT32)(tx_pBuffer + tx_Offset));
EDMA_RSETH(hEDMA,CNT,tempword);
EDMA_RSETH(hEDMA,DST,(SBA+SMSC_DATA));
// Synch the cache
if( (UINT32)tx_pBuffer & 0x80000000 )
OEMCacheCleanSynch();
// Make sure the status word and packet size writes got to the
// SMSC. We do this by reading the SMSC device.
SMSC_READ16(SBA,SMSC_BANK_SELECT);
// Start the DMA
EDMA_setChannel(hEDMA);
// Setup for final transfer
tempword <<= 2;
tx_Size -= tempword;
buffer16 = (UINT16 *)(tx_pBuffer + tx_Offset + tempword);
// Wait for DMA to complete
while( !EDMA_intTest( EdmaEvent ) );
EDMA_intClear( EdmaEvent );
// Send 2 bytes at a time for one go
if( tx_Size >= 2 )
{
SMSC_WRITE16(SBA,SMSC_DATA,*buffer16++);
tx_Size -= 2;
}
// Send any last byte and the control word
if( tx_Size )
tempword = (*buffer16 & 0xFF) | (CONTROLBYTE_ODD<<8);
else
tempword = 0;
SMSC_WRITE16(SBA,SMSC_DATA,tempword);
// Make sure busy bit is low
while( SMSC_READ16(SBA,SMSC_MMU_COMMAND) & BUSY_BIT );
// Enqueue the packet
SMSC_WRITE16(SBA,SMSC_MMU_COMMAND,CMD_ENQUEUE_PACKET);
// Make sure busy bit is low
while( SMSC_READ16(SBA,SMSC_MMU_COMMAND) & BUSY_BIT );
// Assume its a good transmit
TxGood++;
// Now we can free the packet
PBM_free( tx_hPkt );
// Set the transmitter state to SEND
TxState = STATE_SEND;
// We need an interrupt when this packet has been sent
if( IsrState == ISR_STATE_IDLE )
{
tempbyte = SMSC_READ8(SBA,SMSC_INT_MASK) | TX_EMPTY_INT;
SMSC_WRITE8(SBA,SMSC_INT_MASK,tempbyte);
}
}
//--------------------------------------------------------------------
// smscReceivePacket()
//
// This function hanldes all RCV interrupt conditions
//
// Returns 1 if one or more packets received, or 0 on
// error condition.
//--------------------------------------------------------------------
static uint smscReceivePacket()
{
UINT16 tempword,size;
UINT16 *buffer16;
PBM_Handle hPkt;
uint retval = 0;
UINT8 *pData;
// First, set the current RX state
RxState = STATE_DMA;
// Setup pointer to read, rcv, and auto_inc
SMSC_WRITE16(SBA,SMSC_BANK_SELECT,2);
while( NOT_EMPTY & SMSC_READ16( SBA, SMSC_POINTER ) ) {
; // wait for write FIFO to become empty
}
SMSC_WRITE16(SBA,SMSC_POINTER,RCV|READ|AUTO_INCR);
// wait 370 ns
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -