⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at91_ether.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 2 页
字号:
	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 + -