18c2ecf20Sopenharmony_ci/* hamachi.c: A Packet Engines GNIC-II Gigabit Ethernet driver for Linux. */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Written 1998-2000 by Donald Becker. 48c2ecf20Sopenharmony_ci Updates 2000 by Keith Underwood. 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci This software may be used and distributed according to the terms of 78c2ecf20Sopenharmony_ci the GNU General Public License (GPL), incorporated herein by reference. 88c2ecf20Sopenharmony_ci Drivers based on or derived from this code fall under the GPL and must 98c2ecf20Sopenharmony_ci retain the authorship, copyright and license notice. This file is not 108c2ecf20Sopenharmony_ci a complete program and may only be used when the entire operating 118c2ecf20Sopenharmony_ci system is licensed under the GPL. 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci The author may be reached as becker@scyld.com, or C/O 148c2ecf20Sopenharmony_ci Scyld Computing Corporation 158c2ecf20Sopenharmony_ci 410 Severn Ave., Suite 210 168c2ecf20Sopenharmony_ci Annapolis MD 21403 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci This driver is for the Packet Engines GNIC-II PCI Gigabit Ethernet 198c2ecf20Sopenharmony_ci adapter. 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci Support and updates available at 228c2ecf20Sopenharmony_ci http://www.scyld.com/network/hamachi.html 238c2ecf20Sopenharmony_ci [link no longer provides useful info -jgarzik] 248c2ecf20Sopenharmony_ci or 258c2ecf20Sopenharmony_ci http://www.parl.clemson.edu/~keithu/hamachi.html 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci*/ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define DRV_NAME "hamachi" 308c2ecf20Sopenharmony_ci#define DRV_VERSION "2.1" 318c2ecf20Sopenharmony_ci#define DRV_RELDATE "Sept 11, 2006" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* A few user-configurable values. */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ 378c2ecf20Sopenharmony_ci#define final_version 388c2ecf20Sopenharmony_ci#define hamachi_debug debug 398c2ecf20Sopenharmony_ci/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ 408c2ecf20Sopenharmony_cistatic int max_interrupt_work = 40; 418c2ecf20Sopenharmony_cistatic int mtu; 428c2ecf20Sopenharmony_ci/* Default values selected by testing on a dual processor PIII-450 */ 438c2ecf20Sopenharmony_ci/* These six interrupt control parameters may be set directly when loading the 448c2ecf20Sopenharmony_ci * module, or through the rx_params and tx_params variables 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_cistatic int max_rx_latency = 0x11; 478c2ecf20Sopenharmony_cistatic int max_rx_gap = 0x05; 488c2ecf20Sopenharmony_cistatic int min_rx_pkt = 0x18; 498c2ecf20Sopenharmony_cistatic int max_tx_latency = 0x00; 508c2ecf20Sopenharmony_cistatic int max_tx_gap = 0x00; 518c2ecf20Sopenharmony_cistatic int min_tx_pkt = 0x30; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* Set the copy breakpoint for the copy-only-tiny-frames scheme. 548c2ecf20Sopenharmony_ci -Setting to > 1518 causes all frames to be copied 558c2ecf20Sopenharmony_ci -Setting to 0 disables copies 568c2ecf20Sopenharmony_ci*/ 578c2ecf20Sopenharmony_cistatic int rx_copybreak; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* An override for the hardware detection of bus width. 608c2ecf20Sopenharmony_ci Set to 1 to force 32 bit PCI bus detection. Set to 4 to force 64 bit. 618c2ecf20Sopenharmony_ci Add 2 to disable parity detection. 628c2ecf20Sopenharmony_ci*/ 638c2ecf20Sopenharmony_cistatic int force32; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* Used to pass the media type, etc. 678c2ecf20Sopenharmony_ci These exist for driver interoperability. 688c2ecf20Sopenharmony_ci No media types are currently defined. 698c2ecf20Sopenharmony_ci - The lower 4 bits are reserved for the media type. 708c2ecf20Sopenharmony_ci - The next three bits may be set to one of the following: 718c2ecf20Sopenharmony_ci 0x00000000 : Autodetect PCI bus 728c2ecf20Sopenharmony_ci 0x00000010 : Force 32 bit PCI bus 738c2ecf20Sopenharmony_ci 0x00000020 : Disable parity detection 748c2ecf20Sopenharmony_ci 0x00000040 : Force 64 bit PCI bus 758c2ecf20Sopenharmony_ci Default is autodetect 768c2ecf20Sopenharmony_ci - The next bit can be used to force half-duplex. This is a bad 778c2ecf20Sopenharmony_ci idea since no known implementations implement half-duplex, and, 788c2ecf20Sopenharmony_ci in general, half-duplex for gigabit ethernet is a bad idea. 798c2ecf20Sopenharmony_ci 0x00000080 : Force half-duplex 808c2ecf20Sopenharmony_ci Default is full-duplex. 818c2ecf20Sopenharmony_ci - In the original driver, the ninth bit could be used to force 828c2ecf20Sopenharmony_ci full-duplex. Maintain that for compatibility 838c2ecf20Sopenharmony_ci 0x00000200 : Force full-duplex 848c2ecf20Sopenharmony_ci*/ 858c2ecf20Sopenharmony_ci#define MAX_UNITS 8 /* More are supported, limit only on options */ 868c2ecf20Sopenharmony_cistatic int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; 878c2ecf20Sopenharmony_cistatic int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; 888c2ecf20Sopenharmony_ci/* The Hamachi chipset supports 3 parameters each for Rx and Tx 898c2ecf20Sopenharmony_ci * interruput management. Parameters will be loaded as specified into 908c2ecf20Sopenharmony_ci * the TxIntControl and RxIntControl registers. 918c2ecf20Sopenharmony_ci * 928c2ecf20Sopenharmony_ci * The registers are arranged as follows: 938c2ecf20Sopenharmony_ci * 23 - 16 15 - 8 7 - 0 948c2ecf20Sopenharmony_ci * _________________________________ 958c2ecf20Sopenharmony_ci * | min_pkt | max_gap | max_latency | 968c2ecf20Sopenharmony_ci * --------------------------------- 978c2ecf20Sopenharmony_ci * min_pkt : The minimum number of packets processed between 988c2ecf20Sopenharmony_ci * interrupts. 998c2ecf20Sopenharmony_ci * max_gap : The maximum inter-packet gap in units of 8.192 us 1008c2ecf20Sopenharmony_ci * max_latency : The absolute time between interrupts in units of 8.192 us 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_cistatic int rx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; 1048c2ecf20Sopenharmony_cistatic int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Operational parameters that are set at compile time. */ 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci/* Keep the ring sizes a power of two for compile efficiency. 1098c2ecf20Sopenharmony_ci The compiler will convert <unsigned>'%'<2^N> into a bit mask. 1108c2ecf20Sopenharmony_ci Making the Tx ring too large decreases the effectiveness of channel 1118c2ecf20Sopenharmony_ci bonding and packet priority. 1128c2ecf20Sopenharmony_ci There are no ill effects from too-large receive rings, except for 1138c2ecf20Sopenharmony_ci excessive memory usage */ 1148c2ecf20Sopenharmony_ci/* Empirically it appears that the Tx ring needs to be a little bigger 1158c2ecf20Sopenharmony_ci for these Gbit adapters or you get into an overrun condition really 1168c2ecf20Sopenharmony_ci easily. Also, things appear to work a bit better in back-to-back 1178c2ecf20Sopenharmony_ci configurations if the Rx ring is 8 times the size of the Tx ring 1188c2ecf20Sopenharmony_ci*/ 1198c2ecf20Sopenharmony_ci#define TX_RING_SIZE 64 1208c2ecf20Sopenharmony_ci#define RX_RING_SIZE 512 1218c2ecf20Sopenharmony_ci#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct hamachi_desc) 1228c2ecf20Sopenharmony_ci#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct hamachi_desc) 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* 1258c2ecf20Sopenharmony_ci * Enable netdev_ioctl. Added interrupt coalescing parameter adjustment. 1268c2ecf20Sopenharmony_ci * 2/19/99 Pete Wyckoff <wyckoff@ca.sandia.gov> 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* play with 64-bit addrlen; seems to be a teensy bit slower --pw */ 1308c2ecf20Sopenharmony_ci/* #define ADDRLEN 64 */ 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* 1338c2ecf20Sopenharmony_ci * RX_CHECKSUM turns on card-generated receive checksum generation for 1348c2ecf20Sopenharmony_ci * TCP and UDP packets. Otherwise the upper layers do the calculation. 1358c2ecf20Sopenharmony_ci * 3/10/1999 Pete Wyckoff <wyckoff@ca.sandia.gov> 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ci#define RX_CHECKSUM 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* Operational parameters that usually are not changed. */ 1408c2ecf20Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */ 1418c2ecf20Sopenharmony_ci#define TX_TIMEOUT (5*HZ) 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci#include <linux/capability.h> 1448c2ecf20Sopenharmony_ci#include <linux/module.h> 1458c2ecf20Sopenharmony_ci#include <linux/kernel.h> 1468c2ecf20Sopenharmony_ci#include <linux/string.h> 1478c2ecf20Sopenharmony_ci#include <linux/timer.h> 1488c2ecf20Sopenharmony_ci#include <linux/time.h> 1498c2ecf20Sopenharmony_ci#include <linux/errno.h> 1508c2ecf20Sopenharmony_ci#include <linux/ioport.h> 1518c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 1528c2ecf20Sopenharmony_ci#include <linux/pci.h> 1538c2ecf20Sopenharmony_ci#include <linux/init.h> 1548c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 1558c2ecf20Sopenharmony_ci#include <linux/mii.h> 1568c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 1578c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 1588c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 1598c2ecf20Sopenharmony_ci#include <linux/ip.h> 1608c2ecf20Sopenharmony_ci#include <linux/delay.h> 1618c2ecf20Sopenharmony_ci#include <linux/bitops.h> 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 1648c2ecf20Sopenharmony_ci#include <asm/processor.h> /* Processor type for cache alignment. */ 1658c2ecf20Sopenharmony_ci#include <asm/io.h> 1668c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 1678c2ecf20Sopenharmony_ci#include <asm/cache.h> 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic const char version[] = 1708c2ecf20Sopenharmony_ciKERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n" 1718c2ecf20Sopenharmony_ci" Some modifications by Eric kasten <kasten@nscl.msu.edu>\n" 1728c2ecf20Sopenharmony_ci" Further modifications by Keith Underwood <keithu@parl.clemson.edu>\n"; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* IP_MF appears to be only defined in <netinet/ip.h>, however, 1768c2ecf20Sopenharmony_ci we need it for hardware checksumming support. FYI... some of 1778c2ecf20Sopenharmony_ci the definitions in <netinet/ip.h> conflict/duplicate those in 1788c2ecf20Sopenharmony_ci other linux headers causing many compiler warnings. 1798c2ecf20Sopenharmony_ci*/ 1808c2ecf20Sopenharmony_ci#ifndef IP_MF 1818c2ecf20Sopenharmony_ci #define IP_MF 0x2000 /* IP more frags from <netinet/ip.h> */ 1828c2ecf20Sopenharmony_ci#endif 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* Define IP_OFFSET to be IPOPT_OFFSET */ 1858c2ecf20Sopenharmony_ci#ifndef IP_OFFSET 1868c2ecf20Sopenharmony_ci #ifdef IPOPT_OFFSET 1878c2ecf20Sopenharmony_ci #define IP_OFFSET IPOPT_OFFSET 1888c2ecf20Sopenharmony_ci #else 1898c2ecf20Sopenharmony_ci #define IP_OFFSET 2 1908c2ecf20Sopenharmony_ci #endif 1918c2ecf20Sopenharmony_ci#endif 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci#define RUN_AT(x) (jiffies + (x)) 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#ifndef ADDRLEN 1968c2ecf20Sopenharmony_ci#define ADDRLEN 32 1978c2ecf20Sopenharmony_ci#endif 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* Condensed bus+endian portability operations. */ 2008c2ecf20Sopenharmony_ci#if ADDRLEN == 64 2018c2ecf20Sopenharmony_ci#define cpu_to_leXX(addr) cpu_to_le64(addr) 2028c2ecf20Sopenharmony_ci#define leXX_to_cpu(addr) le64_to_cpu(addr) 2038c2ecf20Sopenharmony_ci#else 2048c2ecf20Sopenharmony_ci#define cpu_to_leXX(addr) cpu_to_le32(addr) 2058c2ecf20Sopenharmony_ci#define leXX_to_cpu(addr) le32_to_cpu(addr) 2068c2ecf20Sopenharmony_ci#endif 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/* 2108c2ecf20Sopenharmony_ci Theory of Operation 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ciI. Board Compatibility 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ciThis device driver is designed for the Packet Engines "Hamachi" 2158c2ecf20Sopenharmony_ciGigabit Ethernet chip. The only PCA currently supported is the GNIC-II 64-bit 2168c2ecf20Sopenharmony_ci66Mhz PCI card. 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ciII. Board-specific settings 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ciNo jumpers exist on the board. The chip supports software correction of 2218c2ecf20Sopenharmony_civarious motherboard wiring errors, however this driver does not support 2228c2ecf20Sopenharmony_cithat feature. 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ciIII. Driver operation 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ciIIIa. Ring buffers 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciThe Hamachi uses a typical descriptor based bus-master architecture. 2298c2ecf20Sopenharmony_ciThe descriptor list is similar to that used by the Digital Tulip. 2308c2ecf20Sopenharmony_ciThis driver uses two statically allocated fixed-size descriptor lists 2318c2ecf20Sopenharmony_ciformed into rings by a branch from the final descriptor to the beginning of 2328c2ecf20Sopenharmony_cithe list. The ring sizes are set at compile time by RX/TX_RING_SIZE. 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ciThis driver uses a zero-copy receive and transmit scheme similar my other 2358c2ecf20Sopenharmony_cinetwork drivers. 2368c2ecf20Sopenharmony_ciThe driver allocates full frame size skbuffs for the Rx ring buffers at 2378c2ecf20Sopenharmony_ciopen() time and passes the skb->data field to the Hamachi as receive data 2388c2ecf20Sopenharmony_cibuffers. When an incoming frame is less than RX_COPYBREAK bytes long, 2398c2ecf20Sopenharmony_cia fresh skbuff is allocated and the frame is copied to the new skbuff. 2408c2ecf20Sopenharmony_ciWhen the incoming frame is larger, the skbuff is passed directly up the 2418c2ecf20Sopenharmony_ciprotocol stack and replaced by a newly allocated skbuff. 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ciThe RX_COPYBREAK value is chosen to trade-off the memory wasted by 2448c2ecf20Sopenharmony_ciusing a full-sized skbuff for small frames vs. the copying costs of larger 2458c2ecf20Sopenharmony_ciframes. Gigabit cards are typically used on generously configured machines 2468c2ecf20Sopenharmony_ciand the underfilled buffers have negligible impact compared to the benefit of 2478c2ecf20Sopenharmony_cia single allocation size, so the default value of zero results in never 2488c2ecf20Sopenharmony_cicopying packets. 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ciIIIb/c. Transmit/Receive Structure 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ciThe Rx and Tx descriptor structure are straight-forward, with no historical 2538c2ecf20Sopenharmony_cibaggage that must be explained. Unlike the awkward DBDMA structure, there 2548c2ecf20Sopenharmony_ciare no unused fields or option bits that had only one allowable setting. 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ciTwo details should be noted about the descriptors: The chip supports both 32 2578c2ecf20Sopenharmony_cibit and 64 bit address structures, and the length field is overwritten on 2588c2ecf20Sopenharmony_cithe receive descriptors. The descriptor length is set in the control word 2598c2ecf20Sopenharmony_cifor each channel. The development driver uses 32 bit addresses only, however 2608c2ecf20Sopenharmony_ci64 bit addresses may be enabled for 64 bit architectures e.g. the Alpha. 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ciIIId. Synchronization 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciThis driver is very similar to my other network drivers. 2658c2ecf20Sopenharmony_ciThe driver runs as two independent, single-threaded flows of control. One 2668c2ecf20Sopenharmony_ciis the send-packet routine, which enforces single-threaded use by the 2678c2ecf20Sopenharmony_cidev->tbusy flag. The other thread is the interrupt handler, which is single 2688c2ecf20Sopenharmony_cithreaded by the hardware and other software. 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ciThe send packet thread has partial control over the Tx ring and 'dev->tbusy' 2718c2ecf20Sopenharmony_ciflag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next 2728c2ecf20Sopenharmony_ciqueue slot is empty, it clears the tbusy flag when finished otherwise it sets 2738c2ecf20Sopenharmony_cithe 'hmp->tx_full' flag. 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ciThe interrupt handler has exclusive control over the Rx ring and records stats 2768c2ecf20Sopenharmony_cifrom the Tx ring. After reaping the stats, it marks the Tx queue entry as 2778c2ecf20Sopenharmony_ciempty by incrementing the dirty_tx mark. Iff the 'hmp->tx_full' flag is set, it 2788c2ecf20Sopenharmony_ciclears both the tx_full and tbusy flags. 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ciIV. Notes 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ciThanks to Kim Stearns of Packet Engines for providing a pair of GNIC-II boards. 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ciIVb. References 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ciHamachi Engineering Design Specification, 5/15/97 2878c2ecf20Sopenharmony_ci(Note: This version was marked "Confidential".) 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ciIVc. Errata 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ciNone noted. 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ciV. Recent Changes 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci01/15/1999 EPK Enlargement of the TX and RX ring sizes. This appears 2968c2ecf20Sopenharmony_ci to help avoid some stall conditions -- this needs further research. 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci01/15/1999 EPK Creation of the hamachi_tx function. This function cleans 2998c2ecf20Sopenharmony_ci the Tx ring and is called from hamachi_start_xmit (this used to be 3008c2ecf20Sopenharmony_ci called from hamachi_interrupt but it tends to delay execution of the 3018c2ecf20Sopenharmony_ci interrupt handler and thus reduce bandwidth by reducing the latency 3028c2ecf20Sopenharmony_ci between hamachi_rx()'s). Notably, some modification has been made so 3038c2ecf20Sopenharmony_ci that the cleaning loop checks only to make sure that the DescOwn bit 3048c2ecf20Sopenharmony_ci isn't set in the status flag since the card is not required 3058c2ecf20Sopenharmony_ci to set the entire flag to zero after processing. 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci01/15/1999 EPK In the hamachi_start_tx function, the Tx ring full flag is 3088c2ecf20Sopenharmony_ci checked before attempting to add a buffer to the ring. If the ring is full 3098c2ecf20Sopenharmony_ci an attempt is made to free any dirty buffers and thus find space for 3108c2ecf20Sopenharmony_ci the new buffer or the function returns non-zero which should case the 3118c2ecf20Sopenharmony_ci scheduler to reschedule the buffer later. 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci01/15/1999 EPK Some adjustments were made to the chip initialization. 3148c2ecf20Sopenharmony_ci End-to-end flow control should now be fully active and the interrupt 3158c2ecf20Sopenharmony_ci algorithm vars have been changed. These could probably use further tuning. 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci01/15/1999 EPK Added the max_{rx,tx}_latency options. These are used to 3188c2ecf20Sopenharmony_ci set the rx and tx latencies for the Hamachi interrupts. If you're having 3198c2ecf20Sopenharmony_ci problems with network stalls, try setting these to higher values. 3208c2ecf20Sopenharmony_ci Valid values are 0x00 through 0xff. 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci01/15/1999 EPK In general, the overall bandwidth has increased and 3238c2ecf20Sopenharmony_ci latencies are better (sometimes by a factor of 2). Stalls are rare at 3248c2ecf20Sopenharmony_ci this point, however there still appears to be a bug somewhere between the 3258c2ecf20Sopenharmony_ci hardware and driver. TCP checksum errors under load also appear to be 3268c2ecf20Sopenharmony_ci eliminated at this point. 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci01/18/1999 EPK Ensured that the DescEndRing bit was being set on both the 3298c2ecf20Sopenharmony_ci Rx and Tx rings. This appears to have been affecting whether a particular 3308c2ecf20Sopenharmony_ci peer-to-peer connection would hang under high load. I believe the Rx 3318c2ecf20Sopenharmony_ci rings was typically getting set correctly, but the Tx ring wasn't getting 3328c2ecf20Sopenharmony_ci the DescEndRing bit set during initialization. ??? Does this mean the 3338c2ecf20Sopenharmony_ci hamachi card is using the DescEndRing in processing even if a particular 3348c2ecf20Sopenharmony_ci slot isn't in use -- hypothetically, the card might be searching the 3358c2ecf20Sopenharmony_ci entire Tx ring for slots with the DescOwn bit set and then processing 3368c2ecf20Sopenharmony_ci them. If the DescEndRing bit isn't set, then it might just wander off 3378c2ecf20Sopenharmony_ci through memory until it hits a chunk of data with that bit set 3388c2ecf20Sopenharmony_ci and then looping back. 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci02/09/1999 EPK Added Michel Mueller's TxDMA Interrupt and Tx-timeout 3418c2ecf20Sopenharmony_ci problem (TxCmd and RxCmd need only to be set when idle or stopped. 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci02/09/1999 EPK Added code to check/reset dev->tbusy in hamachi_interrupt. 3448c2ecf20Sopenharmony_ci (Michel Mueller pointed out the ``permanently busy'' potential 3458c2ecf20Sopenharmony_ci problem here). 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci02/22/1999 EPK Added Pete Wyckoff's ioctl to control the Tx/Rx latencies. 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci02/23/1999 EPK Verified that the interrupt status field bits for Tx were 3508c2ecf20Sopenharmony_ci incorrectly defined and corrected (as per Michel Mueller). 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci02/23/1999 EPK Corrected the Tx full check to check that at least 4 slots 3538c2ecf20Sopenharmony_ci were available before resetting the tbusy and tx_full flags 3548c2ecf20Sopenharmony_ci (as per Michel Mueller). 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci03/11/1999 EPK Added Pete Wyckoff's hardware checksumming support. 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci12/31/1999 KDU Cleaned up assorted things and added Don's code to force 3598c2ecf20Sopenharmony_ci32 bit. 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci02/20/2000 KDU Some of the control was just plain odd. Cleaned up the 3628c2ecf20Sopenharmony_cihamachi_start_xmit() and hamachi_interrupt() code. There is still some 3638c2ecf20Sopenharmony_cire-structuring I would like to do. 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci03/01/2000 KDU Experimenting with a WIDE range of interrupt mitigation 3668c2ecf20Sopenharmony_ciparameters on a dual P3-450 setup yielded the new default interrupt 3678c2ecf20Sopenharmony_cimitigation parameters. Tx should interrupt VERY infrequently due to 3688c2ecf20Sopenharmony_ciEric's scheme. Rx should be more often... 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci03/13/2000 KDU Added a patch to make the Rx Checksum code interact 3718c2ecf20Sopenharmony_cinicely with non-linux machines. 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci03/13/2000 KDU Experimented with some of the configuration values: 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci -It seems that enabling PCI performance commands for descriptors 3768c2ecf20Sopenharmony_ci (changing RxDMACtrl and TxDMACtrl lower nibble from 5 to D) has minimal 3778c2ecf20Sopenharmony_ci performance impact for any of my tests. (ttcp, netpipe, netperf) I will 3788c2ecf20Sopenharmony_ci leave them that way until I hear further feedback. 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci -Increasing the PCI_LATENCY_TIMER to 130 3818c2ecf20Sopenharmony_ci (2 + (burst size of 128 * (0 wait states + 1))) seems to slightly 3828c2ecf20Sopenharmony_ci degrade performance. Leaving default at 64 pending further information. 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci03/14/2000 KDU Further tuning: 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci -adjusted boguscnt in hamachi_rx() to depend on interrupt 3878c2ecf20Sopenharmony_ci mitigation parameters chosen. 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci -Selected a set of interrupt parameters based on some extensive testing. 3908c2ecf20Sopenharmony_ci These may change with more testing. 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ciTO DO: 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci-Consider borrowing from the acenic driver code to check PCI_COMMAND for 3958c2ecf20Sopenharmony_ciPCI_COMMAND_INVALIDATE. Set maximum burst size to cache line size in 3968c2ecf20Sopenharmony_cithat case. 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci-fix the reset procedure. It doesn't quite work. 3998c2ecf20Sopenharmony_ci*/ 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci/* A few values that may be tweaked. */ 4028c2ecf20Sopenharmony_ci/* Size of each temporary Rx buffer, calculated as: 4038c2ecf20Sopenharmony_ci * 1518 bytes (ethernet packet) + 2 bytes (to get 8 byte alignment for 4048c2ecf20Sopenharmony_ci * the card) + 8 bytes of status info + 8 bytes for the Rx Checksum 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_ci#define PKT_BUF_SZ 1536 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci/* For now, this is going to be set to the maximum size of an ethernet 4098c2ecf20Sopenharmony_ci * packet. Eventually, we may want to make it a variable that is 4108c2ecf20Sopenharmony_ci * related to the MTU 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ci#define MAX_FRAME_SIZE 1518 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/* The rest of these values should never change. */ 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic void hamachi_timer(struct timer_list *t); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cienum capability_flags {CanHaveMII=1, }; 4198c2ecf20Sopenharmony_cistatic const struct chip_info { 4208c2ecf20Sopenharmony_ci u16 vendor_id, device_id, device_id_mask, pad; 4218c2ecf20Sopenharmony_ci const char *name; 4228c2ecf20Sopenharmony_ci void (*media_timer)(struct timer_list *t); 4238c2ecf20Sopenharmony_ci int flags; 4248c2ecf20Sopenharmony_ci} chip_tbl[] = { 4258c2ecf20Sopenharmony_ci {0x1318, 0x0911, 0xffff, 0, "Hamachi GNIC-II", hamachi_timer, 0}, 4268c2ecf20Sopenharmony_ci {0,}, 4278c2ecf20Sopenharmony_ci}; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci/* Offsets to the Hamachi registers. Various sizes. */ 4308c2ecf20Sopenharmony_cienum hamachi_offsets { 4318c2ecf20Sopenharmony_ci TxDMACtrl=0x00, TxCmd=0x04, TxStatus=0x06, TxPtr=0x08, TxCurPtr=0x10, 4328c2ecf20Sopenharmony_ci RxDMACtrl=0x20, RxCmd=0x24, RxStatus=0x26, RxPtr=0x28, RxCurPtr=0x30, 4338c2ecf20Sopenharmony_ci PCIClkMeas=0x060, MiscStatus=0x066, ChipRev=0x68, ChipReset=0x06B, 4348c2ecf20Sopenharmony_ci LEDCtrl=0x06C, VirtualJumpers=0x06D, GPIO=0x6E, 4358c2ecf20Sopenharmony_ci TxChecksum=0x074, RxChecksum=0x076, 4368c2ecf20Sopenharmony_ci TxIntrCtrl=0x078, RxIntrCtrl=0x07C, 4378c2ecf20Sopenharmony_ci InterruptEnable=0x080, InterruptClear=0x084, IntrStatus=0x088, 4388c2ecf20Sopenharmony_ci EventStatus=0x08C, 4398c2ecf20Sopenharmony_ci MACCnfg=0x0A0, FrameGap0=0x0A2, FrameGap1=0x0A4, 4408c2ecf20Sopenharmony_ci /* See enum MII_offsets below. */ 4418c2ecf20Sopenharmony_ci MACCnfg2=0x0B0, RxDepth=0x0B8, FlowCtrl=0x0BC, MaxFrameSize=0x0CE, 4428c2ecf20Sopenharmony_ci AddrMode=0x0D0, StationAddr=0x0D2, 4438c2ecf20Sopenharmony_ci /* Gigabit AutoNegotiation. */ 4448c2ecf20Sopenharmony_ci ANCtrl=0x0E0, ANStatus=0x0E2, ANXchngCtrl=0x0E4, ANAdvertise=0x0E8, 4458c2ecf20Sopenharmony_ci ANLinkPartnerAbility=0x0EA, 4468c2ecf20Sopenharmony_ci EECmdStatus=0x0F0, EEData=0x0F1, EEAddr=0x0F2, 4478c2ecf20Sopenharmony_ci FIFOcfg=0x0F8, 4488c2ecf20Sopenharmony_ci}; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/* Offsets to the MII-mode registers. */ 4518c2ecf20Sopenharmony_cienum MII_offsets { 4528c2ecf20Sopenharmony_ci MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC, 4538c2ecf20Sopenharmony_ci MII_Status=0xAE, 4548c2ecf20Sopenharmony_ci}; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci/* Bits in the interrupt status/mask registers. */ 4578c2ecf20Sopenharmony_cienum intr_status_bits { 4588c2ecf20Sopenharmony_ci IntrRxDone=0x01, IntrRxPCIFault=0x02, IntrRxPCIErr=0x04, 4598c2ecf20Sopenharmony_ci IntrTxDone=0x100, IntrTxPCIFault=0x200, IntrTxPCIErr=0x400, 4608c2ecf20Sopenharmony_ci LinkChange=0x10000, NegotiationChange=0x20000, StatsMax=0x40000, }; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci/* The Hamachi Rx and Tx buffer descriptors. */ 4638c2ecf20Sopenharmony_cistruct hamachi_desc { 4648c2ecf20Sopenharmony_ci __le32 status_n_length; 4658c2ecf20Sopenharmony_ci#if ADDRLEN == 64 4668c2ecf20Sopenharmony_ci u32 pad; 4678c2ecf20Sopenharmony_ci __le64 addr; 4688c2ecf20Sopenharmony_ci#else 4698c2ecf20Sopenharmony_ci __le32 addr; 4708c2ecf20Sopenharmony_ci#endif 4718c2ecf20Sopenharmony_ci}; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci/* Bits in hamachi_desc.status_n_length */ 4748c2ecf20Sopenharmony_cienum desc_status_bits { 4758c2ecf20Sopenharmony_ci DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000, 4768c2ecf20Sopenharmony_ci DescIntr=0x10000000, 4778c2ecf20Sopenharmony_ci}; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci#define PRIV_ALIGN 15 /* Required alignment mask */ 4808c2ecf20Sopenharmony_ci#define MII_CNT 4 4818c2ecf20Sopenharmony_cistruct hamachi_private { 4828c2ecf20Sopenharmony_ci /* Descriptor rings first for alignment. Tx requires a second descriptor 4838c2ecf20Sopenharmony_ci for status. */ 4848c2ecf20Sopenharmony_ci struct hamachi_desc *rx_ring; 4858c2ecf20Sopenharmony_ci struct hamachi_desc *tx_ring; 4868c2ecf20Sopenharmony_ci struct sk_buff* rx_skbuff[RX_RING_SIZE]; 4878c2ecf20Sopenharmony_ci struct sk_buff* tx_skbuff[TX_RING_SIZE]; 4888c2ecf20Sopenharmony_ci dma_addr_t tx_ring_dma; 4898c2ecf20Sopenharmony_ci dma_addr_t rx_ring_dma; 4908c2ecf20Sopenharmony_ci struct timer_list timer; /* Media selection timer. */ 4918c2ecf20Sopenharmony_ci /* Frequently used and paired value: keep adjacent for cache effect. */ 4928c2ecf20Sopenharmony_ci spinlock_t lock; 4938c2ecf20Sopenharmony_ci int chip_id; 4948c2ecf20Sopenharmony_ci unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ 4958c2ecf20Sopenharmony_ci unsigned int cur_tx, dirty_tx; 4968c2ecf20Sopenharmony_ci unsigned int rx_buf_sz; /* Based on MTU+slack. */ 4978c2ecf20Sopenharmony_ci unsigned int tx_full:1; /* The Tx queue is full. */ 4988c2ecf20Sopenharmony_ci unsigned int duplex_lock:1; 4998c2ecf20Sopenharmony_ci unsigned int default_port:4; /* Last dev->if_port value. */ 5008c2ecf20Sopenharmony_ci /* MII transceiver section. */ 5018c2ecf20Sopenharmony_ci int mii_cnt; /* MII device addresses. */ 5028c2ecf20Sopenharmony_ci struct mii_if_info mii_if; /* MII lib hooks/info */ 5038c2ecf20Sopenharmony_ci unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */ 5048c2ecf20Sopenharmony_ci u32 rx_int_var, tx_int_var; /* interrupt control variables */ 5058c2ecf20Sopenharmony_ci u32 option; /* Hold on to a copy of the options */ 5068c2ecf20Sopenharmony_ci struct pci_dev *pci_dev; 5078c2ecf20Sopenharmony_ci void __iomem *base; 5088c2ecf20Sopenharmony_ci}; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ciMODULE_AUTHOR("Donald Becker <becker@scyld.com>, Eric Kasten <kasten@nscl.msu.edu>, Keith Underwood <keithu@parl.clemson.edu>"); 5118c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Packet Engines 'Hamachi' GNIC-II Gigabit Ethernet driver"); 5128c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cimodule_param(max_interrupt_work, int, 0); 5158c2ecf20Sopenharmony_cimodule_param(mtu, int, 0); 5168c2ecf20Sopenharmony_cimodule_param(debug, int, 0); 5178c2ecf20Sopenharmony_cimodule_param(min_rx_pkt, int, 0); 5188c2ecf20Sopenharmony_cimodule_param(max_rx_gap, int, 0); 5198c2ecf20Sopenharmony_cimodule_param(max_rx_latency, int, 0); 5208c2ecf20Sopenharmony_cimodule_param(min_tx_pkt, int, 0); 5218c2ecf20Sopenharmony_cimodule_param(max_tx_gap, int, 0); 5228c2ecf20Sopenharmony_cimodule_param(max_tx_latency, int, 0); 5238c2ecf20Sopenharmony_cimodule_param(rx_copybreak, int, 0); 5248c2ecf20Sopenharmony_cimodule_param_array(rx_params, int, NULL, 0); 5258c2ecf20Sopenharmony_cimodule_param_array(tx_params, int, NULL, 0); 5268c2ecf20Sopenharmony_cimodule_param_array(options, int, NULL, 0); 5278c2ecf20Sopenharmony_cimodule_param_array(full_duplex, int, NULL, 0); 5288c2ecf20Sopenharmony_cimodule_param(force32, int, 0); 5298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_interrupt_work, "GNIC-II maximum events handled per interrupt"); 5308c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mtu, "GNIC-II MTU (all boards)"); 5318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "GNIC-II debug level (0-7)"); 5328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(min_rx_pkt, "GNIC-II minimum Rx packets processed between interrupts"); 5338c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_rx_gap, "GNIC-II maximum Rx inter-packet gap in 8.192 microsecond units"); 5348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_rx_latency, "GNIC-II time between Rx interrupts in 8.192 microsecond units"); 5358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(min_tx_pkt, "GNIC-II minimum Tx packets processed between interrupts"); 5368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_tx_gap, "GNIC-II maximum Tx inter-packet gap in 8.192 microsecond units"); 5378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_tx_latency, "GNIC-II time between Tx interrupts in 8.192 microsecond units"); 5388c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rx_copybreak, "GNIC-II copy breakpoint for copy-only-tiny-frames"); 5398c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rx_params, "GNIC-II min_rx_pkt+max_rx_gap+max_rx_latency"); 5408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(tx_params, "GNIC-II min_tx_pkt+max_tx_gap+max_tx_latency"); 5418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(options, "GNIC-II Bits 0-3: media type, bits 4-6: as force32, bit 7: half duplex, bit 9 full duplex"); 5428c2ecf20Sopenharmony_ciMODULE_PARM_DESC(full_duplex, "GNIC-II full duplex setting(s) (1)"); 5438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)"); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic int read_eeprom(void __iomem *ioaddr, int location); 5468c2ecf20Sopenharmony_cistatic int mdio_read(struct net_device *dev, int phy_id, int location); 5478c2ecf20Sopenharmony_cistatic void mdio_write(struct net_device *dev, int phy_id, int location, int value); 5488c2ecf20Sopenharmony_cistatic int hamachi_open(struct net_device *dev); 5498c2ecf20Sopenharmony_cistatic int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); 5508c2ecf20Sopenharmony_cistatic void hamachi_timer(struct timer_list *t); 5518c2ecf20Sopenharmony_cistatic void hamachi_tx_timeout(struct net_device *dev, unsigned int txqueue); 5528c2ecf20Sopenharmony_cistatic void hamachi_init_ring(struct net_device *dev); 5538c2ecf20Sopenharmony_cistatic netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, 5548c2ecf20Sopenharmony_ci struct net_device *dev); 5558c2ecf20Sopenharmony_cistatic irqreturn_t hamachi_interrupt(int irq, void *dev_instance); 5568c2ecf20Sopenharmony_cistatic int hamachi_rx(struct net_device *dev); 5578c2ecf20Sopenharmony_cistatic inline int hamachi_tx(struct net_device *dev); 5588c2ecf20Sopenharmony_cistatic void hamachi_error(struct net_device *dev, int intr_status); 5598c2ecf20Sopenharmony_cistatic int hamachi_close(struct net_device *dev); 5608c2ecf20Sopenharmony_cistatic struct net_device_stats *hamachi_get_stats(struct net_device *dev); 5618c2ecf20Sopenharmony_cistatic void set_rx_mode(struct net_device *dev); 5628c2ecf20Sopenharmony_cistatic const struct ethtool_ops ethtool_ops; 5638c2ecf20Sopenharmony_cistatic const struct ethtool_ops ethtool_ops_no_mii; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic const struct net_device_ops hamachi_netdev_ops = { 5668c2ecf20Sopenharmony_ci .ndo_open = hamachi_open, 5678c2ecf20Sopenharmony_ci .ndo_stop = hamachi_close, 5688c2ecf20Sopenharmony_ci .ndo_start_xmit = hamachi_start_xmit, 5698c2ecf20Sopenharmony_ci .ndo_get_stats = hamachi_get_stats, 5708c2ecf20Sopenharmony_ci .ndo_set_rx_mode = set_rx_mode, 5718c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 5728c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 5738c2ecf20Sopenharmony_ci .ndo_tx_timeout = hamachi_tx_timeout, 5748c2ecf20Sopenharmony_ci .ndo_do_ioctl = netdev_ioctl, 5758c2ecf20Sopenharmony_ci}; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic int hamachi_init_one(struct pci_dev *pdev, 5798c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci struct hamachi_private *hmp; 5828c2ecf20Sopenharmony_ci int option, i, rx_int_var, tx_int_var, boguscnt; 5838c2ecf20Sopenharmony_ci int chip_id = ent->driver_data; 5848c2ecf20Sopenharmony_ci int irq; 5858c2ecf20Sopenharmony_ci void __iomem *ioaddr; 5868c2ecf20Sopenharmony_ci unsigned long base; 5878c2ecf20Sopenharmony_ci static int card_idx; 5888c2ecf20Sopenharmony_ci struct net_device *dev; 5898c2ecf20Sopenharmony_ci void *ring_space; 5908c2ecf20Sopenharmony_ci dma_addr_t ring_dma; 5918c2ecf20Sopenharmony_ci int ret = -ENOMEM; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/* when built into the kernel, we only print version if device is found */ 5948c2ecf20Sopenharmony_ci#ifndef MODULE 5958c2ecf20Sopenharmony_ci static int printed_version; 5968c2ecf20Sopenharmony_ci if (!printed_version++) 5978c2ecf20Sopenharmony_ci printk(version); 5988c2ecf20Sopenharmony_ci#endif 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 6018c2ecf20Sopenharmony_ci ret = -EIO; 6028c2ecf20Sopenharmony_ci goto err_out; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci base = pci_resource_start(pdev, 0); 6068c2ecf20Sopenharmony_ci#ifdef __alpha__ /* Really "64 bit addrs" */ 6078c2ecf20Sopenharmony_ci base |= (pci_resource_start(pdev, 1) << 32); 6088c2ecf20Sopenharmony_ci#endif 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci pci_set_master(pdev); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci i = pci_request_regions(pdev, DRV_NAME); 6138c2ecf20Sopenharmony_ci if (i) 6148c2ecf20Sopenharmony_ci return i; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci irq = pdev->irq; 6178c2ecf20Sopenharmony_ci ioaddr = ioremap(base, 0x400); 6188c2ecf20Sopenharmony_ci if (!ioaddr) 6198c2ecf20Sopenharmony_ci goto err_out_release; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci dev = alloc_etherdev(sizeof(struct hamachi_private)); 6228c2ecf20Sopenharmony_ci if (!dev) 6238c2ecf20Sopenharmony_ci goto err_out_iounmap; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 6288c2ecf20Sopenharmony_ci dev->dev_addr[i] = 1 ? read_eeprom(ioaddr, 4 + i) 6298c2ecf20Sopenharmony_ci : readb(ioaddr + StationAddr + i); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci#if ! defined(final_version) 6328c2ecf20Sopenharmony_ci if (hamachi_debug > 4) 6338c2ecf20Sopenharmony_ci for (i = 0; i < 0x10; i++) 6348c2ecf20Sopenharmony_ci printk("%2.2x%s", 6358c2ecf20Sopenharmony_ci read_eeprom(ioaddr, i), i % 16 != 15 ? " " : "\n"); 6368c2ecf20Sopenharmony_ci#endif 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci hmp = netdev_priv(dev); 6398c2ecf20Sopenharmony_ci spin_lock_init(&hmp->lock); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci hmp->mii_if.dev = dev; 6428c2ecf20Sopenharmony_ci hmp->mii_if.mdio_read = mdio_read; 6438c2ecf20Sopenharmony_ci hmp->mii_if.mdio_write = mdio_write; 6448c2ecf20Sopenharmony_ci hmp->mii_if.phy_id_mask = 0x1f; 6458c2ecf20Sopenharmony_ci hmp->mii_if.reg_num_mask = 0x1f; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci ring_space = dma_alloc_coherent(&pdev->dev, TX_TOTAL_SIZE, &ring_dma, 6488c2ecf20Sopenharmony_ci GFP_KERNEL); 6498c2ecf20Sopenharmony_ci if (!ring_space) 6508c2ecf20Sopenharmony_ci goto err_out_cleardev; 6518c2ecf20Sopenharmony_ci hmp->tx_ring = ring_space; 6528c2ecf20Sopenharmony_ci hmp->tx_ring_dma = ring_dma; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci ring_space = dma_alloc_coherent(&pdev->dev, RX_TOTAL_SIZE, &ring_dma, 6558c2ecf20Sopenharmony_ci GFP_KERNEL); 6568c2ecf20Sopenharmony_ci if (!ring_space) 6578c2ecf20Sopenharmony_ci goto err_out_unmap_tx; 6588c2ecf20Sopenharmony_ci hmp->rx_ring = ring_space; 6598c2ecf20Sopenharmony_ci hmp->rx_ring_dma = ring_dma; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* Check for options being passed in */ 6628c2ecf20Sopenharmony_ci option = card_idx < MAX_UNITS ? options[card_idx] : 0; 6638c2ecf20Sopenharmony_ci if (dev->mem_start) 6648c2ecf20Sopenharmony_ci option = dev->mem_start; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* If the bus size is misidentified, do the following. */ 6678c2ecf20Sopenharmony_ci force32 = force32 ? force32 : 6688c2ecf20Sopenharmony_ci ((option >= 0) ? ((option & 0x00000070) >> 4) : 0 ); 6698c2ecf20Sopenharmony_ci if (force32) 6708c2ecf20Sopenharmony_ci writeb(force32, ioaddr + VirtualJumpers); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* Hmmm, do we really need to reset the chip???. */ 6738c2ecf20Sopenharmony_ci writeb(0x01, ioaddr + ChipReset); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci /* After a reset, the clock speed measurement of the PCI bus will not 6768c2ecf20Sopenharmony_ci * be valid for a moment. Wait for a little while until it is. If 6778c2ecf20Sopenharmony_ci * it takes more than 10ms, forget it. 6788c2ecf20Sopenharmony_ci */ 6798c2ecf20Sopenharmony_ci udelay(10); 6808c2ecf20Sopenharmony_ci i = readb(ioaddr + PCIClkMeas); 6818c2ecf20Sopenharmony_ci for (boguscnt = 0; (!(i & 0x080)) && boguscnt < 1000; boguscnt++){ 6828c2ecf20Sopenharmony_ci udelay(10); 6838c2ecf20Sopenharmony_ci i = readb(ioaddr + PCIClkMeas); 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci hmp->base = ioaddr; 6878c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, dev); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci hmp->chip_id = chip_id; 6908c2ecf20Sopenharmony_ci hmp->pci_dev = pdev; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* The lower four bits are the media type. */ 6938c2ecf20Sopenharmony_ci if (option > 0) { 6948c2ecf20Sopenharmony_ci hmp->option = option; 6958c2ecf20Sopenharmony_ci if (option & 0x200) 6968c2ecf20Sopenharmony_ci hmp->mii_if.full_duplex = 1; 6978c2ecf20Sopenharmony_ci else if (option & 0x080) 6988c2ecf20Sopenharmony_ci hmp->mii_if.full_duplex = 0; 6998c2ecf20Sopenharmony_ci hmp->default_port = option & 15; 7008c2ecf20Sopenharmony_ci if (hmp->default_port) 7018c2ecf20Sopenharmony_ci hmp->mii_if.force_media = 1; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) 7048c2ecf20Sopenharmony_ci hmp->mii_if.full_duplex = 1; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* lock the duplex mode if someone specified a value */ 7078c2ecf20Sopenharmony_ci if (hmp->mii_if.full_duplex || (option & 0x080)) 7088c2ecf20Sopenharmony_ci hmp->duplex_lock = 1; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* Set interrupt tuning parameters */ 7118c2ecf20Sopenharmony_ci max_rx_latency = max_rx_latency & 0x00ff; 7128c2ecf20Sopenharmony_ci max_rx_gap = max_rx_gap & 0x00ff; 7138c2ecf20Sopenharmony_ci min_rx_pkt = min_rx_pkt & 0x00ff; 7148c2ecf20Sopenharmony_ci max_tx_latency = max_tx_latency & 0x00ff; 7158c2ecf20Sopenharmony_ci max_tx_gap = max_tx_gap & 0x00ff; 7168c2ecf20Sopenharmony_ci min_tx_pkt = min_tx_pkt & 0x00ff; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci rx_int_var = card_idx < MAX_UNITS ? rx_params[card_idx] : -1; 7198c2ecf20Sopenharmony_ci tx_int_var = card_idx < MAX_UNITS ? tx_params[card_idx] : -1; 7208c2ecf20Sopenharmony_ci hmp->rx_int_var = rx_int_var >= 0 ? rx_int_var : 7218c2ecf20Sopenharmony_ci (min_rx_pkt << 16 | max_rx_gap << 8 | max_rx_latency); 7228c2ecf20Sopenharmony_ci hmp->tx_int_var = tx_int_var >= 0 ? tx_int_var : 7238c2ecf20Sopenharmony_ci (min_tx_pkt << 16 | max_tx_gap << 8 | max_tx_latency); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* The Hamachi-specific entries in the device structure. */ 7278c2ecf20Sopenharmony_ci dev->netdev_ops = &hamachi_netdev_ops; 7288c2ecf20Sopenharmony_ci dev->ethtool_ops = (chip_tbl[hmp->chip_id].flags & CanHaveMII) ? 7298c2ecf20Sopenharmony_ci ðtool_ops : ðtool_ops_no_mii; 7308c2ecf20Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 7318c2ecf20Sopenharmony_ci if (mtu) 7328c2ecf20Sopenharmony_ci dev->mtu = mtu; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci i = register_netdev(dev); 7358c2ecf20Sopenharmony_ci if (i) { 7368c2ecf20Sopenharmony_ci ret = i; 7378c2ecf20Sopenharmony_ci goto err_out_unmap_rx; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: %s type %x at %p, %pM, IRQ %d.\n", 7418c2ecf20Sopenharmony_ci dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), 7428c2ecf20Sopenharmony_ci ioaddr, dev->dev_addr, irq); 7438c2ecf20Sopenharmony_ci i = readb(ioaddr + PCIClkMeas); 7448c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " 7458c2ecf20Sopenharmony_ci "%2.2x, LPA %4.4x.\n", 7468c2ecf20Sopenharmony_ci dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, 7478c2ecf20Sopenharmony_ci i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), 7488c2ecf20Sopenharmony_ci readw(ioaddr + ANLinkPartnerAbility)); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (chip_tbl[hmp->chip_id].flags & CanHaveMII) { 7518c2ecf20Sopenharmony_ci int phy, phy_idx = 0; 7528c2ecf20Sopenharmony_ci for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) { 7538c2ecf20Sopenharmony_ci int mii_status = mdio_read(dev, phy, MII_BMSR); 7548c2ecf20Sopenharmony_ci if (mii_status != 0xffff && 7558c2ecf20Sopenharmony_ci mii_status != 0x0000) { 7568c2ecf20Sopenharmony_ci hmp->phys[phy_idx++] = phy; 7578c2ecf20Sopenharmony_ci hmp->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE); 7588c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: MII PHY found at address %d, status " 7598c2ecf20Sopenharmony_ci "0x%4.4x advertising %4.4x.\n", 7608c2ecf20Sopenharmony_ci dev->name, phy, mii_status, hmp->mii_if.advertising); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci hmp->mii_cnt = phy_idx; 7648c2ecf20Sopenharmony_ci if (hmp->mii_cnt > 0) 7658c2ecf20Sopenharmony_ci hmp->mii_if.phy_id = hmp->phys[0]; 7668c2ecf20Sopenharmony_ci else 7678c2ecf20Sopenharmony_ci memset(&hmp->mii_if, 0, sizeof(hmp->mii_if)); 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci /* Configure gigabit autonegotiation. */ 7708c2ecf20Sopenharmony_ci writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ 7718c2ecf20Sopenharmony_ci writew(0x08e0, ioaddr + ANAdvertise); /* Set our advertise word. */ 7728c2ecf20Sopenharmony_ci writew(0x1000, ioaddr + ANCtrl); /* Enable negotiation */ 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci card_idx++; 7758c2ecf20Sopenharmony_ci return 0; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cierr_out_unmap_rx: 7788c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, hmp->rx_ring, 7798c2ecf20Sopenharmony_ci hmp->rx_ring_dma); 7808c2ecf20Sopenharmony_cierr_out_unmap_tx: 7818c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, hmp->tx_ring, 7828c2ecf20Sopenharmony_ci hmp->tx_ring_dma); 7838c2ecf20Sopenharmony_cierr_out_cleardev: 7848c2ecf20Sopenharmony_ci free_netdev (dev); 7858c2ecf20Sopenharmony_cierr_out_iounmap: 7868c2ecf20Sopenharmony_ci iounmap(ioaddr); 7878c2ecf20Sopenharmony_cierr_out_release: 7888c2ecf20Sopenharmony_ci pci_release_regions(pdev); 7898c2ecf20Sopenharmony_cierr_out: 7908c2ecf20Sopenharmony_ci return ret; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic int read_eeprom(void __iomem *ioaddr, int location) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci int bogus_cnt = 1000; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci /* We should check busy first - per docs -KDU */ 7988c2ecf20Sopenharmony_ci while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0); 7998c2ecf20Sopenharmony_ci writew(location, ioaddr + EEAddr); 8008c2ecf20Sopenharmony_ci writeb(0x02, ioaddr + EECmdStatus); 8018c2ecf20Sopenharmony_ci bogus_cnt = 1000; 8028c2ecf20Sopenharmony_ci while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0); 8038c2ecf20Sopenharmony_ci if (hamachi_debug > 5) 8048c2ecf20Sopenharmony_ci printk(" EEPROM status is %2.2x after %d ticks.\n", 8058c2ecf20Sopenharmony_ci (int)readb(ioaddr + EECmdStatus), 1000- bogus_cnt); 8068c2ecf20Sopenharmony_ci return readb(ioaddr + EEData); 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci/* MII Managemen Data I/O accesses. 8108c2ecf20Sopenharmony_ci These routines assume the MDIO controller is idle, and do not exit until 8118c2ecf20Sopenharmony_ci the command is finished. */ 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic int mdio_read(struct net_device *dev, int phy_id, int location) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 8168c2ecf20Sopenharmony_ci void __iomem *ioaddr = hmp->base; 8178c2ecf20Sopenharmony_ci int i; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* We should check busy first - per docs -KDU */ 8208c2ecf20Sopenharmony_ci for (i = 10000; i >= 0; i--) 8218c2ecf20Sopenharmony_ci if ((readw(ioaddr + MII_Status) & 1) == 0) 8228c2ecf20Sopenharmony_ci break; 8238c2ecf20Sopenharmony_ci writew((phy_id<<8) + location, ioaddr + MII_Addr); 8248c2ecf20Sopenharmony_ci writew(0x0001, ioaddr + MII_Cmd); 8258c2ecf20Sopenharmony_ci for (i = 10000; i >= 0; i--) 8268c2ecf20Sopenharmony_ci if ((readw(ioaddr + MII_Status) & 1) == 0) 8278c2ecf20Sopenharmony_ci break; 8288c2ecf20Sopenharmony_ci return readw(ioaddr + MII_Rd_Data); 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic void mdio_write(struct net_device *dev, int phy_id, int location, int value) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 8348c2ecf20Sopenharmony_ci void __iomem *ioaddr = hmp->base; 8358c2ecf20Sopenharmony_ci int i; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* We should check busy first - per docs -KDU */ 8388c2ecf20Sopenharmony_ci for (i = 10000; i >= 0; i--) 8398c2ecf20Sopenharmony_ci if ((readw(ioaddr + MII_Status) & 1) == 0) 8408c2ecf20Sopenharmony_ci break; 8418c2ecf20Sopenharmony_ci writew((phy_id<<8) + location, ioaddr + MII_Addr); 8428c2ecf20Sopenharmony_ci writew(value, ioaddr + MII_Wr_Data); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci /* Wait for the command to finish. */ 8458c2ecf20Sopenharmony_ci for (i = 10000; i >= 0; i--) 8468c2ecf20Sopenharmony_ci if ((readw(ioaddr + MII_Status) & 1) == 0) 8478c2ecf20Sopenharmony_ci break; 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_cistatic int hamachi_open(struct net_device *dev) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 8548c2ecf20Sopenharmony_ci void __iomem *ioaddr = hmp->base; 8558c2ecf20Sopenharmony_ci int i; 8568c2ecf20Sopenharmony_ci u32 rx_int_var, tx_int_var; 8578c2ecf20Sopenharmony_ci u16 fifo_info; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci i = request_irq(hmp->pci_dev->irq, hamachi_interrupt, IRQF_SHARED, 8608c2ecf20Sopenharmony_ci dev->name, dev); 8618c2ecf20Sopenharmony_ci if (i) 8628c2ecf20Sopenharmony_ci return i; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci hamachi_init_ring(dev); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci#if ADDRLEN == 64 8678c2ecf20Sopenharmony_ci /* writellll anyone ? */ 8688c2ecf20Sopenharmony_ci writel(hmp->rx_ring_dma, ioaddr + RxPtr); 8698c2ecf20Sopenharmony_ci writel(hmp->rx_ring_dma >> 32, ioaddr + RxPtr + 4); 8708c2ecf20Sopenharmony_ci writel(hmp->tx_ring_dma, ioaddr + TxPtr); 8718c2ecf20Sopenharmony_ci writel(hmp->tx_ring_dma >> 32, ioaddr + TxPtr + 4); 8728c2ecf20Sopenharmony_ci#else 8738c2ecf20Sopenharmony_ci writel(hmp->rx_ring_dma, ioaddr + RxPtr); 8748c2ecf20Sopenharmony_ci writel(hmp->tx_ring_dma, ioaddr + TxPtr); 8758c2ecf20Sopenharmony_ci#endif 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* TODO: It would make sense to organize this as words since the card 8788c2ecf20Sopenharmony_ci * documentation does. -KDU 8798c2ecf20Sopenharmony_ci */ 8808c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 8818c2ecf20Sopenharmony_ci writeb(dev->dev_addr[i], ioaddr + StationAddr + i); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* Initialize other registers: with so many this eventually this will 8848c2ecf20Sopenharmony_ci converted to an offset/value list. */ 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci /* Configure the FIFO */ 8878c2ecf20Sopenharmony_ci fifo_info = (readw(ioaddr + GPIO) & 0x00C0) >> 6; 8888c2ecf20Sopenharmony_ci switch (fifo_info){ 8898c2ecf20Sopenharmony_ci case 0 : 8908c2ecf20Sopenharmony_ci /* No FIFO */ 8918c2ecf20Sopenharmony_ci writew(0x0000, ioaddr + FIFOcfg); 8928c2ecf20Sopenharmony_ci break; 8938c2ecf20Sopenharmony_ci case 1 : 8948c2ecf20Sopenharmony_ci /* Configure the FIFO for 512K external, 16K used for Tx. */ 8958c2ecf20Sopenharmony_ci writew(0x0028, ioaddr + FIFOcfg); 8968c2ecf20Sopenharmony_ci break; 8978c2ecf20Sopenharmony_ci case 2 : 8988c2ecf20Sopenharmony_ci /* Configure the FIFO for 1024 external, 32K used for Tx. */ 8998c2ecf20Sopenharmony_ci writew(0x004C, ioaddr + FIFOcfg); 9008c2ecf20Sopenharmony_ci break; 9018c2ecf20Sopenharmony_ci case 3 : 9028c2ecf20Sopenharmony_ci /* Configure the FIFO for 2048 external, 32K used for Tx. */ 9038c2ecf20Sopenharmony_ci writew(0x006C, ioaddr + FIFOcfg); 9048c2ecf20Sopenharmony_ci break; 9058c2ecf20Sopenharmony_ci default : 9068c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: Unsupported external memory config!\n", 9078c2ecf20Sopenharmony_ci dev->name); 9088c2ecf20Sopenharmony_ci /* Default to no FIFO */ 9098c2ecf20Sopenharmony_ci writew(0x0000, ioaddr + FIFOcfg); 9108c2ecf20Sopenharmony_ci break; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (dev->if_port == 0) 9148c2ecf20Sopenharmony_ci dev->if_port = hmp->default_port; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci /* Setting the Rx mode will start the Rx process. */ 9188c2ecf20Sopenharmony_ci /* If someone didn't choose a duplex, default to full-duplex */ 9198c2ecf20Sopenharmony_ci if (hmp->duplex_lock != 1) 9208c2ecf20Sopenharmony_ci hmp->mii_if.full_duplex = 1; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* always 1, takes no more time to do it */ 9238c2ecf20Sopenharmony_ci writew(0x0001, ioaddr + RxChecksum); 9248c2ecf20Sopenharmony_ci writew(0x0000, ioaddr + TxChecksum); 9258c2ecf20Sopenharmony_ci writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */ 9268c2ecf20Sopenharmony_ci writew(0x215F, ioaddr + MACCnfg); 9278c2ecf20Sopenharmony_ci writew(0x000C, ioaddr + FrameGap0); 9288c2ecf20Sopenharmony_ci /* WHAT?!?!? Why isn't this documented somewhere? -KDU */ 9298c2ecf20Sopenharmony_ci writew(0x1018, ioaddr + FrameGap1); 9308c2ecf20Sopenharmony_ci /* Why do we enable receives/transmits here? -KDU */ 9318c2ecf20Sopenharmony_ci writew(0x0780, ioaddr + MACCnfg2); /* Upper 16 bits control LEDs. */ 9328c2ecf20Sopenharmony_ci /* Enable automatic generation of flow control frames, period 0xffff. */ 9338c2ecf20Sopenharmony_ci writel(0x0030FFFF, ioaddr + FlowCtrl); 9348c2ecf20Sopenharmony_ci writew(MAX_FRAME_SIZE, ioaddr + MaxFrameSize); /* dev->mtu+14 ??? */ 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci /* Enable legacy links. */ 9378c2ecf20Sopenharmony_ci writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ 9388c2ecf20Sopenharmony_ci /* Initial Link LED to blinking red. */ 9398c2ecf20Sopenharmony_ci writeb(0x03, ioaddr + LEDCtrl); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* Configure interrupt mitigation. This has a great effect on 9428c2ecf20Sopenharmony_ci performance, so systems tuning should start here!. */ 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci rx_int_var = hmp->rx_int_var; 9458c2ecf20Sopenharmony_ci tx_int_var = hmp->tx_int_var; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci if (hamachi_debug > 1) { 9488c2ecf20Sopenharmony_ci printk("max_tx_latency: %d, max_tx_gap: %d, min_tx_pkt: %d\n", 9498c2ecf20Sopenharmony_ci tx_int_var & 0x00ff, (tx_int_var & 0x00ff00) >> 8, 9508c2ecf20Sopenharmony_ci (tx_int_var & 0x00ff0000) >> 16); 9518c2ecf20Sopenharmony_ci printk("max_rx_latency: %d, max_rx_gap: %d, min_rx_pkt: %d\n", 9528c2ecf20Sopenharmony_ci rx_int_var & 0x00ff, (rx_int_var & 0x00ff00) >> 8, 9538c2ecf20Sopenharmony_ci (rx_int_var & 0x00ff0000) >> 16); 9548c2ecf20Sopenharmony_ci printk("rx_int_var: %x, tx_int_var: %x\n", rx_int_var, tx_int_var); 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci writel(tx_int_var, ioaddr + TxIntrCtrl); 9588c2ecf20Sopenharmony_ci writel(rx_int_var, ioaddr + RxIntrCtrl); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci set_rx_mode(dev); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci netif_start_queue(dev); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci /* Enable interrupts by setting the interrupt mask. */ 9658c2ecf20Sopenharmony_ci writel(0x80878787, ioaddr + InterruptEnable); 9668c2ecf20Sopenharmony_ci writew(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* Configure and start the DMA channels. */ 9698c2ecf20Sopenharmony_ci /* Burst sizes are in the low three bits: size = 4<<(val&7) */ 9708c2ecf20Sopenharmony_ci#if ADDRLEN == 64 9718c2ecf20Sopenharmony_ci writew(0x005D, ioaddr + RxDMACtrl); /* 128 dword bursts */ 9728c2ecf20Sopenharmony_ci writew(0x005D, ioaddr + TxDMACtrl); 9738c2ecf20Sopenharmony_ci#else 9748c2ecf20Sopenharmony_ci writew(0x001D, ioaddr + RxDMACtrl); 9758c2ecf20Sopenharmony_ci writew(0x001D, ioaddr + TxDMACtrl); 9768c2ecf20Sopenharmony_ci#endif 9778c2ecf20Sopenharmony_ci writew(0x0001, ioaddr + RxCmd); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci if (hamachi_debug > 2) { 9808c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Done hamachi_open(), status: Rx %x Tx %x.\n", 9818c2ecf20Sopenharmony_ci dev->name, readw(ioaddr + RxStatus), readw(ioaddr + TxStatus)); 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci /* Set the timer to check for link beat. */ 9848c2ecf20Sopenharmony_ci timer_setup(&hmp->timer, hamachi_timer, 0); 9858c2ecf20Sopenharmony_ci hmp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ 9868c2ecf20Sopenharmony_ci add_timer(&hmp->timer); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic inline int hamachi_tx(struct net_device *dev) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci /* Update the dirty pointer until we find an entry that is 9968c2ecf20Sopenharmony_ci still owned by the card */ 9978c2ecf20Sopenharmony_ci for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++) { 9988c2ecf20Sopenharmony_ci int entry = hmp->dirty_tx % TX_RING_SIZE; 9998c2ecf20Sopenharmony_ci struct sk_buff *skb; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) 10028c2ecf20Sopenharmony_ci break; 10038c2ecf20Sopenharmony_ci /* Free the original skb. */ 10048c2ecf20Sopenharmony_ci skb = hmp->tx_skbuff[entry]; 10058c2ecf20Sopenharmony_ci if (skb) { 10068c2ecf20Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 10078c2ecf20Sopenharmony_ci leXX_to_cpu(hmp->tx_ring[entry].addr), 10088c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 10098c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 10108c2ecf20Sopenharmony_ci hmp->tx_skbuff[entry] = NULL; 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci hmp->tx_ring[entry].status_n_length = 0; 10138c2ecf20Sopenharmony_ci if (entry >= TX_RING_SIZE-1) 10148c2ecf20Sopenharmony_ci hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= 10158c2ecf20Sopenharmony_ci cpu_to_le32(DescEndRing); 10168c2ecf20Sopenharmony_ci dev->stats.tx_packets++; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci return 0; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic void hamachi_timer(struct timer_list *t) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci struct hamachi_private *hmp = from_timer(hmp, t, timer); 10258c2ecf20Sopenharmony_ci struct net_device *dev = hmp->mii_if.dev; 10268c2ecf20Sopenharmony_ci void __iomem *ioaddr = hmp->base; 10278c2ecf20Sopenharmony_ci int next_tick = 10*HZ; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (hamachi_debug > 2) { 10308c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Hamachi Autonegotiation status %4.4x, LPA " 10318c2ecf20Sopenharmony_ci "%4.4x.\n", dev->name, readw(ioaddr + ANStatus), 10328c2ecf20Sopenharmony_ci readw(ioaddr + ANLinkPartnerAbility)); 10338c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Autonegotiation regs %4.4x %4.4x %4.4x " 10348c2ecf20Sopenharmony_ci "%4.4x %4.4x %4.4x.\n", dev->name, 10358c2ecf20Sopenharmony_ci readw(ioaddr + 0x0e0), 10368c2ecf20Sopenharmony_ci readw(ioaddr + 0x0e2), 10378c2ecf20Sopenharmony_ci readw(ioaddr + 0x0e4), 10388c2ecf20Sopenharmony_ci readw(ioaddr + 0x0e6), 10398c2ecf20Sopenharmony_ci readw(ioaddr + 0x0e8), 10408c2ecf20Sopenharmony_ci readw(ioaddr + 0x0eA)); 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci /* We could do something here... nah. */ 10438c2ecf20Sopenharmony_ci hmp->timer.expires = RUN_AT(next_tick); 10448c2ecf20Sopenharmony_ci add_timer(&hmp->timer); 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic void hamachi_tx_timeout(struct net_device *dev, unsigned int txqueue) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci int i; 10508c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 10518c2ecf20Sopenharmony_ci void __iomem *ioaddr = hmp->base; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x," 10548c2ecf20Sopenharmony_ci " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus)); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci { 10578c2ecf20Sopenharmony_ci printk(KERN_DEBUG " Rx ring %p: ", hmp->rx_ring); 10588c2ecf20Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) 10598c2ecf20Sopenharmony_ci printk(KERN_CONT " %8.8x", 10608c2ecf20Sopenharmony_ci le32_to_cpu(hmp->rx_ring[i].status_n_length)); 10618c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 10628c2ecf20Sopenharmony_ci printk(KERN_DEBUG" Tx ring %p: ", hmp->tx_ring); 10638c2ecf20Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) 10648c2ecf20Sopenharmony_ci printk(KERN_CONT " %4.4x", 10658c2ecf20Sopenharmony_ci le32_to_cpu(hmp->tx_ring[i].status_n_length)); 10668c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* Reinit the hardware and make sure the Rx and Tx processes 10708c2ecf20Sopenharmony_ci are up and running. 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_ci dev->if_port = 0; 10738c2ecf20Sopenharmony_ci /* The right way to do Reset. -KDU 10748c2ecf20Sopenharmony_ci * -Clear OWN bit in all Rx/Tx descriptors 10758c2ecf20Sopenharmony_ci * -Wait 50 uS for channels to go idle 10768c2ecf20Sopenharmony_ci * -Turn off MAC receiver 10778c2ecf20Sopenharmony_ci * -Issue Reset 10788c2ecf20Sopenharmony_ci */ 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) 10818c2ecf20Sopenharmony_ci hmp->rx_ring[i].status_n_length &= cpu_to_le32(~DescOwn); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* Presume that all packets in the Tx queue are gone if we have to 10848c2ecf20Sopenharmony_ci * re-init the hardware. 10858c2ecf20Sopenharmony_ci */ 10868c2ecf20Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++){ 10878c2ecf20Sopenharmony_ci struct sk_buff *skb; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (i >= TX_RING_SIZE - 1) 10908c2ecf20Sopenharmony_ci hmp->tx_ring[i].status_n_length = 10918c2ecf20Sopenharmony_ci cpu_to_le32(DescEndRing) | 10928c2ecf20Sopenharmony_ci (hmp->tx_ring[i].status_n_length & 10938c2ecf20Sopenharmony_ci cpu_to_le32(0x0000ffff)); 10948c2ecf20Sopenharmony_ci else 10958c2ecf20Sopenharmony_ci hmp->tx_ring[i].status_n_length &= cpu_to_le32(0x0000ffff); 10968c2ecf20Sopenharmony_ci skb = hmp->tx_skbuff[i]; 10978c2ecf20Sopenharmony_ci if (skb){ 10988c2ecf20Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 10998c2ecf20Sopenharmony_ci leXX_to_cpu(hmp->tx_ring[i].addr), 11008c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 11018c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 11028c2ecf20Sopenharmony_ci hmp->tx_skbuff[i] = NULL; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci udelay(60); /* Sleep 60 us just for safety sake */ 11078c2ecf20Sopenharmony_ci writew(0x0002, ioaddr + RxCmd); /* STOP Rx */ 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci writeb(0x01, ioaddr + ChipReset); /* Reinit the hardware */ 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci hmp->tx_full = 0; 11128c2ecf20Sopenharmony_ci hmp->cur_rx = hmp->cur_tx = 0; 11138c2ecf20Sopenharmony_ci hmp->dirty_rx = hmp->dirty_tx = 0; 11148c2ecf20Sopenharmony_ci /* Rx packets are also presumed lost; however, we need to make sure a 11158c2ecf20Sopenharmony_ci * ring of buffers is in tact. -KDU 11168c2ecf20Sopenharmony_ci */ 11178c2ecf20Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++){ 11188c2ecf20Sopenharmony_ci struct sk_buff *skb = hmp->rx_skbuff[i]; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci if (skb){ 11218c2ecf20Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 11228c2ecf20Sopenharmony_ci leXX_to_cpu(hmp->rx_ring[i].addr), 11238c2ecf20Sopenharmony_ci hmp->rx_buf_sz, DMA_FROM_DEVICE); 11248c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 11258c2ecf20Sopenharmony_ci hmp->rx_skbuff[i] = NULL; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci /* Fill in the Rx buffers. Handle allocation failure gracefully. */ 11298c2ecf20Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 11308c2ecf20Sopenharmony_ci struct sk_buff *skb; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci skb = netdev_alloc_skb_ip_align(dev, hmp->rx_buf_sz); 11338c2ecf20Sopenharmony_ci hmp->rx_skbuff[i] = skb; 11348c2ecf20Sopenharmony_ci if (skb == NULL) 11358c2ecf20Sopenharmony_ci break; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci hmp->rx_ring[i].addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, 11388c2ecf20Sopenharmony_ci skb->data, 11398c2ecf20Sopenharmony_ci hmp->rx_buf_sz, 11408c2ecf20Sopenharmony_ci DMA_FROM_DEVICE)); 11418c2ecf20Sopenharmony_ci hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | 11428c2ecf20Sopenharmony_ci DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2)); 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); 11458c2ecf20Sopenharmony_ci /* Mark the last entry as wrapping the ring. */ 11468c2ecf20Sopenharmony_ci hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci /* Trigger an immediate transmit demand. */ 11498c2ecf20Sopenharmony_ci netif_trans_update(dev); /* prevent tx timeout */ 11508c2ecf20Sopenharmony_ci dev->stats.tx_errors++; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci /* Restart the chip's Tx/Rx processes . */ 11538c2ecf20Sopenharmony_ci writew(0x0002, ioaddr + TxCmd); /* STOP Tx */ 11548c2ecf20Sopenharmony_ci writew(0x0001, ioaddr + TxCmd); /* START Tx */ 11558c2ecf20Sopenharmony_ci writew(0x0001, ioaddr + RxCmd); /* START Rx */ 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci netif_wake_queue(dev); 11588c2ecf20Sopenharmony_ci} 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ 11628c2ecf20Sopenharmony_cistatic void hamachi_init_ring(struct net_device *dev) 11638c2ecf20Sopenharmony_ci{ 11648c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 11658c2ecf20Sopenharmony_ci int i; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci hmp->tx_full = 0; 11688c2ecf20Sopenharmony_ci hmp->cur_rx = hmp->cur_tx = 0; 11698c2ecf20Sopenharmony_ci hmp->dirty_rx = hmp->dirty_tx = 0; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci /* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the 11728c2ecf20Sopenharmony_ci * card needs room to do 8 byte alignment, +2 so we can reserve 11738c2ecf20Sopenharmony_ci * the first 2 bytes, and +16 gets room for the status word from the 11748c2ecf20Sopenharmony_ci * card. -KDU 11758c2ecf20Sopenharmony_ci */ 11768c2ecf20Sopenharmony_ci hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ : 11778c2ecf20Sopenharmony_ci (((dev->mtu+26+7) & ~7) + 16)); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci /* Initialize all Rx descriptors. */ 11808c2ecf20Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 11818c2ecf20Sopenharmony_ci hmp->rx_ring[i].status_n_length = 0; 11828c2ecf20Sopenharmony_ci hmp->rx_skbuff[i] = NULL; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci /* Fill in the Rx buffers. Handle allocation failure gracefully. */ 11858c2ecf20Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 11868c2ecf20Sopenharmony_ci struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz + 2); 11878c2ecf20Sopenharmony_ci hmp->rx_skbuff[i] = skb; 11888c2ecf20Sopenharmony_ci if (skb == NULL) 11898c2ecf20Sopenharmony_ci break; 11908c2ecf20Sopenharmony_ci skb_reserve(skb, 2); /* 16 byte align the IP header. */ 11918c2ecf20Sopenharmony_ci hmp->rx_ring[i].addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, 11928c2ecf20Sopenharmony_ci skb->data, 11938c2ecf20Sopenharmony_ci hmp->rx_buf_sz, 11948c2ecf20Sopenharmony_ci DMA_FROM_DEVICE)); 11958c2ecf20Sopenharmony_ci /* -2 because it doesn't REALLY have that first 2 bytes -KDU */ 11968c2ecf20Sopenharmony_ci hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn | 11978c2ecf20Sopenharmony_ci DescEndPacket | DescIntr | (hmp->rx_buf_sz -2)); 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); 12008c2ecf20Sopenharmony_ci hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) { 12038c2ecf20Sopenharmony_ci hmp->tx_skbuff[i] = NULL; 12048c2ecf20Sopenharmony_ci hmp->tx_ring[i].status_n_length = 0; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci /* Mark the last entry of the ring */ 12078c2ecf20Sopenharmony_ci hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); 12088c2ecf20Sopenharmony_ci} 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_cistatic netdev_tx_t hamachi_start_xmit(struct sk_buff *skb, 12128c2ecf20Sopenharmony_ci struct net_device *dev) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 12158c2ecf20Sopenharmony_ci unsigned entry; 12168c2ecf20Sopenharmony_ci u16 status; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* Ok, now make sure that the queue has space before trying to 12198c2ecf20Sopenharmony_ci add another skbuff. if we return non-zero the scheduler 12208c2ecf20Sopenharmony_ci should interpret this as a queue full and requeue the buffer 12218c2ecf20Sopenharmony_ci for later. 12228c2ecf20Sopenharmony_ci */ 12238c2ecf20Sopenharmony_ci if (hmp->tx_full) { 12248c2ecf20Sopenharmony_ci /* We should NEVER reach this point -KDU */ 12258c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: Hamachi transmit queue full at slot %d.\n",dev->name, hmp->cur_tx); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci /* Wake the potentially-idle transmit channel. */ 12288c2ecf20Sopenharmony_ci /* If we don't need to read status, DON'T -KDU */ 12298c2ecf20Sopenharmony_ci status=readw(hmp->base + TxStatus); 12308c2ecf20Sopenharmony_ci if( !(status & 0x0001) || (status & 0x0002)) 12318c2ecf20Sopenharmony_ci writew(0x0001, hmp->base + TxCmd); 12328c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci /* Caution: the write order is important here, set the field 12368c2ecf20Sopenharmony_ci with the "ownership" bits last. */ 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* Calculate the next Tx descriptor entry. */ 12398c2ecf20Sopenharmony_ci entry = hmp->cur_tx % TX_RING_SIZE; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci hmp->tx_skbuff[entry] = skb; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci hmp->tx_ring[entry].addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, 12448c2ecf20Sopenharmony_ci skb->data, 12458c2ecf20Sopenharmony_ci skb->len, 12468c2ecf20Sopenharmony_ci DMA_TO_DEVICE)); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci /* Hmmmm, could probably put a DescIntr on these, but the way 12498c2ecf20Sopenharmony_ci the driver is currently coded makes Tx interrupts unnecessary 12508c2ecf20Sopenharmony_ci since the clearing of the Tx ring is handled by the start_xmit 12518c2ecf20Sopenharmony_ci routine. This organization helps mitigate the interrupts a 12528c2ecf20Sopenharmony_ci bit and probably renders the max_tx_latency param useless. 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci Update: Putting a DescIntr bit on all of the descriptors and 12558c2ecf20Sopenharmony_ci mitigating interrupt frequency with the tx_min_pkt parameter. -KDU 12568c2ecf20Sopenharmony_ci */ 12578c2ecf20Sopenharmony_ci if (entry >= TX_RING_SIZE-1) /* Wrap ring */ 12588c2ecf20Sopenharmony_ci hmp->tx_ring[entry].status_n_length = cpu_to_le32(DescOwn | 12598c2ecf20Sopenharmony_ci DescEndPacket | DescEndRing | DescIntr | skb->len); 12608c2ecf20Sopenharmony_ci else 12618c2ecf20Sopenharmony_ci hmp->tx_ring[entry].status_n_length = cpu_to_le32(DescOwn | 12628c2ecf20Sopenharmony_ci DescEndPacket | DescIntr | skb->len); 12638c2ecf20Sopenharmony_ci hmp->cur_tx++; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci /* Non-x86 Todo: explicitly flush cache lines here. */ 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci /* Wake the potentially-idle transmit channel. */ 12688c2ecf20Sopenharmony_ci /* If we don't need to read status, DON'T -KDU */ 12698c2ecf20Sopenharmony_ci status=readw(hmp->base + TxStatus); 12708c2ecf20Sopenharmony_ci if( !(status & 0x0001) || (status & 0x0002)) 12718c2ecf20Sopenharmony_ci writew(0x0001, hmp->base + TxCmd); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* Immediately before returning, let's clear as many entries as we can. */ 12748c2ecf20Sopenharmony_ci hamachi_tx(dev); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci /* We should kick the bottom half here, since we are not accepting 12778c2ecf20Sopenharmony_ci * interrupts with every packet. i.e. realize that Gigabit ethernet 12788c2ecf20Sopenharmony_ci * can transmit faster than ordinary machines can load packets; 12798c2ecf20Sopenharmony_ci * hence, any packet that got put off because we were in the transmit 12808c2ecf20Sopenharmony_ci * routine should IMMEDIATELY get a chance to be re-queued. -KDU 12818c2ecf20Sopenharmony_ci */ 12828c2ecf20Sopenharmony_ci if ((hmp->cur_tx - hmp->dirty_tx) < (TX_RING_SIZE - 4)) 12838c2ecf20Sopenharmony_ci netif_wake_queue(dev); /* Typical path */ 12848c2ecf20Sopenharmony_ci else { 12858c2ecf20Sopenharmony_ci hmp->tx_full = 1; 12868c2ecf20Sopenharmony_ci netif_stop_queue(dev); 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (hamachi_debug > 4) { 12908c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n", 12918c2ecf20Sopenharmony_ci dev->name, hmp->cur_tx, entry); 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci/* The interrupt handler does all of the Rx thread work and cleans up 12978c2ecf20Sopenharmony_ci after the Tx thread. */ 12988c2ecf20Sopenharmony_cistatic irqreturn_t hamachi_interrupt(int irq, void *dev_instance) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci struct net_device *dev = dev_instance; 13018c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 13028c2ecf20Sopenharmony_ci void __iomem *ioaddr = hmp->base; 13038c2ecf20Sopenharmony_ci long boguscnt = max_interrupt_work; 13048c2ecf20Sopenharmony_ci int handled = 0; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci#ifndef final_version /* Can never occur. */ 13078c2ecf20Sopenharmony_ci if (dev == NULL) { 13088c2ecf20Sopenharmony_ci printk (KERN_ERR "hamachi_interrupt(): irq %d for unknown device.\n", irq); 13098c2ecf20Sopenharmony_ci return IRQ_NONE; 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci#endif 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci spin_lock(&hmp->lock); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci do { 13168c2ecf20Sopenharmony_ci u32 intr_status = readl(ioaddr + InterruptClear); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci if (hamachi_debug > 4) 13198c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Hamachi interrupt, status %4.4x.\n", 13208c2ecf20Sopenharmony_ci dev->name, intr_status); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci if (intr_status == 0) 13238c2ecf20Sopenharmony_ci break; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci handled = 1; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci if (intr_status & IntrRxDone) 13288c2ecf20Sopenharmony_ci hamachi_rx(dev); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci if (intr_status & IntrTxDone){ 13318c2ecf20Sopenharmony_ci /* This code should RARELY need to execute. After all, this is 13328c2ecf20Sopenharmony_ci * a gigabit link, it should consume packets as fast as we put 13338c2ecf20Sopenharmony_ci * them in AND we clear the Tx ring in hamachi_start_xmit(). 13348c2ecf20Sopenharmony_ci */ 13358c2ecf20Sopenharmony_ci if (hmp->tx_full){ 13368c2ecf20Sopenharmony_ci for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++){ 13378c2ecf20Sopenharmony_ci int entry = hmp->dirty_tx % TX_RING_SIZE; 13388c2ecf20Sopenharmony_ci struct sk_buff *skb; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) 13418c2ecf20Sopenharmony_ci break; 13428c2ecf20Sopenharmony_ci skb = hmp->tx_skbuff[entry]; 13438c2ecf20Sopenharmony_ci /* Free the original skb. */ 13448c2ecf20Sopenharmony_ci if (skb){ 13458c2ecf20Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 13468c2ecf20Sopenharmony_ci leXX_to_cpu(hmp->tx_ring[entry].addr), 13478c2ecf20Sopenharmony_ci skb->len, 13488c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 13498c2ecf20Sopenharmony_ci dev_consume_skb_irq(skb); 13508c2ecf20Sopenharmony_ci hmp->tx_skbuff[entry] = NULL; 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci hmp->tx_ring[entry].status_n_length = 0; 13538c2ecf20Sopenharmony_ci if (entry >= TX_RING_SIZE-1) 13548c2ecf20Sopenharmony_ci hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= 13558c2ecf20Sopenharmony_ci cpu_to_le32(DescEndRing); 13568c2ecf20Sopenharmony_ci dev->stats.tx_packets++; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci if (hmp->cur_tx - hmp->dirty_tx < TX_RING_SIZE - 4){ 13598c2ecf20Sopenharmony_ci /* The ring is no longer full */ 13608c2ecf20Sopenharmony_ci hmp->tx_full = 0; 13618c2ecf20Sopenharmony_ci netif_wake_queue(dev); 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci } else { 13648c2ecf20Sopenharmony_ci netif_wake_queue(dev); 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci /* Abnormal error summary/uncommon events handlers. */ 13708c2ecf20Sopenharmony_ci if (intr_status & 13718c2ecf20Sopenharmony_ci (IntrTxPCIFault | IntrTxPCIErr | IntrRxPCIFault | IntrRxPCIErr | 13728c2ecf20Sopenharmony_ci LinkChange | NegotiationChange | StatsMax)) 13738c2ecf20Sopenharmony_ci hamachi_error(dev, intr_status); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci if (--boguscnt < 0) { 13768c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n", 13778c2ecf20Sopenharmony_ci dev->name, intr_status); 13788c2ecf20Sopenharmony_ci break; 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci } while (1); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (hamachi_debug > 3) 13838c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", 13848c2ecf20Sopenharmony_ci dev->name, readl(ioaddr + IntrStatus)); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci#ifndef final_version 13878c2ecf20Sopenharmony_ci /* Code that should never be run! Perhaps remove after testing.. */ 13888c2ecf20Sopenharmony_ci { 13898c2ecf20Sopenharmony_ci static int stopit = 10; 13908c2ecf20Sopenharmony_ci if (dev->start == 0 && --stopit < 0) { 13918c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", 13928c2ecf20Sopenharmony_ci dev->name); 13938c2ecf20Sopenharmony_ci free_irq(irq, dev); 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci#endif 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci spin_unlock(&hmp->lock); 13998c2ecf20Sopenharmony_ci return IRQ_RETVAL(handled); 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci/* This routine is logically part of the interrupt handler, but separated 14038c2ecf20Sopenharmony_ci for clarity and better register allocation. */ 14048c2ecf20Sopenharmony_cistatic int hamachi_rx(struct net_device *dev) 14058c2ecf20Sopenharmony_ci{ 14068c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 14078c2ecf20Sopenharmony_ci int entry = hmp->cur_rx % RX_RING_SIZE; 14088c2ecf20Sopenharmony_ci int boguscnt = (hmp->dirty_rx + RX_RING_SIZE) - hmp->cur_rx; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (hamachi_debug > 4) { 14118c2ecf20Sopenharmony_ci printk(KERN_DEBUG " In hamachi_rx(), entry %d status %4.4x.\n", 14128c2ecf20Sopenharmony_ci entry, hmp->rx_ring[entry].status_n_length); 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci /* If EOP is set on the next entry, it's a new packet. Send it up. */ 14168c2ecf20Sopenharmony_ci while (1) { 14178c2ecf20Sopenharmony_ci struct hamachi_desc *desc = &(hmp->rx_ring[entry]); 14188c2ecf20Sopenharmony_ci u32 desc_status = le32_to_cpu(desc->status_n_length); 14198c2ecf20Sopenharmony_ci u16 data_size = desc_status; /* Implicit truncate */ 14208c2ecf20Sopenharmony_ci u8 *buf_addr; 14218c2ecf20Sopenharmony_ci s32 frame_status; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (desc_status & DescOwn) 14248c2ecf20Sopenharmony_ci break; 14258c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&hmp->pci_dev->dev, 14268c2ecf20Sopenharmony_ci leXX_to_cpu(desc->addr), 14278c2ecf20Sopenharmony_ci hmp->rx_buf_sz, DMA_FROM_DEVICE); 14288c2ecf20Sopenharmony_ci buf_addr = (u8 *) hmp->rx_skbuff[entry]->data; 14298c2ecf20Sopenharmony_ci frame_status = get_unaligned_le32(&(buf_addr[data_size - 12])); 14308c2ecf20Sopenharmony_ci if (hamachi_debug > 4) 14318c2ecf20Sopenharmony_ci printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n", 14328c2ecf20Sopenharmony_ci frame_status); 14338c2ecf20Sopenharmony_ci if (--boguscnt < 0) 14348c2ecf20Sopenharmony_ci break; 14358c2ecf20Sopenharmony_ci if ( ! (desc_status & DescEndPacket)) { 14368c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " 14378c2ecf20Sopenharmony_ci "multiple buffers, entry %#x length %d status %4.4x!\n", 14388c2ecf20Sopenharmony_ci dev->name, hmp->cur_rx, data_size, desc_status); 14398c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n", 14408c2ecf20Sopenharmony_ci dev->name, desc, &hmp->rx_ring[hmp->cur_rx % RX_RING_SIZE]); 14418c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: Oversized Ethernet frame -- next status %x/%x last status %x.\n", 14428c2ecf20Sopenharmony_ci dev->name, 14438c2ecf20Sopenharmony_ci le32_to_cpu(hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length) & 0xffff0000, 14448c2ecf20Sopenharmony_ci le32_to_cpu(hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length) & 0x0000ffff, 14458c2ecf20Sopenharmony_ci le32_to_cpu(hmp->rx_ring[(hmp->cur_rx-1) % RX_RING_SIZE].status_n_length)); 14468c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 14478c2ecf20Sopenharmony_ci } /* else Omit for prototype errata??? */ 14488c2ecf20Sopenharmony_ci if (frame_status & 0x00380000) { 14498c2ecf20Sopenharmony_ci /* There was an error. */ 14508c2ecf20Sopenharmony_ci if (hamachi_debug > 2) 14518c2ecf20Sopenharmony_ci printk(KERN_DEBUG " hamachi_rx() Rx error was %8.8x.\n", 14528c2ecf20Sopenharmony_ci frame_status); 14538c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 14548c2ecf20Sopenharmony_ci if (frame_status & 0x00600000) 14558c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 14568c2ecf20Sopenharmony_ci if (frame_status & 0x00080000) 14578c2ecf20Sopenharmony_ci dev->stats.rx_frame_errors++; 14588c2ecf20Sopenharmony_ci if (frame_status & 0x00100000) 14598c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors++; 14608c2ecf20Sopenharmony_ci if (frame_status < 0) 14618c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 14628c2ecf20Sopenharmony_ci } else { 14638c2ecf20Sopenharmony_ci struct sk_buff *skb; 14648c2ecf20Sopenharmony_ci /* Omit CRC */ 14658c2ecf20Sopenharmony_ci u16 pkt_len = (frame_status & 0x07ff) - 4; 14668c2ecf20Sopenharmony_ci#ifdef RX_CHECKSUM 14678c2ecf20Sopenharmony_ci u32 pfck = *(u32 *) &buf_addr[data_size - 8]; 14688c2ecf20Sopenharmony_ci#endif 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci#ifndef final_version 14728c2ecf20Sopenharmony_ci if (hamachi_debug > 4) 14738c2ecf20Sopenharmony_ci printk(KERN_DEBUG " hamachi_rx() normal Rx pkt length %d" 14748c2ecf20Sopenharmony_ci " of %d, bogus_cnt %d.\n", 14758c2ecf20Sopenharmony_ci pkt_len, data_size, boguscnt); 14768c2ecf20Sopenharmony_ci if (hamachi_debug > 5) 14778c2ecf20Sopenharmony_ci printk(KERN_DEBUG"%s: rx status %8.8x %8.8x %8.8x %8.8x %8.8x.\n", 14788c2ecf20Sopenharmony_ci dev->name, 14798c2ecf20Sopenharmony_ci *(s32*)&(buf_addr[data_size - 20]), 14808c2ecf20Sopenharmony_ci *(s32*)&(buf_addr[data_size - 16]), 14818c2ecf20Sopenharmony_ci *(s32*)&(buf_addr[data_size - 12]), 14828c2ecf20Sopenharmony_ci *(s32*)&(buf_addr[data_size - 8]), 14838c2ecf20Sopenharmony_ci *(s32*)&(buf_addr[data_size - 4])); 14848c2ecf20Sopenharmony_ci#endif 14858c2ecf20Sopenharmony_ci /* Check if the packet is long enough to accept without copying 14868c2ecf20Sopenharmony_ci to a minimally-sized skbuff. */ 14878c2ecf20Sopenharmony_ci if (pkt_len < rx_copybreak && 14888c2ecf20Sopenharmony_ci (skb = netdev_alloc_skb(dev, pkt_len + 2)) != NULL) { 14898c2ecf20Sopenharmony_ci#ifdef RX_CHECKSUM 14908c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: rx_copybreak non-zero " 14918c2ecf20Sopenharmony_ci "not good with RX_CHECKSUM\n", dev->name); 14928c2ecf20Sopenharmony_ci#endif 14938c2ecf20Sopenharmony_ci skb_reserve(skb, 2); /* 16 byte align the IP header */ 14948c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&hmp->pci_dev->dev, 14958c2ecf20Sopenharmony_ci leXX_to_cpu(hmp->rx_ring[entry].addr), 14968c2ecf20Sopenharmony_ci hmp->rx_buf_sz, 14978c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 14988c2ecf20Sopenharmony_ci /* Call copy + cksum if available. */ 14998c2ecf20Sopenharmony_ci#if 1 || USE_IP_COPYSUM 15008c2ecf20Sopenharmony_ci skb_copy_to_linear_data(skb, 15018c2ecf20Sopenharmony_ci hmp->rx_skbuff[entry]->data, pkt_len); 15028c2ecf20Sopenharmony_ci skb_put(skb, pkt_len); 15038c2ecf20Sopenharmony_ci#else 15048c2ecf20Sopenharmony_ci skb_put_data(skb, hmp->rx_ring_dma 15058c2ecf20Sopenharmony_ci + entry*sizeof(*desc), pkt_len); 15068c2ecf20Sopenharmony_ci#endif 15078c2ecf20Sopenharmony_ci dma_sync_single_for_device(&hmp->pci_dev->dev, 15088c2ecf20Sopenharmony_ci leXX_to_cpu(hmp->rx_ring[entry].addr), 15098c2ecf20Sopenharmony_ci hmp->rx_buf_sz, 15108c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 15118c2ecf20Sopenharmony_ci } else { 15128c2ecf20Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 15138c2ecf20Sopenharmony_ci leXX_to_cpu(hmp->rx_ring[entry].addr), 15148c2ecf20Sopenharmony_ci hmp->rx_buf_sz, 15158c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 15168c2ecf20Sopenharmony_ci skb_put(skb = hmp->rx_skbuff[entry], pkt_len); 15178c2ecf20Sopenharmony_ci hmp->rx_skbuff[entry] = NULL; 15188c2ecf20Sopenharmony_ci } 15198c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci#ifdef RX_CHECKSUM 15238c2ecf20Sopenharmony_ci /* TCP or UDP on ipv4, DIX encoding */ 15248c2ecf20Sopenharmony_ci if (pfck>>24 == 0x91 || pfck>>24 == 0x51) { 15258c2ecf20Sopenharmony_ci struct iphdr *ih = (struct iphdr *) skb->data; 15268c2ecf20Sopenharmony_ci /* Check that IP packet is at least 46 bytes, otherwise, 15278c2ecf20Sopenharmony_ci * there may be pad bytes included in the hardware checksum. 15288c2ecf20Sopenharmony_ci * This wouldn't happen if everyone padded with 0. 15298c2ecf20Sopenharmony_ci */ 15308c2ecf20Sopenharmony_ci if (ntohs(ih->tot_len) >= 46){ 15318c2ecf20Sopenharmony_ci /* don't worry about frags */ 15328c2ecf20Sopenharmony_ci if (!(ih->frag_off & cpu_to_be16(IP_MF|IP_OFFSET))) { 15338c2ecf20Sopenharmony_ci u32 inv = *(u32 *) &buf_addr[data_size - 16]; 15348c2ecf20Sopenharmony_ci u32 *p = (u32 *) &buf_addr[data_size - 20]; 15358c2ecf20Sopenharmony_ci register u32 crc, p_r, p_r1; 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (inv & 4) { 15388c2ecf20Sopenharmony_ci inv &= ~4; 15398c2ecf20Sopenharmony_ci --p; 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci p_r = *p; 15428c2ecf20Sopenharmony_ci p_r1 = *(p-1); 15438c2ecf20Sopenharmony_ci switch (inv) { 15448c2ecf20Sopenharmony_ci case 0: 15458c2ecf20Sopenharmony_ci crc = (p_r & 0xffff) + (p_r >> 16); 15468c2ecf20Sopenharmony_ci break; 15478c2ecf20Sopenharmony_ci case 1: 15488c2ecf20Sopenharmony_ci crc = (p_r >> 16) + (p_r & 0xffff) 15498c2ecf20Sopenharmony_ci + (p_r1 >> 16 & 0xff00); 15508c2ecf20Sopenharmony_ci break; 15518c2ecf20Sopenharmony_ci case 2: 15528c2ecf20Sopenharmony_ci crc = p_r + (p_r1 >> 16); 15538c2ecf20Sopenharmony_ci break; 15548c2ecf20Sopenharmony_ci case 3: 15558c2ecf20Sopenharmony_ci crc = p_r + (p_r1 & 0xff00) + (p_r1 >> 16); 15568c2ecf20Sopenharmony_ci break; 15578c2ecf20Sopenharmony_ci default: /*NOTREACHED*/ crc = 0; 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci if (crc & 0xffff0000) { 15608c2ecf20Sopenharmony_ci crc &= 0xffff; 15618c2ecf20Sopenharmony_ci ++crc; 15628c2ecf20Sopenharmony_ci } 15638c2ecf20Sopenharmony_ci /* tcp/udp will add in pseudo */ 15648c2ecf20Sopenharmony_ci skb->csum = ntohs(pfck & 0xffff); 15658c2ecf20Sopenharmony_ci if (skb->csum > crc) 15668c2ecf20Sopenharmony_ci skb->csum -= crc; 15678c2ecf20Sopenharmony_ci else 15688c2ecf20Sopenharmony_ci skb->csum += (~crc & 0xffff); 15698c2ecf20Sopenharmony_ci /* 15708c2ecf20Sopenharmony_ci * could do the pseudo myself and return 15718c2ecf20Sopenharmony_ci * CHECKSUM_UNNECESSARY 15728c2ecf20Sopenharmony_ci */ 15738c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 15748c2ecf20Sopenharmony_ci } 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci#endif /* RX_CHECKSUM */ 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci netif_rx(skb); 15808c2ecf20Sopenharmony_ci dev->stats.rx_packets++; 15818c2ecf20Sopenharmony_ci } 15828c2ecf20Sopenharmony_ci entry = (++hmp->cur_rx) % RX_RING_SIZE; 15838c2ecf20Sopenharmony_ci } 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci /* Refill the Rx ring buffers. */ 15868c2ecf20Sopenharmony_ci for (; hmp->cur_rx - hmp->dirty_rx > 0; hmp->dirty_rx++) { 15878c2ecf20Sopenharmony_ci struct hamachi_desc *desc; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci entry = hmp->dirty_rx % RX_RING_SIZE; 15908c2ecf20Sopenharmony_ci desc = &(hmp->rx_ring[entry]); 15918c2ecf20Sopenharmony_ci if (hmp->rx_skbuff[entry] == NULL) { 15928c2ecf20Sopenharmony_ci struct sk_buff *skb = netdev_alloc_skb(dev, hmp->rx_buf_sz + 2); 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci hmp->rx_skbuff[entry] = skb; 15958c2ecf20Sopenharmony_ci if (skb == NULL) 15968c2ecf20Sopenharmony_ci break; /* Better luck next round. */ 15978c2ecf20Sopenharmony_ci skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ 15988c2ecf20Sopenharmony_ci desc->addr = cpu_to_leXX(dma_map_single(&hmp->pci_dev->dev, 15998c2ecf20Sopenharmony_ci skb->data, 16008c2ecf20Sopenharmony_ci hmp->rx_buf_sz, 16018c2ecf20Sopenharmony_ci DMA_FROM_DEVICE)); 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci desc->status_n_length = cpu_to_le32(hmp->rx_buf_sz); 16048c2ecf20Sopenharmony_ci if (entry >= RX_RING_SIZE-1) 16058c2ecf20Sopenharmony_ci desc->status_n_length |= cpu_to_le32(DescOwn | 16068c2ecf20Sopenharmony_ci DescEndPacket | DescEndRing | DescIntr); 16078c2ecf20Sopenharmony_ci else 16088c2ecf20Sopenharmony_ci desc->status_n_length |= cpu_to_le32(DescOwn | 16098c2ecf20Sopenharmony_ci DescEndPacket | DescIntr); 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* Restart Rx engine if stopped. */ 16138c2ecf20Sopenharmony_ci /* If we don't need to check status, don't. -KDU */ 16148c2ecf20Sopenharmony_ci if (readw(hmp->base + RxStatus) & 0x0002) 16158c2ecf20Sopenharmony_ci writew(0x0001, hmp->base + RxCmd); 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci return 0; 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci/* This is more properly named "uncommon interrupt events", as it covers more 16218c2ecf20Sopenharmony_ci than just errors. */ 16228c2ecf20Sopenharmony_cistatic void hamachi_error(struct net_device *dev, int intr_status) 16238c2ecf20Sopenharmony_ci{ 16248c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 16258c2ecf20Sopenharmony_ci void __iomem *ioaddr = hmp->base; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (intr_status & (LinkChange|NegotiationChange)) { 16288c2ecf20Sopenharmony_ci if (hamachi_debug > 1) 16298c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Link changed: AutoNegotiation Ctrl" 16308c2ecf20Sopenharmony_ci " %4.4x, Status %4.4x %4.4x Intr status %4.4x.\n", 16318c2ecf20Sopenharmony_ci dev->name, readw(ioaddr + 0x0E0), readw(ioaddr + 0x0E2), 16328c2ecf20Sopenharmony_ci readw(ioaddr + ANLinkPartnerAbility), 16338c2ecf20Sopenharmony_ci readl(ioaddr + IntrStatus)); 16348c2ecf20Sopenharmony_ci if (readw(ioaddr + ANStatus) & 0x20) 16358c2ecf20Sopenharmony_ci writeb(0x01, ioaddr + LEDCtrl); 16368c2ecf20Sopenharmony_ci else 16378c2ecf20Sopenharmony_ci writeb(0x03, ioaddr + LEDCtrl); 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci if (intr_status & StatsMax) { 16408c2ecf20Sopenharmony_ci hamachi_get_stats(dev); 16418c2ecf20Sopenharmony_ci /* Read the overflow bits to clear. */ 16428c2ecf20Sopenharmony_ci readl(ioaddr + 0x370); 16438c2ecf20Sopenharmony_ci readl(ioaddr + 0x3F0); 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci if ((intr_status & ~(LinkChange|StatsMax|NegotiationChange|IntrRxDone|IntrTxDone)) && 16468c2ecf20Sopenharmony_ci hamachi_debug) 16478c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", 16488c2ecf20Sopenharmony_ci dev->name, intr_status); 16498c2ecf20Sopenharmony_ci /* Hmmmmm, it's not clear how to recover from PCI faults. */ 16508c2ecf20Sopenharmony_ci if (intr_status & (IntrTxPCIErr | IntrTxPCIFault)) 16518c2ecf20Sopenharmony_ci dev->stats.tx_fifo_errors++; 16528c2ecf20Sopenharmony_ci if (intr_status & (IntrRxPCIErr | IntrRxPCIFault)) 16538c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 16548c2ecf20Sopenharmony_ci} 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_cistatic int hamachi_close(struct net_device *dev) 16578c2ecf20Sopenharmony_ci{ 16588c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 16598c2ecf20Sopenharmony_ci void __iomem *ioaddr = hmp->base; 16608c2ecf20Sopenharmony_ci struct sk_buff *skb; 16618c2ecf20Sopenharmony_ci int i; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci netif_stop_queue(dev); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci if (hamachi_debug > 1) { 16668c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n", 16678c2ecf20Sopenharmony_ci dev->name, readw(ioaddr + TxStatus), 16688c2ecf20Sopenharmony_ci readw(ioaddr + RxStatus), readl(ioaddr + IntrStatus)); 16698c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", 16708c2ecf20Sopenharmony_ci dev->name, hmp->cur_tx, hmp->dirty_tx, hmp->cur_rx, hmp->dirty_rx); 16718c2ecf20Sopenharmony_ci } 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci /* Disable interrupts by clearing the interrupt mask. */ 16748c2ecf20Sopenharmony_ci writel(0x0000, ioaddr + InterruptEnable); 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci /* Stop the chip's Tx and Rx processes. */ 16778c2ecf20Sopenharmony_ci writel(2, ioaddr + RxCmd); 16788c2ecf20Sopenharmony_ci writew(2, ioaddr + TxCmd); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci#ifdef __i386__ 16818c2ecf20Sopenharmony_ci if (hamachi_debug > 2) { 16828c2ecf20Sopenharmony_ci printk(KERN_DEBUG " Tx ring at %8.8x:\n", 16838c2ecf20Sopenharmony_ci (int)hmp->tx_ring_dma); 16848c2ecf20Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) 16858c2ecf20Sopenharmony_ci printk(KERN_DEBUG " %c #%d desc. %8.8x %8.8x.\n", 16868c2ecf20Sopenharmony_ci readl(ioaddr + TxCurPtr) == (long)&hmp->tx_ring[i] ? '>' : ' ', 16878c2ecf20Sopenharmony_ci i, hmp->tx_ring[i].status_n_length, hmp->tx_ring[i].addr); 16888c2ecf20Sopenharmony_ci printk(KERN_DEBUG " Rx ring %8.8x:\n", 16898c2ecf20Sopenharmony_ci (int)hmp->rx_ring_dma); 16908c2ecf20Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 16918c2ecf20Sopenharmony_ci printk(KERN_DEBUG " %c #%d desc. %4.4x %8.8x\n", 16928c2ecf20Sopenharmony_ci readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ', 16938c2ecf20Sopenharmony_ci i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr); 16948c2ecf20Sopenharmony_ci if (hamachi_debug > 6) { 16958c2ecf20Sopenharmony_ci if (*(u8*)hmp->rx_skbuff[i]->data != 0x69) { 16968c2ecf20Sopenharmony_ci u16 *addr = (u16 *) 16978c2ecf20Sopenharmony_ci hmp->rx_skbuff[i]->data; 16988c2ecf20Sopenharmony_ci int j; 16998c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Addr: "); 17008c2ecf20Sopenharmony_ci for (j = 0; j < 0x50; j++) 17018c2ecf20Sopenharmony_ci printk(" %4.4x", addr[j]); 17028c2ecf20Sopenharmony_ci printk("\n"); 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci } 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci#endif /* __i386__ debugging only */ 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci free_irq(hmp->pci_dev->irq, dev); 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci del_timer_sync(&hmp->timer); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci /* Free all the skbuffs in the Rx queue. */ 17148c2ecf20Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 17158c2ecf20Sopenharmony_ci skb = hmp->rx_skbuff[i]; 17168c2ecf20Sopenharmony_ci hmp->rx_ring[i].status_n_length = 0; 17178c2ecf20Sopenharmony_ci if (skb) { 17188c2ecf20Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 17198c2ecf20Sopenharmony_ci leXX_to_cpu(hmp->rx_ring[i].addr), 17208c2ecf20Sopenharmony_ci hmp->rx_buf_sz, DMA_FROM_DEVICE); 17218c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 17228c2ecf20Sopenharmony_ci hmp->rx_skbuff[i] = NULL; 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci hmp->rx_ring[i].addr = cpu_to_leXX(0xBADF00D0); /* An invalid address. */ 17258c2ecf20Sopenharmony_ci } 17268c2ecf20Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) { 17278c2ecf20Sopenharmony_ci skb = hmp->tx_skbuff[i]; 17288c2ecf20Sopenharmony_ci if (skb) { 17298c2ecf20Sopenharmony_ci dma_unmap_single(&hmp->pci_dev->dev, 17308c2ecf20Sopenharmony_ci leXX_to_cpu(hmp->tx_ring[i].addr), 17318c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 17328c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 17338c2ecf20Sopenharmony_ci hmp->tx_skbuff[i] = NULL; 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci writeb(0x00, ioaddr + LEDCtrl); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci return 0; 17408c2ecf20Sopenharmony_ci} 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_cistatic struct net_device_stats *hamachi_get_stats(struct net_device *dev) 17438c2ecf20Sopenharmony_ci{ 17448c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 17458c2ecf20Sopenharmony_ci void __iomem *ioaddr = hmp->base; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci /* We should lock this segment of code for SMP eventually, although 17488c2ecf20Sopenharmony_ci the vulnerability window is very small and statistics are 17498c2ecf20Sopenharmony_ci non-critical. */ 17508c2ecf20Sopenharmony_ci /* Ok, what goes here? This appears to be stuck at 21 packets 17518c2ecf20Sopenharmony_ci according to ifconfig. It does get incremented in hamachi_tx(), 17528c2ecf20Sopenharmony_ci so I think I'll comment it out here and see if better things 17538c2ecf20Sopenharmony_ci happen. 17548c2ecf20Sopenharmony_ci */ 17558c2ecf20Sopenharmony_ci /* dev->stats.tx_packets = readl(ioaddr + 0x000); */ 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci /* Total Uni+Brd+Multi */ 17588c2ecf20Sopenharmony_ci dev->stats.rx_bytes = readl(ioaddr + 0x330); 17598c2ecf20Sopenharmony_ci /* Total Uni+Brd+Multi */ 17608c2ecf20Sopenharmony_ci dev->stats.tx_bytes = readl(ioaddr + 0x3B0); 17618c2ecf20Sopenharmony_ci /* Multicast Rx */ 17628c2ecf20Sopenharmony_ci dev->stats.multicast = readl(ioaddr + 0x320); 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci /* Over+Undersized */ 17658c2ecf20Sopenharmony_ci dev->stats.rx_length_errors = readl(ioaddr + 0x368); 17668c2ecf20Sopenharmony_ci /* Jabber */ 17678c2ecf20Sopenharmony_ci dev->stats.rx_over_errors = readl(ioaddr + 0x35C); 17688c2ecf20Sopenharmony_ci /* Jabber */ 17698c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors = readl(ioaddr + 0x360); 17708c2ecf20Sopenharmony_ci /* Symbol Errs */ 17718c2ecf20Sopenharmony_ci dev->stats.rx_frame_errors = readl(ioaddr + 0x364); 17728c2ecf20Sopenharmony_ci /* Dropped */ 17738c2ecf20Sopenharmony_ci dev->stats.rx_missed_errors = readl(ioaddr + 0x36C); 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci return &dev->stats; 17768c2ecf20Sopenharmony_ci} 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_cistatic void set_rx_mode(struct net_device *dev) 17798c2ecf20Sopenharmony_ci{ 17808c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 17818c2ecf20Sopenharmony_ci void __iomem *ioaddr = hmp->base; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ 17848c2ecf20Sopenharmony_ci writew(0x000F, ioaddr + AddrMode); 17858c2ecf20Sopenharmony_ci } else if ((netdev_mc_count(dev) > 63) || (dev->flags & IFF_ALLMULTI)) { 17868c2ecf20Sopenharmony_ci /* Too many to match, or accept all multicasts. */ 17878c2ecf20Sopenharmony_ci writew(0x000B, ioaddr + AddrMode); 17888c2ecf20Sopenharmony_ci } else if (!netdev_mc_empty(dev)) { /* Must use the CAM filter. */ 17898c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 17908c2ecf20Sopenharmony_ci int i = 0; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 17938c2ecf20Sopenharmony_ci writel(*(u32 *)(ha->addr), ioaddr + 0x100 + i*8); 17948c2ecf20Sopenharmony_ci writel(0x20000 | (*(u16 *)&ha->addr[4]), 17958c2ecf20Sopenharmony_ci ioaddr + 0x104 + i*8); 17968c2ecf20Sopenharmony_ci i++; 17978c2ecf20Sopenharmony_ci } 17988c2ecf20Sopenharmony_ci /* Clear remaining entries. */ 17998c2ecf20Sopenharmony_ci for (; i < 64; i++) 18008c2ecf20Sopenharmony_ci writel(0, ioaddr + 0x104 + i*8); 18018c2ecf20Sopenharmony_ci writew(0x0003, ioaddr + AddrMode); 18028c2ecf20Sopenharmony_ci } else { /* Normal, unicast/broadcast-only mode. */ 18038c2ecf20Sopenharmony_ci writew(0x0001, ioaddr + AddrMode); 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci} 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_cistatic int check_if_running(struct net_device *dev) 18088c2ecf20Sopenharmony_ci{ 18098c2ecf20Sopenharmony_ci if (!netif_running(dev)) 18108c2ecf20Sopenharmony_ci return -EINVAL; 18118c2ecf20Sopenharmony_ci return 0; 18128c2ecf20Sopenharmony_ci} 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_cistatic void hamachi_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 18158c2ecf20Sopenharmony_ci{ 18168c2ecf20Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 18198c2ecf20Sopenharmony_ci strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 18208c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(np->pci_dev), sizeof(info->bus_info)); 18218c2ecf20Sopenharmony_ci} 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_cistatic int hamachi_get_link_ksettings(struct net_device *dev, 18248c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 18258c2ecf20Sopenharmony_ci{ 18268c2ecf20Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 18278c2ecf20Sopenharmony_ci spin_lock_irq(&np->lock); 18288c2ecf20Sopenharmony_ci mii_ethtool_get_link_ksettings(&np->mii_if, cmd); 18298c2ecf20Sopenharmony_ci spin_unlock_irq(&np->lock); 18308c2ecf20Sopenharmony_ci return 0; 18318c2ecf20Sopenharmony_ci} 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_cistatic int hamachi_set_link_ksettings(struct net_device *dev, 18348c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 18378c2ecf20Sopenharmony_ci int res; 18388c2ecf20Sopenharmony_ci spin_lock_irq(&np->lock); 18398c2ecf20Sopenharmony_ci res = mii_ethtool_set_link_ksettings(&np->mii_if, cmd); 18408c2ecf20Sopenharmony_ci spin_unlock_irq(&np->lock); 18418c2ecf20Sopenharmony_ci return res; 18428c2ecf20Sopenharmony_ci} 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_cistatic int hamachi_nway_reset(struct net_device *dev) 18458c2ecf20Sopenharmony_ci{ 18468c2ecf20Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 18478c2ecf20Sopenharmony_ci return mii_nway_restart(&np->mii_if); 18488c2ecf20Sopenharmony_ci} 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_cistatic u32 hamachi_get_link(struct net_device *dev) 18518c2ecf20Sopenharmony_ci{ 18528c2ecf20Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 18538c2ecf20Sopenharmony_ci return mii_link_ok(&np->mii_if); 18548c2ecf20Sopenharmony_ci} 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_cistatic const struct ethtool_ops ethtool_ops = { 18578c2ecf20Sopenharmony_ci .begin = check_if_running, 18588c2ecf20Sopenharmony_ci .get_drvinfo = hamachi_get_drvinfo, 18598c2ecf20Sopenharmony_ci .nway_reset = hamachi_nway_reset, 18608c2ecf20Sopenharmony_ci .get_link = hamachi_get_link, 18618c2ecf20Sopenharmony_ci .get_link_ksettings = hamachi_get_link_ksettings, 18628c2ecf20Sopenharmony_ci .set_link_ksettings = hamachi_set_link_ksettings, 18638c2ecf20Sopenharmony_ci}; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_cistatic const struct ethtool_ops ethtool_ops_no_mii = { 18668c2ecf20Sopenharmony_ci .begin = check_if_running, 18678c2ecf20Sopenharmony_ci .get_drvinfo = hamachi_get_drvinfo, 18688c2ecf20Sopenharmony_ci}; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_cistatic int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 18718c2ecf20Sopenharmony_ci{ 18728c2ecf20Sopenharmony_ci struct hamachi_private *np = netdev_priv(dev); 18738c2ecf20Sopenharmony_ci struct mii_ioctl_data *data = if_mii(rq); 18748c2ecf20Sopenharmony_ci int rc; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci if (!netif_running(dev)) 18778c2ecf20Sopenharmony_ci return -EINVAL; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci if (cmd == (SIOCDEVPRIVATE+3)) { /* set rx,tx intr params */ 18808c2ecf20Sopenharmony_ci u32 *d = (u32 *)&rq->ifr_ifru; 18818c2ecf20Sopenharmony_ci /* Should add this check here or an ordinary user can do nasty 18828c2ecf20Sopenharmony_ci * things. -KDU 18838c2ecf20Sopenharmony_ci * 18848c2ecf20Sopenharmony_ci * TODO: Shut down the Rx and Tx engines while doing this. 18858c2ecf20Sopenharmony_ci */ 18868c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 18878c2ecf20Sopenharmony_ci return -EPERM; 18888c2ecf20Sopenharmony_ci writel(d[0], np->base + TxIntrCtrl); 18898c2ecf20Sopenharmony_ci writel(d[1], np->base + RxIntrCtrl); 18908c2ecf20Sopenharmony_ci printk(KERN_NOTICE "%s: tx %08x, rx %08x intr\n", dev->name, 18918c2ecf20Sopenharmony_ci (u32) readl(np->base + TxIntrCtrl), 18928c2ecf20Sopenharmony_ci (u32) readl(np->base + RxIntrCtrl)); 18938c2ecf20Sopenharmony_ci rc = 0; 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci else { 18978c2ecf20Sopenharmony_ci spin_lock_irq(&np->lock); 18988c2ecf20Sopenharmony_ci rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL); 18998c2ecf20Sopenharmony_ci spin_unlock_irq(&np->lock); 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci return rc; 19038c2ecf20Sopenharmony_ci} 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_cistatic void hamachi_remove_one(struct pci_dev *pdev) 19078c2ecf20Sopenharmony_ci{ 19088c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci if (dev) { 19118c2ecf20Sopenharmony_ci struct hamachi_private *hmp = netdev_priv(dev); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, hmp->rx_ring, 19148c2ecf20Sopenharmony_ci hmp->rx_ring_dma); 19158c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, hmp->tx_ring, 19168c2ecf20Sopenharmony_ci hmp->tx_ring_dma); 19178c2ecf20Sopenharmony_ci unregister_netdev(dev); 19188c2ecf20Sopenharmony_ci iounmap(hmp->base); 19198c2ecf20Sopenharmony_ci free_netdev(dev); 19208c2ecf20Sopenharmony_ci pci_release_regions(pdev); 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci} 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_cistatic const struct pci_device_id hamachi_pci_tbl[] = { 19258c2ecf20Sopenharmony_ci { 0x1318, 0x0911, PCI_ANY_ID, PCI_ANY_ID, }, 19268c2ecf20Sopenharmony_ci { 0, } 19278c2ecf20Sopenharmony_ci}; 19288c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hamachi_pci_tbl); 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_cistatic struct pci_driver hamachi_driver = { 19318c2ecf20Sopenharmony_ci .name = DRV_NAME, 19328c2ecf20Sopenharmony_ci .id_table = hamachi_pci_tbl, 19338c2ecf20Sopenharmony_ci .probe = hamachi_init_one, 19348c2ecf20Sopenharmony_ci .remove = hamachi_remove_one, 19358c2ecf20Sopenharmony_ci}; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_cistatic int __init hamachi_init (void) 19388c2ecf20Sopenharmony_ci{ 19398c2ecf20Sopenharmony_ci/* when a module, this is printed whether or not devices are found in probe */ 19408c2ecf20Sopenharmony_ci#ifdef MODULE 19418c2ecf20Sopenharmony_ci printk(version); 19428c2ecf20Sopenharmony_ci#endif 19438c2ecf20Sopenharmony_ci return pci_register_driver(&hamachi_driver); 19448c2ecf20Sopenharmony_ci} 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_cistatic void __exit hamachi_exit (void) 19478c2ecf20Sopenharmony_ci{ 19488c2ecf20Sopenharmony_ci pci_unregister_driver(&hamachi_driver); 19498c2ecf20Sopenharmony_ci} 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_cimodule_init(hamachi_init); 19538c2ecf20Sopenharmony_cimodule_exit(hamachi_exit); 1954