📄 fec.c
字号:
*/ MCF_FEC_PALR = (uint32)((pa[0]<<24) | (pa[1]<<16) | (pa[2]<<8) | pa[3]); MCF_FEC_PAUR = (uint32)((pa[4]<<24) | (pa[5]<<16)); /* * Calculate and set the hash for given Physical Address * in the Individual Address Hash registers */ crc = fec_hash_address(pa); if(crc >= 32) MCF_FEC_IAUR |= (uint32)(1 << (crc - 32)); else MCF_FEC_IALR |= (uint32)(1 << crc);}/********************************************************************//* * Reset the selected FEC controller * * Parameters: * ch FEC channel */voidfec_reset (int ch){ int i; /* Set the Reset bit and clear the Enable bit */ MCF_FEC_ECR = MCF_FEC_ECR_RESET; /* Wait at least 8 clock cycles */ for (i=0; i<10; ++i) nop();}/********************************************************************//* * Initialize the selected FEC * * Parameters: * ch FEC channel * mode External interface mode (MII, 7-wire, or internal loopback) * duplex Duplex setting (FEC_MII_FULL_DUPLEX or FEC_MII_HALF_DUPLEX) * prom Promiscuous mode setting (ON/TRUE or OFF/FALSE) * pa Physical (Hardware) Address for the selected FEC */voidfec_init (int ch, int mode, MII_DUPLEX duplex, int prom, const uint8* pa){ /* Enable all the external interface signals */ if (mode == FEC_MODE_7WIRE) { MCF_GPIO_PTIPAR = MCF_GPIO_PTIPAR_FEC_COL_FEC_COL// | MCF_GPIO_PTIPAR_FEC_CRS_FEC_CRS | MCF_GPIO_PTIPAR_FEC_RXCLK_FEC_RXCLK | MCF_GPIO_PTIPAR_FEC_RXD0_FEC_RXD0// | MCF_GPIO_PTIPAR_FEC_RXD1_FEC_RXD1// | MCF_GPIO_PTIPAR_FEC_RXD2_FEC_RXD2// | MCF_GPIO_PTIPAR_FEC_RXD3_FEC_RXD3 | MCF_GPIO_PTIPAR_FEC_RXDV_FEC_RXDV; MCF_GPIO_PTJPAR = //MCF_GPIO_PTJPAR_FEC_RXER_FEC_RXER MCF_GPIO_PTJPAR_FEC_TXCLK_FEC_TXCLK | MCF_GPIO_PTJPAR_FEC_TXD0_FEC_TXD0// | MCF_GPIO_PTJPAR_FEC_TXD1_FEC_TXD1// | MCF_GPIO_PTJPAR_FEC_TXD2_FEC_TXD2// | MCF_GPIO_PTJPAR_FEC_TXD3_FEC_TXD3 | MCF_GPIO_PTJPAR_FEC_TXEN_FEC_TXEN;// | MCF_GPIO_PTJPAR_FEC_TXER_FEC_TXER; } else if (mode == FEC_MODE_MII) { MCF_GPIO_PTIPAR = MCF_GPIO_PTIPAR_FEC_COL_FEC_COL | MCF_GPIO_PTIPAR_FEC_CRS_FEC_CRS | MCF_GPIO_PTIPAR_FEC_RXCLK_FEC_RXCLK | MCF_GPIO_PTIPAR_FEC_RXD0_FEC_RXD0 | MCF_GPIO_PTIPAR_FEC_RXD1_FEC_RXD1 | MCF_GPIO_PTIPAR_FEC_RXD2_FEC_RXD2 | MCF_GPIO_PTIPAR_FEC_RXD3_FEC_RXD3 | MCF_GPIO_PTIPAR_FEC_RXDV_FEC_RXDV; MCF_GPIO_PTJPAR = MCF_GPIO_PTJPAR_FEC_RXER_FEC_RXER | MCF_GPIO_PTJPAR_FEC_TXCLK_FEC_TXCLK | MCF_GPIO_PTJPAR_FEC_TXD0_FEC_TXD0 | MCF_GPIO_PTJPAR_FEC_TXD1_FEC_TXD1 | MCF_GPIO_PTJPAR_FEC_TXD2_FEC_TXD2 | MCF_GPIO_PTJPAR_FEC_TXD3_FEC_TXD3 | MCF_GPIO_PTJPAR_FEC_TXEN_FEC_TXEN | MCF_GPIO_PTJPAR_FEC_TXER_FEC_TXER; } else if (mode == FEC_MODE_RMII) { ASSERT(FALSE); } else { /* oops */ ASSERT(FALSE); } /* Clear the Individual and Group Address Hash registers */ MCF_FEC_IALR = 0; MCF_FEC_IAUR = 0; MCF_FEC_GALR = 0; MCF_FEC_GAUR = 0; /* Set the Physical Address for the selected FEC */ fec_set_address(ch, pa); /* Set Rx Buffer Size */ MCF_FEC_EMRBR = (uint16)RX_BUF_SZ; /* Point to the start of the circular Rx buffer descriptor queue */ MCF_FEC_ERDSR = fecbd_get_start(ch, Rx); /* Point to the start of the circular Tx buffer descriptor queue */ MCF_FEC_ETSDR = fecbd_get_start(ch, Tx); /* Mask all FEC interrupts */ MCF_FEC_EIMR = MCF_FEC_EIMR_MASK_ALL; /* Clear all FEC interrupt events */ MCF_FEC_EIR = MCF_FEC_EIR_CLEAR_ALL; /* Initialize the Receive Control Register */ MCF_FEC_RCR = 0 | MCF_FEC_RCR_MAX_FL(ETH_MAX_FRM) | MCF_FEC_RCR_FCE; if (mode == FEC_MODE_MII) MCF_FEC_RCR |= MCF_FEC_RCR_MII_MODE; else if (mode == FEC_MODE_LOOPBACK) MCF_FEC_RCR |= (MCF_FEC_RCR_LOOP | MCF_FEC_RCR_PROM); if (prom) MCF_FEC_RCR |= MCF_FEC_RCR_PROM; /* Set the duplex */ if (mode == FEC_MODE_LOOPBACK) /* Loopback mode must operate in full-duplex */ fec_duplex(ch, MII_FDX); else fec_duplex(ch, duplex);}/********************************************************************//* * Continue the Rx DMA task * * This routine is called after the DMA task has halted after * encountering an Rx buffer descriptor that wasn't marked as * ready. There is no harm in calling the DMA continue routine * if the DMA is not halted. * * Parameters: * ch FEC channel */voidfec_rx_continue(int ch){ /* Continue/restart the FEC DMA */ MCF_FEC_RDAR = MCF_FEC_RDAR_R_DES_ACTIVE;}/********************************************************************//* * Receive Frame interrupt handler * * Parameters: * nif Pointer to Network Interface structure */voidfec_rx_handler(NIF *nif){ ETH_HDR *eth_hdr; FECBD *pRxBD; NBUF *cur_nbuf, *new_nbuf; int keep; int i = 0; while ((pRxBD = fecbd_rx_alloc(nif->ch)) != NULL) { keep = TRUE; if (pRxBD->status & RX_BD_L) fec_log[nif->ch].rxf++; else fec_log[nif->ch].rxb++; if (pRxBD->status & RX_BD_ERROR) { // keep = FALSE; //mask for UN test if (pRxBD->status & RX_BD_NO) fec_log[nif->ch].rfsw_no++; if (pRxBD->status & RX_BD_CR) fec_log[nif->ch].rfsw_cr++; if (pRxBD->status & RX_BD_OV) fec_log[nif->ch].rfsw_ov++; if (pRxBD->status & RX_BD_TR) fec_log[nif->ch].rfsw_tr++; } else { if (pRxBD->status & RX_BD_LG) fec_log[nif->ch].rfsw_lg++; if (pRxBD->status & RX_BD_M) fec_log[nif->ch].rfsw_m++; if (pRxBD->status & RX_BD_BC) fec_log[nif->ch].rfsw_bc++; if (pRxBD->status & RX_BD_MC) fec_log[nif->ch].rfsw_mc++; } if (keep) { /* Pull the network buffer off the Rx ring queue */ cur_nbuf = (NBUF *)queue_remove(&rxbd_queue[nif->ch]); ASSERT(cur_nbuf); ASSERT(cur_nbuf->data == pRxBD->data); /* Copy the buffer descriptor information to the network buffer */ cur_nbuf->length = (pRxBD->length - (ETH_HDR_LEN + ETH_CRC_LEN)); cur_nbuf->offset = ETH_HDR_LEN; /* Get a new buffer pointer for this buffer descriptor */ new_nbuf = nbuf_alloc(); if (new_nbuf == NULL) { #ifdef DEBUG_PRINT printf("nbuf_alloc() failed\n"); #endif /* * Can't allocate a new network buffer, so we are * going to trash the received data and reuse the buffer * hoping that some buffers will free up in the system * and this frame will be re-transmitted by the host */ pRxBD->length = RX_BUF_SZ; pRxBD->status &= RX_BD_W; pRxBD->status |= RX_BD_E; queue_add(&rxbd_queue[nif->ch],(QNODE *)cur_nbuf); fec_rx_continue(nif->ch); continue; } /* Add the new network buffer to the Rx ring queue */ queue_add(&rxbd_queue[nif->ch],(QNODE *)new_nbuf); /* * Re-initialize the buffer descriptor - pointing it * to the new data buffer. The previous data buffer * will be passed up the stack */ pRxBD->data = new_nbuf->data; pRxBD->length = RX_BUF_SZ; pRxBD->status &= (RX_BD_W); pRxBD->status |= RX_BD_E; /* Let the DMA know that there is a new Rx BD (in case the * ring was full and the DMA was waiting for an empty one) */ fec_rx_continue(nif->ch); /* Get pointer to the frame data inside the network buffer */ eth_hdr = (ETH_HDR *)cur_nbuf->data; /* Pass the received packet up the network stack if the * protocol is supported in our network interface (NIF) */ if (nif_protocol_exist(nif,eth_hdr->type)) { nif_protocol_handler(nif, eth_hdr->type, cur_nbuf); } //else modify by LK nbuf_free(cur_nbuf); } else { /* This frame isn't a keeper * Reset the status and length, but don't need to get another * buffer since we are trashing the data in the current one */ pRxBD->length = RX_BUF_SZ; pRxBD->status &= (RX_BD_W); pRxBD->status |= RX_BD_E; /* Move the current buffer from the beginning to the end of the * Rx ring queue */ cur_nbuf = (NBUF *)queue_remove(&rxbd_queue[nif->ch]); queue_add(&rxbd_queue[nif->ch],(QNODE *)cur_nbuf); /* Let the DMA know that there are new Rx BDs (in case * it is waiting for an empty one) */ fec_rx_continue(nif->ch); } }}/********************************************************************//* * Continue the Tx DMA task * * This routine is called after the DMA task has halted after * encountering an Tx buffer descriptor that wasn't marked as * ready. There is no harm in calling the continue DMA routine * if the DMA was not paused. * * Parameters: * ch FEC channel */voidfec_tx_continue(int ch){ /* Continue/restart the FEC DMA */ MCF_FEC_TDAR = MCF_FEC_TDAR_X_DES_ACTIVE;}/********************************************************************//* * Stop all transmissions on the selected FEC and kill the DMA task * * Parameters: * ch FEC channel */voidfec_tx_stop (int ch){ uint32 mask; int i, channel; /* Save off the EIMR value */ mask = MCF_FEC_EIMR; /* Mask all interrupts */ MCF_FEC_EIMR = 0; /* If the Ethernet is still enabled... */ if (MCF_FEC_ECR & MCF_FEC_ECR_ETHER_EN) { /* Issue the Graceful Transmit Stop */ MCF_FEC_TCR |= MCF_FEC_TCR_GTS; /* Wait for the Graceful Stop Complete interrupt */ i = 500000; while(!(MCF_FEC_EIR & MCF_FEC_EIR_GRA)) { if (!(MCF_FEC_ECR & MCF_FEC_ECR_ETHER_EN)) break; if (--i == 0) break; } /* Clear the Graceful Stop Complete interrupt */ MCF_FEC_EIR = MCF_FEC_EIR_GRA; } /* Restore the interrupt mask register value */ MCF_FEC_EIMR = mask;}/********************************************************************//* * Trasmit Frame interrupt handler - this handler is called when an * FEC Tx interrupt event occurs * * Parameters: * ch FEC channel * event Other interrupt events at the time of the Tx interrupt */voidfec_tx_handler(NIF* nif, int event){ FECBD *pTxBD; NBUF *pNbuf; int i = 0; /* * Here is where we could check "event" to see if any errors * occurred during transmission. If the Tx interrupt isn't serviced * before a second packet is sent, then it will not be possible to * determine which events correspond to which packet(s). */ (void) event; while ((pTxBD = fecbd_tx_free(nif->ch)) != NULL) { if (pTxBD->status & TX_BD_L) fec_log[nif->ch].txf++; else fec_log[nif->ch].txb++; /* Grab the network buffer associated with this descriptor */ pNbuf = (NBUF *)queue_remove(&txbd_queue[nif->ch]); ASSERT(pNbuf); ASSERT(pNbuf->data == pTxBD->data); /* If there is a Tx callback function enabled, call it and pass * it the pointer to the packet that was just transmitted. If not, * free the network buffer now. If there is a callback function, * it is responsible for freeing the network buffer! */ if (nif[nif->ch].txcallback != NULL) { nif[nif->ch].txcallback(pNbuf); } else { /* Free up the network buffer that was just transmitted */ nbuf_free(pNbuf); } /* Check for packets in the send holding queue */ pNbuf = (NBUF *)queue_remove(&send_queue[nif->ch]); if (pNbuf != NULL) { /* There was a packet waiting in the send queue */ /* Put the buffer into the TxBD ring queue */ queue_add(&txbd_queue[nif->ch],(QNODE *)pNbuf); /* Setup the buffer descriptor for transmission */ pTxBD->data = pNbuf->data; pTxBD->length = pNbuf->length + ETH_HDR_LEN; pTxBD->status |= (TX_BD_R | TX_BD_L); /* Kick the Tx DMA */ fec_tx_continue(nif->ch); } else { /* There is nothing in the send holding queue */ /* Re-initialize the Tx BD to empty */ pTxBD->data = NULL; pTxBD->length = 0; } }}/********************************************************************//* * Send a packet out the selected FEC *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -