162306a36Sopenharmony_ci/* hamachi.c: A Packet Engines GNIC-II Gigabit Ethernet driver for Linux. */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci Written 1998-2000 by Donald Becker. 462306a36Sopenharmony_ci Updates 2000 by Keith Underwood. 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci This software may be used and distributed according to the terms of 762306a36Sopenharmony_ci the GNU General Public License (GPL), incorporated herein by reference. 862306a36Sopenharmony_ci Drivers based on or derived from this code fall under the GPL and must 962306a36Sopenharmony_ci retain the authorship, copyright and license notice. This file is not 1062306a36Sopenharmony_ci a complete program and may only be used when the entire operating 1162306a36Sopenharmony_ci system is licensed under the GPL. 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci The author may be reached as becker@scyld.com, or C/O 1462306a36Sopenharmony_ci Scyld Computing Corporation 1562306a36Sopenharmony_ci 410 Severn Ave., Suite 210 1662306a36Sopenharmony_ci Annapolis MD 21403 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci This driver is for the Packet Engines GNIC-II PCI Gigabit Ethernet 1962306a36Sopenharmony_ci adapter. 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci Support and updates available at 2262306a36Sopenharmony_ci http://www.scyld.com/network/hamachi.html 2362306a36Sopenharmony_ci [link no longer provides useful info -jgarzik] 2462306a36Sopenharmony_ci or 2562306a36Sopenharmony_ci http://www.parl.clemson.edu/~keithu/hamachi.html 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci*/ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define DRV_NAME "hamachi" 3062306a36Sopenharmony_ci#define DRV_VERSION "2.1" 3162306a36Sopenharmony_ci#define DRV_RELDATE "Sept 11, 2006" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* A few user-configurable values. */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ 3762306a36Sopenharmony_ci#define final_version 3862306a36Sopenharmony_ci#define hamachi_debug debug 3962306a36Sopenharmony_ci/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ 4062306a36Sopenharmony_cistatic int max_interrupt_work = 40; 4162306a36Sopenharmony_cistatic int mtu; 4262306a36Sopenharmony_ci/* Default values selected by testing on a dual processor PIII-450 */ 4362306a36Sopenharmony_ci/* These six interrupt control parameters may be set directly when loading the 4462306a36Sopenharmony_ci * module, or through the rx_params and tx_params variables 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_cistatic int max_rx_latency = 0x11; 4762306a36Sopenharmony_cistatic int max_rx_gap = 0x05; 4862306a36Sopenharmony_cistatic int min_rx_pkt = 0x18; 4962306a36Sopenharmony_cistatic int max_tx_latency = 0x00; 5062306a36Sopenharmony_cistatic int max_tx_gap = 0x00; 5162306a36Sopenharmony_cistatic int min_tx_pkt = 0x30; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* Set the copy breakpoint for the copy-only-tiny-frames scheme. 5462306a36Sopenharmony_ci -Setting to > 1518 causes all frames to be copied 5562306a36Sopenharmony_ci -Setting to 0 disables copies 5662306a36Sopenharmony_ci*/ 5762306a36Sopenharmony_cistatic int rx_copybreak; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* An override for the hardware detection of bus width. 6062306a36Sopenharmony_ci Set to 1 to force 32 bit PCI bus detection. Set to 4 to force 64 bit. 6162306a36Sopenharmony_ci Add 2 to disable parity detection. 6262306a36Sopenharmony_ci*/ 6362306a36Sopenharmony_cistatic int force32; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* Used to pass the media type, etc. 6762306a36Sopenharmony_ci These exist for driver interoperability. 6862306a36Sopenharmony_ci No media types are currently defined. 6962306a36Sopenharmony_ci - The lower 4 bits are reserved for the media type. 7062306a36Sopenharmony_ci - The next three bits may be set to one of the following: 7162306a36Sopenharmony_ci 0x00000000 : Autodetect PCI bus 7262306a36Sopenharmony_ci 0x00000010 : Force 32 bit PCI bus 7362306a36Sopenharmony_ci 0x00000020 : Disable parity detection 7462306a36Sopenharmony_ci 0x00000040 : Force 64 bit PCI bus 7562306a36Sopenharmony_ci Default is autodetect 7662306a36Sopenharmony_ci - The next bit can be used to force half-duplex. This is a bad 7762306a36Sopenharmony_ci idea since no known implementations implement half-duplex, and, 7862306a36Sopenharmony_ci in general, half-duplex for gigabit ethernet is a bad idea. 7962306a36Sopenharmony_ci 0x00000080 : Force half-duplex 8062306a36Sopenharmony_ci Default is full-duplex. 8162306a36Sopenharmony_ci - In the original driver, the ninth bit could be used to force 8262306a36Sopenharmony_ci full-duplex. Maintain that for compatibility 8362306a36Sopenharmony_ci 0x00000200 : Force full-duplex 8462306a36Sopenharmony_ci*/ 8562306a36Sopenharmony_ci#define MAX_UNITS 8 /* More are supported, limit only on options */ 8662306a36Sopenharmony_cistatic int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; 8762306a36Sopenharmony_cistatic int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; 8862306a36Sopenharmony_ci/* The Hamachi chipset supports 3 parameters each for Rx and Tx 8962306a36Sopenharmony_ci * interruput management. Parameters will be loaded as specified into 9062306a36Sopenharmony_ci * the TxIntControl and RxIntControl registers. 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * The registers are arranged as follows: 9362306a36Sopenharmony_ci * 23 - 16 15 - 8 7 - 0 9462306a36Sopenharmony_ci * _________________________________ 9562306a36Sopenharmony_ci * | min_pkt | max_gap | max_latency | 9662306a36Sopenharmony_ci * --------------------------------- 9762306a36Sopenharmony_ci * min_pkt : The minimum number of packets processed between 9862306a36Sopenharmony_ci * interrupts. 9962306a36Sopenharmony_ci * max_gap : The maximum inter-packet gap in units of 8.192 us 10062306a36Sopenharmony_ci * max_latency : The absolute time between interrupts in units of 8.192 us 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_cistatic int rx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; 10462306a36Sopenharmony_cistatic int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* Operational parameters that are set at compile time. */ 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* Keep the ring sizes a power of two for compile efficiency. 10962306a36Sopenharmony_ci The compiler will convert <unsigned>'%'<2^N> into a bit mask. 11062306a36Sopenharmony_ci Making the Tx ring too large decreases the effectiveness of channel 11162306a36Sopenharmony_ci bonding and packet priority. 11262306a36Sopenharmony_ci There are no ill effects from too-large receive rings, except for 11362306a36Sopenharmony_ci excessive memory usage */ 11462306a36Sopenharmony_ci/* Empirically it appears that the Tx ring needs to be a little bigger 11562306a36Sopenharmony_ci for these Gbit adapters or you get into an overrun condition really 11662306a36Sopenharmony_ci easily. Also, things appear to work a bit better in back-to-back 11762306a36Sopenharmony_ci configurations if the Rx ring is 8 times the size of the Tx ring 11862306a36Sopenharmony_ci*/ 11962306a36Sopenharmony_ci#define TX_RING_SIZE 64 12062306a36Sopenharmony_ci#define RX_RING_SIZE 512 12162306a36Sopenharmony_ci#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct hamachi_desc) 12262306a36Sopenharmony_ci#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct hamachi_desc) 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* 12562306a36Sopenharmony_ci * Enable netdev_ioctl. Added interrupt coalescing parameter adjustment. 12662306a36Sopenharmony_ci * 2/19/99 Pete Wyckoff <wyckoff@ca.sandia.gov> 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* play with 64-bit addrlen; seems to be a teensy bit slower --pw */ 13062306a36Sopenharmony_ci/* #define ADDRLEN 64 */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* 13362306a36Sopenharmony_ci * RX_CHECKSUM turns on card-generated receive checksum generation for 13462306a36Sopenharmony_ci * TCP and UDP packets. Otherwise the upper layers do the calculation. 13562306a36Sopenharmony_ci * 3/10/1999 Pete Wyckoff <wyckoff@ca.sandia.gov> 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ci#define RX_CHECKSUM 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* Operational parameters that usually are not changed. */ 14062306a36Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */ 14162306a36Sopenharmony_ci#define TX_TIMEOUT (5*HZ) 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci#include <linux/capability.h> 14462306a36Sopenharmony_ci#include <linux/module.h> 14562306a36Sopenharmony_ci#include <linux/kernel.h> 14662306a36Sopenharmony_ci#include <linux/string.h> 14762306a36Sopenharmony_ci#include <linux/timer.h> 14862306a36Sopenharmony_ci#include <linux/time.h> 14962306a36Sopenharmony_ci#include <linux/errno.h> 15062306a36Sopenharmony_ci#include <linux/ioport.h> 15162306a36Sopenharmony_ci#include <linux/interrupt.h> 15262306a36Sopenharmony_ci#include <linux/pci.h> 15362306a36Sopenharmony_ci#include <linux/init.h> 15462306a36Sopenharmony_ci#include <linux/ethtool.h> 15562306a36Sopenharmony_ci#include <linux/mii.h> 15662306a36Sopenharmony_ci#include <linux/netdevice.h> 15762306a36Sopenharmony_ci#include <linux/etherdevice.h> 15862306a36Sopenharmony_ci#include <linux/skbuff.h> 15962306a36Sopenharmony_ci#include <linux/ip.h> 16062306a36Sopenharmony_ci#include <linux/delay.h> 16162306a36Sopenharmony_ci#include <linux/bitops.h> 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci#include <linux/uaccess.h> 16462306a36Sopenharmony_ci#include <asm/processor.h> /* Processor type for cache alignment. */ 16562306a36Sopenharmony_ci#include <asm/io.h> 16662306a36Sopenharmony_ci#include <asm/unaligned.h> 16762306a36Sopenharmony_ci#include <asm/cache.h> 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic const char version[] = 17062306a36Sopenharmony_ciKERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n" 17162306a36Sopenharmony_ci" Some modifications by Eric kasten <kasten@nscl.msu.edu>\n" 17262306a36Sopenharmony_ci" Further modifications by Keith Underwood <keithu@parl.clemson.edu>\n"; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* IP_MF appears to be only defined in <netinet/ip.h>, however, 17662306a36Sopenharmony_ci we need it for hardware checksumming support. FYI... some of 17762306a36Sopenharmony_ci the definitions in <netinet/ip.h> conflict/duplicate those in 17862306a36Sopenharmony_ci other linux headers causing many compiler warnings. 17962306a36Sopenharmony_ci*/ 18062306a36Sopenharmony_ci#ifndef IP_MF 18162306a36Sopenharmony_ci #define IP_MF 0x2000 /* IP more frags from <netinet/ip.h> */ 18262306a36Sopenharmony_ci#endif 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* Define IP_OFFSET to be IPOPT_OFFSET */ 18562306a36Sopenharmony_ci#ifndef IP_OFFSET 18662306a36Sopenharmony_ci #ifdef IPOPT_OFFSET 18762306a36Sopenharmony_ci #define IP_OFFSET IPOPT_OFFSET 18862306a36Sopenharmony_ci #else 18962306a36Sopenharmony_ci #define IP_OFFSET 2 19062306a36Sopenharmony_ci #endif 19162306a36Sopenharmony_ci#endif 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci#define RUN_AT(x) (jiffies + (x)) 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci#ifndef ADDRLEN 19662306a36Sopenharmony_ci#define ADDRLEN 32 19762306a36Sopenharmony_ci#endif 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* Condensed bus+endian portability operations. */ 20062306a36Sopenharmony_ci#if ADDRLEN == 64 20162306a36Sopenharmony_ci#define cpu_to_leXX(addr) cpu_to_le64(addr) 20262306a36Sopenharmony_ci#define leXX_to_cpu(addr) le64_to_cpu(addr) 20362306a36Sopenharmony_ci#else 20462306a36Sopenharmony_ci#define cpu_to_leXX(addr) cpu_to_le32(addr) 20562306a36Sopenharmony_ci#define leXX_to_cpu(addr) le32_to_cpu(addr) 20662306a36Sopenharmony_ci#endif 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci/* 21062306a36Sopenharmony_ci Theory of Operation 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ciI. Board Compatibility 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ciThis device driver is designed for the Packet Engines "Hamachi" 21562306a36Sopenharmony_ciGigabit Ethernet chip. The only PCA currently supported is the GNIC-II 64-bit 21662306a36Sopenharmony_ci66Mhz PCI card. 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciII. Board-specific settings 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciNo jumpers exist on the board. The chip supports software correction of 22162306a36Sopenharmony_civarious motherboard wiring errors, however this driver does not support 22262306a36Sopenharmony_cithat feature. 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ciIII. Driver operation 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ciIIIa. Ring buffers 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ciThe Hamachi uses a typical descriptor based bus-master architecture. 22962306a36Sopenharmony_ciThe descriptor list is similar to that used by the Digital Tulip. 23062306a36Sopenharmony_ciThis driver uses two statically allocated fixed-size descriptor lists 23162306a36Sopenharmony_ciformed into rings by a branch from the final descriptor to the beginning of 23262306a36Sopenharmony_cithe list. The ring sizes are set at compile time by RX/TX_RING_SIZE. 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciThis driver uses a zero-copy receive and transmit scheme similar my other 23562306a36Sopenharmony_cinetwork drivers. 23662306a36Sopenharmony_ciThe driver allocates full frame size skbuffs for the Rx ring buffers at 23762306a36Sopenharmony_ciopen() time and passes the skb->data field to the Hamachi as receive data 23862306a36Sopenharmony_cibuffers. When an incoming frame is less than RX_COPYBREAK bytes long, 23962306a36Sopenharmony_cia fresh skbuff is allocated and the frame is copied to the new skbuff. 24062306a36Sopenharmony_ciWhen the incoming frame is larger, the skbuff is passed directly up the 24162306a36Sopenharmony_ciprotocol stack and replaced by a newly allocated skbuff. 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ciThe RX_COPYBREAK value is chosen to trade-off the memory wasted by 24462306a36Sopenharmony_ciusing a full-sized skbuff for small frames vs. the copying costs of larger 24562306a36Sopenharmony_ciframes. Gigabit cards are typically used on generously configured machines 24662306a36Sopenharmony_ciand the underfilled buffers have negligible impact compared to the benefit of 24762306a36Sopenharmony_cia single allocation size, so the default value of zero results in never 24862306a36Sopenharmony_cicopying packets. 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciIIIb/c. Transmit/Receive Structure 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ciThe Rx and Tx descriptor structure are straight-forward, with no historical 25362306a36Sopenharmony_cibaggage that must be explained. Unlike the awkward DBDMA structure, there 25462306a36Sopenharmony_ciare no unused fields or option bits that had only one allowable setting. 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ciTwo details should be noted about the descriptors: The chip supports both 32 25762306a36Sopenharmony_cibit and 64 bit address structures, and the length field is overwritten on 25862306a36Sopenharmony_cithe receive descriptors. The descriptor length is set in the control word 25962306a36Sopenharmony_cifor each channel. The development driver uses 32 bit addresses only, however 26062306a36Sopenharmony_ci64 bit addresses may be enabled for 64 bit architectures e.g. the Alpha. 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ciIIId. Synchronization 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ciThis driver is very similar to my other network drivers. 26562306a36Sopenharmony_ciThe driver runs as two independent, single-threaded flows of control. One 26662306a36Sopenharmony_ciis the send-packet routine, which enforces single-threaded use by the 26762306a36Sopenharmony_cidev->tbusy flag. The other thread is the interrupt handler, which is single 26862306a36Sopenharmony_cithreaded by the hardware and other software. 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ciThe send packet thread has partial control over the Tx ring and 'dev->tbusy' 27162306a36Sopenharmony_ciflag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next 27262306a36Sopenharmony_ciqueue slot is empty, it clears the tbusy flag when finished otherwise it sets 27362306a36Sopenharmony_cithe 'hmp->tx_full' flag. 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ciThe interrupt handler has exclusive control over the Rx ring and records stats 27662306a36Sopenharmony_cifrom the Tx ring. After reaping the stats, it marks the Tx queue entry as 27762306a36Sopenharmony_ciempty by incrementing the dirty_tx mark. Iff the 'hmp->tx_full' flag is set, it 27862306a36Sopenharmony_ciclears both the tx_full and tbusy flags. 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ciIV. Notes 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ciThanks to Kim Stearns of Packet Engines for providing a pair of GNIC-II boards. 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ciIVb. References 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ciHamachi Engineering Design Specification, 5/15/97 28762306a36Sopenharmony_ci(Note: This version was marked "Confidential".) 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ciIVc. Errata 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ciNone noted. 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ciV. Recent Changes 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci01/15/1999 EPK Enlargement of the TX and RX ring sizes. This appears 29662306a36Sopenharmony_ci to help avoid some stall conditions -- this needs further research. 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci01/15/1999 EPK Creation of the hamachi_tx function. This function cleans 29962306a36Sopenharmony_ci the Tx ring and is called from hamachi_start_xmit (this used to be 30062306a36Sopenharmony_ci called from hamachi_interrupt but it tends to delay execution of the 30162306a36Sopenharmony_ci interrupt handler and thus reduce bandwidth by reducing the latency 30262306a36Sopenharmony_ci between hamachi_rx()'s). Notably, some modification has been made so 30362306a36Sopenharmony_ci that the cleaning loop checks only to make sure that the DescOwn bit 30462306a36Sopenharmony_ci isn't set in the status flag since the card is not required 30562306a36Sopenharmony_ci to set the entire flag to zero after processing. 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci01/15/1999 EPK In the hamachi_start_tx function, the Tx ring full flag is 30862306a36Sopenharmony_ci checked before attempting to add a buffer to the ring. If the ring is full 30962306a36Sopenharmony_ci an attempt is made to free any dirty buffers and thus find space for 31062306a36Sopenharmony_ci the new buffer or the function returns non-zero which should case the 31162306a36Sopenharmony_ci scheduler to reschedule the buffer later. 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci01/15/1999 EPK Some adjustments were made to the chip initialization. 31462306a36Sopenharmony_ci End-to-end flow control should now be fully active and the interrupt 31562306a36Sopenharmony_ci algorithm vars have been changed. These could probably use further tuning. 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci01/15/1999 EPK Added the max_{rx,tx}_latency options. These are used to 31862306a36Sopenharmony_ci set the rx and tx latencies for the Hamachi interrupts. If you're having 31962306a36Sopenharmony_ci problems with network stalls, try setting these to higher values. 32062306a36Sopenharmony_ci Valid values are 0x00 through 0xff. 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci01/15/1999 EPK In general, the overall bandwidth has increased and 32362306a36Sopenharmony_ci latencies are better (sometimes by a factor of 2). Stalls are rare at 32462306a36Sopenharmony_ci this point, however there still appears to be a bug somewhere between the 32562306a36Sopenharmony_ci hardware and driver. TCP checksum errors under load also appear to be 32662306a36Sopenharmony_ci eliminated at this point. 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci01/18/1999 EPK Ensured that the DescEndRing bit was being set on both the 32962306a36Sopenharmony_ci Rx and Tx rings. This appears to have been affecting whether a particular 33062306a36Sopenharmony_ci peer-to-peer connection would hang under high load. I believe the Rx 33162306a36Sopenharmony_ci rings was typically getting set correctly, but the Tx ring wasn't getting 33262306a36Sopenharmony_ci the DescEndRing bit set during initialization. ??? Does this mean the 33362306a36Sopenharmony_ci hamachi card is using the DescEndRing in processing even if a particular 33462306a36Sopenharmony_ci slot isn't in use -- hypothetically, the card might be searching the 33562306a36Sopenharmony_ci entire Tx ring for slots with the DescOwn bit set and then processing 33662306a36Sopenharmony_ci them. If the DescEndRing bit isn't set, then it might just wander off 33762306a36Sopenharmony_ci through memory until it hits a chunk of data with that bit set 33862306a36Sopenharmony_ci and then looping back. 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci02/09/1999 EPK Added Michel Mueller's TxDMA Interrupt and Tx-timeout 34162306a36Sopenharmony_ci problem (TxCmd and RxCmd need only to be set when idle or stopped. 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci02/09/1999 EPK Added code to check/reset dev->tbusy in hamachi_interrupt. 34462306a36Sopenharmony_ci (Michel Mueller pointed out the ``permanently busy'' potential 34562306a36Sopenharmony_ci problem here). 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci02/22/1999 EPK Added Pete Wyckoff's ioctl to control the Tx/Rx latencies. 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci02/23/1999 EPK Verified that the interrupt status field bits for Tx were 35062306a36Sopenharmony_ci incorrectly defined and corrected (as per Michel Mueller). 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci02/23/1999 EPK Corrected the Tx full check to check that at least 4 slots 35362306a36Sopenharmony_ci were available before resetting the tbusy and tx_full flags 35462306a36Sopenharmony_ci (as per Michel Mueller). 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci03/11/1999 EPK Added Pete Wyckoff's hardware checksumming support. 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci12/31/1999 KDU Cleaned up assorted things and added Don's code to force 35962306a36Sopenharmony_ci32 bit. 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci02/20/2000 KDU Some of the control was just plain odd. Cleaned up the 36262306a36Sopenharmony_cihamachi_start_xmit() and hamachi_interrupt() code. There is still some 36362306a36Sopenharmony_cire-structuring I would like to do. 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci03/01/2000 KDU Experimenting with a WIDE range of interrupt mitigation 36662306a36Sopenharmony_ciparameters on a dual P3-450 setup yielded the new default interrupt 36762306a36Sopenharmony_cimitigation parameters. Tx should interrupt VERY infrequently due to 36862306a36Sopenharmony_ciEric's scheme. Rx should be more often... 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci03/13/2000 KDU Added a patch to make the Rx Checksum code interact 37162306a36Sopenharmony_cinicely with non-linux machines. 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci03/13/2000 KDU Experimented with some of the configuration values: 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci -It seems that enabling PCI performance commands for descriptors 37662306a36Sopenharmony_ci (changing RxDMACtrl and TxDMACtrl lower nibble from 5 to D) has minimal 37762306a36Sopenharmony_ci performance impact for any of my tests. (ttcp, netpipe, netperf) I will 37862306a36Sopenharmony_ci leave them that way until I hear further feedback. 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci -Increasing the PCI_LATENCY_TIMER to 130 38162306a36Sopenharmony_ci (2 + (burst size of 128 * (0 wait states + 1))) seems to slightly 38262306a36Sopenharmony_ci degrade performance. Leaving default at 64 pending further information. 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci03/14/2000 KDU Further tuning: 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci -adjusted boguscnt in hamachi_rx() to depend on interrupt 38762306a36Sopenharmony_ci mitigation parameters chosen. 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci -Selected a set of interrupt parameters based on some extensive testing. 39062306a36Sopenharmony_ci These may change with more testing. 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ciTO DO: 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci-Consider borrowing from the acenic driver code to check PCI_COMMAND for 39562306a36Sopenharmony_ciPCI_COMMAND_INVALIDATE. Set maximum burst size to cache line size in 39662306a36Sopenharmony_cithat case. 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci-fix the reset procedure. It doesn't quite work. 39962306a36Sopenharmony_ci*/ 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci/* A few values that may be tweaked. */ 40262306a36Sopenharmony_ci/* Size of each temporary Rx buffer, calculated as: 40362306a36Sopenharmony_ci * 1518 bytes (ethernet packet) + 2 bytes (to get 8 byte alignment for 40462306a36Sopenharmony_ci * the card) + 8 bytes of status info + 8 bytes for the Rx Checksum 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci#define PKT_BUF_SZ 1536 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/* For now, this is going to be set to the maximum size of an ethernet 40962306a36Sopenharmony_ci * packet. Eventually, we may want to make it a variable that is 41062306a36Sopenharmony_ci * related to the MTU 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ci#define MAX_FRAME_SIZE 1518 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci/* The rest of these values should never change. */ 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic void hamachi_timer(struct timer_list *t); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cienum capability_flags {CanHaveMII=1, }; 41962306a36Sopenharmony_cistatic const struct chip_info { 42062306a36Sopenharmony_ci u16 vendor_id, device_id, device_id_mask, pad; 42162306a36Sopenharmony_ci const char *name; 42262306a36Sopenharmony_ci void (*media_timer)(struct timer_list *t); 42362306a36Sopenharmony_ci int flags; 42462306a36Sopenharmony_ci} chip_tbl[] = { 42562306a36Sopenharmony_ci {0x1318, 0x0911, 0xffff, 0, "Hamachi GNIC-II", hamachi_timer, 0}, 42662306a36Sopenharmony_ci {0,}, 42762306a36Sopenharmony_ci}; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/* Offsets to the Hamachi registers. Various sizes. */ 43062306a36Sopenharmony_cienum hamachi_offsets { 43162306a36Sopenharmony_ci TxDMACtrl=0x00, TxCmd=0x04, TxStatus=0x06, TxPtr=0x08, TxCurPtr=0x10, 43262306a36Sopenharmony_ci RxDMACtrl=0x20, RxCmd=0x24, RxStatus=0x26, RxPtr=0x28, RxCurPtr=0x30, 43362306a36Sopenharmony_ci PCIClkMeas=0x060, MiscStatus=0x066, ChipRev=0x68, ChipReset=0x06B, 43462306a36Sopenharmony_ci LEDCtrl=0x06C, VirtualJumpers=0x06D, GPIO=0x6E, 43562306a36Sopenharmony_ci TxChecksum=0x074, RxChecksum=0x076, 43662306a36Sopenharmony_ci TxIntrCtrl=0x078, RxIntrCtrl=0x07C, 43762306a36Sopenharmony_ci InterruptEnable=0x080, InterruptClear=0x084, IntrStatus=0x088, 43862306a36Sopenharmony_ci EventStatus=0x08C, 43962306a36Sopenharmony_ci MACCnfg=0x0A0, FrameGap0=0x0A2, FrameGap1=0x0A4, 44062306a36Sopenharmony_ci /* See enum MII_offsets below. */ 44162306a36Sopenharmony_ci MACCnfg2=0x0B0, RxDepth=0x0B8, FlowCtrl=0x0BC, MaxFrameSize=0x0CE, 44262306a36Sopenharmony_ci AddrMode=0x0D0, StationAddr=0x0D2, 44362306a36Sopenharmony_ci /* Gigabit AutoNegotiation. */ 44462306a36Sopenharmony_ci ANCtrl=0x0E0, ANStatus=0x0E2, ANXchngCtrl=0x0E4, ANAdvertise=0x0E8, 44562306a36Sopenharmony_ci ANLinkPartnerAbility=0x0EA, 44662306a36Sopenharmony_ci EECmdStatus=0x0F0, EEData=0x0F1, EEAddr=0x0F2, 44762306a36Sopenharmony_ci FIFOcfg=0x0F8, 44862306a36Sopenharmony_ci}; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci/* Offsets to the MII-mode registers. */ 45162306a36Sopenharmony_cienum MII_offsets { 45262306a36Sopenharmony_ci MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC, 45362306a36Sopenharmony_ci MII_Status=0xAE, 45462306a36Sopenharmony_ci}; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci/* Bits in the interrupt status/mask registers. */ 45762306a36Sopenharmony_cienum intr_status_bits { 45862306a36Sopenharmony_ci IntrRxDone=0x01, IntrRxPCIFault=0x02, IntrRxPCIErr=0x04, 45962306a36Sopenharmony_ci IntrTxDone=0x100, IntrTxPCIFault=0x200, IntrTxPCIErr=0x400, 46062306a36Sopenharmony_ci LinkChange=0x10000, NegotiationChange=0x20000, StatsMax=0x40000, }; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci/* The Hamachi Rx and Tx buffer descriptors. */ 46362306a36Sopenharmony_cistruct hamachi_desc { 46462306a36Sopenharmony_ci __le32 status_n_length; 46562306a36Sopenharmony_ci#if ADDRLEN == 64 46662306a36Sopenharmony_ci u32 pad; 46762306a36Sopenharmony_ci __le64 addr; 46862306a36Sopenharmony_ci#else 46962306a36Sopenharmony_ci __le32 addr; 47062306a36Sopenharmony_ci#endif 47162306a36Sopenharmony_ci}; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/* Bits in hamachi_desc.status_n_length */ 47462306a36Sopenharmony_cienum desc_status_bits { 47562306a36Sopenharmony_ci DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000, 47662306a36Sopenharmony_ci DescIntr=0x10000000, 47762306a36Sopenharmony_ci}; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci#define PRIV_ALIGN 15 /* Required alignment mask */ 48062306a36Sopenharmony_ci#define MII_CNT 4 48162306a36Sopenharmony_cistruct hamachi_private { 48262306a36Sopenharmony_ci /* Descriptor rings first for alignment. Tx requires a second descriptor 48362306a36Sopenharmony_ci for status. */ 48462306a36Sopenharmony_ci struct hamachi_desc *rx_ring; 48562306a36Sopenharmony_ci struct hamachi_desc *tx_ring; 48662306a36Sopenharmony_ci struct sk_buff* rx_skbuff[RX_RING_SIZE]; 48762306a36Sopenharmony_ci struct sk_buff* tx_skbuff[TX_RING_SIZE]; 48862306a36Sopenharmony_ci dma_addr_t tx_ring_dma; 48962306a36Sopenharmony_ci dma_addr_t rx_ring_dma; 49062306a36Sopenharmony_ci struct timer_list timer; /* Media selection timer. */ 49162306a36Sopenharmony_ci /* Frequently used and paired value: keep adjacent for cache effect. */ 49262306a36Sopenharmony_ci spinlock_t lock; 49362306a36Sopenharmony_ci int chip_id; 49462306a36Sopenharmony_ci unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ 49562306a36Sopenharmony_ci unsigned int cur_tx, dirty_tx; 49662306a36Sopenharmony_ci unsigned int rx_buf_sz; /* Based on MTU+slack. */ 49762306a36Sopenharmony_ci unsigned int tx_full:1; /* The Tx queue is full. */ 49862306a36Sopenharmony_ci unsigned int duplex_lock:1; 49962306a36Sopenharmony_ci unsigned int default_port:4; /* Last dev->if_port value. */ 50062306a36Sopenharmony_ci /* MII transceiver section. */ 50162306a36Sopenharmony_ci int mii_cnt; /* MII device addresses. */ 50262306a36Sopenharmony_ci struct mii_if_info mii_if; /* MII lib hooks/info */ 50362306a36Sopenharmony_ci unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ 50462306a36Sopenharmony_ci u32 rx_int_var, tx_int_var; /* interrupt control variables */ 50562306a36Sopenharmony_ci u32 option; /* Hold on to a copy of the options */ 50662306a36Sopenharmony_ci struct pci_dev *pci_dev; 50762306a36Sopenharmony_ci void __iomem *base; 50862306a36Sopenharmony_ci}; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ciMODULE_AUTHOR("Donald Becker <becker@scyld.com>, Eric Kasten <kasten@nscl.msu.edu>, Keith Underwood <keithu@parl.clemson.edu>"); 51162306a36Sopenharmony_ciMODULE_DESCRIPTION("Packet Engines 'Hamachi' GNIC-II Gigabit Ethernet driver"); 51262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cimodule_param(max_interrupt_work, int, 0); 51562306a36Sopenharmony_cimodule_param(mtu, int, 0); 51662306a36Sopenharmony_cimodule_param(debug, int, 0); 51762306a36Sopenharmony_cimodule_param(min_rx_pkt, int, 0); 51862306a36Sopenharmony_cimodule_param(max_rx_gap, int, 0); 51962306a36Sopenharmony_cimodule_param(max_rx_latency, int, 0); 52062306a36Sopenharmony_cimodule_param(min_tx_pkt, int, 0); 52162306a36Sopenharmony_cimodule_param(max_tx_gap, int, 0); 52262306a36Sopenharmony_cimodule_param(max_tx_latency, int, 0); 52362306a36Sopenharmony_cimodule_param(rx_copybreak, int, 0); 52462306a36Sopenharmony_cimodule_param_array(rx_params, int, NULL, 0); 52562306a36Sopenharmony_cimodule_param_array(tx_params, int, NULL, 0); 52662306a36Sopenharmony_cimodule_param_array(options, int, NULL, 0); 52762306a36Sopenharmony_cimodule_param_array(full_duplex, int, NULL, 0); 52862306a36Sopenharmony_cimodule_param(force32, int, 0); 52962306a36Sopenharmony_ciMODULE_PARM_DESC(max_interrupt_work, "GNIC-II maximum events handled per interrupt"); 53062306a36Sopenharmony_ciMODULE_PARM_DESC(mtu, "GNIC-II MTU (all boards)"); 53162306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "GNIC-II debug level (0-7)"); 53262306a36Sopenharmony_ciMODULE_PARM_DESC(min_rx_pkt, "GNIC-II minimum Rx packets processed between interrupts"); 53362306a36Sopenharmony_ciMODULE_PARM_DESC(max_rx_gap, "GNIC-II maximum Rx inter-packet gap in 8.192 microsecond units"); 53462306a36Sopenharmony_ciMODULE_PARM_DESC(max_rx_latency, "GNIC-II time between Rx interrupts in 8.192 microsecond units"); 53562306a36Sopenharmony_ciMODULE_PARM_DESC(min_tx_pkt, "GNIC-II minimum Tx packets processed between interrupts"); 53662306a36Sopenharmony_ciMODULE_PARM_DESC(max_tx_gap, "GNIC-II maximum Tx inter-packet gap in 8.192 microsecond units"); 53762306a36Sopenharmony_ciMODULE_PARM_DESC(max_tx_latency, "GNIC-II time between Tx interrupts in 8.192 microsecond units"); 53862306a36Sopenharmony_ciMODULE_PARM_DESC(rx_copybreak, "GNIC-II copy breakpoint for copy-only-tiny-frames"); 53962306a36Sopenharmony_ciMODULE_PARM_DESC(rx_params, "GNIC-II min_rx_pkt+max_rx_gap+max_rx_latency"); 54062306a36Sopenharmony_ciMODULE_PARM_DESC(tx_params, "GNIC-II min_tx_pkt+max_tx_gap+max_tx_latency"); 54162306a36Sopenharmony_ciMODULE_PARM_DESC(options, "GNIC-II Bits 0-3: media type, bits 4-6: as force32, bit 7: half duplex, bit 9 full duplex"); 54262306a36Sopenharmony_ciMODULE_PARM_DESC(full_duplex, "GNIC-II full duplex setting(s) (1)"); 54362306a36Sopenharmony_ciMODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)"); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic int read_eeprom(void __iomem *ioaddr, int location); 54662306a36Sopenharmony_cistatic int mdio_read(struct net_device *dev, int phy_id, int location); 54762306a36Sopenharmony_cistatic void mdio_write(struct net_device *dev, int phy_id, int location, int value); 54862306a36Sopenharmony_cistatic int hamachi_open(struct net_device *dev); 54962306a36Sopenharmony_cistatic int hamachi_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); 55062306a36Sopenharmony_cistatic int hamachi_siocdevprivate(struct net_device *dev, struct ifreq *rq, 55162306a36Sopenharmony_ci void __user *data, int cmd); 55262306a36Sopenharmony_cistatic void hamachi_timer(struct timer_list *t); 55362306a36Sopenharmony_cistatic void hamachi_tx_timeout(struct net_device *dev, unsigned int txqueue); 55462306a36Sopenharmony_cistatic void hamachi_init_ring(struct net_device *dev); 55562306a36Sopenharmony_cistatic netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, 55662306a36Sopenharmony_ci struct net_device *dev); 55762306a36Sopenharmony_cistatic irqreturn_t hamachi_interrupt(int irq, void *dev_instance); 55862306a36Sopenharmony_cistatic int hamachi_rx(struct net_device *dev); 55962306a36Sopenharmony_cistatic inline int hamachi_tx(struct net_device *dev); 56062306a36Sopenharmony_cistatic void hamachi_error(struct net_device *dev, int intr_status); 56162306a36Sopenharmony_cistatic int hamachi_close(struct net_device *dev); 56262306a36Sopenharmony_cistatic struct net_device_stats *hamachi_get_stats(struct net_device *dev); 56362306a36Sopenharmony_cistatic void set_rx_mode(struct net_device *dev); 56462306a36Sopenharmony_cistatic const struct ethtool_ops ethtool_ops; 56562306a36Sopenharmony_cistatic const struct ethtool_ops ethtool_ops_no_mii; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic const struct net_device_ops hamachi_netdev_ops = { 56862306a36Sopenharmony_ci .ndo_open = hamachi_open, 56962306a36Sopenharmony_ci .ndo_stop = hamachi_close, 57062306a36Sopenharmony_ci .ndo_start_xmit = hamachi_start_xmit, 57162306a36Sopenharmony_ci .ndo_get_stats = hamachi_get_stats, 57262306a36Sopenharmony_ci .ndo_set_rx_mode = set_rx_mode, 57362306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 57462306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 57562306a36Sopenharmony_ci .ndo_tx_timeout = hamachi_tx_timeout, 57662306a36Sopenharmony_ci .ndo_eth_ioctl = hamachi_ioctl, 57762306a36Sopenharmony_ci .ndo_siocdevprivate = hamachi_siocdevprivate, 57862306a36Sopenharmony_ci}; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic int hamachi_init_one(struct pci_dev *pdev, 58262306a36Sopenharmony_ci const struct pci_device_id *ent) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci struct hamachi_private *hmp; 58562306a36Sopenharmony_ci int option, i, rx_int_var, tx_int_var, boguscnt; 58662306a36Sopenharmony_ci int chip_id = ent->driver_data; 58762306a36Sopenharmony_ci int irq; 58862306a36Sopenharmony_ci void __iomem *ioaddr; 58962306a36Sopenharmony_ci unsigned long base; 59062306a36Sopenharmony_ci static int card_idx; 59162306a36Sopenharmony_ci struct net_device *dev; 59262306a36Sopenharmony_ci void *ring_space; 59362306a36Sopenharmony_ci dma_addr_t ring_dma; 59462306a36Sopenharmony_ci int ret = -ENOMEM; 59562306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci/* when built into the kernel, we only print version if device is found */ 59862306a36Sopenharmony_ci#ifndef MODULE 59962306a36Sopenharmony_ci static int printed_version; 60062306a36Sopenharmony_ci if (!printed_version++) 60162306a36Sopenharmony_ci printk(version); 60262306a36Sopenharmony_ci#endif 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (pci_enable_device(pdev)) { 60562306a36Sopenharmony_ci ret = -EIO; 60662306a36Sopenharmony_ci goto err_out; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci base = pci_resource_start(pdev, 0); 61062306a36Sopenharmony_ci#ifdef __alpha__ /* Really "64 bit addrs" */ 61162306a36Sopenharmony_ci base |= (pci_resource_start(pdev, 1) << 32); 61262306a36Sopenharmony_ci#endif 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci pci_set_master(pdev); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci i = pci_request_regions(pdev, DRV_NAME); 61762306a36Sopenharmony_ci if (i) 61862306a36Sopenharmony_ci return i; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci irq = pdev->irq; 62162306a36Sopenharmony_ci ioaddr = ioremap(base, 0x400); 62262306a36Sopenharmony_ci if (!ioaddr) 62362306a36Sopenharmony_ci goto err_out_release; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci dev = alloc_etherdev(sizeof(struct hamachi_private)); 62662306a36Sopenharmony_ci if (!dev) 62762306a36Sopenharmony_ci goto err_out_iounmap; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci for (i = 0; i < 6; i++) 63262306a36Sopenharmony_ci addr[i] = read_eeprom(ioaddr, 4 + i); 63362306a36Sopenharmony_ci eth_hw_addr_set(dev, addr); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci#if ! defined(final_version) 63662306a36Sopenharmony_ci if (hamachi_debug > 4) 63762306a36Sopenharmony_ci for (i = 0; i < 0x10; i++) 63862306a36Sopenharmony_ci printk("%2.2x%s", 63962306a36Sopenharmony_ci read_eeprom(ioaddr, i), i % 16 != 15 ? " " : "\n"); 64062306a36Sopenharmony_ci#endif 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci hmp = netdev_priv(dev); 64362306a36Sopenharmony_ci spin_lock_init(&hmp->lock); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci hmp->mii_if.dev = dev; 64662306a36Sopenharmony_ci hmp->mii_if.mdio_read = mdio_read; 64762306a36Sopenharmony_ci hmp->mii_if.mdio_write = mdio_write; 64862306a36Sopenharmony_ci hmp->mii_if.phy_id_mask = 0x1f; 64962306a36Sopenharmony_ci hmp->mii_if.reg_num_mask = 0x1f; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, &ring_dma, 65262306a36Sopenharmony_ci GFP_KERNEL); 65362306a36Sopenharmony_ci if (!ring_space) 65462306a36Sopenharmony_ci goto err_out_cleardev; 65562306a36Sopenharmony_ci hmp->tx_ring = ring_space; 65662306a36Sopenharmony_ci hmp->tx_ring_dma = ring_dma; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, &ring_dma, 65962306a36Sopenharmony_ci GFP_KERNEL); 66062306a36Sopenharmony_ci if (!ring_space) 66162306a36Sopenharmony_ci goto err_out_unmap_tx; 66262306a36Sopenharmony_ci hmp->rx_ring = ring_space; 66362306a36Sopenharmony_ci hmp->rx_ring_dma = ring_dma; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* Check for options being passed in */ 66662306a36Sopenharmony_ci option = card_idx < MAX_UNITS ? options[card_idx] : 0; 66762306a36Sopenharmony_ci if (dev->mem_start) 66862306a36Sopenharmony_ci option = dev->mem_start; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* If the bus size is misidentified, do the following. */ 67162306a36Sopenharmony_ci force32 = force32 ? force32 : 67262306a36Sopenharmony_ci ((option >= 0) ? ((option & 0x00000070) >> 4) : 0 ); 67362306a36Sopenharmony_ci if (force32) 67462306a36Sopenharmony_ci writeb(force32, ioaddr + VirtualJumpers); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* Hmmm, do we really need to reset the chip???. */ 67762306a36Sopenharmony_ci writeb(0x01, ioaddr + ChipReset); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* After a reset, the clock speed measurement of the PCI bus will not 68062306a36Sopenharmony_ci * be valid for a moment. Wait for a little while until it is. If 68162306a36Sopenharmony_ci * it takes more than 10ms, forget it. 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_ci udelay(10); 68462306a36Sopenharmony_ci i = readb(ioaddr + PCIClkMeas); 68562306a36Sopenharmony_ci for (boguscnt = 0; (!(i & 0x080)) && boguscnt < 1000; boguscnt++){ 68662306a36Sopenharmony_ci udelay(10); 68762306a36Sopenharmony_ci i = readb(ioaddr + PCIClkMeas); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci hmp->base = ioaddr; 69162306a36Sopenharmony_ci pci_set_drvdata(pdev, dev); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci hmp->chip_id = chip_id; 69462306a36Sopenharmony_ci hmp->pci_dev = pdev; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* The lower four bits are the media type. */ 69762306a36Sopenharmony_ci if (option > 0) { 69862306a36Sopenharmony_ci hmp->option = option; 69962306a36Sopenharmony_ci if (option & 0x200) 70062306a36Sopenharmony_ci hmp->mii_if.full_duplex = 1; 70162306a36Sopenharmony_ci else if (option & 0x080) 70262306a36Sopenharmony_ci hmp->mii_if.full_duplex = 0; 70362306a36Sopenharmony_ci hmp->default_port = option & 15; 70462306a36Sopenharmony_ci if (hmp->default_port) 70562306a36Sopenharmony_ci hmp->mii_if.force_media = 1; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) 70862306a36Sopenharmony_ci hmp->mii_if.full_duplex = 1; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* lock the duplex mode if someone specified a value */ 71162306a36Sopenharmony_ci if (hmp->mii_if.full_duplex || (option & 0x080)) 71262306a36Sopenharmony_ci hmp->duplex_lock = 1; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* Set interrupt tuning parameters */ 71562306a36Sopenharmony_ci max_rx_latency = max_rx_latency & 0x00ff; 71662306a36Sopenharmony_ci max_rx_gap = max_rx_gap & 0x00ff; 71762306a36Sopenharmony_ci min_rx_pkt = min_rx_pkt & 0x00ff; 71862306a36Sopenharmony_ci max_tx_latency = max_tx_latency & 0x00ff; 71962306a36Sopenharmony_ci max_tx_gap = max_tx_gap & 0x00ff; 72062306a36Sopenharmony_ci min_tx_pkt = min_tx_pkt & 0x00ff; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci rx_int_var = card_idx < MAX_UNITS ? rx_params[card_idx] : -1; 72362306a36Sopenharmony_ci tx_int_var = card_idx < MAX_UNITS ? tx_params[card_idx] : -1; 72462306a36Sopenharmony_ci hmp->rx_int_var = rx_int_var >= 0 ? rx_int_var : 72562306a36Sopenharmony_ci (min_rx_pkt << 16 | max_rx_gap << 8 | max_rx_latency); 72662306a36Sopenharmony_ci hmp->tx_int_var = tx_int_var >= 0 ? tx_int_var : 72762306a36Sopenharmony_ci (min_tx_pkt << 16 | max_tx_gap << 8 | max_tx_latency); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* The Hamachi-specific entries in the device structure. */ 73162306a36Sopenharmony_ci dev->netdev_ops = &hamachi_netdev_ops; 73262306a36Sopenharmony_ci dev->ethtool_ops = (chip_tbl[hmp->chip_id].flags & CanHaveMII) ? 73362306a36Sopenharmony_ci ðtool_ops : ðtool_ops_no_mii; 73462306a36Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 73562306a36Sopenharmony_ci if (mtu) 73662306a36Sopenharmony_ci dev->mtu = mtu; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci i = register_netdev(dev); 73962306a36Sopenharmony_ci if (i) { 74062306a36Sopenharmony_ci ret = i; 74162306a36Sopenharmony_ci goto err_out_unmap_rx; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci printk(KERN_INFO "%s: %s type %x at %p, %pM, IRQ %d.\n", 74562306a36Sopenharmony_ci dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), 74662306a36Sopenharmony_ci ioaddr, dev->dev_addr, irq); 74762306a36Sopenharmony_ci i = readb(ioaddr + PCIClkMeas); 74862306a36Sopenharmony_ci printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " 74962306a36Sopenharmony_ci "%2.2x, LPA %4.4x.\n", 75062306a36Sopenharmony_ci dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, 75162306a36Sopenharmony_ci i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), 75262306a36Sopenharmony_ci readw(ioaddr + ANLinkPartnerAbility)); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (chip_tbl[hmp->chip_id].flags & CanHaveMII) { 75562306a36Sopenharmony_ci int phy, phy_idx = 0; 75662306a36Sopenharmony_ci for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { 75762306a36Sopenharmony_ci int mii_status = mdio_read(dev, phy, MII_BMSR); 75862306a36Sopenharmony_ci if (mii_status != 0xffff && 75962306a36Sopenharmony_ci mii_status != 0x0000) { 76062306a36Sopenharmony_ci hmp->phys[phy_idx++] = phy; 76162306a36Sopenharmony_ci hmp->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); 76262306a36Sopenharmony_ci printk(KERN_INFO "%s: MII PHY found at address %d, status " 76362306a36Sopenharmony_ci "0x%4.4x advertising %4.4x.\n", 76462306a36Sopenharmony_ci dev->name, phy, mii_status, hmp->mii_if.advertising); 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci hmp->mii_cnt = phy_idx; 76862306a36Sopenharmony_ci if (hmp->mii_cnt > 0) 76962306a36Sopenharmony_ci hmp->mii_if.phy_id = hmp->phys[0]; 77062306a36Sopenharmony_ci else 77162306a36Sopenharmony_ci memset(&hmp->mii_if, 0, sizeof(hmp->mii_if)); 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci /* Configure gigabit autonegotiation. */ 77462306a36Sopenharmony_ci writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ 77562306a36Sopenharmony_ci writew(0x08e0, ioaddr + ANAdvertise); /* Set our advertise word. */ 77662306a36Sopenharmony_ci writew(0x1000, ioaddr + ANCtrl); /* Enable negotiation */ 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci card_idx++; 77962306a36Sopenharmony_ci return 0; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cierr_out_unmap_rx: 78262306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, hmp->rx_ring, 78362306a36Sopenharmony_ci hmp->rx_ring_dma); 78462306a36Sopenharmony_cierr_out_unmap_tx: 78562306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, hmp->tx_ring, 78662306a36Sopenharmony_ci hmp->tx_ring_dma); 78762306a36Sopenharmony_cierr_out_cleardev: 78862306a36Sopenharmony_ci free_netdev (dev); 78962306a36Sopenharmony_cierr_out_iounmap: 79062306a36Sopenharmony_ci iounmap(ioaddr); 79162306a36Sopenharmony_cierr_out_release: 79262306a36Sopenharmony_ci pci_release_regions(pdev); 79362306a36Sopenharmony_cierr_out: 79462306a36Sopenharmony_ci return ret; 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic int read_eeprom(void __iomem *ioaddr, int location) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci int bogus_cnt = 1000; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci /* We should check busy first - per docs -KDU */ 80262306a36Sopenharmony_ci while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0); 80362306a36Sopenharmony_ci writew(location, ioaddr + EEAddr); 80462306a36Sopenharmony_ci writeb(0x02, ioaddr + EECmdStatus); 80562306a36Sopenharmony_ci bogus_cnt = 1000; 80662306a36Sopenharmony_ci while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0); 80762306a36Sopenharmony_ci if (hamachi_debug > 5) 80862306a36Sopenharmony_ci printk(" EEPROM status is %2.2x after %d ticks.\n", 80962306a36Sopenharmony_ci (int)readb(ioaddr + EECmdStatus), 1000- bogus_cnt); 81062306a36Sopenharmony_ci return readb(ioaddr + EEData); 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci/* MII Managemen Data I/O accesses. 81462306a36Sopenharmony_ci These routines assume the MDIO controller is idle, and do not exit until 81562306a36Sopenharmony_ci the command is finished. */ 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic int mdio_read(struct net_device *dev, int phy_id, int location) 81862306a36Sopenharmony_ci{ 81962306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 82062306a36Sopenharmony_ci void __iomem *ioaddr = hmp->base; 82162306a36Sopenharmony_ci int i; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* We should check busy first - per docs -KDU */ 82462306a36Sopenharmony_ci for (i = 10000; i >= 0; i--) 82562306a36Sopenharmony_ci if ((readw(ioaddr + MII_Status) & 1) == 0) 82662306a36Sopenharmony_ci break; 82762306a36Sopenharmony_ci writew((phy_id<<8) + location, ioaddr + MII_Addr); 82862306a36Sopenharmony_ci writew(0x0001, ioaddr + MII_Cmd); 82962306a36Sopenharmony_ci for (i = 10000; i >= 0; i--) 83062306a36Sopenharmony_ci if ((readw(ioaddr + MII_Status) & 1) == 0) 83162306a36Sopenharmony_ci break; 83262306a36Sopenharmony_ci return readw(ioaddr + MII_Rd_Data); 83362306a36Sopenharmony_ci} 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_cistatic void mdio_write(struct net_device *dev, int phy_id, int location, int value) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 83862306a36Sopenharmony_ci void __iomem *ioaddr = hmp->base; 83962306a36Sopenharmony_ci int i; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* We should check busy first - per docs -KDU */ 84262306a36Sopenharmony_ci for (i = 10000; i >= 0; i--) 84362306a36Sopenharmony_ci if ((readw(ioaddr + MII_Status) & 1) == 0) 84462306a36Sopenharmony_ci break; 84562306a36Sopenharmony_ci writew((phy_id<<8) + location, ioaddr + MII_Addr); 84662306a36Sopenharmony_ci writew(value, ioaddr + MII_Wr_Data); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* Wait for the command to finish. */ 84962306a36Sopenharmony_ci for (i = 10000; i >= 0; i--) 85062306a36Sopenharmony_ci if ((readw(ioaddr + MII_Status) & 1) == 0) 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic int hamachi_open(struct net_device *dev) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 85862306a36Sopenharmony_ci void __iomem *ioaddr = hmp->base; 85962306a36Sopenharmony_ci int i; 86062306a36Sopenharmony_ci u32 rx_int_var, tx_int_var; 86162306a36Sopenharmony_ci u16 fifo_info; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci i = request_irq(hmp->pci_dev->irq, hamachi_interrupt, IRQF_SHARED, 86462306a36Sopenharmony_ci dev->name, dev); 86562306a36Sopenharmony_ci if (i) 86662306a36Sopenharmony_ci return i; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci hamachi_init_ring(dev); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci#if ADDRLEN == 64 87162306a36Sopenharmony_ci /* writellll anyone ? */ 87262306a36Sopenharmony_ci writel(hmp->rx_ring_dma, ioaddr + RxPtr); 87362306a36Sopenharmony_ci writel(hmp->rx_ring_dma >> 32, ioaddr + RxPtr + 4); 87462306a36Sopenharmony_ci writel(hmp->tx_ring_dma, ioaddr + TxPtr); 87562306a36Sopenharmony_ci writel(hmp->tx_ring_dma >> 32, ioaddr + TxPtr + 4); 87662306a36Sopenharmony_ci#else 87762306a36Sopenharmony_ci writel(hmp->rx_ring_dma, ioaddr + RxPtr); 87862306a36Sopenharmony_ci writel(hmp->tx_ring_dma, ioaddr + TxPtr); 87962306a36Sopenharmony_ci#endif 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci /* TODO: It would make sense to organize this as words since the card 88262306a36Sopenharmony_ci * documentation does. -KDU 88362306a36Sopenharmony_ci */ 88462306a36Sopenharmony_ci for (i = 0; i < 6; i++) 88562306a36Sopenharmony_ci writeb(dev->dev_addr[i], ioaddr + StationAddr + i); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* Initialize other registers: with so many this eventually this will 88862306a36Sopenharmony_ci converted to an offset/value list. */ 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci /* Configure the FIFO */ 89162306a36Sopenharmony_ci fifo_info = (readw(ioaddr + GPIO) & 0x00C0) >> 6; 89262306a36Sopenharmony_ci switch (fifo_info){ 89362306a36Sopenharmony_ci case 0 : 89462306a36Sopenharmony_ci /* No FIFO */ 89562306a36Sopenharmony_ci writew(0x0000, ioaddr + FIFOcfg); 89662306a36Sopenharmony_ci break; 89762306a36Sopenharmony_ci case 1 : 89862306a36Sopenharmony_ci /* Configure the FIFO for 512K external, 16K used for Tx. */ 89962306a36Sopenharmony_ci writew(0x0028, ioaddr + FIFOcfg); 90062306a36Sopenharmony_ci break; 90162306a36Sopenharmony_ci case 2 : 90262306a36Sopenharmony_ci /* Configure the FIFO for 1024 external, 32K used for Tx. */ 90362306a36Sopenharmony_ci writew(0x004C, ioaddr + FIFOcfg); 90462306a36Sopenharmony_ci break; 90562306a36Sopenharmony_ci case 3 : 90662306a36Sopenharmony_ci /* Configure the FIFO for 2048 external, 32K used for Tx. */ 90762306a36Sopenharmony_ci writew(0x006C, ioaddr + FIFOcfg); 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci default : 91062306a36Sopenharmony_ci printk(KERN_WARNING "%s: Unsupported external memory config!\n", 91162306a36Sopenharmony_ci dev->name); 91262306a36Sopenharmony_ci /* Default to no FIFO */ 91362306a36Sopenharmony_ci writew(0x0000, ioaddr + FIFOcfg); 91462306a36Sopenharmony_ci break; 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci if (dev->if_port == 0) 91862306a36Sopenharmony_ci dev->if_port = hmp->default_port; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* Setting the Rx mode will start the Rx process. */ 92262306a36Sopenharmony_ci /* If someone didn't choose a duplex, default to full-duplex */ 92362306a36Sopenharmony_ci if (hmp->duplex_lock != 1) 92462306a36Sopenharmony_ci hmp->mii_if.full_duplex = 1; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci /* always 1, takes no more time to do it */ 92762306a36Sopenharmony_ci writew(0x0001, ioaddr + RxChecksum); 92862306a36Sopenharmony_ci writew(0x0000, ioaddr + TxChecksum); 92962306a36Sopenharmony_ci writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */ 93062306a36Sopenharmony_ci writew(0x215F, ioaddr + MACCnfg); 93162306a36Sopenharmony_ci writew(0x000C, ioaddr + FrameGap0); 93262306a36Sopenharmony_ci /* WHAT?!?!? Why isn't this documented somewhere? -KDU */ 93362306a36Sopenharmony_ci writew(0x1018, ioaddr + FrameGap1); 93462306a36Sopenharmony_ci /* Why do we enable receives/transmits here? -KDU */ 93562306a36Sopenharmony_ci writew(0x0780, ioaddr + MACCnfg2); /* Upper 16 bits control LEDs. */ 93662306a36Sopenharmony_ci /* Enable automatic generation of flow control frames, period 0xffff. */ 93762306a36Sopenharmony_ci writel(0x0030FFFF, ioaddr + FlowCtrl); 93862306a36Sopenharmony_ci writew(MAX_FRAME_SIZE, ioaddr + MaxFrameSize); /* dev->mtu+14 ??? */ 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci /* Enable legacy links. */ 94162306a36Sopenharmony_ci writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ 94262306a36Sopenharmony_ci /* Initial Link LED to blinking red. */ 94362306a36Sopenharmony_ci writeb(0x03, ioaddr + LEDCtrl); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* Configure interrupt mitigation. This has a great effect on 94662306a36Sopenharmony_ci performance, so systems tuning should start here!. */ 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci rx_int_var = hmp->rx_int_var; 94962306a36Sopenharmony_ci tx_int_var = hmp->tx_int_var; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (hamachi_debug > 1) { 95262306a36Sopenharmony_ci printk("max_tx_latency: %d, max_tx_gap: %d, min_tx_pkt: %d\n", 95362306a36Sopenharmony_ci tx_int_var & 0x00ff, (tx_int_var & 0x00ff00) >> 8, 95462306a36Sopenharmony_ci (tx_int_var & 0x00ff0000) >> 16); 95562306a36Sopenharmony_ci printk("max_rx_latency: %d, max_rx_gap: %d, min_rx_pkt: %d\n", 95662306a36Sopenharmony_ci rx_int_var & 0x00ff, (rx_int_var & 0x00ff00) >> 8, 95762306a36Sopenharmony_ci (rx_int_var & 0x00ff0000) >> 16); 95862306a36Sopenharmony_ci printk("rx_int_var: %x, tx_int_var: %x\n", rx_int_var, tx_int_var); 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci writel(tx_int_var, ioaddr + TxIntrCtrl); 96262306a36Sopenharmony_ci writel(rx_int_var, ioaddr + RxIntrCtrl); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci set_rx_mode(dev); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci netif_start_queue(dev); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* Enable interrupts by setting the interrupt mask. */ 96962306a36Sopenharmony_ci writel(0x80878787, ioaddr + InterruptEnable); 97062306a36Sopenharmony_ci writew(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci /* Configure and start the DMA channels. */ 97362306a36Sopenharmony_ci /* Burst sizes are in the low three bits: size = 4<<(val&7) */ 97462306a36Sopenharmony_ci#if ADDRLEN == 64 97562306a36Sopenharmony_ci writew(0x005D, ioaddr + RxDMACtrl); /* 128 dword bursts */ 97662306a36Sopenharmony_ci writew(0x005D, ioaddr + TxDMACtrl); 97762306a36Sopenharmony_ci#else 97862306a36Sopenharmony_ci writew(0x001D, ioaddr + RxDMACtrl); 97962306a36Sopenharmony_ci writew(0x001D, ioaddr + TxDMACtrl); 98062306a36Sopenharmony_ci#endif 98162306a36Sopenharmony_ci writew(0x0001, ioaddr + RxCmd); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (hamachi_debug > 2) { 98462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Done hamachi_open(), status: Rx %x Tx %x.\n", 98562306a36Sopenharmony_ci dev->name, readw(ioaddr + RxStatus), readw(ioaddr + TxStatus)); 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci /* Set the timer to check for link beat. */ 98862306a36Sopenharmony_ci timer_setup(&hmp->timer, hamachi_timer, 0); 98962306a36Sopenharmony_ci hmp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ 99062306a36Sopenharmony_ci add_timer(&hmp->timer); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci return 0; 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_cistatic inline int hamachi_tx(struct net_device *dev) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* Update the dirty pointer until we find an entry that is 100062306a36Sopenharmony_ci still owned by the card */ 100162306a36Sopenharmony_ci for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++) { 100262306a36Sopenharmony_ci int entry = hmp->dirty_tx % TX_RING_SIZE; 100362306a36Sopenharmony_ci struct sk_buff *skb; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) 100662306a36Sopenharmony_ci break; 100762306a36Sopenharmony_ci /* Free the original skb. */ 100862306a36Sopenharmony_ci skb = hmp->tx_skbuff[entry]; 100962306a36Sopenharmony_ci if (skb) { 101062306a36Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 101162306a36Sopenharmony_ci leXX_to_cpu(hmp->tx_ring[entry].addr), 101262306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 101362306a36Sopenharmony_ci dev_kfree_skb(skb); 101462306a36Sopenharmony_ci hmp->tx_skbuff[entry] = NULL; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci hmp->tx_ring[entry].status_n_length = 0; 101762306a36Sopenharmony_ci if (entry >= TX_RING_SIZE-1) 101862306a36Sopenharmony_ci hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= 101962306a36Sopenharmony_ci cpu_to_le32(DescEndRing); 102062306a36Sopenharmony_ci dev->stats.tx_packets++; 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci return 0; 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic void hamachi_timer(struct timer_list *t) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci struct hamachi_private *hmp = from_timer(hmp, t, timer); 102962306a36Sopenharmony_ci struct net_device *dev = hmp->mii_if.dev; 103062306a36Sopenharmony_ci void __iomem *ioaddr = hmp->base; 103162306a36Sopenharmony_ci int next_tick = 10*HZ; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (hamachi_debug > 2) { 103462306a36Sopenharmony_ci printk(KERN_INFO "%s: Hamachi Autonegotiation status %4.4x, LPA " 103562306a36Sopenharmony_ci "%4.4x.\n", dev->name, readw(ioaddr + ANStatus), 103662306a36Sopenharmony_ci readw(ioaddr + ANLinkPartnerAbility)); 103762306a36Sopenharmony_ci printk(KERN_INFO "%s: Autonegotiation regs %4.4x %4.4x %4.4x " 103862306a36Sopenharmony_ci "%4.4x %4.4x %4.4x.\n", dev->name, 103962306a36Sopenharmony_ci readw(ioaddr + 0x0e0), 104062306a36Sopenharmony_ci readw(ioaddr + 0x0e2), 104162306a36Sopenharmony_ci readw(ioaddr + 0x0e4), 104262306a36Sopenharmony_ci readw(ioaddr + 0x0e6), 104362306a36Sopenharmony_ci readw(ioaddr + 0x0e8), 104462306a36Sopenharmony_ci readw(ioaddr + 0x0eA)); 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci /* We could do something here... nah. */ 104762306a36Sopenharmony_ci hmp->timer.expires = RUN_AT(next_tick); 104862306a36Sopenharmony_ci add_timer(&hmp->timer); 104962306a36Sopenharmony_ci} 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_cistatic void hamachi_tx_timeout(struct net_device *dev, unsigned int txqueue) 105262306a36Sopenharmony_ci{ 105362306a36Sopenharmony_ci int i; 105462306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 105562306a36Sopenharmony_ci void __iomem *ioaddr = hmp->base; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x," 105862306a36Sopenharmony_ci " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus)); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci { 106162306a36Sopenharmony_ci printk(KERN_DEBUG " Rx ring %p: ", hmp->rx_ring); 106262306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) 106362306a36Sopenharmony_ci printk(KERN_CONT " %8.8x", 106462306a36Sopenharmony_ci le32_to_cpu(hmp->rx_ring[i].status_n_length)); 106562306a36Sopenharmony_ci printk(KERN_CONT "\n"); 106662306a36Sopenharmony_ci printk(KERN_DEBUG" Tx ring %p: ", hmp->tx_ring); 106762306a36Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) 106862306a36Sopenharmony_ci printk(KERN_CONT " %4.4x", 106962306a36Sopenharmony_ci le32_to_cpu(hmp->tx_ring[i].status_n_length)); 107062306a36Sopenharmony_ci printk(KERN_CONT "\n"); 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* Reinit the hardware and make sure the Rx and Tx processes 107462306a36Sopenharmony_ci are up and running. 107562306a36Sopenharmony_ci */ 107662306a36Sopenharmony_ci dev->if_port = 0; 107762306a36Sopenharmony_ci /* The right way to do Reset. -KDU 107862306a36Sopenharmony_ci * -Clear OWN bit in all Rx/Tx descriptors 107962306a36Sopenharmony_ci * -Wait 50 uS for channels to go idle 108062306a36Sopenharmony_ci * -Turn off MAC receiver 108162306a36Sopenharmony_ci * -Issue Reset 108262306a36Sopenharmony_ci */ 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) 108562306a36Sopenharmony_ci hmp->rx_ring[i].status_n_length &= cpu_to_le32(~DescOwn); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci /* Presume that all packets in the Tx queue are gone if we have to 108862306a36Sopenharmony_ci * re-init the hardware. 108962306a36Sopenharmony_ci */ 109062306a36Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++){ 109162306a36Sopenharmony_ci struct sk_buff *skb; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (i >= TX_RING_SIZE - 1) 109462306a36Sopenharmony_ci hmp->tx_ring[i].status_n_length = 109562306a36Sopenharmony_ci cpu_to_le32(DescEndRing) | 109662306a36Sopenharmony_ci (hmp->tx_ring[i].status_n_length & 109762306a36Sopenharmony_ci cpu_to_le32(0x0000ffff)); 109862306a36Sopenharmony_ci else 109962306a36Sopenharmony_ci hmp->tx_ring[i].status_n_length &= cpu_to_le32(0x0000ffff); 110062306a36Sopenharmony_ci skb = hmp->tx_skbuff[i]; 110162306a36Sopenharmony_ci if (skb){ 110262306a36Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 110362306a36Sopenharmony_ci leXX_to_cpu(hmp->tx_ring[i].addr), 110462306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 110562306a36Sopenharmony_ci dev_kfree_skb(skb); 110662306a36Sopenharmony_ci hmp->tx_skbuff[i] = NULL; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci udelay(60); /* Sleep 60 us just for safety sake */ 111162306a36Sopenharmony_ci writew(0x0002, ioaddr + RxCmd); /* STOP Rx */ 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci writeb(0x01, ioaddr + ChipReset); /* Reinit the hardware */ 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci hmp->tx_full = 0; 111662306a36Sopenharmony_ci hmp->cur_rx = hmp->cur_tx = 0; 111762306a36Sopenharmony_ci hmp->dirty_rx = hmp->dirty_tx = 0; 111862306a36Sopenharmony_ci /* Rx packets are also presumed lost; however, we need to make sure a 111962306a36Sopenharmony_ci * ring of buffers is in tact. -KDU 112062306a36Sopenharmony_ci */ 112162306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++){ 112262306a36Sopenharmony_ci struct sk_buff *skb = hmp->rx_skbuff[i]; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (skb){ 112562306a36Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 112662306a36Sopenharmony_ci leXX_to_cpu(hmp->rx_ring[i].addr), 112762306a36Sopenharmony_ci hmp->rx_buf_sz, DMA_FROM_DEVICE); 112862306a36Sopenharmony_ci dev_kfree_skb(skb); 112962306a36Sopenharmony_ci hmp->rx_skbuff[i] = NULL; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci /* Fill in the Rx buffers. Handle allocation failure gracefully. */ 113362306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 113462306a36Sopenharmony_ci struct sk_buff *skb; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci skb = netdev_alloc_skb_ip_align(dev, hmp->rx_buf_sz); 113762306a36Sopenharmony_ci hmp->rx_skbuff[i] = skb; 113862306a36Sopenharmony_ci if (skb == NULL) 113962306a36Sopenharmony_ci break; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci hmp->rx_ring[i].addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, 114262306a36Sopenharmony_ci skb->data, 114362306a36Sopenharmony_ci hmp->rx_buf_sz, 114462306a36Sopenharmony_ci DMA_FROM_DEVICE)); 114562306a36Sopenharmony_ci hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | 114662306a36Sopenharmony_ci DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2)); 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); 114962306a36Sopenharmony_ci /* Mark the last entry as wrapping the ring. */ 115062306a36Sopenharmony_ci hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci /* Trigger an immediate transmit demand. */ 115362306a36Sopenharmony_ci netif_trans_update(dev); /* prevent tx timeout */ 115462306a36Sopenharmony_ci dev->stats.tx_errors++; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci /* Restart the chip's Tx/Rx processes . */ 115762306a36Sopenharmony_ci writew(0x0002, ioaddr + TxCmd); /* STOP Tx */ 115862306a36Sopenharmony_ci writew(0x0001, ioaddr + TxCmd); /* START Tx */ 115962306a36Sopenharmony_ci writew(0x0001, ioaddr + RxCmd); /* START Rx */ 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci netif_wake_queue(dev); 116262306a36Sopenharmony_ci} 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ 116662306a36Sopenharmony_cistatic void hamachi_init_ring(struct net_device *dev) 116762306a36Sopenharmony_ci{ 116862306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 116962306a36Sopenharmony_ci int i; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci hmp->tx_full = 0; 117262306a36Sopenharmony_ci hmp->cur_rx = hmp->cur_tx = 0; 117362306a36Sopenharmony_ci hmp->dirty_rx = hmp->dirty_tx = 0; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the 117662306a36Sopenharmony_ci * card needs room to do 8 byte alignment, +2 so we can reserve 117762306a36Sopenharmony_ci * the first 2 bytes, and +16 gets room for the status word from the 117862306a36Sopenharmony_ci * card. -KDU 117962306a36Sopenharmony_ci */ 118062306a36Sopenharmony_ci hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ : 118162306a36Sopenharmony_ci (((dev->mtu+26+7) & ~7) + 16)); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci /* Initialize all Rx descriptors. */ 118462306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 118562306a36Sopenharmony_ci hmp->rx_ring[i].status_n_length = 0; 118662306a36Sopenharmony_ci hmp->rx_skbuff[i] = NULL; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci /* Fill in the Rx buffers. Handle allocation failure gracefully. */ 118962306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 119062306a36Sopenharmony_ci struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz + 2); 119162306a36Sopenharmony_ci hmp->rx_skbuff[i] = skb; 119262306a36Sopenharmony_ci if (skb == NULL) 119362306a36Sopenharmony_ci break; 119462306a36Sopenharmony_ci skb_reserve(skb, 2); /* 16 byte align the IP header. */ 119562306a36Sopenharmony_ci hmp->rx_ring[i].addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, 119662306a36Sopenharmony_ci skb->data, 119762306a36Sopenharmony_ci hmp->rx_buf_sz, 119862306a36Sopenharmony_ci DMA_FROM_DEVICE)); 119962306a36Sopenharmony_ci /* -2 because it doesn't REALLY have that first 2 bytes -KDU */ 120062306a36Sopenharmony_ci hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | 120162306a36Sopenharmony_ci DescEndPacket | DescIntr | (hmp->rx_buf_sz -2)); 120262306a36Sopenharmony_ci } 120362306a36Sopenharmony_ci hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); 120462306a36Sopenharmony_ci hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) { 120762306a36Sopenharmony_ci hmp->tx_skbuff[i] = NULL; 120862306a36Sopenharmony_ci hmp->tx_ring[i].status_n_length = 0; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci /* Mark the last entry of the ring */ 121162306a36Sopenharmony_ci hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); 121262306a36Sopenharmony_ci} 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, 121662306a36Sopenharmony_ci struct net_device *dev) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 121962306a36Sopenharmony_ci unsigned entry; 122062306a36Sopenharmony_ci u16 status; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci /* Ok, now make sure that the queue has space before trying to 122362306a36Sopenharmony_ci add another skbuff. if we return non-zero the scheduler 122462306a36Sopenharmony_ci should interpret this as a queue full and requeue the buffer 122562306a36Sopenharmony_ci for later. 122662306a36Sopenharmony_ci */ 122762306a36Sopenharmony_ci if (hmp->tx_full) { 122862306a36Sopenharmony_ci /* We should NEVER reach this point -KDU */ 122962306a36Sopenharmony_ci printk(KERN_WARNING "%s: Hamachi transmit queue full at slot %d.\n",dev->name, hmp->cur_tx); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci /* Wake the potentially-idle transmit channel. */ 123262306a36Sopenharmony_ci /* If we don't need to read status, DON'T -KDU */ 123362306a36Sopenharmony_ci status=readw(hmp->base + TxStatus); 123462306a36Sopenharmony_ci if( !(status & 0x0001) || (status & 0x0002)) 123562306a36Sopenharmony_ci writew(0x0001, hmp->base + TxCmd); 123662306a36Sopenharmony_ci return NETDEV_TX_BUSY; 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci /* Caution: the write order is important here, set the field 124062306a36Sopenharmony_ci with the "ownership" bits last. */ 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci /* Calculate the next Tx descriptor entry. */ 124362306a36Sopenharmony_ci entry = hmp->cur_tx % TX_RING_SIZE; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci hmp->tx_skbuff[entry] = skb; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci hmp->tx_ring[entry].addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, 124862306a36Sopenharmony_ci skb->data, 124962306a36Sopenharmony_ci skb->len, 125062306a36Sopenharmony_ci DMA_TO_DEVICE)); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* Hmmmm, could probably put a DescIntr on these, but the way 125362306a36Sopenharmony_ci the driver is currently coded makes Tx interrupts unnecessary 125462306a36Sopenharmony_ci since the clearing of the Tx ring is handled by the start_xmit 125562306a36Sopenharmony_ci routine. This organization helps mitigate the interrupts a 125662306a36Sopenharmony_ci bit and probably renders the max_tx_latency param useless. 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci Update: Putting a DescIntr bit on all of the descriptors and 125962306a36Sopenharmony_ci mitigating interrupt frequency with the tx_min_pkt parameter. -KDU 126062306a36Sopenharmony_ci */ 126162306a36Sopenharmony_ci if (entry >= TX_RING_SIZE-1) /* Wrap ring */ 126262306a36Sopenharmony_ci hmp->tx_ring[entry].status_n_length = cpu_to_le32(DescOwn | 126362306a36Sopenharmony_ci DescEndPacket | DescEndRing | DescIntr | skb->len); 126462306a36Sopenharmony_ci else 126562306a36Sopenharmony_ci hmp->tx_ring[entry].status_n_length = cpu_to_le32(DescOwn | 126662306a36Sopenharmony_ci DescEndPacket | DescIntr | skb->len); 126762306a36Sopenharmony_ci hmp->cur_tx++; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci /* Non-x86 Todo: explicitly flush cache lines here. */ 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci /* Wake the potentially-idle transmit channel. */ 127262306a36Sopenharmony_ci /* If we don't need to read status, DON'T -KDU */ 127362306a36Sopenharmony_ci status=readw(hmp->base + TxStatus); 127462306a36Sopenharmony_ci if( !(status & 0x0001) || (status & 0x0002)) 127562306a36Sopenharmony_ci writew(0x0001, hmp->base + TxCmd); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci /* Immediately before returning, let's clear as many entries as we can. */ 127862306a36Sopenharmony_ci hamachi_tx(dev); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci /* We should kick the bottom half here, since we are not accepting 128162306a36Sopenharmony_ci * interrupts with every packet. i.e. realize that Gigabit ethernet 128262306a36Sopenharmony_ci * can transmit faster than ordinary machines can load packets; 128362306a36Sopenharmony_ci * hence, any packet that got put off because we were in the transmit 128462306a36Sopenharmony_ci * routine should IMMEDIATELY get a chance to be re-queued. -KDU 128562306a36Sopenharmony_ci */ 128662306a36Sopenharmony_ci if ((hmp->cur_tx - hmp->dirty_tx) < (TX_RING_SIZE - 4)) 128762306a36Sopenharmony_ci netif_wake_queue(dev); /* Typical path */ 128862306a36Sopenharmony_ci else { 128962306a36Sopenharmony_ci hmp->tx_full = 1; 129062306a36Sopenharmony_ci netif_stop_queue(dev); 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci if (hamachi_debug > 4) { 129462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n", 129562306a36Sopenharmony_ci dev->name, hmp->cur_tx, entry); 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci return NETDEV_TX_OK; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci/* The interrupt handler does all of the Rx thread work and cleans up 130162306a36Sopenharmony_ci after the Tx thread. */ 130262306a36Sopenharmony_cistatic irqreturn_t hamachi_interrupt(int irq, void *dev_instance) 130362306a36Sopenharmony_ci{ 130462306a36Sopenharmony_ci struct net_device *dev = dev_instance; 130562306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 130662306a36Sopenharmony_ci void __iomem *ioaddr = hmp->base; 130762306a36Sopenharmony_ci long boguscnt = max_interrupt_work; 130862306a36Sopenharmony_ci int handled = 0; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci#ifndef final_version /* Can never occur. */ 131162306a36Sopenharmony_ci if (dev == NULL) { 131262306a36Sopenharmony_ci printk (KERN_ERR "hamachi_interrupt(): irq %d for unknown device.\n", irq); 131362306a36Sopenharmony_ci return IRQ_NONE; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci#endif 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci spin_lock(&hmp->lock); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci do { 132062306a36Sopenharmony_ci u32 intr_status = readl(ioaddr + InterruptClear); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (hamachi_debug > 4) 132362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Hamachi interrupt, status %4.4x.\n", 132462306a36Sopenharmony_ci dev->name, intr_status); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci if (intr_status == 0) 132762306a36Sopenharmony_ci break; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci handled = 1; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci if (intr_status & IntrRxDone) 133262306a36Sopenharmony_ci hamachi_rx(dev); 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci if (intr_status & IntrTxDone){ 133562306a36Sopenharmony_ci /* This code should RARELY need to execute. After all, this is 133662306a36Sopenharmony_ci * a gigabit link, it should consume packets as fast as we put 133762306a36Sopenharmony_ci * them in AND we clear the Tx ring in hamachi_start_xmit(). 133862306a36Sopenharmony_ci */ 133962306a36Sopenharmony_ci if (hmp->tx_full){ 134062306a36Sopenharmony_ci for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++){ 134162306a36Sopenharmony_ci int entry = hmp->dirty_tx % TX_RING_SIZE; 134262306a36Sopenharmony_ci struct sk_buff *skb; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) 134562306a36Sopenharmony_ci break; 134662306a36Sopenharmony_ci skb = hmp->tx_skbuff[entry]; 134762306a36Sopenharmony_ci /* Free the original skb. */ 134862306a36Sopenharmony_ci if (skb){ 134962306a36Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 135062306a36Sopenharmony_ci leXX_to_cpu(hmp->tx_ring[entry].addr), 135162306a36Sopenharmony_ci skb->len, 135262306a36Sopenharmony_ci DMA_TO_DEVICE); 135362306a36Sopenharmony_ci dev_consume_skb_irq(skb); 135462306a36Sopenharmony_ci hmp->tx_skbuff[entry] = NULL; 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci hmp->tx_ring[entry].status_n_length = 0; 135762306a36Sopenharmony_ci if (entry >= TX_RING_SIZE-1) 135862306a36Sopenharmony_ci hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= 135962306a36Sopenharmony_ci cpu_to_le32(DescEndRing); 136062306a36Sopenharmony_ci dev->stats.tx_packets++; 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci if (hmp->cur_tx - hmp->dirty_tx < TX_RING_SIZE - 4){ 136362306a36Sopenharmony_ci /* The ring is no longer full */ 136462306a36Sopenharmony_ci hmp->tx_full = 0; 136562306a36Sopenharmony_ci netif_wake_queue(dev); 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci } else { 136862306a36Sopenharmony_ci netif_wake_queue(dev); 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci /* Abnormal error summary/uncommon events handlers. */ 137462306a36Sopenharmony_ci if (intr_status & 137562306a36Sopenharmony_ci (IntrTxPCIFault | IntrTxPCIErr | IntrRxPCIFault | IntrRxPCIErr | 137662306a36Sopenharmony_ci LinkChange | NegotiationChange | StatsMax)) 137762306a36Sopenharmony_ci hamachi_error(dev, intr_status); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci if (--boguscnt < 0) { 138062306a36Sopenharmony_ci printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n", 138162306a36Sopenharmony_ci dev->name, intr_status); 138262306a36Sopenharmony_ci break; 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci } while (1); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (hamachi_debug > 3) 138762306a36Sopenharmony_ci printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", 138862306a36Sopenharmony_ci dev->name, readl(ioaddr + IntrStatus)); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci#ifndef final_version 139162306a36Sopenharmony_ci /* Code that should never be run! Perhaps remove after testing.. */ 139262306a36Sopenharmony_ci { 139362306a36Sopenharmony_ci static int stopit = 10; 139462306a36Sopenharmony_ci if (dev->start == 0 && --stopit < 0) { 139562306a36Sopenharmony_ci printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", 139662306a36Sopenharmony_ci dev->name); 139762306a36Sopenharmony_ci free_irq(irq, dev); 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci#endif 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci spin_unlock(&hmp->lock); 140362306a36Sopenharmony_ci return IRQ_RETVAL(handled); 140462306a36Sopenharmony_ci} 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci/* This routine is logically part of the interrupt handler, but separated 140762306a36Sopenharmony_ci for clarity and better register allocation. */ 140862306a36Sopenharmony_cistatic int hamachi_rx(struct net_device *dev) 140962306a36Sopenharmony_ci{ 141062306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 141162306a36Sopenharmony_ci int entry = hmp->cur_rx % RX_RING_SIZE; 141262306a36Sopenharmony_ci int boguscnt = (hmp->dirty_rx + RX_RING_SIZE) - hmp->cur_rx; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (hamachi_debug > 4) { 141562306a36Sopenharmony_ci printk(KERN_DEBUG " In hamachi_rx(), entry %d status %4.4x.\n", 141662306a36Sopenharmony_ci entry, hmp->rx_ring[entry].status_n_length); 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci /* If EOP is set on the next entry, it's a new packet. Send it up. */ 142062306a36Sopenharmony_ci while (1) { 142162306a36Sopenharmony_ci struct hamachi_desc *desc = &(hmp->rx_ring[entry]); 142262306a36Sopenharmony_ci u32 desc_status = le32_to_cpu(desc->status_n_length); 142362306a36Sopenharmony_ci u16 data_size = desc_status; /* Implicit truncate */ 142462306a36Sopenharmony_ci u8 *buf_addr; 142562306a36Sopenharmony_ci s32 frame_status; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci if (desc_status & DescOwn) 142862306a36Sopenharmony_ci break; 142962306a36Sopenharmony_ci dma_sync_single_for_cpu(&hmp->pci_dev->dev, 143062306a36Sopenharmony_ci leXX_to_cpu(desc->addr), 143162306a36Sopenharmony_ci hmp->rx_buf_sz, DMA_FROM_DEVICE); 143262306a36Sopenharmony_ci buf_addr = (u8 *) hmp->rx_skbuff[entry]->data; 143362306a36Sopenharmony_ci frame_status = get_unaligned_le32(&(buf_addr[data_size - 12])); 143462306a36Sopenharmony_ci if (hamachi_debug > 4) 143562306a36Sopenharmony_ci printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n", 143662306a36Sopenharmony_ci frame_status); 143762306a36Sopenharmony_ci if (--boguscnt < 0) 143862306a36Sopenharmony_ci break; 143962306a36Sopenharmony_ci if ( ! (desc_status & DescEndPacket)) { 144062306a36Sopenharmony_ci printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " 144162306a36Sopenharmony_ci "multiple buffers, entry %#x length %d status %4.4x!\n", 144262306a36Sopenharmony_ci dev->name, hmp->cur_rx, data_size, desc_status); 144362306a36Sopenharmony_ci printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n", 144462306a36Sopenharmony_ci dev->name, desc, &hmp->rx_ring[hmp->cur_rx % RX_RING_SIZE]); 144562306a36Sopenharmony_ci printk(KERN_WARNING "%s: Oversized Ethernet frame -- next status %x/%x last status %x.\n", 144662306a36Sopenharmony_ci dev->name, 144762306a36Sopenharmony_ci le32_to_cpu(hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length) & 0xffff0000, 144862306a36Sopenharmony_ci le32_to_cpu(hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length) & 0x0000ffff, 144962306a36Sopenharmony_ci le32_to_cpu(hmp->rx_ring[(hmp->cur_rx-1) % RX_RING_SIZE].status_n_length)); 145062306a36Sopenharmony_ci dev->stats.rx_length_errors++; 145162306a36Sopenharmony_ci } /* else Omit for prototype errata??? */ 145262306a36Sopenharmony_ci if (frame_status & 0x00380000) { 145362306a36Sopenharmony_ci /* There was an error. */ 145462306a36Sopenharmony_ci if (hamachi_debug > 2) 145562306a36Sopenharmony_ci printk(KERN_DEBUG " hamachi_rx() Rx error was %8.8x.\n", 145662306a36Sopenharmony_ci frame_status); 145762306a36Sopenharmony_ci dev->stats.rx_errors++; 145862306a36Sopenharmony_ci if (frame_status & 0x00600000) 145962306a36Sopenharmony_ci dev->stats.rx_length_errors++; 146062306a36Sopenharmony_ci if (frame_status & 0x00080000) 146162306a36Sopenharmony_ci dev->stats.rx_frame_errors++; 146262306a36Sopenharmony_ci if (frame_status & 0x00100000) 146362306a36Sopenharmony_ci dev->stats.rx_crc_errors++; 146462306a36Sopenharmony_ci if (frame_status < 0) 146562306a36Sopenharmony_ci dev->stats.rx_dropped++; 146662306a36Sopenharmony_ci } else { 146762306a36Sopenharmony_ci struct sk_buff *skb; 146862306a36Sopenharmony_ci /* Omit CRC */ 146962306a36Sopenharmony_ci u16 pkt_len = (frame_status & 0x07ff) - 4; 147062306a36Sopenharmony_ci#ifdef RX_CHECKSUM 147162306a36Sopenharmony_ci u32 pfck = *(u32 *) &buf_addr[data_size - 8]; 147262306a36Sopenharmony_ci#endif 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci#ifndef final_version 147662306a36Sopenharmony_ci if (hamachi_debug > 4) 147762306a36Sopenharmony_ci printk(KERN_DEBUG " hamachi_rx() normal Rx pkt length %d" 147862306a36Sopenharmony_ci " of %d, bogus_cnt %d.\n", 147962306a36Sopenharmony_ci pkt_len, data_size, boguscnt); 148062306a36Sopenharmony_ci if (hamachi_debug > 5) 148162306a36Sopenharmony_ci printk(KERN_DEBUG"%s: rx status %8.8x %8.8x %8.8x %8.8x %8.8x.\n", 148262306a36Sopenharmony_ci dev->name, 148362306a36Sopenharmony_ci *(s32*)&(buf_addr[data_size - 20]), 148462306a36Sopenharmony_ci *(s32*)&(buf_addr[data_size - 16]), 148562306a36Sopenharmony_ci *(s32*)&(buf_addr[data_size - 12]), 148662306a36Sopenharmony_ci *(s32*)&(buf_addr[data_size - 8]), 148762306a36Sopenharmony_ci *(s32*)&(buf_addr[data_size - 4])); 148862306a36Sopenharmony_ci#endif 148962306a36Sopenharmony_ci /* Check if the packet is long enough to accept without copying 149062306a36Sopenharmony_ci to a minimally-sized skbuff. */ 149162306a36Sopenharmony_ci if (pkt_len < rx_copybreak && 149262306a36Sopenharmony_ci (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { 149362306a36Sopenharmony_ci#ifdef RX_CHECKSUM 149462306a36Sopenharmony_ci printk(KERN_ERR "%s: rx_copybreak non-zero " 149562306a36Sopenharmony_ci "not good with RX_CHECKSUM\n", dev->name); 149662306a36Sopenharmony_ci#endif 149762306a36Sopenharmony_ci skb_reserve(skb, 2); /* 16 byte align the IP header */ 149862306a36Sopenharmony_ci dma_sync_single_for_cpu(&hmp->pci_dev->dev, 149962306a36Sopenharmony_ci leXX_to_cpu(hmp->rx_ring[entry].addr), 150062306a36Sopenharmony_ci hmp->rx_buf_sz, 150162306a36Sopenharmony_ci DMA_FROM_DEVICE); 150262306a36Sopenharmony_ci /* Call copy + cksum if available. */ 150362306a36Sopenharmony_ci#if 1 || USE_IP_COPYSUM 150462306a36Sopenharmony_ci skb_copy_to_linear_data(skb, 150562306a36Sopenharmony_ci hmp->rx_skbuff[entry]->data, pkt_len); 150662306a36Sopenharmony_ci skb_put(skb, pkt_len); 150762306a36Sopenharmony_ci#else 150862306a36Sopenharmony_ci skb_put_data(skb, hmp->rx_ring_dma 150962306a36Sopenharmony_ci + entry*sizeof(*desc), pkt_len); 151062306a36Sopenharmony_ci#endif 151162306a36Sopenharmony_ci dma_sync_single_for_device(&hmp->pci_dev->dev, 151262306a36Sopenharmony_ci leXX_to_cpu(hmp->rx_ring[entry].addr), 151362306a36Sopenharmony_ci hmp->rx_buf_sz, 151462306a36Sopenharmony_ci DMA_FROM_DEVICE); 151562306a36Sopenharmony_ci } else { 151662306a36Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 151762306a36Sopenharmony_ci leXX_to_cpu(hmp->rx_ring[entry].addr), 151862306a36Sopenharmony_ci hmp->rx_buf_sz, 151962306a36Sopenharmony_ci DMA_FROM_DEVICE); 152062306a36Sopenharmony_ci skb_put(skb = hmp->rx_skbuff[entry], pkt_len); 152162306a36Sopenharmony_ci hmp->rx_skbuff[entry] = NULL; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci#ifdef RX_CHECKSUM 152762306a36Sopenharmony_ci /* TCP or UDP on ipv4, DIX encoding */ 152862306a36Sopenharmony_ci if (pfck>>24 == 0x91 || pfck>>24 == 0x51) { 152962306a36Sopenharmony_ci struct iphdr *ih = (struct iphdr *) skb->data; 153062306a36Sopenharmony_ci /* Check that IP packet is at least 46 bytes, otherwise, 153162306a36Sopenharmony_ci * there may be pad bytes included in the hardware checksum. 153262306a36Sopenharmony_ci * This wouldn't happen if everyone padded with 0. 153362306a36Sopenharmony_ci */ 153462306a36Sopenharmony_ci if (ntohs(ih->tot_len) >= 46){ 153562306a36Sopenharmony_ci /* don't worry about frags */ 153662306a36Sopenharmony_ci if (!(ih->frag_off & cpu_to_be16(IP_MF|IP_OFFSET))) { 153762306a36Sopenharmony_ci u32 inv = *(u32 *) &buf_addr[data_size - 16]; 153862306a36Sopenharmony_ci u32 *p = (u32 *) &buf_addr[data_size - 20]; 153962306a36Sopenharmony_ci register u32 crc, p_r, p_r1; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci if (inv & 4) { 154262306a36Sopenharmony_ci inv &= ~4; 154362306a36Sopenharmony_ci --p; 154462306a36Sopenharmony_ci } 154562306a36Sopenharmony_ci p_r = *p; 154662306a36Sopenharmony_ci p_r1 = *(p-1); 154762306a36Sopenharmony_ci switch (inv) { 154862306a36Sopenharmony_ci case 0: 154962306a36Sopenharmony_ci crc = (p_r & 0xffff) + (p_r >> 16); 155062306a36Sopenharmony_ci break; 155162306a36Sopenharmony_ci case 1: 155262306a36Sopenharmony_ci crc = (p_r >> 16) + (p_r & 0xffff) 155362306a36Sopenharmony_ci + (p_r1 >> 16 & 0xff00); 155462306a36Sopenharmony_ci break; 155562306a36Sopenharmony_ci case 2: 155662306a36Sopenharmony_ci crc = p_r + (p_r1 >> 16); 155762306a36Sopenharmony_ci break; 155862306a36Sopenharmony_ci case 3: 155962306a36Sopenharmony_ci crc = p_r + (p_r1 & 0xff00) + (p_r1 >> 16); 156062306a36Sopenharmony_ci break; 156162306a36Sopenharmony_ci default: /*NOTREACHED*/ crc = 0; 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci if (crc & 0xffff0000) { 156462306a36Sopenharmony_ci crc &= 0xffff; 156562306a36Sopenharmony_ci ++crc; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci /* tcp/udp will add in pseudo */ 156862306a36Sopenharmony_ci skb->csum = ntohs(pfck & 0xffff); 156962306a36Sopenharmony_ci if (skb->csum > crc) 157062306a36Sopenharmony_ci skb->csum -= crc; 157162306a36Sopenharmony_ci else 157262306a36Sopenharmony_ci skb->csum += (~crc & 0xffff); 157362306a36Sopenharmony_ci /* 157462306a36Sopenharmony_ci * could do the pseudo myself and return 157562306a36Sopenharmony_ci * CHECKSUM_UNNECESSARY 157662306a36Sopenharmony_ci */ 157762306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci } 158162306a36Sopenharmony_ci#endif /* RX_CHECKSUM */ 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci netif_rx(skb); 158462306a36Sopenharmony_ci dev->stats.rx_packets++; 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci entry = (++hmp->cur_rx) % RX_RING_SIZE; 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci /* Refill the Rx ring buffers. */ 159062306a36Sopenharmony_ci for (; hmp->cur_rx - hmp->dirty_rx > 0; hmp->dirty_rx++) { 159162306a36Sopenharmony_ci struct hamachi_desc *desc; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci entry = hmp->dirty_rx % RX_RING_SIZE; 159462306a36Sopenharmony_ci desc = &(hmp->rx_ring[entry]); 159562306a36Sopenharmony_ci if (hmp->rx_skbuff[entry] == NULL) { 159662306a36Sopenharmony_ci struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz + 2); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci hmp->rx_skbuff[entry] = skb; 159962306a36Sopenharmony_ci if (skb == NULL) 160062306a36Sopenharmony_ci break; /* Better luck next round. */ 160162306a36Sopenharmony_ci skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ 160262306a36Sopenharmony_ci desc->addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, 160362306a36Sopenharmony_ci skb->data, 160462306a36Sopenharmony_ci hmp->rx_buf_sz, 160562306a36Sopenharmony_ci DMA_FROM_DEVICE)); 160662306a36Sopenharmony_ci } 160762306a36Sopenharmony_ci desc->status_n_length = cpu_to_le32(hmp->rx_buf_sz); 160862306a36Sopenharmony_ci if (entry >= RX_RING_SIZE-1) 160962306a36Sopenharmony_ci desc->status_n_length |= cpu_to_le32(DescOwn | 161062306a36Sopenharmony_ci DescEndPacket | DescEndRing | DescIntr); 161162306a36Sopenharmony_ci else 161262306a36Sopenharmony_ci desc->status_n_length |= cpu_to_le32(DescOwn | 161362306a36Sopenharmony_ci DescEndPacket | DescIntr); 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci /* Restart Rx engine if stopped. */ 161762306a36Sopenharmony_ci /* If we don't need to check status, don't. -KDU */ 161862306a36Sopenharmony_ci if (readw(hmp->base + RxStatus) & 0x0002) 161962306a36Sopenharmony_ci writew(0x0001, hmp->base + RxCmd); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci return 0; 162262306a36Sopenharmony_ci} 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci/* This is more properly named "uncommon interrupt events", as it covers more 162562306a36Sopenharmony_ci than just errors. */ 162662306a36Sopenharmony_cistatic void hamachi_error(struct net_device *dev, int intr_status) 162762306a36Sopenharmony_ci{ 162862306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 162962306a36Sopenharmony_ci void __iomem *ioaddr = hmp->base; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci if (intr_status & (LinkChange|NegotiationChange)) { 163262306a36Sopenharmony_ci if (hamachi_debug > 1) 163362306a36Sopenharmony_ci printk(KERN_INFO "%s: Link changed: AutoNegotiation Ctrl" 163462306a36Sopenharmony_ci " %4.4x, Status %4.4x %4.4x Intr status %4.4x.\n", 163562306a36Sopenharmony_ci dev->name, readw(ioaddr + 0x0E0), readw(ioaddr + 0x0E2), 163662306a36Sopenharmony_ci readw(ioaddr + ANLinkPartnerAbility), 163762306a36Sopenharmony_ci readl(ioaddr + IntrStatus)); 163862306a36Sopenharmony_ci if (readw(ioaddr + ANStatus) & 0x20) 163962306a36Sopenharmony_ci writeb(0x01, ioaddr + LEDCtrl); 164062306a36Sopenharmony_ci else 164162306a36Sopenharmony_ci writeb(0x03, ioaddr + LEDCtrl); 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci if (intr_status & StatsMax) { 164462306a36Sopenharmony_ci hamachi_get_stats(dev); 164562306a36Sopenharmony_ci /* Read the overflow bits to clear. */ 164662306a36Sopenharmony_ci readl(ioaddr + 0x370); 164762306a36Sopenharmony_ci readl(ioaddr + 0x3F0); 164862306a36Sopenharmony_ci } 164962306a36Sopenharmony_ci if ((intr_status & ~(LinkChange|StatsMax|NegotiationChange|IntrRxDone|IntrTxDone)) && 165062306a36Sopenharmony_ci hamachi_debug) 165162306a36Sopenharmony_ci printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", 165262306a36Sopenharmony_ci dev->name, intr_status); 165362306a36Sopenharmony_ci /* Hmmmmm, it's not clear how to recover from PCI faults. */ 165462306a36Sopenharmony_ci if (intr_status & (IntrTxPCIErr | IntrTxPCIFault)) 165562306a36Sopenharmony_ci dev->stats.tx_fifo_errors++; 165662306a36Sopenharmony_ci if (intr_status & (IntrRxPCIErr | IntrRxPCIFault)) 165762306a36Sopenharmony_ci dev->stats.rx_fifo_errors++; 165862306a36Sopenharmony_ci} 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_cistatic int hamachi_close(struct net_device *dev) 166162306a36Sopenharmony_ci{ 166262306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 166362306a36Sopenharmony_ci void __iomem *ioaddr = hmp->base; 166462306a36Sopenharmony_ci struct sk_buff *skb; 166562306a36Sopenharmony_ci int i; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci netif_stop_queue(dev); 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci if (hamachi_debug > 1) { 167062306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n", 167162306a36Sopenharmony_ci dev->name, readw(ioaddr + TxStatus), 167262306a36Sopenharmony_ci readw(ioaddr + RxStatus), readl(ioaddr + IntrStatus)); 167362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", 167462306a36Sopenharmony_ci dev->name, hmp->cur_tx, hmp->dirty_tx, hmp->cur_rx, hmp->dirty_rx); 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci /* Disable interrupts by clearing the interrupt mask. */ 167862306a36Sopenharmony_ci writel(0x0000, ioaddr + InterruptEnable); 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci /* Stop the chip's Tx and Rx processes. */ 168162306a36Sopenharmony_ci writel(2, ioaddr + RxCmd); 168262306a36Sopenharmony_ci writew(2, ioaddr + TxCmd); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci#ifdef __i386__ 168562306a36Sopenharmony_ci if (hamachi_debug > 2) { 168662306a36Sopenharmony_ci printk(KERN_DEBUG " Tx ring at %8.8x:\n", 168762306a36Sopenharmony_ci (int)hmp->tx_ring_dma); 168862306a36Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) 168962306a36Sopenharmony_ci printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x.\n", 169062306a36Sopenharmony_ci readl(ioaddr + TxCurPtr) == (long)&hmp->tx_ring[i] ? '>' : ' ', 169162306a36Sopenharmony_ci i, hmp->tx_ring[i].status_n_length, hmp->tx_ring[i].addr); 169262306a36Sopenharmony_ci printk(KERN_DEBUG " Rx ring %8.8x:\n", 169362306a36Sopenharmony_ci (int)hmp->rx_ring_dma); 169462306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 169562306a36Sopenharmony_ci printk(KERN_DEBUG " %c #%d desc. %4.4x %8.8x\n", 169662306a36Sopenharmony_ci readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ', 169762306a36Sopenharmony_ci i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr); 169862306a36Sopenharmony_ci if (hamachi_debug > 6) { 169962306a36Sopenharmony_ci if (*(u8*)hmp->rx_skbuff[i]->data != 0x69) { 170062306a36Sopenharmony_ci u16 *addr = (u16 *) 170162306a36Sopenharmony_ci hmp->rx_skbuff[i]->data; 170262306a36Sopenharmony_ci int j; 170362306a36Sopenharmony_ci printk(KERN_DEBUG "Addr: "); 170462306a36Sopenharmony_ci for (j = 0; j < 0x50; j++) 170562306a36Sopenharmony_ci printk(" %4.4x", addr[j]); 170662306a36Sopenharmony_ci printk("\n"); 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci } 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci } 171162306a36Sopenharmony_ci#endif /* __i386__ debugging only */ 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci free_irq(hmp->pci_dev->irq, dev); 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci del_timer_sync(&hmp->timer); 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci /* Free all the skbuffs in the Rx queue. */ 171862306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 171962306a36Sopenharmony_ci skb = hmp->rx_skbuff[i]; 172062306a36Sopenharmony_ci hmp->rx_ring[i].status_n_length = 0; 172162306a36Sopenharmony_ci if (skb) { 172262306a36Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 172362306a36Sopenharmony_ci leXX_to_cpu(hmp->rx_ring[i].addr), 172462306a36Sopenharmony_ci hmp->rx_buf_sz, DMA_FROM_DEVICE); 172562306a36Sopenharmony_ci dev_kfree_skb(skb); 172662306a36Sopenharmony_ci hmp->rx_skbuff[i] = NULL; 172762306a36Sopenharmony_ci } 172862306a36Sopenharmony_ci hmp->rx_ring[i].addr = cpu_to_leXX(0xBADF00D0); /* An invalid address. */ 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) { 173162306a36Sopenharmony_ci skb = hmp->tx_skbuff[i]; 173262306a36Sopenharmony_ci if (skb) { 173362306a36Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 173462306a36Sopenharmony_ci leXX_to_cpu(hmp->tx_ring[i].addr), 173562306a36Sopenharmony_ci skb->len, DMA_TO_DEVICE); 173662306a36Sopenharmony_ci dev_kfree_skb(skb); 173762306a36Sopenharmony_ci hmp->tx_skbuff[i] = NULL; 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci } 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci writeb(0x00, ioaddr + LEDCtrl); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci return 0; 174462306a36Sopenharmony_ci} 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_cistatic struct net_device_stats *hamachi_get_stats(struct net_device *dev) 174762306a36Sopenharmony_ci{ 174862306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 174962306a36Sopenharmony_ci void __iomem *ioaddr = hmp->base; 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci /* We should lock this segment of code for SMP eventually, although 175262306a36Sopenharmony_ci the vulnerability window is very small and statistics are 175362306a36Sopenharmony_ci non-critical. */ 175462306a36Sopenharmony_ci /* Ok, what goes here? This appears to be stuck at 21 packets 175562306a36Sopenharmony_ci according to ifconfig. It does get incremented in hamachi_tx(), 175662306a36Sopenharmony_ci so I think I'll comment it out here and see if better things 175762306a36Sopenharmony_ci happen. 175862306a36Sopenharmony_ci */ 175962306a36Sopenharmony_ci /* dev->stats.tx_packets = readl(ioaddr + 0x000); */ 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci /* Total Uni+Brd+Multi */ 176262306a36Sopenharmony_ci dev->stats.rx_bytes = readl(ioaddr + 0x330); 176362306a36Sopenharmony_ci /* Total Uni+Brd+Multi */ 176462306a36Sopenharmony_ci dev->stats.tx_bytes = readl(ioaddr + 0x3B0); 176562306a36Sopenharmony_ci /* Multicast Rx */ 176662306a36Sopenharmony_ci dev->stats.multicast = readl(ioaddr + 0x320); 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci /* Over+Undersized */ 176962306a36Sopenharmony_ci dev->stats.rx_length_errors = readl(ioaddr + 0x368); 177062306a36Sopenharmony_ci /* Jabber */ 177162306a36Sopenharmony_ci dev->stats.rx_over_errors = readl(ioaddr + 0x35C); 177262306a36Sopenharmony_ci /* Jabber */ 177362306a36Sopenharmony_ci dev->stats.rx_crc_errors = readl(ioaddr + 0x360); 177462306a36Sopenharmony_ci /* Symbol Errs */ 177562306a36Sopenharmony_ci dev->stats.rx_frame_errors = readl(ioaddr + 0x364); 177662306a36Sopenharmony_ci /* Dropped */ 177762306a36Sopenharmony_ci dev->stats.rx_missed_errors = readl(ioaddr + 0x36C); 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci return &dev->stats; 178062306a36Sopenharmony_ci} 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_cistatic void set_rx_mode(struct net_device *dev) 178362306a36Sopenharmony_ci{ 178462306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 178562306a36Sopenharmony_ci void __iomem *ioaddr = hmp->base; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ 178862306a36Sopenharmony_ci writew(0x000F, ioaddr + AddrMode); 178962306a36Sopenharmony_ci } else if ((netdev_mc_count(dev) > 63) || (dev->flags & IFF_ALLMULTI)) { 179062306a36Sopenharmony_ci /* Too many to match, or accept all multicasts. */ 179162306a36Sopenharmony_ci writew(0x000B, ioaddr + AddrMode); 179262306a36Sopenharmony_ci } else if (!netdev_mc_empty(dev)) { /* Must use the CAM filter. */ 179362306a36Sopenharmony_ci struct netdev_hw_addr *ha; 179462306a36Sopenharmony_ci int i = 0; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 179762306a36Sopenharmony_ci writel(*(u32 *)(ha->addr), ioaddr + 0x100 + i*8); 179862306a36Sopenharmony_ci writel(0x20000 | (*(u16 *)&ha->addr[4]), 179962306a36Sopenharmony_ci ioaddr + 0x104 + i*8); 180062306a36Sopenharmony_ci i++; 180162306a36Sopenharmony_ci } 180262306a36Sopenharmony_ci /* Clear remaining entries. */ 180362306a36Sopenharmony_ci for (; i < 64; i++) 180462306a36Sopenharmony_ci writel(0, ioaddr + 0x104 + i*8); 180562306a36Sopenharmony_ci writew(0x0003, ioaddr + AddrMode); 180662306a36Sopenharmony_ci } else { /* Normal, unicast/broadcast-only mode. */ 180762306a36Sopenharmony_ci writew(0x0001, ioaddr + AddrMode); 180862306a36Sopenharmony_ci } 180962306a36Sopenharmony_ci} 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_cistatic int check_if_running(struct net_device *dev) 181262306a36Sopenharmony_ci{ 181362306a36Sopenharmony_ci if (!netif_running(dev)) 181462306a36Sopenharmony_ci return -EINVAL; 181562306a36Sopenharmony_ci return 0; 181662306a36Sopenharmony_ci} 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_cistatic void hamachi_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 181962306a36Sopenharmony_ci{ 182062306a36Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci strscpy(info->driver, DRV_NAME, sizeof(info->driver)); 182362306a36Sopenharmony_ci strscpy(info->version, DRV_VERSION, sizeof(info->version)); 182462306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_cistatic int hamachi_get_link_ksettings(struct net_device *dev, 182862306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 182962306a36Sopenharmony_ci{ 183062306a36Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 183162306a36Sopenharmony_ci spin_lock_irq(&np->lock); 183262306a36Sopenharmony_ci mii_ethtool_get_link_ksettings(&np->mii_if, cmd); 183362306a36Sopenharmony_ci spin_unlock_irq(&np->lock); 183462306a36Sopenharmony_ci return 0; 183562306a36Sopenharmony_ci} 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_cistatic int hamachi_set_link_ksettings(struct net_device *dev, 183862306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 183962306a36Sopenharmony_ci{ 184062306a36Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 184162306a36Sopenharmony_ci int res; 184262306a36Sopenharmony_ci spin_lock_irq(&np->lock); 184362306a36Sopenharmony_ci res = mii_ethtool_set_link_ksettings(&np->mii_if, cmd); 184462306a36Sopenharmony_ci spin_unlock_irq(&np->lock); 184562306a36Sopenharmony_ci return res; 184662306a36Sopenharmony_ci} 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_cistatic int hamachi_nway_reset(struct net_device *dev) 184962306a36Sopenharmony_ci{ 185062306a36Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 185162306a36Sopenharmony_ci return mii_nway_restart(&np->mii_if); 185262306a36Sopenharmony_ci} 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_cistatic u32 hamachi_get_link(struct net_device *dev) 185562306a36Sopenharmony_ci{ 185662306a36Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 185762306a36Sopenharmony_ci return mii_link_ok(&np->mii_if); 185862306a36Sopenharmony_ci} 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_cistatic const struct ethtool_ops ethtool_ops = { 186162306a36Sopenharmony_ci .begin = check_if_running, 186262306a36Sopenharmony_ci .get_drvinfo = hamachi_get_drvinfo, 186362306a36Sopenharmony_ci .nway_reset = hamachi_nway_reset, 186462306a36Sopenharmony_ci .get_link = hamachi_get_link, 186562306a36Sopenharmony_ci .get_link_ksettings = hamachi_get_link_ksettings, 186662306a36Sopenharmony_ci .set_link_ksettings = hamachi_set_link_ksettings, 186762306a36Sopenharmony_ci}; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_cistatic const struct ethtool_ops ethtool_ops_no_mii = { 187062306a36Sopenharmony_ci .begin = check_if_running, 187162306a36Sopenharmony_ci .get_drvinfo = hamachi_get_drvinfo, 187262306a36Sopenharmony_ci}; 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_ci/* private ioctl: set rx,tx intr params */ 187562306a36Sopenharmony_cistatic int hamachi_siocdevprivate(struct net_device *dev, struct ifreq *rq, 187662306a36Sopenharmony_ci void __user *data, int cmd) 187762306a36Sopenharmony_ci{ 187862306a36Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 187962306a36Sopenharmony_ci u32 *d = (u32 *)&rq->ifr_ifru; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci if (!netif_running(dev)) 188262306a36Sopenharmony_ci return -EINVAL; 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci if (cmd != SIOCDEVPRIVATE + 3) 188562306a36Sopenharmony_ci return -EOPNOTSUPP; 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci /* Should add this check here or an ordinary user can do nasty 188862306a36Sopenharmony_ci * things. -KDU 188962306a36Sopenharmony_ci * 189062306a36Sopenharmony_ci * TODO: Shut down the Rx and Tx engines while doing this. 189162306a36Sopenharmony_ci */ 189262306a36Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 189362306a36Sopenharmony_ci return -EPERM; 189462306a36Sopenharmony_ci writel(d[0], np->base + TxIntrCtrl); 189562306a36Sopenharmony_ci writel(d[1], np->base + RxIntrCtrl); 189662306a36Sopenharmony_ci printk(KERN_NOTICE "%s: tx %08x, rx %08x intr\n", dev->name, 189762306a36Sopenharmony_ci (u32)readl(np->base + TxIntrCtrl), 189862306a36Sopenharmony_ci (u32)readl(np->base + RxIntrCtrl)); 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci return 0; 190162306a36Sopenharmony_ci} 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_cistatic int hamachi_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 190462306a36Sopenharmony_ci{ 190562306a36Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 190662306a36Sopenharmony_ci struct mii_ioctl_data *data = if_mii(rq); 190762306a36Sopenharmony_ci int rc; 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci if (!netif_running(dev)) 191062306a36Sopenharmony_ci return -EINVAL; 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci spin_lock_irq(&np->lock); 191362306a36Sopenharmony_ci rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL); 191462306a36Sopenharmony_ci spin_unlock_irq(&np->lock); 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci return rc; 191762306a36Sopenharmony_ci} 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_cistatic void hamachi_remove_one(struct pci_dev *pdev) 192162306a36Sopenharmony_ci{ 192262306a36Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci if (dev) { 192562306a36Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, hmp->rx_ring, 192862306a36Sopenharmony_ci hmp->rx_ring_dma); 192962306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, hmp->tx_ring, 193062306a36Sopenharmony_ci hmp->tx_ring_dma); 193162306a36Sopenharmony_ci unregister_netdev(dev); 193262306a36Sopenharmony_ci iounmap(hmp->base); 193362306a36Sopenharmony_ci free_netdev(dev); 193462306a36Sopenharmony_ci pci_release_regions(pdev); 193562306a36Sopenharmony_ci } 193662306a36Sopenharmony_ci} 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_cistatic const struct pci_device_id hamachi_pci_tbl[] = { 193962306a36Sopenharmony_ci { 0x1318, 0x0911, PCI_ANY_ID, PCI_ANY_ID, }, 194062306a36Sopenharmony_ci { 0, } 194162306a36Sopenharmony_ci}; 194262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hamachi_pci_tbl); 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_cistatic struct pci_driver hamachi_driver = { 194562306a36Sopenharmony_ci .name = DRV_NAME, 194662306a36Sopenharmony_ci .id_table = hamachi_pci_tbl, 194762306a36Sopenharmony_ci .probe = hamachi_init_one, 194862306a36Sopenharmony_ci .remove = hamachi_remove_one, 194962306a36Sopenharmony_ci}; 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_cistatic int __init hamachi_init (void) 195262306a36Sopenharmony_ci{ 195362306a36Sopenharmony_ci/* when a module, this is printed whether or not devices are found in probe */ 195462306a36Sopenharmony_ci#ifdef MODULE 195562306a36Sopenharmony_ci printk(version); 195662306a36Sopenharmony_ci#endif 195762306a36Sopenharmony_ci return pci_register_driver(&hamachi_driver); 195862306a36Sopenharmony_ci} 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_cistatic void __exit hamachi_exit (void) 196162306a36Sopenharmony_ci{ 196262306a36Sopenharmony_ci pci_unregister_driver(&hamachi_driver); 196362306a36Sopenharmony_ci} 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_cimodule_init(hamachi_init); 196762306a36Sopenharmony_cimodule_exit(hamachi_exit); 1968