📄 drivers_net_arm_ep93xx_eth_c_diff.htm
字号:
+ pP->d.stats.tx_errors++;
+ if (pQTxSts->f.lcrs)
+ pP->d.stats.tx_carrier_errors++; /*loss of CRS */
+ if (pQTxSts->f.txu)
+ pP->d.stats.tx_fifo_errors++; /*underrun */
+ if (pQTxSts->f.ecoll)
+ pP->d.stats.collisions++; /*excessive collision */
+ } /*else */
+
+ /*ahead Tx Descriptor Queue tail index */
+ pP->d.idxQueTxDescTail =
+ IdxNext(pP->d.idxQueTxDescTail, LEN_QueTxDesc);
+ } /*while */
+
+ return 0;
+} /*eth_cleanUpTx() */
+
+/*****************************************************************************
+* eth_restartTx()
+*****************************************************************************/
+static int eth_restartTx(struct net_device *pD)
+{
+ struct ep93xxEth_info *pP = netdev_priv(pD);
+ int i;
+
+ _PRTK_ENTRY(("eth_restartTx(pD:0x%p)\n", pD));
+
+ /*disable int */
+ RegWr32(REG_GIntMsk, RegRd32(REG_GIntMsk) & ~GIntMsk_IntEn); /*turn off master INT control */
+
+ /*stop Tx and Tx DMA */
+ RegWr32(REG_TxCTL, RegRd32(REG_TxCTL) & ~TxCTL_STxON); /*Tx off */
+ RegWr32(REG_BMCtl, RegRd32(REG_BMCtl) | BMCtl_TxDis); /*disable Tx DMA */
+
+ /*reset Tx DMA */
+ RegWr32(REG_BMCtl, BMCtl_TxChR | RegRd32(REG_BMCtl)); /*reset Tx DMA */
+
+ /*release Tx buffers */
+ for (i = 0; i < LEN_QueTxDesc; i++) {
+ if (pP->s.pTxBufDesc[i].pFreeRtn) {
+ pP->s.pTxBufDesc[i].pFreeRtn(pP->s.pTxBufDesc[i].vaddr);
+ pP->s.pTxBufDesc[i].pFreeRtn = NULL;
+ } /*if */
+ pP->d.stats.tx_dropped++;
+ } /*for */
+
+ /*init Tx Queues and flush cache */
+ memset(pP->s.pQueTxSts, 0, sizeof(pP->s.pQueTxSts[0]) * LEN_QueTxSts); /*clear FP flag */
+
+ /*init variables */
+ pP->d.txStopped = 0;
+ pP->d.idxQueTxSts = pP->d.idxQueTxDescHead = pP->d.idxQueTxDescTail = 0;
+
+ /*init registers */
+ waitOnReg32(pD, REG_BMSts, BMCtl_TxChR, ~BMCtl_TxChR, 1); /*wait to finish Tx DMA reset */
+ RegWr32(REG_TxSBA, pP->s.phyQueTxSts); /*base addr of Tx Status Queue */
+ RegWr32(REG_TxSCA, pP->s.phyQueTxSts); /*current addr */
+ RegWr16(REG_TxSBL, sizeof(pP->s.pQueTxSts[0]) * LEN_QueTxSts); /*base len */
+ RegWr16(REG_TxSCL, sizeof(pP->s.pQueTxSts[0]) * LEN_QueTxSts); /*current len */
+ RegWr32(REG_TxDBA, pP->s.phyQueTxDesc); /*base addr of Tx Descriptor Queue */
+ RegWr32(REG_TxDCA, pP->s.phyQueTxDesc); /*current addr */
+ RegWr16(REG_TxDBL, sizeof(pP->s.pQueTxDesc[0]) * LEN_QueTxDesc); /*base len */
+ RegWr16(REG_TxDCL, sizeof(pP->s.pQueTxDesc[0]) * LEN_QueTxDesc); /*current len */
+
+ /*start Tx and Tx DMA */
+ RegWr32(REG_TxCTL, RegRd32(REG_TxCTL) | TxCTL_STxON); /*Tx on */
+ RegWr32(REG_BMCtl, RegRd32(REG_BMCtl) | BMCtl_TxEn); /*enable Tx DMA */
+
+ /*enable int again */
+ RegWr32(REG_GIntMsk, RegRd32(REG_GIntMsk) | GIntMsk_IntEn); /*turn on master INT control */
+
+ return 0;
+} /*eth_restartTx() */
+
+/*****************************************************************************
+* eth_reset()
+*****************************************************************************/
+static int eth_reset(struct net_device *pD)
+{
+ int err;
+
+ _PRTK_ENTRY(("eth_reset(pD:0x%p)\n", pD));
+
+ RegWr8(REG_SelfCTL, SelfCTL_RESET); /*soft reset command */
+ err = waitOnReg32(pD, REG_SelfCTL, SelfCTL_RESET, ~SelfCTL_RESET, 1);
+ if (err)
+ _PRTK_WARN(("eth_reset(): Soft Reset does not self-clear\n"));
+
+ /*if */
+ /*reset PHY */
+ /*phy_reset(pD); */
+
+ return 0;
+} /*eth_reset() */
+
+/*****************************************************************************
+ . Function: eth_shutDown()
+ . Purpose: closes down the Ethernet module
+ . Make sure to:
+ . 1. disable all interrupt mask
+ . 2. disable Rx
+ . 3. disable Tx
+ .
+ . TODO:
+ . (1) maybe utilize power down mode.
+ . Why not yet? Because while the chip will go into power down mode,
+ . the manual says that it will wake up in response to any I/O requests
+ . in the register space. Empirical results do not show this working.
+*
+*****************************************************************************/
+static int eth_shutDown(struct net_device *pD)
+{
+
+ _PRTK_ENTRY(("eth_shutDown(pD:0x%p)\n", pD));
+
+ eth_reset(pD);
+ /*@ power down the Ethernet module */
+
+ return 0;
+} /*eth_shutDown() */
+
+/*****************************************************************************
+* eth_enable()
+
+ Purpose:
+ Turn on device interrupt for interrupt driven operation.
+ Also turn on Rx but no Tx.
+*
+*****************************************************************************/
+static int eth_enable(struct net_device *pD)
+{
+
+ _PRTK_ENTRY(("eth_enable(pD:0x%p)\n", pD));
+
+ RegWr32(REG_IntEn, Default_IntSrc); /*setup Interrupt sources */
+ RegWr32(REG_GIntMsk, GIntMsk_IntEn); /*turn on INT */
+ eth_rxCtl(pD, 1); /*turn on Rx */
+
+ return 0;
+} /*eth_enable() */
+
+/*****************************************************************************
+* eth_init()
+
+ Purpose:
+ Reset and initialize the device.
+ Device should be initialized enough to function in polling mode.
+ Tx and Rx must be disabled and no INT generation.
+*
+*****************************************************************************/
+static int eth_init(struct net_device *pD)
+{
+ int status;
+
+ _PRTK_ENTRY(("eth_init(pD:0x%p)\n", pD));
+
+ /*reset device */
+ eth_reset(pD);
+
+ /*init PHY */
+ gPhyAutoNegoDone = 0;
+ status = phy_init(pD);
+ if (status != 0) {
+ printk(KERN_WARNING "%s: No network cable detected!\n",
+ pD->name);
+ }
+
+ /*init MAC */
+ RegWr32(REG_SelfCTL, 0x0f00); /*Set MDC clock to be divided by 8
+ and enable PreambleSuppress bit */
+ RegWr32(REG_GIntMsk, 0x00); /*mask Interrupt */
+ RegWr32(REG_RxCTL, RxCTL_BA | RxCTL_IA0); /*no Rx on at this point */
+ RegWr32(REG_TxCTL, 0x00);
+ RegWr32(REG_GT, 0x00);
+ RegWr32(REG_BMCtl, 0x00);
+ RegWr32(REG_RxBTH, (0x80 << 16) | (0x40 << 0)); /*Buffer Threshold */
+ RegWr32(REG_TxBTH, (0x80 << 16) | (0x40 << 0));
+ RegWr32(REG_RxSTH, (4 << 16) | (2 << 0)); /*Status Threshold */
+ RegWr32(REG_TxSTH, (4 << 16) | (2 << 0));
+ RegWr32(REG_RxDTH, (4 << 16) | (2 << 0)); /*Descriptor Threshold */
+ RegWr32(REG_TxDTH, (4 << 16) | (2 << 0));
+ RegWr32(REG_MaxFL, ((1518 + 1) << 16) | (944 << 0)); /*Max Frame Length & Tx Start Threshold */
+
+ RegRd32(REG_TxCollCnt); /*clear Tx Collision Counter */
+ RegRd32(REG_RxMissCnt); /*clear Rx Miss Counter */
+ RegRd32(REG_RxRntCnt); /*clear Rx Runt Counter */
+
+ RegRd32(REG_IntStsC); /*clear Pending INT */
+
+ RegWr32(REG_TxCTL, TxCTL_STxON | RegRd32(REG_TxCTL)); /*Tx on */
+
+ /*Set MAC address */
+ eth_indAddrWr(pD, AFP_AFP_IA0, &pD->dev_addr[0]);
+
+ /*init queue */
+ devQue_start(pD);
+
+ return 0;
+} /*eth_init() */
+
+/*****************************************************************************
+* driver_init()
+*
+* Purpose:
+* Logical driver initialization for an individual device
+* Minimum device H/W access at this point
+*
+* Task:
+* Initialize the structure if needed
+* print out my vanity message if not done so already
+* print out what type of hardware is detected
+* print out the ethernet address
+* find the IRQ
+* set up my private data
+* configure the dev structure with my subroutines
+* actually GRAB the irq.
+* GRAB the region
+*
+*****************************************************************************/
+static int __init driver_init(struct net_device *pD, u32 baseA, int irq)
+{
+ struct ep93xxEth_info *pP;
+ int err = 0;
+ int i;
+ struct resource *res;
+
+ _PRTK_ENTRY(("driver_init(pD:0x%p,baseA:0x%x,irq:%d)\n", pD,
+ (unsigned int)baseA, irq));
+
+ /*print out driver version */
+ if (0 == numOfInstance)
+ printk("ep93xx_eth() version: %s", version);
+
+ /*allocate the private structure */
+ if (0 == pD->priv) {
+ pD->priv = kmalloc(sizeof(struct ep93xxEth_info), GFP_KERNEL);
+ if (0 == pD->priv) {
+ _PRTK_SYSFAIL((cardname
+ " initDriver(): fail to allocate pD->priv\n"));
+ return -ENOMEM;
+ } /*if */
+ } /*if */
+ memset(pD->priv, 0x00, sizeof(struct ep93xxEth_info)); /*init to 0 */
+
+ /*privite info */
+ pP = netdev_priv(pD);
+ pP->s.id = numOfInstance; /*device instance ID */
+ pP->s.miiIdPhy = 1; /*MII Bus ID of PHY device */
+
+ /*device access info */
+ pD->base_addr = baseA; /*base address */
+ pD->irq = irq; /*IRQ number */
+
+ /*Grab the region so that no one else tries to probe this device */
+ res = request_region(baseA, DEV_REG_SPACE, cardname);
+ if (res == NULL) {
+ _PRTK_SYSFAIL((cardname
+ " initDriver(): unable to get region 0x%x-0x%x\n",
+ (int)baseA, (int)(baseA + DEV_REG_SPACE - 1)));
+ return -EAGAIN;
+ }
+
+ /*if */
+ /*Grab the IRQ (support no auto-probing) */
+ _PRTK_INFO(("initDriver(): grabbing IRQ %d\n", pD->irq));
+ err = request_irq(pD->irq, &ep93xxEth_isr, 0, cardname, pD);
+ if (err) {
+ _PRTK_SYSFAIL((cardname
+ " initDriver(): unable to get IRQ %d (err=%d)\n",
+ pD->irq, err));
+ return -EAGAIN;
+ }
+
+ /*if */
+ /*init device handler functions */
+ pD->open = &ep93xxEth_open;
+ pD->stop = &ep93xxEth_close;
+ pD->hard_start_xmit = &ep93xxEth_hardStartXmit;
+ pD->tx_timeout = &ep93xxEth_txTimeout;
+ pD->watchdog_timeo = /*@ HZ/2 */ HZ * 5;
+ pD->get_stats = &ep93xxEth_getStats;
+ pD->set_multicast_list = &ep93xxEth_setMulticastList;
+
+ /*Fill in the fields of the device structure with ethernet values */
+ ether_setup(pD);
+
+ /*init device descriptor/status queues */
+ devQue_init(pD);
+ /*reset the device, and put it into a known state */
+ eth_reset(pD);
+
+ /*print out the device info */
+ PRINTK((cardname " #%d at 0x%x IRQ:%d MAC", pP->s.id,
+ (int)pD->base_addr, pD->irq));
+ for (i = 0; i < 6; i++)
+ PRINTK((":%02x", pD->dev_addr[i]));
+ PRINTK(("\n"));
+
+ numOfInstance++; /*inc Number Of Instance under this device driver */
+
+ return 0;
+} /*driver_init() */
+
+/*****************************************************************************
+* eth_isrRx()
+*
+* Interrupt Service Routines
+*
+*****************************************************************************/
+static int eth_isrRx(struct net_device *pD)
+{
+ struct ep93xxEth_info *pP = netdev_priv(pD);
+ union receiveStatus *pQRxSts;
+ int idxQRxStsHead; /*index of Rx Status Queue Head from device (next put point) */
+ int idxSts;
+ int cntStsProcessed, cntDescProcessed;
+ char *pDest;
+ struct sk_buff *pSkb;
+ int len;
+ unsigned int dt;
+
+ _PRTK_ENTRY_ISR(("eth_isrRx(pD:0x%x)\n", (unsigned int)pD));
+
+ /*get Current Rx Status Queue pointer */
+ dt = RegRd32(REG_RxSCA);
+ idxQRxStsHead = (dt - pP->s.phyQueRxSts) / sizeof(pP->s.pQueRxSts[0]); /*convert to array index */
+ _PRTK_INFO_ISR(("eth_isrRx(): RxSCA:0x%x -> idx:%d\n", dt,
+ idxQRxStsHead));
+ if (!(0 <= idxQRxStsHead && idxQRxStsHead < LEN_QueRxSts)) {
+ _PRTK_HWFAIL(("eth_isrRx(): invalid REG_RxSCA:0x%x idx:%d (phyQueRxSts:0x%x Len:%x)\n", dt, idxQRxStsHead, (int)pP->s.phyQueRxSts, LEN_QueRxSts));
+ /*@ do recover */
+ return -1;
+ }
+
+ /*if */
+ /*process Rx (limit to idxQRxStsHead due to cache) */
+ cntStsProcessed = cntDescProcessed = 0;
+ while (idxQRxStsHead != pP->d.idxQueRxSts) {
+ idxSts = pP->d.idxQueRxSts;
+ pP->d.idxQueRxSts = IdxNext(pP->d.idxQueRxSts, LEN_QueRxSts);
+ pQRxSts = &pP->s.pQueRxSts[idxSts];
+ _PRTK_INFO_ISR(("eth_isrRx(): QRxSts[%d]:0x%x 0x%x\n", idxSts,
+ (unsigned int)pQRxSts->w.e0,
+ (unsigned int)pQRxSts->w.e1));
+ if (!pQRxSts->f.rfp) { /*empty? */
+ _PRTK_HWFAIL(("eth_isrRx(): QueRxSts[%d] is empty; Hd:%d\n", idxSts, idxQRxStsHead));
+ /*@ do recover */
+ return -1;
+ } /*if */
+ pQRxSts->f.rfp = 0; /*mark processed */
+
+ if (pQRxSts->f.eob) { /*buffer has data */
+ if (pQRxSts->f.bi == pP->d.idxQueRxDesc) { /*check BI */
+ pP->d.idxQueRxDesc = IdxNext(pP->d.idxQueRxDesc, LEN_QueRxDesc); /*inc Desc index */
+ cntDescProcessed++;
+ if (pQRxSts->f.eof && pQRxSts->f.rwe) { /*received a frame without error */
+ len = pQRxSts->f.fl;
+ _PRTK_INFO_ISR(("eth_isrRx(): Rx Len:%d\n", len));
+ pSkb = dev_alloc_skb(len + 5); /*alloc buffer for protocal stack */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -