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

📄 smc91x.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * smc91x.c * This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices. * * Copyright (C) 1996 by Erik Stahlman * Copyright (C) 2001 Standard Microsystems Corporation *	Developed by Simple Network Magic Corporation * Copyright (C) 2003 Monta Vista Software, Inc. *	Unified SMC91x driver by Nicolas Pitre * * 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 * * Arguments: * 	io	= for the base address *	irq	= for the IRQ *	nowait	= 0 for normal wait states, 1 eliminates additional wait states * * original author: * 	Erik Stahlman <erik@vt.edu> * * hardware multicast code: *    Peter Cammaert <pc@denkart.be> * * contributors: * 	Daris A Nevil <dnevil@snmc.com> *      Nicolas Pitre <nico@cam.org> *	Russell King <rmk@arm.linux.org.uk> * * History: *   08/20/00  Arnaldo Melo       fix kfree(skb) in smc_hardware_send_packet *   12/15/00  Christian Jullien  fix "Warning: kfree_skb on hard IRQ" *   03/16/01  Daris A Nevil      modified smc9194.c for use with LAN91C111 *   08/22/01  Scott Anderson     merge changes from smc9194 to smc91111 *   08/21/01  Pramod B Bhardwaj  added support for RevB of LAN91C111 *   12/20/01  Jeff Sutherland    initial port to Xscale PXA with DMA support *   04/07/03  Nicolas Pitre      unified SMC91x driver, killed irq races, *                                more bus abstraction, big cleanup, etc. *   29/09/03  Russell King       - add driver model support *                                - ethtool support *                                - convert to use generic MII interface *                                - add link up/down notification *                                - don't try to handle full negotiation in *                                  smc_phy_configure *                                - clean up (and fix stack overrun) in PHY *                                  MII read/write functions *   22/09/04  Nicolas Pitre      big update (see commit log for details) */static const char version[] =	"smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre <nico@cam.org>\n";/* Debugging level */#ifndef SMC_DEBUG#define SMC_DEBUG		0#endif#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/crc32.h>#include <linux/platform_device.h>#include <linux/spinlock.h>#include <linux/ethtool.h>#include <linux/mii.h>#include <linux/workqueue.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <asm/io.h>#include "smc91x.h"#ifdef CONFIG_ISA/* * the LAN91C111 can be at any of the following port addresses.  To change, * for a slightly different card, you can add it to the array.  Keep in * mind that the array must end in zero. */static unsigned int smc_portlist[] __initdata = {	0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,	0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0};#ifndef SMC_IOADDR# define SMC_IOADDR		-1#endifstatic unsigned long io = SMC_IOADDR;module_param(io, ulong, 0400);MODULE_PARM_DESC(io, "I/O base address");#ifndef SMC_IRQ# define SMC_IRQ		-1#endifstatic int irq = SMC_IRQ;module_param(irq, int, 0400);MODULE_PARM_DESC(irq, "IRQ number");#endif  /* CONFIG_ISA */#ifndef SMC_NOWAIT# define SMC_NOWAIT		0#endifstatic int nowait = SMC_NOWAIT;module_param(nowait, int, 0400);MODULE_PARM_DESC(nowait, "set to 1 for no wait state");/* * Transmit timeout, default 5 seconds. */static int watchdog = 1000;module_param(watchdog, int, 0400);MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");MODULE_LICENSE("GPL");/* * The internal workings of the driver.  If you are changing anything * here with the SMC stuff, you should have the datasheet and know * what you are doing. */#define CARDNAME "smc91x"/* * Use power-down feature of the chip */#define POWER_DOWN		1/* * Wait time for memory to be free.  This probably shouldn't be * tuned that much, as waiting for this means nothing else happens * in the system */#define MEMORY_WAIT_TIME	16/* * The maximum number of processing loops allowed for each call to the * IRQ handler. */#define MAX_IRQ_LOOPS		8/* * This selects whether TX packets are sent one by one to the SMC91x internal * memory and throttled until transmission completes.  This may prevent * RX overruns a litle by keeping much of the memory free for RX packets * but to the expense of reduced TX throughput and increased IRQ overhead. * Note this is not a cure for a too slow data bus or too high IRQ latency. */#define THROTTLE_TX_PKTS	0/* * The MII clock high/low times.  2x this number gives the MII clock period * in microseconds. (was 50, but this gives 6.4ms for each MII transaction!) */#define MII_DELAY		1#if SMC_DEBUG > 0#define DBG(n, args...)					\	do {						\		if (SMC_DEBUG >= (n))			\			printk(args);	\	} while (0)#define PRINTK(args...)   printk(args)#else#define DBG(n, args...)   do { } while(0)#define PRINTK(args...)   printk(KERN_DEBUG args)#endif#if SMC_DEBUG > 3static void PRINT_PKT(u_char *buf, int length){	int i;	int remainder;	int lines;	lines = length / 16;	remainder = length % 16;	for (i = 0; i < lines ; i ++) {		int cur;		for (cur = 0; cur < 8; cur++) {			u_char a, b;			a = *buf++;			b = *buf++;			printk("%02x%02x ", a, b);		}		printk("\n");	}	for (i = 0; i < remainder/2 ; i++) {		u_char a, b;		a = *buf++;		b = *buf++;		printk("%02x%02x ", a, b);	}	printk("\n");}#else#define PRINT_PKT(x...)  do { } while(0)#endif/* this enables an interrupt in the interrupt mask register */#define SMC_ENABLE_INT(x) do {						\	unsigned char mask;						\	spin_lock_irq(&lp->lock);					\	mask = SMC_GET_INT_MASK();					\	mask |= (x);							\	SMC_SET_INT_MASK(mask);						\	spin_unlock_irq(&lp->lock);					\} while (0)/* this disables an interrupt from the interrupt mask register */#define SMC_DISABLE_INT(x) do {						\	unsigned char mask;						\	spin_lock_irq(&lp->lock);					\	mask = SMC_GET_INT_MASK();					\	mask &= ~(x);							\	SMC_SET_INT_MASK(mask);						\	spin_unlock_irq(&lp->lock);					\} while (0)/* * Wait while MMU is busy.  This is usually in the order of a few nanosecs * if at all, but let's avoid deadlocking the system if the hardware * decides to go south. */#define SMC_WAIT_MMU_BUSY() do {					\	if (unlikely(SMC_GET_MMU_CMD() & MC_BUSY)) {			\		unsigned long timeout = jiffies + 2;			\		while (SMC_GET_MMU_CMD() & MC_BUSY) {			\			if (time_after(jiffies, timeout)) {		\				printk("%s: timeout %s line %d\n",	\					dev->name, __FILE__, __LINE__);	\				break;					\			}						\			cpu_relax();					\		}							\	}								\} while (0)/* * this does a soft reset on the device */static void smc_reset(struct net_device *dev){	struct smc_local *lp = netdev_priv(dev);	void __iomem *ioaddr = lp->base;	unsigned int ctl, cfg;	struct sk_buff *pending_skb;	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);	/* Disable all interrupts, block TX tasklet */	spin_lock_irq(&lp->lock);	SMC_SELECT_BANK(2);	SMC_SET_INT_MASK(0);	pending_skb = lp->pending_tx_skb;	lp->pending_tx_skb = NULL;	spin_unlock_irq(&lp->lock);	/* free any pending tx skb */	if (pending_skb) {		dev_kfree_skb(pending_skb);		dev->stats.tx_errors++;		dev->stats.tx_aborted_errors++;	}	/*	 * This resets the registers mostly to defaults, but doesn't	 * affect EEPROM.  That seems unnecessary	 */	SMC_SELECT_BANK(0);	SMC_SET_RCR(RCR_SOFTRST);	/*	 * Setup the Configuration Register	 * This is necessary because the CONFIG_REG is not affected	 * by a soft reset	 */	SMC_SELECT_BANK(1);	cfg = CONFIG_DEFAULT;	/*	 * Setup for fast accesses if requested.  If the card/system	 * can't handle it then there will be no recovery except for	 * a hard reset or power cycle	 */	if (nowait)		cfg |= CONFIG_NO_WAIT;	/*	 * Release from possible power-down state	 * Configuration register is not affected by Soft Reset	 */	cfg |= CONFIG_EPH_POWER_EN;	SMC_SET_CONFIG(cfg);	/* this should pause enough for the chip to be happy */	/*	 * elaborate?  What does the chip _need_? --jgarzik	 *	 * This seems to be undocumented, but something the original	 * driver(s) have always done.  Suspect undocumented timing	 * info/determined empirically. --rmk	 */	udelay(1);	/* Disable transmit and receive functionality */	SMC_SELECT_BANK(0);	SMC_SET_RCR(RCR_CLEAR);	SMC_SET_TCR(TCR_CLEAR);	SMC_SELECT_BANK(1);	ctl = SMC_GET_CTL() | CTL_LE_ENABLE;	/*	 * Set the control register to automatically release successfully	 * transmitted packets, to make the best use out of our limited	 * memory	 */	if(!THROTTLE_TX_PKTS)		ctl |= CTL_AUTO_RELEASE;	else		ctl &= ~CTL_AUTO_RELEASE;	SMC_SET_CTL(ctl);	/* Reset the MMU */	SMC_SELECT_BANK(2);	SMC_SET_MMU_CMD(MC_RESET);	SMC_WAIT_MMU_BUSY();}/* * Enable Interrupts, Receive, and Transmit */static void smc_enable(struct net_device *dev){	struct smc_local *lp = netdev_priv(dev);	void __iomem *ioaddr = lp->base;	int mask;	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);	/* see the header file for options in TCR/RCR DEFAULT */	SMC_SELECT_BANK(0);	SMC_SET_TCR(lp->tcr_cur_mode);	SMC_SET_RCR(lp->rcr_cur_mode);	SMC_SELECT_BANK(1);	SMC_SET_MAC_ADDR(dev->dev_addr);	/* now, enable interrupts */	mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT;	if (lp->version >= (CHIP_91100 << 4))		mask |= IM_MDINT;	SMC_SELECT_BANK(2);	SMC_SET_INT_MASK(mask);	/*	 * From this point the register bank must _NOT_ be switched away	 * to something else than bank 2 without proper locking against	 * races with any tasklet or interrupt handlers until smc_shutdown()	 * or smc_reset() is called.	 */}/* * this puts the device in an inactive state */static void smc_shutdown(struct net_device *dev){	struct smc_local *lp = netdev_priv(dev);	void __iomem *ioaddr = lp->base;	struct sk_buff *pending_skb;	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);	/* no more interrupts for me */	spin_lock_irq(&lp->lock);	SMC_SELECT_BANK(2);	SMC_SET_INT_MASK(0);	pending_skb = lp->pending_tx_skb;	lp->pending_tx_skb = NULL;	spin_unlock_irq(&lp->lock);	if (pending_skb)		dev_kfree_skb(pending_skb);	/* and tell the card to stay away from that nasty outside world */	SMC_SELECT_BANK(0);	SMC_SET_RCR(RCR_CLEAR);	SMC_SET_TCR(TCR_CLEAR);#ifdef POWER_DOWN	/* finally, shut the chip down */	SMC_SELECT_BANK(1);	SMC_SET_CONFIG(SMC_GET_CONFIG() & ~CONFIG_EPH_POWER_EN);#endif}/* * This is the procedure to handle the receipt of a packet. */static inline void  smc_rcv(struct net_device *dev){	struct smc_local *lp = netdev_priv(dev);	void __iomem *ioaddr = lp->base;	unsigned int packet_number, status, packet_len;	DBG(3, "%s: %s\n", dev->name, __FUNCTION__);	packet_number = SMC_GET_RXFIFO();	if (unlikely(packet_number & RXFIFO_REMPTY)) {		PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name);		return;	}	/* read from start of packet */	SMC_SET_PTR(PTR_READ | PTR_RCV | PTR_AUTOINC);	/* First two words are status and packet length */	SMC_GET_PKT_HDR(status, packet_len);	packet_len &= 0x07ff;  /* mask off top bits */	DBG(2, "%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n",		dev->name, packet_number, status,		packet_len, packet_len);	back:	if (unlikely(packet_len < 6 || status & RS_ERRORS)) {		if (status & RS_TOOLONG && packet_len <= (1514 + 4 + 6)) {			/* accept VLAN packets */			status &= ~RS_TOOLONG;			goto back;		}		if (packet_len < 6) {			/* bloody hardware */			printk(KERN_ERR "%s: fubar (rxlen %u status %x\n",					dev->name, packet_len, status);			status |= RS_TOOSHORT;		}		SMC_WAIT_MMU_BUSY();		SMC_SET_MMU_CMD(MC_RELEASE);		dev->stats.rx_errors++;		if (status & RS_ALGNERR)			dev->stats.rx_frame_errors++;		if (status & (RS_TOOSHORT | RS_TOOLONG))			dev->stats.rx_length_errors++;		if (status & RS_BADCRC)			dev->stats.rx_crc_errors++;	} else {		struct sk_buff *skb;		unsigned char *data;		unsigned int data_len;		/* set multicast stats */		if (status & RS_MULTICAST)			dev->stats.multicast++;		/*		 * Actual payload is packet_len - 6 (or 5 if odd byte).		 * We want skb_reserve(2) and the final ctrl word		 * (2 bytes, possibly containing the payload odd byte).		 * Furthermore, we add 2 bytes to allow rounding up to		 * multiple of 4 bytes on 32 bit buses.		 * Hence packet_len - 6 + 2 + 2 + 2.		 */		skb = dev_alloc_skb(packet_len);		if (unlikely(skb == NULL)) {			printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",				dev->name);			SMC_WAIT_MMU_BUSY();			SMC_SET_MMU_CMD(MC_RELEASE);			dev->stats.rx_dropped++;			return;		}		/* Align IP header to 32 bits */		skb_reserve(skb, 2);		/* BUG: the LAN91C111 rev A never sets this bit. Force it. */		if (lp->version == 0x90)			status |= RS_ODDFRAME;		/*		 * If odd length: packet_len - 5,		 * otherwise packet_len - 6.		 * With the trailing ctrl byte it's packet_len - 4.		 */		data_len = packet_len - ((status & RS_ODDFRAME) ? 5 : 6);		data = skb_put(skb, data_len);		SMC_PULL_DATA(data, packet_len - 4);		SMC_WAIT_MMU_BUSY();		SMC_SET_MMU_CMD(MC_RELEASE);		PRINT_PKT(data, packet_len - 4);		dev->last_rx = jiffies;		skb->protocol = eth_type_trans(skb, dev);		netif_rx(skb);		dev->stats.rx_packets++;		dev->stats.rx_bytes += data_len;	}}#ifdef CONFIG_SMP/* * On SMP we have the following problem: * * 	A = smc_hardware_send_pkt() * 	B = smc_hard_start_xmit() * 	C = smc_interrupt() * * A and B can never be executed simultaneously.  However, at least on UP, * it is possible (and even desirable) for C to interrupt execution of * A or B in order to have better RX reliability and avoid overruns. * C, just like A and B, must have exclusive access to the chip and * each of them must lock against any other concurrent access. * Unfortunately this is not possible to have C suspend execution of A or * B taking place on another CPU. On UP this is no an issue since A and B * are run from softirq context and C from hard IRQ context, and there is * no other CPU where concurrent access can happen. * If ever there is a way to force at least B and C to always be executed * on the same CPU then we could use read/write locks to protect against * any other concurrent access and C would always interrupt B. But life * isn't that easy in a SMP world... */#define smc_special_trylock(lock)					\({									\	int __ret;							\	local_irq_disable();						\	__ret = spin_trylock(lock);					\	if (!__ret)							\		local_irq_enable();					\	__ret;								\})#define smc_special_lock(lock)		spin_lock_irq(lock)#define smc_special_unlock(lock)	spin_unlock_irq(lock)#else#define smc_special_trylock(lock)	(1)#define smc_special_lock(lock)		do { } while (0)#define smc_special_unlock(lock)	do { } while (0)#endif/* * This is called to actually send a packet to the chip. */static void smc_hardware_send_pkt(unsigned long data){	struct net_device *dev = (struct net_device *)data;	struct smc_local *lp = netdev_priv(dev);	void __iomem *ioaddr = lp->base;	struct sk_buff *skb;	unsigned int packet_no, len;

⌨️ 快捷键说明

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