mv643xx_eth.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,225 行 · 第 1/5 页

C
2,225
字号
/* * drivers/net/mv64340_eth.c - Driver for MV64340X ethernet ports * Copyright (C) 2002 Matthew Dharm <mdharm@momenco.com> * * Based on the 64360 driver from: * Copyright (C) 2002 rabeeh@galileo.co.il * * Copyright (C) 2003 PMC-Sierra, Inc., *	written by Manish Lachwani (lachwani@pmc-sierra.com) * * Copyright (C) 2003 Ralf Baechle <ralf@linux-mips.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */#include <linux/config.h>#include <linux/version.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/config.h>#include <linux/sched.h>#include <linux/ptrace.h>#include <linux/fcntl.h>#include <linux/ioport.h>#include <linux/interrupt.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/errno.h>#include <linux/ip.h>#include <linux/init.h>#include <linux/in.h>#include <linux/pci.h>#include <linux/workqueue.h>#include <asm/smp.h>#include <linux/skbuff.h>#include <linux/tcp.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <net/ip.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/types.h>#include <asm/pgtable.h>#include <asm/system.h>#include "mv643xx_eth.h"/* * The first part is the high level driver of the gigE ethernet ports.  *//* Definition for configuring driver */#undef MV64340_RX_QUEUE_FILL_ON_TASK/* Constants */#define EXTRA_BYTES 32#define WRAP       ETH_HLEN + 2 + 4 + 16#define BUFFER_MTU dev->mtu + WRAP#define INT_CAUSE_UNMASK_ALL		0x0007ffff#define INT_CAUSE_UNMASK_ALL_EXT	0x0011ffff#ifdef MV64340_RX_FILL_ON_TASK#define INT_CAUSE_MASK_ALL		0x00000000#define INT_CAUSE_CHECK_BITS		INT_CAUSE_UNMASK_ALL#define INT_CAUSE_CHECK_BITS_EXT	INT_CAUSE_UNMASK_ALL_EXT#endif/* Static function declarations */static int mv64340_eth_real_open(struct net_device *);static int mv64340_eth_real_stop(struct net_device *);static int mv64340_eth_change_mtu(struct net_device *, int);static struct net_device_stats *mv64340_eth_get_stats(struct net_device *);static void eth_port_init_mac_tables(unsigned int eth_port_num);#ifdef MV64340_NAPIstatic int mv64340_poll(struct net_device *dev, int *budget);#endifunsigned char prom_mac_addr_base[6];unsigned long mv64340_sram_base;/* * Changes MTU (maximum transfer unit) of the gigabit ethenret port * * Input : pointer to ethernet interface network device structure *         new mtu size  * Output : 0 upon success, -EINVAL upon failure */static int mv64340_eth_change_mtu(struct net_device *dev, int new_mtu){	struct mv64340_private *mp = netdev_priv(dev);	unsigned long flags;	spin_lock_irqsave(&mp->lock, flags);	if ((new_mtu > 9500) || (new_mtu < 64)) {		spin_unlock_irqrestore(&mp->lock, flags);		return -EINVAL;	}	dev->mtu = new_mtu;	/* 	 * Stop then re-open the interface. This will allocate RX skb's with	 * the new MTU.	 * There is a possible danger that the open will not successed, due	 * to memory is full, which might fail the open function.	 */	if (netif_running(dev)) {		if (mv64340_eth_real_stop(dev))			printk(KERN_ERR			       "%s: Fatal error on stopping device\n",			       dev->name);		if (mv64340_eth_real_open(dev))			printk(KERN_ERR			       "%s: Fatal error on opening device\n",			       dev->name);	}	spin_unlock_irqrestore(&mp->lock, flags);	return 0;}/* * mv64340_eth_rx_task *								        * Fills / refills RX queue on a certain gigabit ethernet port * * Input : pointer to ethernet interface network device structure * Output : N/A */static void mv64340_eth_rx_task(void *data){	struct net_device *dev = (struct net_device *) data;	struct mv64340_private *mp = netdev_priv(dev);	struct pkt_info pkt_info;	struct sk_buff *skb;	if (test_and_set_bit(0, &mp->rx_task_busy))		panic("%s: Error in test_set_bit / clear_bit", dev->name);	while (mp->rx_ring_skbs < (mp->rx_ring_size - 5)) {		/* The +8 for buffer allignment and another 32 byte extra */		skb = dev_alloc_skb(BUFFER_MTU + 8 + EXTRA_BYTES);		if (!skb)			/* Better luck next time */			break;		mp->rx_ring_skbs++;		pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT;		pkt_info.byte_cnt = dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES;		/* Allign buffer to 8 bytes */		if (pkt_info.byte_cnt & ~0x7) {			pkt_info.byte_cnt &= ~0x7;			pkt_info.byte_cnt += 8;		}		pkt_info.buf_ptr =		    pci_map_single(0, skb->data,				   dev->mtu + ETH_HLEN + 4 + 2 + EXTRA_BYTES,				   PCI_DMA_FROMDEVICE);		pkt_info.return_info = skb;		if (eth_rx_return_buff(mp, &pkt_info) != ETH_OK) {			printk(KERN_ERR			       "%s: Error allocating RX Ring\n", dev->name);			break;		}		skb_reserve(skb, 2);	}	clear_bit(0, &mp->rx_task_busy);	/*	 * If RX ring is empty of SKB, set a timer to try allocating	 * again in a later time .	 */	if ((mp->rx_ring_skbs == 0) && (mp->rx_timer_flag == 0)) {		printk(KERN_INFO "%s: Rx ring is empty\n", dev->name);		/* After 100mSec */		mp->timeout.expires = jiffies + (HZ / 10);		add_timer(&mp->timeout);		mp->rx_timer_flag = 1;	}#if MV64340_RX_QUEUE_FILL_ON_TASK	else {		/* Return interrupts */		MV_WRITE(MV64340_ETH_INTERRUPT_MASK_REG(mp->port_num),			 INT_CAUSE_UNMASK_ALL);	}#endif}/* * mv64340_eth_rx_task_timer_wrapper *								        * Timer routine to wake up RX queue filling task. This function is * used only in case the RX queue is empty, and all alloc_skb has * failed (due to out of memory event). * * Input : pointer to ethernet interface network device structure * Output : N/A */static void mv64340_eth_rx_task_timer_wrapper(unsigned long data){	struct net_device *dev = (struct net_device *) data;	struct mv64340_private *mp = netdev_priv(dev);	mp->rx_timer_flag = 0;	mv64340_eth_rx_task((void *) data);}/* * mv64340_eth_update_mac_address *								        * Update the MAC address of the port in the address table * * Input : pointer to ethernet interface network device structure * Output : N/A */static void mv64340_eth_update_mac_address(struct net_device *dev){	struct mv64340_private *mp = netdev_priv(dev);	unsigned int port_num = mp->port_num;	eth_port_init_mac_tables(port_num);	memcpy(mp->port_mac_addr, dev->dev_addr, 6);	eth_port_uc_addr_set(port_num, mp->port_mac_addr);}/* * mv64340_eth_set_rx_mode *								        * Change from promiscuos to regular rx mode * * Input : pointer to ethernet interface network device structure * Output : N/A */static void mv64340_eth_set_rx_mode(struct net_device *dev){	struct mv64340_private *mp = netdev_priv(dev);	if (dev->flags & IFF_PROMISC) {		ethernet_set_config_reg		    (mp->port_num,		     ethernet_get_config_reg(mp->port_num) |		     ETH_UNICAST_PROMISCUOUS_MODE);	} else {		ethernet_set_config_reg		    (mp->port_num,		     ethernet_get_config_reg(mp->port_num) &		     ~(unsigned int) ETH_UNICAST_PROMISCUOUS_MODE);	}}/* * mv64340_eth_set_mac_address *								        * Change the interface's mac address. * No special hardware thing should be done because interface is always * put in promiscuous mode. * * Input : pointer to ethernet interface network device structure and *         a pointer to the designated entry to be added to the cache. * Output : zero upon success, negative upon failure */static int mv64340_eth_set_mac_address(struct net_device *dev, void *addr){	int i;	for (i = 0; i < 6; i++)		/* +2 is for the offset of the HW addr type */		dev->dev_addr[i] = ((unsigned char *) addr)[i + 2];	mv64340_eth_update_mac_address(dev);	return 0;}/* * mv64340_eth_tx_timeout *								        * Called upon a timeout on transmitting a packet * * Input : pointer to ethernet interface network device structure. * Output : N/A */static void mv64340_eth_tx_timeout(struct net_device *dev){	struct mv64340_private *mp = netdev_priv(dev);	printk(KERN_INFO "%s: TX timeout  ", dev->name);	/* Do the reset outside of interrupt context */	schedule_work(&mp->tx_timeout_task);}/* * mv64340_eth_tx_timeout_task * * Actual routine to reset the adapter when a timeout on Tx has occurred */static void mv64340_eth_tx_timeout_task(struct net_device *dev){        struct mv64340_private *mp = netdev_priv(dev);        netif_device_detach(dev);        eth_port_reset(mp->port_num);        eth_port_start(mp);        netif_device_attach(dev);}/* * mv64340_eth_free_tx_queue * * Input : dev - a pointer to the required interface * * Output : 0 if was able to release skb , nonzero otherwise */static int mv64340_eth_free_tx_queue(struct net_device *dev,			      unsigned int eth_int_cause_ext){	struct mv64340_private *mp = netdev_priv(dev);	struct net_device_stats *stats = &mp->stats;	struct pkt_info pkt_info;	int released = 1;	if (!(eth_int_cause_ext & (BIT0 | BIT8)))		return released;	spin_lock(&mp->lock);	/* Check only queue 0 */	while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) {		if (pkt_info.cmd_sts & BIT0) {			printk("%s: Error in TX\n", dev->name);			stats->tx_errors++;		}		/* 		 * If return_info is different than 0, release the skb.		 * The case where return_info is not 0 is only in case		 * when transmitted a scatter/gather packet, where only		 * last skb releases the whole chain.		 */		if (pkt_info.return_info) {			dev_kfree_skb_irq((struct sk_buff *)					  pkt_info.return_info);			released = 0;			if (skb_shinfo(pkt_info.return_info)->nr_frags)				pci_unmap_page(NULL, pkt_info.buf_ptr,					pkt_info.byte_cnt, PCI_DMA_TODEVICE);			if (mp->tx_ring_skbs != 1)				mp->tx_ring_skbs--;		} else 			pci_unmap_page(NULL, pkt_info.buf_ptr,					pkt_info.byte_cnt, PCI_DMA_TODEVICE);		/* 		 * Decrement the number of outstanding skbs counter on		 * the TX queue.		 */		if (mp->tx_ring_skbs == 0)			panic("ERROR - TX outstanding SKBs counter is corrupted");	}	spin_unlock(&mp->lock);	return released;}/* * mv64340_eth_receive * * This function is forward packets that are received from the port's * queues toward kernel core or FastRoute them to another interface. * * Input : dev - a pointer to the required interface *         max - maximum number to receive (0 means unlimted) * * Output : number of served packets */#ifdef MV64340_NAPIstatic int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max,								int budget)#elsestatic int mv64340_eth_receive_queue(struct net_device *dev, unsigned int max)#endif{	struct mv64340_private *mp = netdev_priv(dev);	struct net_device_stats *stats = &mp->stats;	unsigned int received_packets = 0;	struct sk_buff *skb;	struct pkt_info pkt_info;#ifdef MV64340_NAPI	while (eth_port_receive(mp, &pkt_info) == ETH_OK && budget > 0) {#else	while ((--max) && eth_port_receive(mp, &pkt_info) == ETH_OK) {#endif		mp->rx_ring_skbs--;		received_packets++;#ifdef MV64340_NAPI		budget--;#endif		/* Update statistics. Note byte count includes 4 byte CRC count */		stats->rx_packets++;		stats->rx_bytes += pkt_info.byte_cnt;		skb = (struct sk_buff *) pkt_info.return_info;		/*		 * In case received a packet without first / last bits on OR		 * the error summary bit is on, the packets needs to be dropeed.		 */		if (((pkt_info.cmd_sts		      & (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) !=		     (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC))		    || (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)) {			stats->rx_dropped++;			if ((pkt_info.cmd_sts & (ETH_RX_FIRST_DESC |						 ETH_RX_LAST_DESC)) !=			    (ETH_RX_FIRST_DESC | ETH_RX_LAST_DESC)) {				if (net_ratelimit())					printk(KERN_ERR					       "%s: Received packet spread on multiple"					       " descriptors\n",					       dev->name);			}			if (pkt_info.cmd_sts & ETH_ERROR_SUMMARY)				stats->rx_errors++;			dev_kfree_skb_irq(skb);		} else {			/*			 * The -4 is for the CRC in the trailer of the			 * received packet			 */			skb_put(skb, pkt_info.byte_cnt - 4);			skb->dev = dev;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?