📄 ks5000_ether.c
字号:
#endif
return CYG_ISR_HANDLED;
}
//======================================================================
// This interrupt only happens when errors occur
static cyg_uint32 BDMA_Tx_isr(cyg_vector_t vector, cyg_addrword_t data)
{
U32 IntBDMATxStatus;
cyg_drv_interrupt_acknowledge(vector);
IntBDMATxStatus = BDMASTAT;
BDMASTAT = IntBDMATxStatus;
++ks5000_BDMA_Tx_Isr_Cnt;
#if defined(CYGPKG_NET)
++ifStats.interrupts;
#endif
if (IntBDMATxStatus & BDMASTAT_TX_CCP)
{
debug1_printf("+-- Control Packet Transfered : %x\r",ERMPZCNT);
debug1_printf(" Tx Control Frame Status : %x\r",ETXSTAT);
}
if (IntBDMATxStatus & (BDMASTAT_TX_NL|BDMASTAT_TX_NO|BDMASTAT_TX_EMPTY) )
{
if (IntBDMATxStatus & BDMASTAT_TX_NL)
BDMATxErrCnt.BTxNLErr++;
if (IntBDMATxStatus & BDMASTAT_TX_NO)
BDMATxErrCnt.BTxNOErr++;
if (IntBDMATxStatus & BDMASTAT_TX_EMPTY)
BDMATxErrCnt.BTxEmptyErr++;
}
// free any buffers we're done with
while (txDonePointer->FrameDataPtr && !(txDonePointer->FrameDataPtr & FRM_OWNERSHIP_BDMA))
{
freeBuffer((tEthBuffer*)txDonePointer->FrameDataPtr);
txDonePointer->FrameDataPtr = 0;
txDonePointer = txDonePointer->NextFD;
}
// don't call tx dsr for now -- it has nothing to do
return CYG_ISR_HANDLED;
}
static void BDMA_Tx_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
++ks5000_BDMA_Tx_Dsr_Cnt;
}
//======================================================================
static cyg_uint32 BDMA_Rx_isr(cyg_vector_t vector, cyg_addrword_t data)
{
U32 IntBDMARxStatus;
cyg_drv_interrupt_acknowledge(vector);
IntBDMARxStatus = BDMASTAT;
BDMASTAT = IntBDMARxStatus;
++ks5000_BDMA_Rx_Isr_Cnt;
#if defined(CYGPKG_NET)
++ifStats.interrupts;
#endif
if (IntBDMARxStatus & (BDMASTAT_RX_NL | BDMASTAT_RX_NO |
BDMASTAT_RX_MSO | BDMASTAT_RX_EMPTY |
BDMASTAT_RX_SEARLY) )
{
// printf("RxIsr %u\r\n", (unsigned)cyg_current_time());
if (IntBDMARxStatus & BDMASTAT_RX_NL)
BDMARxErrCnt.BRxNLErr++;
if (IntBDMARxStatus & BDMASTAT_RX_NO)
BDMARxErrCnt.BRxNOErr++;
if (IntBDMARxStatus & BDMASTAT_RX_MSO)
BDMARxErrCnt.BRxMSOErr++;
if (IntBDMARxStatus & BDMASTAT_RX_EMPTY)
BDMARxErrCnt.BRxEmptyErr++;
if (IntBDMARxStatus & BDMASTAT_RX_SEARLY)
BDMARxErrCnt.sBRxSEarly++;
}
return CYG_ISR_HANDLED|CYG_ISR_CALL_DSR;
}
static void eth_handle_recv_buffer(tEthBuffer*);
static cyg_handle_t bdmaRxIntrHandle;
static cyg_handle_t bdmaTxIntrHandle;
static cyg_handle_t macRxIntrHandle;
static cyg_handle_t macTxIntrHandle;
static cyg_interrupt bdmaRxIntrObject;
static cyg_interrupt bdmaTxIntrObject;
static cyg_interrupt macRxIntrObject;
static cyg_interrupt macTxIntrObject;
static int ethernetRunning;
#if HavePHYinterrupt
static cyg_handle_t macPhyIntrHandle;
static cyg_interrupt macPhyIntrObject;
#endif
static void ks32c5000_eth_deliver(struct eth_drv_sc *sc)
{
unsigned short p;
tEthBuffer *rxBuffer;
extern void cyg_interrupt_post_dsr(CYG_ADDRWORD intr_obj);
++ks5000_BDMA_Rx_Dsr_Cnt;
while (1)
{
if (!rx_frame_avail())
{
// no more frames
return;
}
if (!(rxBuffer=ks32c5000_eth_get_recv_buffer()))
{
// no buffers available
return;
}
p = *((unsigned short*)(rxBuffer->data+EtherFramePadding+ETH_HEADER_SIZE-2));
if (ethernetRunning)
eth_handle_recv_buffer(rxBuffer);
else
freeBuffer(rxBuffer);
}
}
static void installInterrupts(void)
{
extern struct eth_drv_sc ks32c5000_sc;
static bool firstTime=true;
debug1_printf("ks5000_ether: installInterrupts()\n");
if (!firstTime)
return;
firstTime = false;
initFreeList();
Init_RxFrameDescriptorArray();
Init_TxFrameDescriptorArray();
BDMARXPTR = (U32)rxReadPointer;
BDMATXPTR = (U32)txWritePointer;
cyg_drv_mutex_init(&txMutex);
cyg_drv_mutex_init(&oldRxMutex);
cyg_drv_cond_init(&oldRxCond,&oldRxMutex);
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX,0,(unsigned)&ks32c5000_sc,BDMA_Rx_isr,eth_drv_dsr,&bdmaRxIntrHandle,&bdmaRxIntrObject);
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_ETH_BDMA_TX,0,0,BDMA_Tx_isr,BDMA_Tx_dsr,&bdmaTxIntrHandle,&bdmaTxIntrObject);
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_ETH_MAC_RX,0,0,MAC_Rx_isr,NULL,&macRxIntrHandle,&macRxIntrObject);
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_ETH_MAC_TX,0,0,MAC_Tx_isr,NULL,&macTxIntrHandle,&macTxIntrObject);
#if HavePHYinterrupt
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_EXT0,0,0,MAC_Phy_isr,NULL,&macPhyIntrHandle,&macPhyIntrObject);
cyg_drv_interrupt_attach(macPhyIntrHandle);
#endif
cyg_drv_interrupt_attach(bdmaRxIntrHandle);
cyg_drv_interrupt_attach(bdmaTxIntrHandle);
cyg_drv_interrupt_attach(macRxIntrHandle);
cyg_drv_interrupt_attach(macTxIntrHandle);
#if HavePHYinterrupt
cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_EXT0);
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EXT0);
#endif
}
//======================================================================
// Driver code that interfaces to the TCP/IP stack via the common
// Ethernet interface.
// don't have any private data, but if we did, this is where it would go
typedef struct
{
int j;
}ks32c5000_priv_data_t;
ks32c5000_priv_data_t ks32c5000_priv_data;
#define eth_drv_tx_done(sc,key,retval) (sc)->funs->eth_drv->tx_done(sc,key,retval)
#define eth_drv_init(sc,enaddr) ((sc)->funs->eth_drv->init)(sc, enaddr)
#define eth_drv_recv(sc,len) ((sc)->funs->eth_drv->recv)(sc, len)
static bool ks32c5000_eth_init(struct cyg_netdevtab_entry *tab)
{
unsigned char myMacAddr[6] = { CYGPKG_DEVS_ETH_ARM_KS32C5000_MACADDR };
struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
bool ok;
#ifdef CYGHWR_DEVS_ETH_ARM_KS32C5000_GET_ESA
// Get MAC address from RedBoot configuration variables
CYGHWR_DEVS_ETH_ARM_KS32C5000_GET_ESA(&myMacAddr[0], ok);
// If this call fails myMacAddr is unchanged and MAC address from CDL is used
#endif
debug1_printf("ks32c5000_eth_init()\n");
debug1_printf(" MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",myMacAddr[0],myMacAddr[1],myMacAddr[2],myMacAddr[3],myMacAddr[4],myMacAddr[5]);
#if defined(CYGPKG_NET)
ifStats.duplex = 1; //unknown
ifStats.operational = 1; //unknown
ifStats.tx_queue_len = MAX_TX_FRAME_DESCRIPTORS;
strncpy(ifStats.description,"Ethernet device",sizeof(ifStats.description));
ifStats.snmp_chipset[0] = 0;
ifStats.supports_dot3 = 1; // support dot3
#endif
installInterrupts();
EthInit(myMacAddr);
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX);
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_TX);
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_MAC_RX);
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_MAC_TX);
configDone = 1;
ethernetRunning = 1;
eth_drv_init(sc, myMacAddr);
return true;
}
static void ks32c5000_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
{
debug2_printf("ks32c5000_eth_start()\n");
if (!ethernetRunning)
{
cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX);
cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_TX);
cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_ETH_MAC_RX);
cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_ETH_MAC_TX);
EthInit(enaddr);
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX);
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_TX);
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_MAC_RX);
cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_MAC_TX);
ethernetRunning = 1;
}
}
static void ks32c5000_eth_stop(struct eth_drv_sc *sc)
{
debug1_printf("ks32c5000_eth_stop()\n");
ethernetRunning = 0;
}
static int ks32c5000_eth_control(struct eth_drv_sc *sc,
unsigned long cmd,
void *data,
int len)
{
switch (cmd)
{
#if defined(CYGPKG_NET)
case ETH_DRV_GET_IF_STATS_UD:
case ETH_DRV_GET_IF_STATS:
{
struct ether_drv_stats *p = (struct ether_drv_stats*)data;
#if CYGINT_DEVS_ETH_ARM_KS32C5000_PHY
unsigned linkStatus;
// Read link status to be up to date
linkStatus = PhyStatus();
if (linkStatus & PhyStatus_FullDuplex)
ifStats.duplex = 3;
else
ifStats.duplex = 2;
if (linkStatus & PhyStatus_LinkUp)
ifStats.operational = 3;
else
ifStats.operational = 2;
if (linkStatus & PhyStatus_100Mb)
ifStats.speed = 100000000;
else
ifStats.speed = 10000000;
#endif
*p = ifStats;
return 0;
}
#endif
case ETH_DRV_SET_MAC_ADDRESS: {
int act;
if (ETHER_ADDR_LEN != len)
return -1;
debug1_printf("ks32c5000_eth_control: ETH_DRV_SET_MAC_ADDRESS.\n");
act = ethernetRunning;
ks32c5000_eth_stop(sc);
ks32c5000_eth_start(sc, data, 0);
ethernetRunning = act;
return 0;
}
#ifdef ETH_DRV_GET_MAC_ADDRESS
case ETH_DRV_GET_MAC_ADDRESS: {
if (len < ETHER_ADDR_LEN)
return -1;
debug1_printf("ks32c5000_eth_control: ETH_DRV_GET_MAC_ADDRESS.\n");
memcpy(data, (void *)CAM_BaseAddr, ETHER_ADDR_LEN);
return 0;
}
#endif
default:
return -1;
}
}
static int ks32c5000_eth_can_send_count=0;
static int ks32c5000_eth_can_send_count_OK=0;
// In case there are multiple Tx frames waiting, we should
// return how many empty Tx spots we have. For now we just
// return 0 or 1.
static int ks32c5000_eth_can_send(struct eth_drv_sc *sc)
{
FRAME_DESCRIPTOR *TxFp, *StartFp;
// find the next unused spot in the queue
++ks32c5000_eth_can_send_count;
StartFp = TxFp = (FRAME_DESCRIPTOR*)BDMATXPTR;
while (TxFp->FrameDataPtr & FRM_OWNERSHIP_BDMA)
{
TxFp = TxFp->NextFD;
if (TxFp == StartFp)
return 0;
}
++ks32c5000_eth_can_send_count_OK;
return 1;
}
static int ks5000_eth_send_count=0;
static void ks32c5000_eth_send(struct eth_drv_sc *sc,
struct eth_drv_sg *sg_list,
int sg_len,
int total_len,
unsigned long key)
{
unsigned char *dest;
unsigned len;
tEthBuffer *buf;
if (total_len >= MAX_ETH_FRAME_SIZE)
{
eth_drv_tx_done(sc,key,-EINVAL);
return;
}
++ks5000_eth_send_count;
// allocate buffer
buf = allocBuffer();
if (!buf)
{
// out of buffers
eth_drv_tx_done(sc,key,-EIO);
return;
}
// copy data from scatter/gather list into BDMA data buffer
len = 0;
dest = buf->data;
while (sg_len)
{
memcpy(dest,(unsigned char*)sg_list->buf,sg_list->len);
len += sg_list->len;
dest += sg_list->len;
++sg_list;
--sg_len;
}
buf->length = len;
// tell upper layer that we're done with this sglist
eth_drv_tx_done(sc,key,0);
// queue packet for transmit
while(!ks32c5000_eth_buffer_send(buf))
{
#if defined(CYGPKG_KERNEL)
// wait a tick and try again.
cyg_thread_delay(1);
#else
// toss it.
freeBuffer(buf);
break;
#endif
}
}
static int ks5000_eth_rcv_count=0;
static tEthBuffer *tcpIpRxBuffer;
// called from DSR
static void eth_handle_recv_buffer(tEthBuffer* rxBuffer)
{
extern struct eth_drv_sc ks32c5000_sc;
tcpIpRxBuffer = rxBuffer;
eth_drv_recv(&ks32c5000_sc,tcpIpRxBuffer->length-4); // discard 32-bit CRC
}
static void ks32c5000_eth_recv(struct eth_drv_sc *sc,
struct eth_drv_sg *sg_list,
int sg_len)
{
unsigned char *source;
++ks5000_eth_rcv_count;
if (!tcpIpRxBuffer)
return; // no packet waiting, shouldn't be here!
// copy data from eth buffer into scatter/gather list
source = tcpIpRxBuffer->data + EtherFramePadding;
while (sg_len)
{
if (sg_list->buf)
memcpy((unsigned char*)sg_list->buf,source,sg_list->len);
source += sg_list->len;
++sg_list;
--sg_len;
}
freeBuffer(tcpIpRxBuffer);
tcpIpRxBuffer = NULL;
return;
}
// routine called to handle ethernet controller in polled mode
static void ks32c5000_eth_poll(struct eth_drv_sc *sc)
{
BDMA_Rx_isr(CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX, 0); // Call ISR routine
ks32c5000_eth_deliver(sc); // handle rx frames
ks32c5000_handle_tx_complete();
}
static int ks32c5000_eth_int_vector(struct eth_drv_sc *sc)
{
return CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX;
}
ETH_DRV_SC(ks32c5000_sc,
&ks32c5000_priv_data, // Driver specific data
"eth0", // Name for this interface
ks32c5000_eth_start,
ks32c5000_eth_stop,
ks32c5000_eth_control,
ks32c5000_eth_can_send,
ks32c5000_eth_send,
ks32c5000_eth_recv,
ks32c5000_eth_deliver,
ks32c5000_eth_poll,
ks32c5000_eth_int_vector
);
NETDEVTAB_ENTRY(ks32c5000_netdev,
"ks32c5000",
ks32c5000_eth_init,
&ks32c5000_sc);
// EOF ks5000_ether.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -