📄 at91_ether.c
字号:
res = -EOPNOTSUPP; } disable_mdi(regs); spin_unlock_irq(&lp->lock); return res;}/* * User-space ioctl interface. */static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ switch(cmd) { case SIOCETHTOOL: return at91ether_ethtool_ioctl(dev, (void *) rq->ifr_data); default: return -EOPNOTSUPP; }}#endif/* ................................ MAC ................................ *//* * Initialize and start the Receiver and Transmit subsystems */ static void at91ether_start(struct net_device *dev){ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; struct at91_private *lp = (struct at91_private *) dev->priv; int i; struct recv_desc_bufs *dlist, *dlist_phys;/* char *pNewCluster;*/ dlist = lp->dlist; dlist_phys = lp->dlist_phys; for (i = 0; i < MAX_RX_DESCR; i++) {/* dlist->descriptors[i].addr = (unsigned int) &dlist_phys->recv_buf[i][0];*/ /* pNewCluster = netClusterGet (dev->endObj.pNetPool, dev->endObj.pNetPool->clTbl[0]); if (pNewCluster == NULL) { dev->lastError.errCode = END_ERR_NO_BUF; muxError(&dev->endObj, &dev->lastError); return ; } pNewCluster = END_CACHE_VIRT_TO_PHYS(pNewCluster); dlist->descriptors[i].addr = pNewCluster;*/ dlist->descriptors[i].addr = (unsigned int)dlist->recv_buf[i]; dlist->descriptors[i].size = 0; } /* Set the Wrap bit on the last descriptor */ dlist->descriptors[i-1].addr |= EMAC_DESC_WRAP; /* Reset buffer index */ lp->rxBuffIndex = 0; /* Program address of descriptor list in Rx Buffer Queue register */ regs->EMAC_RBQP = (AT91_REG) dlist_phys; /* Enable Receive and Transmit */ regs->EMAC_CTL |= (AT91C_EMAC_RE | AT91C_EMAC_TE); intEnable(AT91C_ID_PIOC); intEnable(dev->irq);}/* * Open the ethernet interface */static int at91ether_open(struct net_device *dev){/* struct at91_private *lp = (struct at91_private *) dev->priv;*/ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; if (!is_valid_ether_addr(dev->dev_addr)) return -EADDRNOTAVAIL; AT91_SYS->PMC_PCER = 1 << AT91C_ID_EMAC; /* Re-enable Peripheral clock */ regs->EMAC_CTL |= AT91C_EMAC_CSR; /* Clear internal statistics */ /* Update the MAC address (incase user has changed it) */ update_mac_address(dev); /* Enable PHY interrupt */ enable_phyirq(dev, regs); /* Enable MAC interrupts */ regs->EMAC_IER = AT91C_EMAC_RCOM | AT91C_EMAC_RBNA | AT91C_EMAC_TUND | AT91C_EMAC_RTRY | AT91C_EMAC_TCOM | AT91C_EMAC_ROVR | AT91C_EMAC_HRESP; /* Determine current link speed */ spin_lock_irq(&lp->lock); enable_mdi(regs); (void) update_linkspeed(dev, regs); disable_mdi(regs); spin_unlock_irq(&lp->lock); at91ether_start(dev);/* netif_start_queue(dev);*/ return 0;}/* * Close the interface */static int at91ether_close(struct net_device *dev){ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; /* Disable Receiver and Transmitter */ regs->EMAC_CTL &= ~(AT91C_EMAC_TE | AT91C_EMAC_RE); /* Disable PHY interrupt */ disable_phyirq(dev, regs); /* Disable MAC interrupts */ regs->EMAC_IDR = AT91C_EMAC_RCOM | AT91C_EMAC_RBNA | AT91C_EMAC_TUND | AT91C_EMAC_RTRY | AT91C_EMAC_TCOM | AT91C_EMAC_ROVR | AT91C_EMAC_HRESP; /*netif_stop_queue(dev);*/ AT91_SYS->PMC_PCDR = 1 << AT91C_ID_EMAC; /* Disable Peripheral clock */ return 0;}#if 0/* * Transmit packet. */static int at91ether_tx(struct sk_buff *skb, struct net_device *dev){ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; struct at91_private *lp = (struct at91_private *) dev->priv; if (regs->EMAC_TSR & AT91C_EMAC_BNQ) { /*netif_stop_queue(dev);*/ /* Store packet information (to free when Tx completed) */ lp->skb = skb; lp->skb_length = skb->len; lp->skb_physaddr = pci_map_single(NULL, skb->data, skb->len, PCI_DMA_TODEVICE); lp->stats.tx_bytes += skb->len; /* Set address of the data in the Transmit Address register */ regs->EMAC_TAR = lp->skb_physaddr; /* Set length of the packet in the Transmit Control register */ regs->EMAC_TCR = skb->len; dev->trans_start = jiffies; } else { printk(KERN_ERR "at91_ether.c: at91ether_tx() called, but device is busy!\n"); return 1; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb) on this skb, he also reports -ENETDOWN and printk's, so either we free and return(0) or don't free and return 1 */ } return 0;}#endif/* * Update the current statistics from the internal statistics registers. */struct net_device_stats *at91ether_stats(struct net_device *dev){ struct at91_private *lp = (struct at91_private *) dev->priv; AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; int ale, lenerr, seqe, lcol, ecol; /*if (netif_running(dev)) */{ lp->stats.rx_packets += regs->EMAC_OK; /* Good frames received */ ale = regs->EMAC_ALE; lp->stats.rx_frame_errors += ale; /* Alignment errors */ lenerr = regs->EMAC_ELR + regs->EMAC_USF; lp->stats.rx_length_errors += lenerr; /* Excessive Length or Undersize Frame error */ seqe = regs->EMAC_SEQE; lp->stats.rx_crc_errors += seqe; /* CRC error */ lp->stats.rx_fifo_errors += regs->EMAC_DRFC; /* Receive buffer not available */ lp->stats.rx_errors += (ale + lenerr + seqe + regs->EMAC_CDE + regs->EMAC_RJB); lp->stats.tx_packets += regs->EMAC_FRA; /* Frames successfully transmitted */ lp->stats.tx_fifo_errors += regs->EMAC_TUE; /* Transmit FIFO underruns */ lp->stats.tx_carrier_errors += regs->EMAC_CSE; /* Carrier Sense errors */ lp->stats.tx_heartbeat_errors += regs->EMAC_SQEE; /* Heartbeat error */ lcol = regs->EMAC_LCOL; ecol = regs->EMAC_ECOL; lp->stats.tx_window_errors += lcol; /* Late collisions */ lp->stats.tx_aborted_errors += ecol; /* 16 collisions */ lp->stats.collisions += (regs->EMAC_SCOL + regs->EMAC_MCOL + lcol + ecol); } return &lp->stats;}/* * Extract received frame from buffer descriptors and sent to upper layers. * (Called from interrupt context) */static void at91ether_rx(struct net_device *dev){/* struct at91_private *lp = (struct at91_private *) dev->priv;*//* struct recv_desc_bufs *dlist;*//* unsigned char *p_recv;*//* struct sk_buff *skb;*//* unsigned int pktlen;*/ AT91PS_EMAC emac = (AT91PS_EMAC) dev->base_addr; if (emac->EMAC_RSR & AT91C_EMAC_REC) emac->EMAC_RSR |= AT91C_EMAC_REC; if(( !dev->bPolling) && (!dev->bRxHandler)) { dev->bRxHandler = TRUE; netJobAdd((FUNCPTR)at91EthRxHandler, (int)dev, 0, 0, 0, 0); }#ifdef DEBUG_END_TRACE else logMsg("\n#",0,0,0,0,0,0);#endif}/* * MAC interrupt handler */static void at91ether_interrupt(ETH_DRV_CTRL *dev ){ struct at91_private *lp = (struct at91_private *) dev->priv; AT91PS_EMAC emac = (AT91PS_EMAC) dev->base_addr; unsigned long intstatus; /* MAC Interrupt Status register indicates what interrupts are pending. It is automatically cleared once read. */ intstatus = emac->EMAC_ISR; if (intstatus & AT91C_EMAC_RCOM) /* Receive complete */ at91ether_rx(dev); if (intstatus & AT91C_EMAC_TCOM)/* Transmit complete */ { /*dev->bTxHandler = FALSE;*/ /* The TCOM bit is set even if the transmission failed. */ if (intstatus & (AT91C_EMAC_TUND | AT91C_EMAC_RTRY)) { lp->stats.tx_errors += 1;#ifdef DEBUG_END_TRACE logMsg("\nETH%d TX FAIL",dev->unit,0,0,0,0,0);#endif } emac->EMAC_TSR |= AT91C_EMAC_COMP; dev->TxBuffLastIndex = ((dev->TxBuffLastIndex) < (MAX_TX_DESCR - 1))?((dev->TxBuffLastIndex) + 1):(0);/*DEBUG_END_TRACE*/#ifdef DEBUG_END_TRACE logMsg("\nTxBuffLastIndex:%d",dev->TxBuffLastIndex,0,0,0,0,0);#endif#if 0 if ((!dev->bPolling) && (!dev->bTxHandler)) { dev->bTxHandler = TRUE; netJobAdd((FUNCPTR)at91EthTxHandler, (int)dev, 0, 0, 0, 0); } else { #if 0 logMsg("&",0,0,0,0,0,0); #else logMsg("\nETH%d polling or TxHandler\n",dev->unit,0,0,0,0,0); #endif }#endif /*dev_kfree_skb_irq(lp->skb);*/ /*pci_unmap_single(NULL, lp->skb_physaddr, lp->skb_length, PCI_DMA_TODEVICE);*/ /*netif_wake_queue(dev);*/ } /* Work-around for Errata #11 */ if (intstatus & AT91C_EMAC_RBNA) { emac->EMAC_CTL &= ~AT91C_EMAC_RE; emac->EMAC_CTL |= AT91C_EMAC_RE;#ifdef DEBUG_END_TRACE logMsg("\nETH%d RBNA\n",dev->unit,0,0,0,0,0);#endif } if (intstatus & AT91C_EMAC_ROVR) {#ifdef DEBUG_END_TRACE /*printk("%s: ROVR error\n", dev->name);*/ logMsg("\nETH%d ROVR\n",dev->unit,0,0,0,0,0);#endif } /* Restart Tx if it was blocked. */ if (dev->bTxBlocked) { netJobAdd((FUNCPTR)at91EthTxRestart, (int)dev, 0, 0, 0, 0);/*DEBUG_END_TRACE*/ }}static int at91EthTxRestart(ETH_DRV_CTRL *dev){ UINT8 i = 0; logMsg("eth%d Restart Tx\n", dev->unit,0,0,0,0,0); END_TX_SEM_TAKE(&dev->endObj, WAIT_FOREVER); /*at91EthTbdFree(dev,gpBuf);*/ for(i = 0;i < MAX_TX_DESCR;i++) { if(dev->pTxBuffAddr[i] != NULL) { cacheDmaFree(dev->pTxBuffAddr[i]); } } END_TX_SEM_GIVE(&dev->endObj); muxTxRestart(&dev->endObj); dev->bTxBlocked = FALSE; return OK;}/* * Initialize the ethernet interface */static int at91ether_setup(struct net_device *dev, unsigned long phy_type){ UINT8 i = 0; AT91PS_EMAC regs; static int already_initialized = 0; struct at91_private *lp = &at91_mac_private; unsigned int val; unsigned long addr; if (already_initialized) return 0;/* dev = init_etherdev(dev, sizeof(struct at91_private));*/ dev->base_addr = AT91C_VA_BASE_EMAC; dev->irq = AT91C_ID_EMAC; /* Install the interrupt handler */ if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) return -EBUSY; memset(lp, 0, sizeof(struct at91_private)); dev->priv = lp; /* Allocate memory for DMA Receive descriptors */ addr = (unsigned long) cacheDmaMalloc(sizeof(struct recv_desc_bufs)+0x100); if(addr&0xFF) addr=(addr&0xffffff00)+0x100; lp->dlist = (struct recv_desc_bufs *) addr; lp->dlist_phys = lp->dlist ; /* cacheDrvVirtToPhys();*/ for(i = 0;i < MAX_TX_DESCR;i++)/*DEBUG_END_TRACE*/ { dev->pTxBuffAddr[i] = cacheDmaMalloc(MAX_TBUFF_SZ);#ifdef DEBUG_END_TRACE printf("\ndev->pTxBuffAddr[%d]:0x%x",i,(unsigned int)dev->pTxBuffAddr[i]);#endif } dev->TxBuffIndex = 0; dev->TxBuffLastIndex = 0; spin_lock_init(&lp->lock);/* ether_setup(dev); dev->open = at91ether_open; dev->stop = at91ether_close; dev->hard_start_xmit = at91ether_tx; dev->get_stats = at91ether_stats; dev->set_multicast_list = at91ether_set_rx_mode; dev->do_ioctl = at91ether_ioctl; dev->set_mac_address = set_mac_address;*/ get_mac_address(dev); /* Get ethernet address and store it in dev->dev_addr */ update_mac_address(dev); /* Program ethernet address into MAC */ regs = (AT91PS_EMAC) dev->base_addr; regs->EMAC_CTL = 0;#ifdef CONFIG_AT91_ETHER_RMII regs->EMAC_CFG = AT91C_EMAC_BIG | AT91C_EMAC_RMII;#else regs->EMAC_CFG = AT91C_EMAC_BIG;#endif if (phy_type == MII_LXT971A_ID) regs->EMAC_CFG |= AT91C_EMAC_CLK_HCLK_64; /* MDIO clock = system clock/64 */ if (phy_type == MII_DM9161_ID) { spin_lock_irq(&lp->lock); enable_mdi(regs); read_phy(regs, 0, MII_DSCR_REG, &val); if ((val & (1 << 10)) == 0) /* DSCR bit 10 is 0 -- fiber mode */ lp->phy_media = PORT_FIBRE; disable_mdi(regs); spin_unlock_irq(&lp->lock); } if (phy_type == MII_RTL8201BL_ID) regs->EMAC_CFG |= AT91C_EMAC_CLK_HCLK_64; /* MDIO clock = system clock/64 */ /* lp->mii.dev = dev; lp->mii.mdio_read = mdio_read; lp->mii.mdio_write = mdio_write; */ lp->phy_type = phy_type; /* Type of PHY connected */ /* Determine current link speed */ spin_lock_irq(&lp->lock); enable_mdi(regs); (void) update_linkspeed(dev, regs); disable_mdi(regs); spin_unlock_irq(&lp->lock); if (phy_type == MII_DM9161_ID) printk(KERN_INFO "%s: Davicom 9196 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)"); else if (phy_type == MII_LXT971A_ID) printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name); if (phy_type == MII_RTL8201BL_ID) printk(KERN_INFO "%s: Realtek 8201BL PHY\n", dev->name); already_initialized = 1; return 0;}/* * Detect MAC and PHY and perform initialization */static int at91ether_probe(struct net_device *dev){ AT91PS_EMAC regs = (AT91PS_EMAC) AT91C_VA_BASE_EMAC; unsigned int phyid1, phyid2; int detected = -1; /* Configure the hardware - RMII vs MII mode */#ifdef CONFIG_AT91_ETHER_RMII AT91_CfgPIO_EMAC_RMII();#else AT91_CfgPIO_EMAC_MII();#endif AT91_CfgPIO_EMAC_PHY(); /* Configure PHY interrupt */ AT91_SYS->PMC_PCER = 1 << AT91C_ID_EMAC; /* Enable Peripheral clock */ /* Read the PHY ID registers */ enable_mdi(regs); read_phy(regs, 0, MII_PHYSID1, &phyid1); read_phy(regs, 0, MII_PHYSID2, &phyid2); disable_mdi(regs); /* Davicom 9161: PHY_ID1 = 0x181 PHY_ID2 = B881 */ if (((phyid1 << 16) | (phyid2 & 0xfff0)) == MII_DM9161_ID) { detected = at91ether_setup(dev, MII_DM9161_ID); } /* Intel LXT971A: PHY_ID1 = 0x13 PHY_ID2 = 78E0 */ else if (((phyid1 << 16) | (phyid2 & 0xfff0)) == MII_LXT971A_ID) { detected = at91ether_setup(dev, MII_LXT971A_ID); }else if (((phyid1 << 16) | (phyid2 & 0xffff)) == MII_RTL8201BL_ID) { detected = at91ether_setup(dev, MII_RTL8201BL_ID); } AT91_SYS->PMC_PCDR = 1 << AT91C_ID_EMAC; /* Disable Peripheral clock */ return detected;}/* * Test MAC and PHY */int at91ether_get_phy_id(void){ AT91PS_EMAC regs = (AT91PS_EMAC) AT91C_VA_BASE_EMAC; unsigned int phyid1, phyid2; int detected = -1;#if 0 /* Configure the hardware - RMII vs MII mode */#ifdef CONFIG_AT91_ETHER_RMII AT91_CfgPIO_EMAC_RMII();#else AT91_CfgPIO_EMAC_MII();#endif AT91_CfgPIO_EMAC_PHY(); /* Configure PHY interrupt */ AT91_SYS->PMC_PCER = 1 << AT91C_ID_EMAC; /* Enable Peripheral clock */#endif /* Read the PHY ID registers */ enable_mdi(regs); read_phy(regs, 0, MII_PHYSID1, &phyid1); read_phy(regs, 0, MII_PHYSID2, &phyid2); disable_mdi(regs); if ((((phyid1 << 16) | (phyid2 & 0xfff0)) == MII_DM9161_ID) || (((phyid1 << 16) | (phyid2 & 0xfff0)) == MII_LXT971A_ID) || (((phyid1 << 16) | (phyid2 & 0xffff)) == MII_RTL8201BL_ID)) { detected = 0; }#if 0/*this will cause to die when app call at91ether_get_phy_id(). wurj*/ AT91_SYS->PMC_PCDR = 1 << AT91C_ID_EMAC; /* Disable Peripheral clock */#endif return detected;} int at91ether_test(void)/*static --> extern wurj*/{ int test_result = 0; /* read the phy id */ if (test_result == 0) { printf("Check PHY chip id..."); if (at91ether_get_phy_id() == 0) { printf("OK.\r\n\n"); } else { test_result = -1; printf("FAIL.\r\n\n"); } } return test_result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -