📄 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 * 09/15/04 Hayato Fujiwara - Add m32r support. * - Modify for SMP kernel; Change spin-locked * regions. */static const char version[] = "smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre <nico@cam.org>\n";/* Debugging level */#ifndef SMC_DEBUG#define SMC_DEBUG 0#endif#include <linux/config.h>#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/timer.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/crc32.h>#include <linux/device.h>#include <linux/spinlock.h>#include <linux/ethtool.h>#include <linux/mii.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <asm/io.h>#include <asm/mach-types.h>#include <asm/irq.h>#if defined(CONFIG_ARCH_OMAP)#include <asm/arch/gpio.h> #include <asm/arch/fpga.h>#include <asm/arch/mux.h>#endif#if defined(CONFIG_ARCH_OMAP24XX)#include <asm/arch/gpio.h>#endif#include "smc91x.h"#if defined(CONFIG_MACH_OMAP_H4)void h4reset (void){ #define LAN_RESET_REGISTER (H4_DEBUG_FPGA_VA_BASE+0x1c) int cnt = 20; __raw_writew(0x0, LAN_RESET_REGISTER); do { __raw_writew(0x1, LAN_RESET_REGISTER); udelay (100); if(cnt == 0) goto h4reset_err_out; --cnt; } while (__raw_readw(LAN_RESET_REGISTER) != 0x1); cnt = 20; do { __raw_writew(0x0, LAN_RESET_REGISTER); udelay (100); if(cnt == 0) goto h4reset_err_out; --cnt; } while (__raw_readw(LAN_RESET_REGISTER) != 0x0000); udelay (400);h4reset_err_out: return;}#endif#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 = 5000;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/* * 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/* store this information for the driver.. */struct smc_local { /* * If I have to wait until memory is available to send a * packet, I will store the skbuff here, until I get the * desired memory. Then, I'll send it out and free it. */ struct sk_buff *saved_skb; /* * these are things that the kernel wants me to keep, so users * can find out semi-useless statistics of how well the card is * performing */ struct net_device_stats stats; /* version/revision of the SMC91x chip */ int version; /* Contains the current active transmission mode */ int tcr_cur_mode; /* Contains the current active receive mode */ int rcr_cur_mode; /* Contains the current active receive/phy mode */ int rpc_cur_mode; int ctl_rfduplx; int ctl_rspeed; u32 msg_enable; u32 phy_type; struct mii_if_info mii; spinlock_t lock;#ifdef SMC_USE_PXA_DMA /* DMA needs the physical address of the chip */ u_long physaddr;#endif};#if SMC_DEBUG > 0#define DBG(n, args...) \ do { \ if (SMC_DEBUG >= (n)) \ printk(KERN_DEBUG 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; \ mask = SMC_GET_INT_MASK(); \ mask |= (x); \ SMC_SET_INT_MASK(mask); \} while (0)/* this disables an interrupt from the interrupt mask register */#define SMC_DISABLE_INT(x) do { \ unsigned char mask; \ mask = SMC_GET_INT_MASK(); \ mask &= ~(x); \ SMC_SET_INT_MASK(mask); \} 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){ unsigned long ioaddr = dev->base_addr; unsigned int ctl, cfg; DBG(2, "%s: %s\n", dev->name, __FUNCTION__); /* * 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;#endif SMC_SET_CTL(ctl); /* Disable all interrupts */ SMC_SELECT_BANK(2); SMC_SET_INT_MASK(0); /* Reset the MMU */ SMC_SET_MMU_CMD(MC_RESET); SMC_WAIT_MMU_BUSY();}/* * Enable Interrupts, Receive, and Transmit */static void smc_enable(struct net_device *dev){ unsigned long ioaddr = dev->base_addr; struct smc_local *lp = netdev_priv(dev); 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); /* 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);}/* * this puts the device in an inactive state */static void smc_shutdown(unsigned long ioaddr){ DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__); /* no more interrupts for me */ SMC_SELECT_BANK(2); SMC_SET_INT_MASK(0); /* 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); unsigned long ioaddr = dev->base_addr; 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); if (unlikely(status & RS_ERRORS)) { lp->stats.rx_errors++; if (status & RS_ALGNERR) lp->stats.rx_frame_errors++; if (status & (RS_TOOSHORT | RS_TOOLONG)) lp->stats.rx_length_errors++; if (status & RS_BADCRC) lp->stats.rx_crc_errors++; } else { struct sk_buff *skb; unsigned char *data; unsigned int data_len; /* set multicast stats */ if (status & RS_MULTICAST) lp->stats.multicast++; /* * Actual payload is packet_len - 4 (or 3 if odd byte). * We want skb_reserve(2) and the final ctrl word * (2 bytes, possibly containing the payload odd byte). * Ence packet_len - 4 + 2 + 2. */ skb = dev_alloc_skb(packet_len); if (unlikely(skb == NULL)) { printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", dev->name); lp->stats.rx_dropped++; goto done; } /* 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 - 3, * otherwise packet_len - 4. */ data_len = packet_len - ((status & RS_ODDFRAME) ? 3 : 4); data = skb_put(skb, data_len); SMC_PULL_DATA(data, packet_len - 2); PRINT_PKT(data, packet_len - 2); dev->last_rx = jiffies; skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); lp->stats.rx_packets++; lp->stats.rx_bytes += data_len; }done: SMC_WAIT_MMU_BUSY(); SMC_SET_MMU_CMD(MC_RELEASE);}/* * This is called to actually send a packet to the chip. * Returns non-zero when successful. */static void smc_hardware_send_packet(struct net_device *dev){ struct smc_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; struct sk_buff *skb = lp->saved_skb; unsigned int packet_no, len; unsigned char *buf; DBG(3, "%s: %s\n", dev->name, __FUNCTION__); packet_no = SMC_GET_AR(); if (unlikely(packet_no & AR_FAILED)) { printk("%s: Memory allocation failed.\n", dev->name); lp->saved_skb = NULL; lp->stats.tx_errors++; lp->stats.tx_fifo_errors++; if (!skb){ dev_kfree_skb_any(skb); } else { printk (KERN_ERR "Trying to free NULL skb\n"); } return; } /* point to the beginning of the packet */ SMC_SET_PN(packet_no); SMC_SET_PTR(PTR_AUTOINC);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -