📄 smc9194.c
字号:
/*------------------------------------------------------------------------ . smc9194.c . This is a driver for SMC's 9000 series of Ethernet cards. . . Copyright (C) 1996 by Erik Stahlman . This software may be used and distributed according to the terms . of the GNU General Public License, incorporated herein by reference. . . "Features" of the SMC chip: . 4608 byte packet memory. ( for the 91C92. Others have more ) . EEPROM for configuration . AUI/TP selection ( mine has 10Base2/10BaseT select ) . . Arguments: . io = for the base address . irq = for the IRQ . ifport = 0 for autodetect, 1 for TP, 2 for AUI ( or 10base2 ) . . author: . Erik Stahlman ( erik@vt.edu ) . contributors: . Arnaldo Carvalho de Melo <acme@conectiva.com.br> . . Hardware multicast code from Peter Cammaert ( pc@denkart.be ) . . Sources: . o SMC databook . o skeleton.c by Donald Becker ( becker@scyld.com ) . o ( a LOT of advice from Becker as well ) . . History: . 12/07/95 Erik Stahlman written, got receive/xmit handled . 01/03/96 Erik Stahlman worked out some bugs, actually usable!!! :-) . 01/06/96 Erik Stahlman cleaned up some, better testing, etc . 01/29/96 Erik Stahlman fixed autoirq, added multicast . 02/01/96 Erik Stahlman 1. disabled all interrupts in smc_reset . 2. got rid of post-decrementing bug -- UGH. . 02/13/96 Erik Stahlman Tried to fix autoirq failure. Added more . descriptive error messages. . 02/15/96 Erik Stahlman Fixed typo that caused detection failure . 02/23/96 Erik Stahlman Modified it to fit into kernel tree . Added support to change hardware address . Cleared stats on opens . 02/26/96 Erik Stahlman Trial support for Kernel 1.2.13 . Kludge for automatic IRQ detection . 03/04/96 Erik Stahlman Fixed kernel 1.3.70 + . Fixed bug reported by Gardner Buchanan in . smc_enable, with outw instead of outb . 03/06/96 Erik Stahlman Added hardware multicast from Peter Cammaert . 04/14/00 Heiko Pruessing (SMA Regelsysteme) Fixed bug in chip memory . allocation . 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" . 11/08/01 Matt Domsch Use common crc32 function ----------------------------------------------------------------------------*/static const char version[] = "smc9194.c:v0.14 12/15/00 by Erik Stahlman (erik@vt.edu)\n";#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/init.h>#include <linux/crc32.h>#include <linux/errno.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/bitops.h>#include <asm/io.h>#include "smc9194.h"#define DRV_NAME "smc9194"/*------------------------------------------------------------------------ . . Configuration options, for the experienced user to change. . -------------------------------------------------------------------------*//* . Do you want to use 32 bit xfers? This should work on all chips, as . the chipset is designed to accommodate them.*/#ifdef __sh__#undef USE_32_BIT#else#define USE_32_BIT 1#endif#if defined(__H8300H__) || defined(__H8300S__)#define NO_AUTOPROBE#undef insl#undef outsl#define insl(a,b,l) io_insl_noswap(a,b,l)#define outsl(a,b,l) io_outsl_noswap(a,b,l)#endif/* .the SMC9194 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.*/struct devlist { unsigned int port; unsigned int irq;};#if defined(CONFIG_H8S_EDOSK2674)static struct devlist smc_devlist[] __initdata = { {.port = 0xf80000, .irq = 16}, {.port = 0, .irq = 0 },};#elsestatic struct devlist smc_devlist[] __initdata = { {.port = 0x200, .irq = 0}, {.port = 0x220, .irq = 0}, {.port = 0x240, .irq = 0}, {.port = 0x260, .irq = 0}, {.port = 0x280, .irq = 0}, {.port = 0x2A0, .irq = 0}, {.port = 0x2C0, .irq = 0}, {.port = 0x2E0, .irq = 0}, {.port = 0x300, .irq = 0}, {.port = 0x320, .irq = 0}, {.port = 0x340, .irq = 0}, {.port = 0x360, .irq = 0}, {.port = 0x380, .irq = 0}, {.port = 0x3A0, .irq = 0}, {.port = 0x3C0, .irq = 0}, {.port = 0x3E0, .irq = 0}, {.port = 0, .irq = 0},};#endif/* . 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/* . DEBUGGING LEVELS . . 0 for normal operation . 1 for slightly more details . >2 for various levels of increasingly useless information . 2 for interrupt tracking, status flags . 3 for packet dumps, etc.*/#define SMC_DEBUG 0#if (SMC_DEBUG > 2 )#define PRINTK3(x) printk x#else#define PRINTK3(x)#endif#if SMC_DEBUG > 1#define PRINTK2(x) printk x#else#define PRINTK2(x)#endif#ifdef SMC_DEBUG#define PRINTK(x) printk x#else#define PRINTK(x)#endif/*------------------------------------------------------------------------ . . The internal workings of the driver. If you are changing anything . here with the SMC stuff, you should have the datasheet and known . what you are doing. . -------------------------------------------------------------------------*/#define CARDNAME "SMC9194"/* 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; /* . This keeps track of how many packets that I have . sent out. When an TX_EMPTY interrupt comes, I know . that all of these have been sent. */ int packets_waiting;};/*----------------------------------------------------------------- . . The driver can be entered at any of the following entry points. . .------------------------------------------------------------------ *//* . This is called by register_netdev(). It is responsible for . checking the portlist for the SMC9000 series chipset. If it finds . one, then it will initialize the device, find the hardware information, . and sets up the appropriate device parameters. . NOTE: Interrupts are *OFF* when this procedure is called. . . NB:This shouldn't be static since it is referred to externally.*/struct net_device *smc_init(int unit);/* . The kernel calls this function when someone wants to use the device, . typically 'ifconfig ethX up'.*/static int smc_open(struct net_device *dev);/* . Our watchdog timed out. Called by the networking layer*/static void smc_timeout(struct net_device *dev);/* . This is called by the kernel in response to 'ifconfig ethX down'. It . is responsible for cleaning up everything that the open routine . does, and maybe putting the card into a powerdown state.*/static int smc_close(struct net_device *dev);/* . Finally, a call to set promiscuous mode ( for TCPDUMP and related . programs ) and multicast modes.*/static void smc_set_multicast_list(struct net_device *dev);/*--------------------------------------------------------------- . . Interrupt level calls.. . ----------------------------------------------------------------*//* . Handles the actual interrupt*/static irqreturn_t smc_interrupt(int irq, void *);/* . This is a separate procedure to handle the receipt of a packet, to . leave the interrupt code looking slightly cleaner*/static inline void smc_rcv( struct net_device *dev );/* . This handles a TX interrupt, which is only called when an error . relating to a packet is sent.*/static inline void smc_tx( struct net_device * dev );/* ------------------------------------------------------------ . . Internal routines . ------------------------------------------------------------*//* . Test if a given location contains a chip, trying to cause as . little damage as possible if it's not a SMC chip.*/static int smc_probe(struct net_device *dev, int ioaddr);/* . A rather simple routine to print out a packet for debugging purposes.*/#if SMC_DEBUG > 2static void print_packet( byte *, int );#endif#define tx_done(dev) 1/* this is called to actually send the packet to the chip */static void smc_hardware_send_packet( struct net_device * dev );/* Since I am not sure if I will have enough room in the chip's ram . to store the packet, I call this routine, which either sends it . now, or generates an interrupt when the card is ready for the . packet */static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev );/* this does a soft reset on the device */static void smc_reset( int ioaddr );/* Enable Interrupts, Receive, and Transmit */static void smc_enable( int ioaddr );/* this puts the device in an inactive state */static void smc_shutdown( int ioaddr );/* This routine will find the IRQ of the driver if one is not . specified in the input to the device. */static int smc_findirq( int ioaddr );/* . Function: smc_reset( int ioaddr ) . Purpose: . This sets the SMC91xx chip to its normal state, hopefully from whatever . mess that any other DOS driver has put it in. . . Maybe I should reset more registers to defaults in here? SOFTRESET should . do that for me. . . Method: . 1. send a SOFT RESET . 2. wait for it to finish . 3. enable autorelease mode . 4. reset the memory management unit . 5. clear all interrupts .*/static void smc_reset( int ioaddr ){ /* This resets the registers mostly to defaults, but doesn't affect EEPROM. That seems unnecessary */ SMC_SELECT_BANK( 0 ); outw( RCR_SOFTRESET, ioaddr + RCR ); /* this should pause enough for the chip to be happy */ SMC_DELAY( ); /* Set the transmit and receive configuration registers to default values */ outw( RCR_CLEAR, ioaddr + RCR ); outw( TCR_CLEAR, ioaddr + TCR ); /* set the control register to automatically release successfully transmitted packets, to make the best use out of our limited memory */ SMC_SELECT_BANK( 1 ); outw( inw( ioaddr + CONTROL ) | CTL_AUTO_RELEASE , ioaddr + CONTROL ); /* Reset the MMU */ SMC_SELECT_BANK( 2 ); outw( MC_RESET, ioaddr + MMU_CMD ); /* Note: It doesn't seem that waiting for the MMU busy is needed here, but this is a place where future chipsets _COULD_ break. Be wary of issuing another MMU command right after this */ outb( 0, ioaddr + INT_MASK );}/* . Function: smc_enable . Purpose: let the chip talk to the outside work . Method: . 1. Enable the transmitter . 2. Enable the receiver . 3. Enable interrupts*/static void smc_enable( int ioaddr ){ SMC_SELECT_BANK( 0 ); /* see the header file for options in TCR/RCR NORMAL*/ outw( TCR_NORMAL, ioaddr + TCR ); outw( RCR_NORMAL, ioaddr + RCR ); /* now, enable interrupts */ SMC_SELECT_BANK( 2 ); outb( SMC_INTERRUPT_MASK, ioaddr + INT_MASK );}/* . Function: smc_shutdown . Purpose: closes down the SMC91xxx chip. . Method: . 1. zero the interrupt mask . 2. clear the enable receive flag . 3. clear the enable xmit flags . . TODO: . (1) maybe utilize power down mode. . Why not yet? Because while the chip will go into power down mode, . the manual says that it will wake up in response to any I/O requests . in the register space. Empirical results do not show this working.*/static void smc_shutdown( int ioaddr ){ /* no more interrupts for me */ SMC_SELECT_BANK( 2 ); outb( 0, ioaddr + INT_MASK ); /* and tell the card to stay away from that nasty outside world */ SMC_SELECT_BANK( 0 ); outb( RCR_CLEAR, ioaddr + RCR ); outb( TCR_CLEAR, ioaddr + TCR );#if 0 /* finally, shut the chip down */ SMC_SELECT_BANK( 1 ); outw( inw( ioaddr + CONTROL ), CTL_POWERDOWN, ioaddr + CONTROL );#endif}/* . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds ) . Purpose: . This sets the internal hardware table to filter out unwanted multicast . packets before they take up memory. . . The SMC chip uses a hash table where the high 6 bits of the CRC of . address are the offset into the table. If that bit is 1, then the . multicast packet is accepted. Otherwise, it's dropped silently. . . To use the 6 bits as an offset into the table, the high 3 bits are the . number of the 8 bit register, while the low 3 bits are the bit within . that register. . . This routine is based very heavily on the one provided by Peter Cammaert.*/static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) { int i; unsigned char multicast_table[ 8 ]; struct dev_mc_list * cur_addr; /* table for flipping the order of 3 bits */ unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; /* start with a table of all zeros: reject all */ memset( multicast_table, 0, sizeof( multicast_table ) ); cur_addr = addrs; for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) { int position; /* do we have a pointer here? */ if ( !cur_addr ) break; /* make sure this is a multicast address - shouldn't this be a given if we have it here ? */ if ( !( *cur_addr->dmi_addr & 1 ) ) continue; /* only use the low order bits */ position = ether_crc_le(6, cur_addr->dmi_addr) & 0x3f; /* do some messy swapping to put the bit in the right spot */ multicast_table[invert3[position&7]] |= (1<<invert3[(position>>3)&7]); } /* now, the table can be loaded into the chipset */ SMC_SELECT_BANK( 3 ); for ( i = 0; i < 8 ; i++ ) { outb( multicast_table[i], ioaddr + MULTICAST1 + i ); }}/* . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * ) . Purpose: . Attempt to allocate memory for a packet, if chip-memory is not . available, then tell the card to generate an interrupt when it . is available. . . Algorithm: . . o if the saved_skb is not currently null, then drop this packet . on the floor. This should never happen, because of TBUSY. . o if the saved_skb is null, then replace it with the current packet, . o See if I can sending it now. . o (NO): Enable interrupts and let the interrupt handler deal with it. . o (YES):Send it now.*/static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ){ struct smc_local *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; word length; unsigned short numPages; word time_out; netif_stop_queue(dev); /* Well, I want to send the packet.. but I don't know if I can send it right now... */ if ( lp->saved_skb) { /* THIS SHOULD NEVER HAPPEN. */ dev->stats.tx_aborted_errors++; printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); return 1; } lp->saved_skb = skb; length = skb->len; if (length < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) { netif_wake_queue(dev); return 0; } length = ETH_ZLEN; } /* ** The MMU wants the number of pages to be the number of 256 bytes ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) ** ** Pkt size for allocating is data length +6 (for additional status words, ** length and ctl!) If odd size last byte is included in this header. */ numPages = ((length & 0xfffe) + 6) / 256; if (numPages > 7 ) { printk(CARDNAME": Far too big packet error. \n"); /* freeing the packet is a good thing here... but should . any packets of this size get down here? */ dev_kfree_skb (skb);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -