📄 at91_ether.c
字号:
{ AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; write_phy(regs, phy_id, location, value);}#if 0/* * ethtool support. */static int at91ether_ethtool_ioctl (struct net_device *dev, void *useraddr){ struct at91_private *lp = (struct at91_private *) dev->priv; AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr; unsigned long ethcmd; int res = 0; if (copy_from_user (ðcmd, useraddr, sizeof (ethcmd))) return -EFAULT; spin_lock_irq(&lp->lock); enable_mdi(regs); switch (ethcmd) { case ETHTOOL_GSET: { struct ethtool_cmd ecmd = { ETHTOOL_GSET }; res = mii_ethtool_gset(&lp->mii, &ecmd); if (lp->phy_media == PORT_FIBRE) { /* override media type since mii.c doesn't know */ ecmd.supported = SUPPORTED_FIBRE; ecmd.port = PORT_FIBRE; } if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) res = -EFAULT; break; } case ETHTOOL_SSET: { struct ethtool_cmd ecmd; if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) res = -EFAULT; else res = mii_ethtool_sset(&lp->mii, &ecmd); break; } case ETHTOOL_NWAY_RST: { res = mii_nway_restart(&lp->mii); break; } case ETHTOOL_GLINK: { struct ethtool_value edata = { ETHTOOL_GLINK }; edata.data = mii_link_ok(&lp->mii); if (copy_to_user(useraddr, &edata, sizeof(edata))) res = -EFAULT; break; } default: 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 = 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. */static 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); } }/* * 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 */ /* The TCOM bit is set even if the transmission failed. */ if (intstatus & (AT91C_EMAC_TUND | AT91C_EMAC_RTRY)) lp->stats.tx_errors += 1; if ((!dev->bPolling) && (!dev->bTxHandler)) { dev->bTxHandler = TRUE; netJobAdd((FUNCPTR)at91EthTxHandler, (int)dev, 0, 0, 0, 0); } /*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; } if (intstatus & AT91C_EMAC_ROVR) printk("%s: ROVR error\n", dev->name);}/* * Initialize the ethernet interface */static int at91ether_setup(struct net_device *dev, unsigned long phy_type){ 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();*/ 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -