📄 at91_ether.c
字号:
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; }}/* ................................ 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; 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]; 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);}/* * 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 */ /* 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;}/* * 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;}/* * 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; dlist = lp->dlist; while (dlist->descriptors[lp->rxBuffIndex].addr & EMAC_DESC_DONE) { p_recv = dlist->recv_buf[lp->rxBuffIndex]; pktlen = dlist->descriptors[lp->rxBuffIndex].size & 0x7ff; /* Length of frame including FCS */ skb = alloc_skb(pktlen + 2, GFP_ATOMIC); if (skb != NULL) { skb_reserve(skb, 2); memcpy(skb_put(skb, pktlen), p_recv, pktlen); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->len = pktlen; dev->last_rx = jiffies; lp->stats.rx_bytes += pktlen; netif_rx(skb); } else { lp->stats.rx_dropped += 1; printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); } if (dlist->descriptors[lp->rxBuffIndex].size & EMAC_MULTICAST) lp->stats.multicast++; dlist->descriptors[lp->rxBuffIndex].addr &= ~EMAC_DESC_DONE; /* reset ownership bit */ if (lp->rxBuffIndex == MAX_RX_DESCR-1) /* wrap after last buffer */ lp->rxBuffIndex = 0; else lp->rxBuffIndex++; }}/* * MAC interrupt handler */static void at91ether_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = (struct net_device *) dev_id; 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; dev_kfree_skb_irq(lp->skb); pci_unmap_single(NULL, lp->skb_physaddr, lp->skb_length, PCI_DMA_TODEVICE); netif_wake_queue(dev); } if (intstatus & AT91C_EMAC_RBNA) printk("%s: RBNA error\n", dev->name); if (intstatus & AT91C_EMAC_ROVR) printk("%s: ROVR error\n", dev->name);}/* * Initialize the ethernet interface */static int at91ether_setup(struct net_device *dev){ struct at91_private *lp; AT91PS_EMAC regs; static int already_initialized = 0; 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; SET_MODULE_OWNER(dev); /* Install the interrupt handler */ if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) return -EBUSY; /* Allocate memory for private data structure */ lp = (struct at91_private *) kmalloc(sizeof(struct at91_private), GFP_KERNEL); if (lp == NULL) { free_irq(dev->irq, dev); return -ENOMEM; } memset(lp, 0, sizeof(struct at91_private)); dev->priv = lp; /* Allocate memory for DMA Receive descriptors */ lp->dlist = (struct recv_desc_bufs *) consistent_alloc(GFP_DMA | GFP_KERNEL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys); if (lp->dlist == NULL) { kfree(dev->priv); free_irq(dev->irq, dev); return -ENOMEM; } 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;#ifdef AT91_ETHER_ADDR_CONFIGURABLE dev->set_mac_address = set_mac_address;#endif 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_RMII;#else regs->EMAC_CFG = 0;#endif lp->mii.dev = dev; /* Support for ethtool */ lp->mii.mdio_read = mdio_read; lp->mii.mdio_write = mdio_write; enable_phyirq(dev, regs); /* 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); /* Display ethernet banner */ printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n", dev->name, (uint) dev->base_addr, dev->irq, regs->EMAC_CFG & AT91C_EMAC_SPD ? "100-" : "10-", regs->EMAC_CFG & AT91C_EMAC_FD ? "FullDuplex" : "HalfDuplex", dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); already_initialized = 1; return 0;}/* * Detect MAC and PHY and perform initialization */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_SYS->PMC_PCER = 1 << AT91C_ID_EMAC; /* Enable Peripheral clock */ /* Read the PHY ID registers */ enable_mdi(regs); read_phy(regs, MII_PHYSID1, &phyid1); read_phy(regs, 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); } AT91_SYS->PMC_PCDR = 1 << AT91C_ID_EMAC; /* Disable Peripheral clock */ return detected;}static int __init at91ether_init(void){ if (!at91ether_probe(&at91_dev)) return register_netdev(&at91_dev); return -1;}static void __exit at91ether_exit(void){ unregister_netdev(&at91_dev);}module_init(at91ether_init)module_exit(at91ether_exit)MODULE_LICENSE("GPL");MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver");MODULE_AUTHOR("Andrew Victor");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -