if_fec.c
来自「eCos操作系统源码」· C语言 代码 · 共 711 行 · 第 1/2 页
C
711 行
E_fcc->iaddr_l = 0; E_fcc->minflr = FEC_MIN_FLR; E_fcc->taddr_h = 0; E_fcc->taddr_m = 0; E_fcc->taddr_l = 0; E_fcc->pad_ptr = FEC_PRAM_TIPTR; // No special padding char ... E_fcc->cf_type = 0; E_fcc->maxd1 = FEC_PRAM_MAXD; E_fcc->maxd2 = FEC_PRAM_MAXD; // FCC register initialization IMM->fcc_regs[FCC2].fcc_gfmr = FEC_GFMR_INIT; IMM->fcc_regs[FCC2].fcc_psmr = FEC_PSMR_INIT; IMM->fcc_regs[FCC2].fcc_dsr = FEC_DSR_INIT;#ifdef CYGPKG_NET // clear the events of FCC2 IMM->fcc_regs[FCC2].fcc_fcce = 0xFFFF0000; IMM->fcc_regs[FCC2].fcc_fccm = FEC_EV_TXE | FEC_EV_TXB | FEC_EV_RXF; // Set up to handle interrupts cyg_drv_interrupt_create(FEC_ETH_INT, 0, // Highest //CYGARC_SIU_PRIORITY_HIGH, (cyg_addrword_t)sc, // Data passed to ISR (cyg_ISR_t *)fec_eth_isr, (cyg_DSR_t *)eth_drv_dsr, &fec_eth_interrupt_handle, &fec_eth_interrupt); cyg_drv_interrupt_attach(fec_eth_interrupt_handle); cyg_drv_interrupt_acknowledge(FEC_ETH_INT); cyg_drv_interrupt_unmask(FEC_ETH_INT);#else // Mask the interrupts IMM->fcc_regs[FCC2].fcc_fccm = 0;#endif // Issue Init RX & TX Parameters Command for FCC2 while ((IMM->cpm_cpcr & CPCR_FLG) != CPCR_READY_TO_RX_CMD); IMM->cpm_cpcr = CPCR_INIT_TX_RX_PARAMS | CPCR_FCC2_CH | CPCR_MCN_FEC | CPCR_FLG; /* ISSUE COMMAND */ while ((IMM->cpm_cpcr & CPCR_FLG) != CPCR_READY_TO_RX_CMD); // Initialize upper level driver for ecos (sc->funs->eth_drv->init)(sc, (unsigned char *)&enaddr); return true;} //// This function is called to "start up" the interface. It may be called// multiple times, even when the hardware is already running. It will be// called whenever something "hardware oriented" changes and should leave// the hardware ready to send/receive packets.//static voidfec_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags){ struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; // Enable the device : // Set the ENT/ENR bits in the GFMR -- Enable Transmit/Receive qi->fcc_reg->fcc_gfmr |= (FEC_GFMR_EN_Rx | FEC_GFMR_EN_Tx); }//// This function is called to shut down the interface.//static voidfec_eth_stop(struct eth_drv_sc *sc){ struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; // Disable the device : // Clear the ENT/ENR bits in the GFMR -- Disable Transmit/Receive qi->fcc_reg->fcc_gfmr &= ~(FEC_GFMR_EN_Rx | FEC_GFMR_EN_Tx);}//// This function is called for low level "control" operations//static intfec_eth_control(struct eth_drv_sc *sc, unsigned long key, void *data, int length){ switch (key) { case ETH_DRV_SET_MAC_ADDRESS: return 0; break; default: return 1; break; }}//// This function is called to see if another packet can be sent.// It should return the number of packets which can be handled.// Zero should be returned if the interface is busy and can not send any more.//static intfec_eth_can_send(struct eth_drv_sc *sc){ struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; volatile struct fec_bd *txbd = qi->txbd; int cache_state; HAL_DCACHE_IS_ENABLED(cache_state);#ifndef FEC_BDs_NONCACHED if (cache_state) { HAL_DCACHE_INVALIDATE(fec_eth_txring, 8*CYGNUM_DEVS_ETH_POWERPC_QUICC2_TxNUM); }#endif return ((txbd->ctrl & (FCC_BD_Tx_TC | FCC_BD_Tx_Ready)) == 0);}//// This routine is called to send data to the hardware.static void fec_eth_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total_len, unsigned long key){ struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; struct fec_bd *txbd, *txfirst; volatile char *bp; int i, txindex, cache_state; HAL_DCACHE_IS_ENABLED(cache_state);#ifndef FEC_BDs_NONCACHED if (cache_state) { HAL_DCACHE_INVALIDATE(fec_eth_txring, 8*CYGNUM_DEVS_ETH_POWERPC_QUICC2_TxNUM); }#endif // Find a free buffer txbd = txfirst = qi->txbd; while (txbd->ctrl & FEC_BD_Tx_Ready) { // This buffer is busy, move to next one if (txbd->ctrl & FEC_BD_Tx_Wrap) { txbd = qi->tbase; } else { txbd++; } if (txbd == txfirst) {#ifdef CYGPKG_NET panic ("No free xmit buffers");#else os_printf("FEC Ethernet: No free xmit buffers\n");#endif } } // Remember the next buffer to try if (txbd->ctrl & FEC_BD_Tx_Wrap) { qi->txbd = qi->tbase; } else { qi->txbd = txbd+1; } txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd); qi->txkey[txindex] = key; // Set up buffer txbd->length = total_len; bp = txbd->buffer; for (i = 0; i < sg_len; i++) { memcpy((void *)bp, (void *)sg_list[i].buf, sg_list[i].len); bp += sg_list[i].len; } // Make sure no stale data buffer ... if (cache_state) { HAL_DCACHE_FLUSH(txbd->buffer, txbd->length); } // Send it on it's way txbd->ctrl |= FEC_BD_Tx_Ready | FEC_BD_Tx_Last | FEC_BD_Tx_TC;#ifndef FEC_BDs_NONCACHED if (cache_state) { HAL_DCACHE_FLUSH(fec_eth_txring, 8*CYGNUM_DEVS_ETH_POWERPC_QUICC2_TxNUM); }#endif }//// This function is called when a packet has been received. It's job is// to prepare to unload the packet from the hardware. Once the length of// the packet is known, the upper layer of the driver can be told. When// the upper layer is ready to unload the packet, the internal function// 'fec_eth_recv' will be called to actually fetch it from the hardware.//static voidfec_eth_RxEvent(struct eth_drv_sc *sc){ struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; struct fec_bd *rxbd; int cache_state; HAL_DCACHE_IS_ENABLED(cache_state);#ifndef FEC_BDs_NONCACHED if (cache_state) { HAL_DCACHE_INVALIDATE(fec_eth_rxring, 8*CYGNUM_DEVS_ETH_POWERPC_QUICC2_RxNUM); }#endif rxbd = qi->rnext; while ((rxbd->ctrl & FEC_BD_Rx_Empty) == 0) { qi->rxbd = rxbd; // Save for callback // This is the right way of doing it, but dcbi has a bug ... // if (cache_state) { // HAL_DCACHE_INVALIDATE(rxbd->buffer, rxbd->length); // } (sc->funs->eth_drv->recv)(sc, rxbd->length); if (cache_state) { HAL_DCACHE_FLUSH(rxbd->buffer, rxbd->length); } rxbd->ctrl |= FEC_BD_Rx_Empty; if (rxbd->ctrl & FEC_BD_Rx_Wrap) { rxbd = qi->rbase; } else { rxbd++; } } // Remember where we left off qi->rnext = (struct fec_bd *)rxbd; // Make sure no stale data#ifndef FEC_BDs_NONCACHED if (cache_state) { HAL_DCACHE_FLUSH(fec_eth_rxring, 8*CYGNUM_DEVS_ETH_POWERPC_QUICC2_RxNUM); }#endif}//// This function is called as a result of the "eth_drv_recv()" call above.// It's job is to actually fetch data for a packet from the hardware once// memory buffers have been allocated for the packet. Note that the buffers// may come in pieces, using a scatter-gather list. This allows for more// efficient processing in the upper layers of the stack.//static voidfec_eth_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len){ struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; unsigned char *bp; int i; bp = (unsigned char *)qi->rxbd->buffer; for (i = 0; i < sg_len; i++) { if (sg_list[i].buf != 0) { memcpy((void *)sg_list[i].buf, bp, sg_list[i].len); bp += sg_list[i].len; } }}static voidfec_eth_TxEvent(struct eth_drv_sc *sc, int stat){ struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; struct fec_bd *txbd; int txindex, cache_state; // Make sure no stale data HAL_DCACHE_IS_ENABLED(cache_state);#ifndef FEC_BDs_NONCACHED if (cache_state) { HAL_DCACHE_INVALIDATE(fec_eth_txring, 8*CYGNUM_DEVS_ETH_POWERPC_QUICC2_TxNUM); }#endif txbd = qi->tnext; // Note: TC field is used to indicate the buffer has/had data in it while ( (txbd->ctrl & (FEC_BD_Tx_TC | FEC_BD_Tx_Ready)) == FEC_BD_Tx_TC ) { txindex = ((unsigned long)txbd - (unsigned long)qi->tbase) / sizeof(*txbd); (sc->funs->eth_drv->tx_done)(sc, qi->txkey[txindex], 0); txbd->ctrl &= ~FEC_BD_Tx_TC; if (txbd->ctrl & FEC_BD_Tx_Wrap) { txbd = qi->tbase; } else { txbd++; } } // Remember where we left off qi->tnext = (struct fec_bd *)txbd; // Make sure no stale data #ifndef FEC_BDs_NONCACHED if (cache_state) { HAL_DCACHE_FLUSH(fec_eth_txring, 8*CYGNUM_DEVS_ETH_POWERPC_QUICC2_TxNUM); }#endif}//// Interrupt processing//static void fec_eth_int(struct eth_drv_sc *sc){ struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private; unsigned long iEvent; while ((iEvent = qi->fcc_reg->fcc_fcce) != 0){ // Writing 1's clear fcce, Writing 0's have no effect qi->fcc_reg->fcc_fcce = iEvent; // Tx Done or Tx Error if ( iEvent & (FEC_EV_TXB | FEC_EV_TXE) ) { fec_eth_TxEvent(sc, iEvent); } // Complete or non-complete frame receive if (iEvent & (FEC_EV_RXF | FEC_EV_RXB) ) { fec_eth_RxEvent(sc); } } }//// Interrupt vector//static int fec_eth_int_vector(struct eth_drv_sc *sc){ return (FEC_ETH_INT);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?