📄 smc91x.c
字号:
/* * 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 + -