11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* znet.c: An Zenith Z-Note ethernet driver for linux. */ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Written by Donald Becker. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The author may be reached as becker@scyld.com. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver is based on the Linux skeleton driver. The copyright of the 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skeleton driver is held by the United States Government, as represented 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds by DIRNSA, and it is released under the GPL. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Thanks to Mike Hollick for alpha testing and suggestions. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds References: 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The Crynwr packet driver. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Intel Microcommunications Databook, Vol. 1, 1990. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds As usual with Intel, the documentation is incomplete and inaccurate. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds I had to read the Crynwr packet driver to figure out how to actually 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds use the i82593, and guess at what register bits matched the loosely 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds related i82586. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Theory of Operation 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The i82593 used in the Zenith Z-Note series operates using two(!) slave 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DMA channels, one interrupt, and one 8-bit I/O port. 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds While there several ways to configure '593 DMA system, I chose the one 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds that seemed commensurate with the highest system performance in the face 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds of moderate interrupt latency: Both DMA channels are configured as 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds recirculating ring buffers, with one channel (#0) dedicated to Rx and 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the other channel (#1) to Tx and configuration. (Note that this is 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds different than the Crynwr driver, where the Tx DMA channel is initialized 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds before each operation. That approach simplifies operation and Tx error 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds recovery, but requires additional I/O in normal operation and precludes 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds transmit buffer chaining.) 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE. This provides 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds a reasonable ring size for Rx, while simplifying DMA buffer allocation -- 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DMA buffers must not cross a 128K boundary. (In truth the size selection 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds was influenced by my lack of '593 documentation. I thus was constrained 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to use the Crynwr '593 initialization table, which sets the Rx ring size 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to 8K.) 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Despite my usual low opinion about Intel-designed parts, I must admit 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds that the bulk data handling of the i82593 is a good design for 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds an integrated system, like a laptop, where using two slave DMA channels 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds doesn't pose a problem. I still take issue with using only a single I/O 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds port. In the same controlled environment there are essentially no 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds limitations on I/O space, and using multiple locations would eliminate 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the need for multiple operations when looking at status registers, 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds setting the Rx ring boundary, or switching to promiscuous mode. 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds I also question Zenith's selection of the '593: one of the advertised 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds advantages of earlier Intel parts was that if you figured out the magic 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds initialization incantation you could use the same part on many different 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds network types. Zenith's use of the "FriendlyNet" (sic) connector rather 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds than an on-board transceiver leads me to believe that they were planning 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to take advantage of this. But, uhmmm, the '593 omits all but ethernet 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds functionality from the serial subsystem. 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 10/2002 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds o Resurected for Linux 2.5+ by Marc Zyngier <maz@wild-wind.fr.eu.org> : 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Removed strange DMA snooping in znet_sent_packet, which lead to 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TX buffer corruption on my laptop. 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Use init_etherdev stuff. 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Use kmalloc-ed DMA buffers. 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Use as few global variables as possible. 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Use proper resources management. 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Use wireless/i82593.h as much as possible (structure, constants) 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Compiles as module or build-in. 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Now survives unplugging/replugging cable. 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Some code was taken from wavelan_cs. 786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds anything else. Testers (and detailed bug reports) are welcome :-). 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds o TODO : 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Properly handle multicast 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Understand why some traffic patterns add a 1s latency... 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 915a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h> 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h> 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 106c85e9d7739fc8d879c4293ea020760926d6f87cdJohn W. Linville#include <linux/i82593.h> 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n"; 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef ZNET_DEBUG 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ZNET_DEBUG 1 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int znet_debug = ZNET_DEBUG; 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param (znet_debug, int, 0); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC (znet_debug, "ZNet debug level"); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The DMA modes we need aren't in <dma.h>. */ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DMA_RX_MODE 0x14 /* Auto init, I/O to mem, ++, demand. */ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DMA_TX_MODE 0x18 /* Auto init, Mem to I/O, ++, demand. */ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_BUF_SIZE 8192 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_BUF_SIZE 8192 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DMA_BUF_SIZE (RX_BUF_SIZE + 16) /* 8k + 16 bytes for trailers */ 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 126c63fdf46ad0a7f8fe3c0252a0e763515617e0ea7Eric Dumazet#define TX_TIMEOUT (HZ/10) 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct znet_private { 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int rx_dma, tx_dma; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short sia_base, sia_size, io_size; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i82593_conf_block i593_init; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The starting, current, and end pointers for the packet buffers. */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort *rx_start, *rx_cur, *rx_end; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort *tx_start, *tx_cur, *tx_end; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort tx_buf_len; /* Tx buffer length, in words. */ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Only one can be built-in;-> */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *znet_dev; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct netidblk { 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char magic[8]; /* The magic number (string) "NETIDBLK" */ 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char netid[8]; /* The physical station address */ 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char nettype, globalopt; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char vendor[8]; /* The machine vendor and product name. */ 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char product[8]; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char irq1, irq2; /* Interrupts, only one is currently used. */ 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char dma1, dma2; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short dma_mem_misc[8]; /* DMA buffer locations (unused in Linux). */ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short iobase1, iosize1; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short iobase2, iosize2; /* Second iobase unused. */ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char driver_options; /* Misc. bits */ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char pad; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int znet_open(struct net_device *dev); 15861357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t znet_send_packet(struct sk_buff *skb, 15961357325f377889a1daffa14962d705dc814dd0eStephen Hemminger struct net_device *dev); 1607d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t znet_interrupt(int irq, void *dev_id); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void znet_rx(struct net_device *dev); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int znet_close(struct net_device *dev); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hardware_init(struct net_device *dev); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void update_stop_hit(short ioaddr, unsigned short rx_stop_offset); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void znet_tx_timeout (struct net_device *dev); 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Request needed resources */ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int znet_request_resources (struct net_device *dev) 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 170524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen struct znet_private *znet = netdev_priv(dev); 1716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 172a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches if (request_irq (dev->irq, znet_interrupt, 0, "ZNet", dev)) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto failed; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_dma (znet->rx_dma, "ZNet rx")) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_irq; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_dma (znet->tx_dma, "ZNet tx")) 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_rx_dma; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region (znet->sia_base, znet->sia_size, "ZNet SIA")) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_tx_dma; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region (dev->base_addr, znet->io_size, "ZNet I/O")) 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_sia; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; /* Happy ! */ 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_sia: 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region (znet->sia_base, znet->sia_size); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_tx_dma: 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dma (znet->tx_dma); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_rx_dma: 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dma (znet->rx_dma); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq: 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq (dev->irq, dev); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds failed: 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void znet_release_resources (struct net_device *dev) 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 199524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen struct znet_private *znet = netdev_priv(dev); 2006aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region (znet->sia_base, znet->sia_size); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region (dev->base_addr, znet->io_size); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dma (znet->tx_dma); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dma (znet->rx_dma); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq (dev->irq, dev); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Keep the magical SIA stuff in a single function... */ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void znet_transceiver_power (struct net_device *dev, int on) 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 211524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen struct znet_private *znet = netdev_priv(dev); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char v; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Turn on/off the 82501 SIA, using zenith-specific magic. */ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Select LAN control register */ 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x10, znet->sia_base); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (on) 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v = inb(znet->sia_base + 1) | 0x84; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds v = inb(znet->sia_base + 1) & ~0x84; 2226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(v, znet->sia_base+1); /* Turn on/off LAN power (bit 2). */ 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Init the i82593, with current promisc/mcast configuration. 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Also used from hardware_init. */ 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void znet_set_multicast_list (struct net_device *dev) 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 230524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen struct znet_private *znet = netdev_priv(dev); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short ioaddr = dev->base_addr; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i82593_conf_block *cfblk = &znet->i593_init; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(cfblk, 0x00, sizeof(struct i82593_conf_block)); 2356aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The configuration block. What an undocumented nightmare. 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The first set of values are those suggested (without explanation) 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for ethernet in the Intel 82586 databook. The rest appear to be 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds completely undocumented, except for cryptic notes in the Crynwr 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packet driver. This driver uses the Crynwr values verbatim. */ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* maz : Rewritten to take advantage of the wanvelan includes. 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds At least we have names, not just blind values */ 2446aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte 0 */ 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->fifo_limit = 10; /* = 16 B rx and 80 B tx fifo thresholds */ 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->forgnesi = 0; /* 0=82C501, 1=AMD7992B compatibility */ 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->fifo_32 = 1; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->d6mod = 0; /* Run in i82593 advanced mode */ 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->throttle_enb = 1; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte 1 */ 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->throttle = 8; /* Continuous w/interrupts, 128-clock DMA. */ 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->cntrxint = 0; /* enable continuous mode receive interrupts */ 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->contin = 1; /* enable continuous mode */ 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte 2 */ 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->addr_len = ETH_ALEN; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->acloc = 1; /* Disable source addr insertion by i82593 */ 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->preamb_len = 2; /* 8 bytes preamble */ 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->loopback = 0; /* Loopback off */ 2626aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte 3 */ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->lin_prio = 0; /* Default priorities & backoff methods. */ 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->tbofstop = 0; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->exp_prio = 0; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->bof_met = 0; 2686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte 4 */ 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->ifrm_spc = 6; /* 96 bit times interframe spacing */ 2716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte 5 */ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->slottim_low = 0; /* 512 bit times slot time (low) */ 2746aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte 6 */ 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->slottim_hi = 2; /* 512 bit times slot time (high) */ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->max_retr = 15; /* 15 collisions retries */ 2786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte 7 */ 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->prmisc = ((dev->flags & IFF_PROMISC) ? 1 : 0); /* Promiscuous mode */ 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->bc_dis = 0; /* Enable broadcast reception */ 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->crs_1 = 0; /* Don't transmit without carrier sense */ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->nocrc_ins = 0; /* i82593 generates CRC */ 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->crc_1632 = 0; /* 32-bit Autodin-II CRC */ 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->crs_cdt = 0; /* CD not to be interpreted as CS */ 2866aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte 8 */ 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->cs_filter = 0; /* CS is recognized immediately */ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->crs_src = 0; /* External carrier sense */ 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->cd_filter = 0; /* CD is recognized immediately */ 2916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte 9 */ 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */ 2946aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte A */ 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->lng_typ = 1; /* Type/length checks OFF */ 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->lng_fld = 1; /* Disable 802.3 length field check */ 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->rxcrc_xf = 1; /* Don't transfer CRC to memory */ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->artx = 1; /* Disable automatic retransmission */ 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->sarec = 1; /* Disable source addr trig of CD */ 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->tx_jabber = 0; /* Disable jabber jam sequence */ 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->hash_1 = 1; /* Use bits 0-5 in mc address hash */ 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->lbpkpol = 0; /* Loopback pin active high */ 3046aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte B */ 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->fdx = 0; /* Disable full duplex operation */ 3076aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte C */ 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->dummy_6 = 0x3f; /* all ones, Default multicast addresses & backoff. */ 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->mult_ia = 0; /* No multiple individual addresses */ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->dis_bof = 0; /* Disable the backoff algorithm ?! */ 3126aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte D */ 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->dummy_1 = 1; /* set to 1 */ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */ 316567ec874d15b478c8eda7e9a5d2dcb05f13f1fb5Jiri Pirko cfblk->mc_all = (!netdev_mc_empty(dev) || 317567ec874d15b478c8eda7e9a5d2dcb05f13f1fb5Jiri Pirko (dev->flags & IFF_ALLMULTI)); /* multicast all mode */ 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->rcv_mon = 0; /* Monitor mode disabled */ 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->frag_acpt = 0; /* Do not accept fragments */ 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->tstrttrs = 0; /* No start transmission threshold */ 3216aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte E */ 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->fretx = 1; /* FIFO automatic retransmission */ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->runt_eop = 0; /* drop "runt" packets */ 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->hw_sw_pin = 0; /* ?? */ 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->big_endn = 0; /* Big Endian ? no... */ 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->syncrqs = 1; /* Synchronous DRQ deassertion... */ 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->sttlen = 1; /* 6 byte status registers */ 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->rx_eop = 0; /* Signal EOP on packet reception */ 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->tx_eop = 0; /* Signal EOP on packet transmission */ 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Byte F */ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->rbuf_size = RX_BUF_SIZE >> 12; /* Set receive buffer size */ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cfblk->rcvstop = 1; /* Enable Receive Stop Register */ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 2) { 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *c; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0, c = (char *) cfblk; i < sizeof (*cfblk); i++) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("%02X ", c[i]); 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk ("\n"); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3446aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *znet->tx_cur++ = sizeof(struct i82593_conf_block); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(znet->tx_cur, cfblk, sizeof(struct i82593_conf_block)); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->tx_cur += sizeof(struct i82593_conf_block)/2; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(OP0_CONFIGURE | CR0_CHNL, ioaddr); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* XXX FIXME maz : Add multicast addresses here, so having a 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * multicast address configured isn't equal to IFF_ALLMULTI */ 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3536aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 354bc0443fc38f802c5b7a7489b4a31577f1fadd4e4Stephen Hemmingerstatic const struct net_device_ops znet_netdev_ops = { 355bc0443fc38f802c5b7a7489b4a31577f1fadd4e4Stephen Hemminger .ndo_open = znet_open, 356bc0443fc38f802c5b7a7489b4a31577f1fadd4e4Stephen Hemminger .ndo_stop = znet_close, 357bc0443fc38f802c5b7a7489b4a31577f1fadd4e4Stephen Hemminger .ndo_start_xmit = znet_send_packet, 358afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = znet_set_multicast_list, 359bc0443fc38f802c5b7a7489b4a31577f1fadd4e4Stephen Hemminger .ndo_tx_timeout = znet_tx_timeout, 360bc0443fc38f802c5b7a7489b4a31577f1fadd4e4Stephen Hemminger .ndo_change_mtu = eth_change_mtu, 361bc0443fc38f802c5b7a7489b4a31577f1fadd4e4Stephen Hemminger .ndo_set_mac_address = eth_mac_addr, 362bc0443fc38f802c5b7a7489b4a31577f1fadd4e4Stephen Hemminger .ndo_validate_addr = eth_validate_addr, 363bc0443fc38f802c5b7a7489b4a31577f1fadd4e4Stephen Hemminger}; 364bc0443fc38f802c5b7a7489b4a31577f1fadd4e4Stephen Hemminger 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The Z-Note probe is pretty easy. The NETIDBLK exists in the safe-to-probe 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BIOS area. We just scan for the signature, and pull the vital parameters 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out of the structure. */ 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init znet_probe (void) 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netidblk *netinfo; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct znet_private *znet; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *p; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -ENOMEM; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++) 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0) 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (p >= (char *)phys_to_virt(0x100000)) { 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 1) 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "No Z-Note ethernet adaptor found.\n"); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = alloc_etherdev(sizeof(struct znet_private)); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 393524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen znet = netdev_priv(dev); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netinfo = (struct netidblk *)p; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = netinfo->iobase1; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = netinfo->irq1; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The station address is in the "netidblk" at 0x0f0000. */ 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 6; i++) 4010795af5729b18218767fab27c44b1384f72dc9adJoe Perches dev->dev_addr[i] = netinfo->netid[i]; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 403e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk(KERN_INFO "%s: ZNET at %#3lx, %pM" 4040795af5729b18218767fab27c44b1384f72dc9adJoe Perches ", using IRQ %d DMA %d and %d.\n", 405e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, dev->base_addr, dev->dev_addr, 4060795af5729b18218767fab27c44b1384f72dc9adJoe Perches dev->irq, netinfo->dma1, netinfo->dma2); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 1) { 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n", 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, netinfo->vendor, 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netinfo->irq1, netinfo->irq2, 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netinfo->dma1, netinfo->dma2); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n", 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, netinfo->iobase1, netinfo->iosize1, 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netinfo->iobase2, netinfo->iosize2, netinfo->nettype); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 0) 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s", version); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->rx_dma = netinfo->dma1; 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->tx_dma = netinfo->dma2; 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&znet->lock); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->sia_base = 0xe6; /* Magic address for the 82501 SIA */ 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->sia_size = 2; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* maz: Despite the '593 being advertised above as using a 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * single 8bits I/O port, this driver does many 16bits 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * access. So set io_size accordingly */ 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->io_size = 2; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(znet->rx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA))) 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_dev; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(znet->tx_start = kmalloc (DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA))) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_rx; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dma_page_eq (znet->rx_start, znet->rx_start + (RX_BUF_SIZE/2-1)) || 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !dma_page_eq (znet->tx_start, znet->tx_start + (TX_BUF_SIZE/2-1))) { 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (KERN_WARNING "tx/rx crossing DMA frontiers, giving up\n"); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_tx; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4416aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->rx_end = znet->rx_start + RX_BUF_SIZE/2; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->tx_buf_len = TX_BUF_SIZE/2; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->tx_end = znet->tx_start + znet->tx_buf_len; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The ZNET-specific entries in the device structure. */ 447bc0443fc38f802c5b7a7489b4a31577f1fadd4e4Stephen Hemminger dev->netdev_ops = &znet_netdev_ops; 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->watchdog_timeo = TX_TIMEOUT; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_tx; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet_dev = dev; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_tx: 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(znet->tx_start); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_rx: 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(znet->rx_start); 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dev: 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4646aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int znet_open(struct net_device *dev) 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 2) 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "%s: znet_open() called.\n", dev->name); 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* These should never fail. You can't add devices to a sealed box! */ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_request_resources (dev)) { 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet_transceiver_power (dev, 1); 4796aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* According to the Crynwr driver we should wait 50 msec. for the 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LAN clock to stabilize. My experiments indicates that the '593 can 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds be initialized immediately. The delay is probably needed for the 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DC-to-DC converter to come up to full voltage, and for the oscillator 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to be spot-on at 20Mhz before transmitting. 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Until this proves to be a problem we rely on the higher layers for the 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delay and save allocating a timer entry. */ 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* maz : Well, I'm getting every time the following message 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * without the delay on a 486@33. This machine is much too 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fast... :-) So maybe the Crynwr driver wasn't wrong after 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all, even if the message is completly harmless on my 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * setup. */ 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay (50); 4946aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This follows the packet driver's lead, and checks for success. */ 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00) 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n", 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hardware_init(dev); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue (dev); 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void znet_tx_timeout (struct net_device *dev) 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort event, tx_status, rx_offset, state; 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (CR0_STATUS_0, ioaddr); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds event = inb (ioaddr); 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (CR0_STATUS_1, ioaddr); 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_status = inw (ioaddr); 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (CR0_STATUS_2, ioaddr); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_offset = inw (ioaddr); 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (CR0_STATUS_3, ioaddr); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = inb (ioaddr); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x," 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " resetting.\n", dev->name, event, tx_status, rx_offset, state); 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_status == TX_LOST_CRS) 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n", 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name); 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (OP0_RESET, ioaddr); 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hardware_init (dev); 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue (dev); 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53061357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t znet_send_packet(struct sk_buff *skb, struct net_device *dev) 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 533524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen struct znet_private *znet = netdev_priv(dev); 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short length = skb->len; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 4) 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "%s: ZNet_send_packet.\n", dev->name); 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (length < ETH_ZLEN) { 5415b057c6b1a25d57edf2b4d1e956e50936480a9ffHerbert Xu if (skb_padto(skb, ETH_ZLEN)) 5426ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds length = ETH_ZLEN; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5456aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue (dev); 5476aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check that the part hasn't reset itself, probably from suspend. */ 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(CR0_STATUS_0, ioaddr); 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inw(ioaddr) == 0x0010 && 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr) == 0x0000 && 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inw(ioaddr) == 0x0010) { 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 1) 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk (KERN_WARNING "%s : waking up\n", dev->name); 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hardware_init(dev); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet_transceiver_power (dev, 1); 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (1) { 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *buf = (void *)skb->data; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort *tx_link = znet->tx_cur - 1; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort rnd_len = (length + 1)>>1; 5636aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 56409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_bytes+=length; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet->tx_cur >= znet->tx_end) 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->tx_cur = znet->tx_start; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *znet->tx_cur++ = length; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet->tx_cur + rnd_len + 1 > znet->tx_end) { 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int semi_cnt = (znet->tx_end - znet->tx_cur)<<1; /* Cvrt to byte cnt. */ 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(znet->tx_cur, buf, semi_cnt); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rnd_len -= semi_cnt>>1; 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(znet->tx_start, buf + semi_cnt, length - semi_cnt); 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->tx_cur = znet->tx_start + rnd_len; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(znet->tx_cur, buf, skb->len); 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->tx_cur += rnd_len; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *znet->tx_cur++ = 0; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&znet->lock, flags); 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *tx_link = OP0_TRANSMIT | CR0_CHNL; 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Is this always safe to do? */ 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(OP0_TRANSMIT | CR0_CHNL, ioaddr); 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore (&znet->lock, flags); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue (dev); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 4) 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length); 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5946aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik dev_kfree_skb(skb); 5956ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The ZNET interrupt handler. */ 5997d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t znet_interrupt(int irq, void *dev_id) 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = dev_id; 602524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen struct znet_private *znet = netdev_priv(dev); 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr; 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int boguscnt = 20; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int handled = 0; 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock (&znet->lock); 6086aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr = dev->base_addr; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(CR0_STATUS_0, ioaddr); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort status = inb(ioaddr); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 5) { 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort result, rx_ptr, running; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(CR0_STATUS_1, ioaddr); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = inw(ioaddr); 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(CR0_STATUS_2, ioaddr); 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rx_ptr = inw(ioaddr); 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(CR0_STATUS_3, ioaddr); 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds running = inb(ioaddr); 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n", 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, status, result, rx_ptr, running, boguscnt); 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & SR0_INTERRUPT) == 0) 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds handled = 1; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE || 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (status & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE || 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (status & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) { 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tx_status; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(CR0_STATUS_1, ioaddr); 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_status = inw(ioaddr); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* It's undocumented, but tx_status seems to match the i82586. */ 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_status & TX_OK) { 63809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_packets++; 63909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.collisions += tx_status & TX_NCOL_MASK; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_status & (TX_LOST_CTS | TX_LOST_CRS)) 64209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_carrier_errors++; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_status & TX_UND_RUN) 64409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_fifo_errors++; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(tx_status & TX_HRT_BEAT)) 64609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_heartbeat_errors++; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tx_status & TX_MAX_COL) 64809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_aborted_errors++; 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ...and the catch-all. */ 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) 65109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_errors++; 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Transceiver may be stuck if cable 65425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * was removed while emitting a 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * packet. Flip it off, then on to 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reset it. This is very empirical, 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but it seems to work. */ 6586aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet_transceiver_power (dev, 0); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet_transceiver_power (dev, 1); 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue (dev); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & SR0_RECEPTION) || 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (status & SR0_EVENT_MASK) == SR0_STOP_REG_HIT) { 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet_rx(dev); 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear the interrupts we've handled. */ 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(CR0_INT_ACK, ioaddr); 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (boguscnt--); 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock (&znet->lock); 6746aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_RETVAL(handled); 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void znet_rx(struct net_device *dev) 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 680524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen struct znet_private *znet = netdev_priv(dev); 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int boguscount = 1; 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short next_frame_end_offset = 0; /* Offset of next frame start. */ 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short *cur_frame_end; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short cur_frame_end_offset; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(CR0_STATUS_2, ioaddr); 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_frame_end_offset = inw(ioaddr); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cur_frame_end_offset == znet->rx_cur - znet->rx_start) { 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n", 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, cur_frame_end_offset); 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Use same method as the Crynwr driver: construct a forward list in 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the same area of the backwards links we now have. This allows us to 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pass packets to the upper layers in the order they were received -- 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds important for fast-path sequential operations. */ 7008e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches while (znet->rx_start + cur_frame_end_offset != znet->rx_cur && 7018e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches ++boguscount < 5) { 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short hi_cnt, lo_cnt, hi_status, lo_status; 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count, status; 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cur_frame_end_offset < 4) { 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Oh no, we have a special case: the frame trailer wraps around 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the end of the ring buffer. We've saved space at the end of 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the ring buffer for just this problem. */ 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(znet->rx_end, znet->rx_start, 8); 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_frame_end_offset += (RX_BUF_SIZE/2); 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_frame_end = znet->rx_start + cur_frame_end_offset - 4; 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo_status = *cur_frame_end++; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hi_status = *cur_frame_end++; 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = ((hi_status & 0xff) << 8) + (lo_status & 0xff); 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lo_cnt = *cur_frame_end++; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hi_cnt = *cur_frame_end++; 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 5) 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x" 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " count %#x status %04x.\n", 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt, 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count, status); 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_frame_end[-4] = status; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_frame_end[-3] = next_frame_end_offset; 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_frame_end[-2] = count; 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_frame_end_offset = cur_frame_end_offset; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_frame_end_offset -= ((count + 1)>>1) + 3; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cur_frame_end_offset < 0) 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur_frame_end_offset += RX_BUF_SIZE/2; 7336403eab143205a45a5493166ff8bf7e3646f4a77Joe Perches } 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now step forward through the list. */ 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort *this_rfp_ptr = znet->rx_start + next_frame_end_offset; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status = this_rfp_ptr[-4]; 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int pkt_len = this_rfp_ptr[-2]; 7406aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 5) 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x" 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds " next %04x.\n", next_frame_end_offset<<1, status, pkt_len, 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds this_rfp_ptr[-3]<<1); 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Once again we must assume that the i82586 docs apply. */ 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( ! (status & RX_RCV_OK)) { /* There was an error. */ 74709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_errors++; 74809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++; 74909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++; 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 75109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */ 75209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & 0x0100) dev->stats.rx_fifo_errors++; 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* maz : Wild guess... */ 75509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & RX_OVRRUN) dev->stats.rx_over_errors++; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 75709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & RX_SRT_FRM) dev->stats.rx_length_errors++; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (pkt_len > 1536) { 75909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_length_errors++; 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Malloc up new buffer. */ 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 764c056b734e54e12f38f34a2583a4824e6cecc16c1Pradeep A Dalvi skb = netdev_alloc_skb(dev, pkt_len); 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb == NULL) { 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug) 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); 76809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_dropped++; 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (&znet->rx_cur[(pkt_len+1)>>1] > znet->rx_end) { 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int semi_cnt = (znet->rx_end - znet->rx_cur)<<1; 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb,semi_cnt), znet->rx_cur, semi_cnt); 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb,pkt_len-semi_cnt), znet->rx_start, 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len - semi_cnt); 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(skb_put(skb,pkt_len), znet->rx_cur, pkt_len); 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 6) { 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int *packet = (unsigned int *) skb->data; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0], 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packet[1], packet[2], packet[3]); 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol=eth_type_trans(skb,dev); 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 78709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_packets++; 78809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_bytes += pkt_len; 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->rx_cur = this_rfp_ptr; 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet->rx_cur >= znet->rx_end) 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->rx_cur -= RX_BUF_SIZE/2; 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_stop_hit(ioaddr, (znet->rx_cur - znet->rx_start)<<1); 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds next_frame_end_offset = this_rfp_ptr[-3]; 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (next_frame_end_offset == 0) /* Read all the frames? */ 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* Done for now */ 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds this_rfp_ptr = znet->rx_start + next_frame_end_offset; 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (--boguscount); 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If any worth-while packets have been received, dev_rint() 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds has done a mark_bh(INET_BH) for us and will work on them 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds when we get to the bottom-half routine. */ 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The inverse routine to znet_open(). */ 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int znet_close(struct net_device *dev) 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue (dev); 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(OP0_RESET, ioaddr); /* CMD0_RESET */ 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 1) 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Turn off transceiver power. */ 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet_transceiver_power (dev, 0); 8186aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet_release_resources (dev); 8206aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void show_dma(struct net_device *dev) 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short ioaddr = dev->base_addr; 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char stat = inb (ioaddr); 828524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen struct znet_private *znet = netdev_priv(dev); 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE; 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned addr = inb(dma_port); 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short residue; 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds addr |= inb(dma_port) << 8; 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds residue = get_dma_residue(znet->tx_dma); 8366aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 1) { 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags=claim_dma_lock(); 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "Stat:%02x Addr: %04x cnt:%3x\n", 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stat, addr<<1, residue); 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_dma_lock(flags); 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize the hardware. We have to do this when the board is open()ed 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds or when we come out of suspend mode. */ 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hardware_init(struct net_device *dev) 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short ioaddr = dev->base_addr; 851524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen struct znet_private *znet = netdev_priv(dev); 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->rx_cur = znet->rx_start; 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->tx_cur = znet->tx_start; 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reset the chip, and start it up. */ 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(OP0_RESET, ioaddr); 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flags=claim_dma_lock(); 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disable_dma(znet->rx_dma); /* reset by an interrupting task. */ 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_dma_ff(znet->rx_dma); 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_dma_mode(znet->rx_dma, DMA_RX_MODE); 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_dma_addr(znet->rx_dma, (unsigned int) znet->rx_start); 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_dma_count(znet->rx_dma, RX_BUF_SIZE); 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_dma(znet->rx_dma); 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Now set up the Tx channel. */ 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disable_dma(znet->tx_dma); 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds clear_dma_ff(znet->tx_dma); 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_dma_mode(znet->tx_dma, DMA_TX_MODE); 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_dma_addr(znet->tx_dma, (unsigned int) znet->tx_start); 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_dma_count(znet->tx_dma, znet->tx_buf_len<<1); 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_dma(znet->tx_dma); 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_dma_lock(flags); 8746aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 1) 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "%s: Initializing the i82593, rx buf %p tx buf %p\n", 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, znet->rx_start,znet->tx_start); 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Do an empty configure command, just like the Crynwr driver. This 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resets to chip to its default values. */ 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *znet->tx_cur++ = 0; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *znet->tx_cur++ = 0; 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_dma(dev); 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(OP0_CONFIGURE | CR0_CHNL, ioaddr); 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet_set_multicast_list (dev); 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *znet->tx_cur++ = 6; 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(znet->tx_cur, dev->dev_addr, 6); 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds znet->tx_cur += 3; 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_dma(dev); 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(OP0_IA_SETUP | CR0_CHNL, ioaddr); 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_dma(dev); 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds update_stop_hit(ioaddr, 8192); 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 1) printk(KERN_DEBUG "enabling Rx.\n"); 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(OP0_RCV_ENABLE, ioaddr); 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue (dev); 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void update_stop_hit(short ioaddr, unsigned short rx_stop_offset) 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, ioaddr); 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_debug > 5) 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "Updating stop hit with value %02x.\n", 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE); 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb((rx_stop_offset >> 6) | CR1_STOP_REG_UPDATE, ioaddr); 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(OP1_SWIT_TO_PORT_0, ioaddr); 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic __exit void znet_cleanup (void) 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (znet_dev) { 913524ad0a79126efabf58d0a49eace6155ab5b4549Wang Chen struct znet_private *znet = netdev_priv(znet_dev); 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdev (znet_dev); 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (znet->rx_start); 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree (znet->tx_start); 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev (znet_dev); 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init (znet_probe); 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit (znet_cleanup); 924