11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* sun3lance.c: Ethernet driver for SUN3 Lance chip */ 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik Sun3 Lance ethernet driver, by Sam Creasey (sammy@users.qual.net). 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver is a part of the linux kernel, and is thus distributed 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds under the GNU General Public License. 76aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The values used in LANCE_OBIO and LANCE_IRQ seem to be empirically 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds true for the correct IRQ and address of the lance registers. They 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds have not been widely tested, however. What we probably need is a 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "proper" way to search for a device in the sun3's prom, but, alas, 126aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik linux has no such thing. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver is largely based on atarilance.c, by Roman Hodek. Other 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sources of inspiration were the NetBSD sun3 am7990 driver, and the 166aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik linux sparc lance driver (sunlance.c). 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds There are more assumptions made throughout this driver, it almost 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds certainly still needs work, but it does work at least for RARP/BOOTP and 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mounting the root NFS filesystem. 216aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *version = "sun3lance.c: v1.2 1/12/2001 Sam Creasey (sammy@sammy.net)\n"; 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stddef.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40a1f8e7f7fb9d7e2cbcb53170edca7c0ac4680697Al Viro#include <asm/cacheflush.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/setup.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/irq.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dvma.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/idprom.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/machines.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sun3mmu.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sun3xprom.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* sun3/60 addr/irq for the lance chip. If your sun is different, 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds change this. */ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_OBIO 0x120000 584facfde9f1d7b8a61fb0017460da45e23e60115cRoman Zippel#define LANCE_IRQ IRQ_AUTO_3 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Debug level: 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0 = silent, print only serious errors 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1 = normal, print error messages 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 = debug, print debug infos 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3 = debug, print even more debug infos (packet data) 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LANCE_DEBUG 0 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef LANCE_DEBUG 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = LANCE_DEBUG; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_debug = 1; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 748d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(lance_debug, int, 0); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(lance_debug, "SUN3 Lance debug level (0-3)"); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DPRINTK(n,a) \ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { \ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lance_debug >= n) \ 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk a; \ 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while( 0 ) 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* we're only using 32k of memory, so we use 4 TX 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffers and 16 RX buffers. These values are expressed as log2. */ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_LOG_RING_SIZE 3 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_LOG_RING_SIZE 5 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These are the derived values */ 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_SIZE (1 << TX_LOG_RING_SIZE) 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_LEN_BITS (TX_LOG_RING_SIZE << 5) 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_SIZE (1 << RX_LOG_RING_SIZE) 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_LEN_BITS (RX_LOG_RING_SIZE << 5) 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Definitions for packet buffer access: */ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_BUF_SZ 1544 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Get the address of a packet buffer corresponding to a given buffer head */ 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKTBUF_ADDR(head) (void *)((unsigned long)(MEM) | (head)->base) 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE Rx and Tx ring descriptors. */ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_rx_head { 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short base; /* Low word of base addr */ 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile unsigned char flag; 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char base_hi; /* High word of base addr (unused) */ 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short buf_length; /* This length is 2s complement! */ 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile short msg_length; /* This length is "normal". */ 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_tx_head { 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short base; /* Low word of base addr */ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile unsigned char flag; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char base_hi; /* High word of base addr (unused) */ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short length; /* Length is 2s complement! */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile short misc; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE initialization block, described in databook. */ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_init_block { 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short mode; /* Pre-set mode */ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char hwaddr[6]; /* Physical ethernet address */ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int filter[2]; /* Multicast filter (unused). */ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Receive and transmit ring base, along with length bits. */ 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short rdra; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short rlen; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short tdra; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short tlen; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short pad[4]; /* is thie needed? */ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The whole layout of the Lance shared memory */ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_memory { 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_init_block init; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_tx_head tx_head[TX_RING_SIZE]; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_rx_head rx_head[RX_RING_SIZE]; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char rx_data[RX_RING_SIZE][PKT_BUF_SZ]; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char tx_data[TX_RING_SIZE][PKT_BUF_SZ]; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The driver's private device structure */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lance_private { 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile unsigned short *iobase; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_memory *mem; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int new_rx, new_tx; /* The next free ring entry */ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int old_tx, old_rx; /* ring entry to be processed */ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* These two must be longs for set_bit() */ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long tx_full; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long lock; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* I/O register access macros */ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MEM lp->mem 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DREG lp->iobase[0] 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AREG lp->iobase[1] 164e345d5ef6d476cc236f64d90d9528143a70745c8Al Viro#define REGA(a) (*( AREG = (a), &DREG )) 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Definitions for the Lance */ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tx_head flags */ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ENP 0x01 /* end of packet */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_STP 0x02 /* start of packet */ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_DEF 0x04 /* deferred */ 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ONE 0x08 /* one retry needed */ 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_MORE 0x10 /* more than one retry needed */ 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_ERR 0x40 /* error summary */ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN 0x80 /* ownership (set: chip owns) */ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN_CHIP TMD1_OWN 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD1_OWN_HOST 0 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tx_head misc field */ 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_TDR 0x03FF /* Time Domain Reflectometry counter */ 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_RTRY 0x0400 /* failed after 16 retries */ 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_LCAR 0x0800 /* carrier lost */ 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_LCOL 0x1000 /* late collision */ 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_UFLO 0x4000 /* underflow (late memory) */ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMD3_BUFF 0x8000 /* buffering error (no ENP) */ 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* rx_head flags */ 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_ENP 0x01 /* end of packet */ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_STP 0x02 /* start of packet */ 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_BUFF 0x04 /* buffer error */ 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_CRC 0x08 /* CRC error */ 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OFLO 0x10 /* overflow */ 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_FRAM 0x20 /* framing error */ 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_ERR 0x40 /* error summary */ 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN 0x80 /* ownership (set: ship owns) */ 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN_CHIP RMD1_OWN 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RMD1_OWN_HOST 0 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* register names */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0 0 /* mode/status */ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR1 1 /* init block addr (low) */ 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR2 2 /* init block addr (high) */ 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3 3 /* misc */ 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR8 8 /* address filter */ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR15 15 /* promiscuous mode */ 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CSR0 */ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* (R=readable, W=writeable, S=set on write, C=clear on write) */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INIT 0x0001 /* initialize (RS) */ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_STRT 0x0002 /* start (RS) */ 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_STOP 0x0004 /* stop (RS) */ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TDMD 0x0008 /* transmit demand (RS) */ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TXON 0x0010 /* transmitter on (R) */ 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_RXON 0x0020 /* receiver on (R) */ 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INEA 0x0040 /* interrupt enable (RW) */ 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_INTR 0x0080 /* interrupt active (R) */ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_IDON 0x0100 /* initialization done (RC) */ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_TINT 0x0200 /* transmitter interrupt (RC) */ 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_RINT 0x0400 /* receiver interrupt (RC) */ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_MERR 0x0800 /* memory error (RC) */ 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_MISS 0x1000 /* missed frame (RC) */ 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_CERR 0x2000 /* carrier error (no heartbeat :-) (RC) */ 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_BABL 0x4000 /* babble: tx-ed too many bits (RC) */ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR0_ERR 0x8000 /* error (RC) */ 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* CSR3 */ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_BCON 0x0001 /* byte control */ 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_ACON 0x0002 /* ALE control */ 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CSR3_BSWP 0x0004 /* byte swap (1=big endian) */ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************** Prototypes *****************************/ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_probe( struct net_device *dev); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_open( struct net_device *dev ); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_init_ring( struct net_device *dev ); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ); 2397d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt( int irq, void *dev_id); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_rx( struct net_device *dev ); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_close( struct net_device *dev ); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list( struct net_device *dev ); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/************************* End of Prototypes **************************/ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device * __init sun3lance_probe(int unit) 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static int found; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -ENODEV; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2520f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven if (!MACH_IS_SUN3 && !MACH_IS_SUN3X) 2530f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven return ERR_PTR(-ENODEV); 2540f734484ac51711f6b9e48b42242e19e88eb2926Geert Uytterhoeven 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check that this machine has an onboard lance */ 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(idprom->id_machtype) { 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SM_SUN3|SM_3_50: 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SM_SUN3|SM_3_60: 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SM_SUN3X|SM_3_80: 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* these machines have lance */ 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENODEV); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (found) 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENODEV); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = alloc_etherdev(sizeof(struct lance_private)); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENOMEM); 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unit >= 0) { 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(dev->name, "eth%d", unit); 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netdev_boot_setup_check(dev); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!lance_probe(dev)) 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out1; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found = 1; 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dev; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1: 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3 289437111ca381263520d23c877e55e0a83558e79daAl Viro iounmap((void __iomem *)dev->base_addr); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(err); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2962160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalovstatic const struct net_device_ops lance_netdev_ops = { 2972160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov .ndo_open = lance_open, 2982160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov .ndo_stop = lance_close, 2992160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov .ndo_start_xmit = lance_start_xmit, 300afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = set_multicast_list, 3012160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov .ndo_set_mac_address = NULL, 3022160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov .ndo_change_mtu = eth_change_mtu, 3032160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov .ndo_validate_addr = eth_validate_addr, 3042160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov}; 3052160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init lance_probe( struct net_device *dev) 3076aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik{ 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long ioaddr; 3096aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_private *lp; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static int did_version; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds volatile unsigned short *ioaddr_probe; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short tmp1, tmp2; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ioaddr) 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr = SUN3X_LANCE; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* test to see if there's really a lance here */ 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* (CSRO_INIT shouldn't be readable) */ 3266aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr_probe = (volatile unsigned short *)ioaddr; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp1 = ioaddr_probe[0]; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp2 = ioaddr_probe[1]; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr_probe[1] = CSR0; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr_probe[0] = CSR0_INIT | CSR0_STOP; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(ioaddr_probe[0] != CSR0_STOP) { 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr_probe[0] = tmp1; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr_probe[1] = tmp2; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3 339437111ca381263520d23c877e55e0a83558e79daAl Viro iounmap((void __iomem *)ioaddr); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp = netdev_priv(dev); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* XXX - leak? */ 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000); 348c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov if (MEM == NULL) { 349c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov#ifdef CONFIG_SUN3 350c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov iounmap((void __iomem *)ioaddr); 351c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov#endif 352c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov printk(KERN_WARNING "SUN3 Lance couldn't allocate DVMA memory\n"); 353c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov return 0; 354c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov } 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->iobase = (volatile unsigned short *)ioaddr; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = (unsigned long)ioaddr; /* informational only */ 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3596aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik REGA(CSR0) = CSR0_STOP; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov if (request_irq(LANCE_IRQ, lance_interrupt, IRQF_DISABLED, "SUN3 Lance", dev) < 0) { 362c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov#ifdef CONFIG_SUN3 363c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov iounmap((void __iomem *)ioaddr); 364c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov#endif 365c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov dvma_free((void *)MEM); 366c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov printk(KERN_WARNING "SUN3 Lance unable to allocate IRQ\n"); 367c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov return 0; 368c14bac628b9fad6fd4dad8fbb9e864c61a8924c9Cyrill V. Gorcunov } 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = (unsigned short)LANCE_IRQ; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: SUN3 Lance at io %#lx, mem %#lx, irq %d, hwaddr ", 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long)ioaddr, 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned long)MEM, 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* copy in the ethernet address from the prom */ 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i = 0; i < 6 ; i++) 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->dev_addr[i] = idprom->id_ethaddr[i]; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* tell the card it's ether address, bytes swapped */ 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[0] = dev->dev_addr[1]; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[1] = dev->dev_addr[0]; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[2] = dev->dev_addr[3]; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[3] = dev->dev_addr[2]; 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[4] = dev->dev_addr[5]; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[5] = dev->dev_addr[4]; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 390e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk("%pM\n", dev->dev_addr); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.mode = 0x0000; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.filter[0] = 0x00000000; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.filter[1] = 0x00000000; 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.rdra = dvma_vtob(MEM->rx_head); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.rlen = (RX_LOG_RING_SIZE << 13) | 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dvma_vtob(MEM->rx_head) >> 16); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.tdra = dvma_vtob(MEM->tx_head); 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.tlen = (TX_LOG_RING_SIZE << 13) | 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dvma_vtob(MEM->tx_head) >> 16); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK(2, ("initaddr: %08lx rx_ring: %08lx tx_ring: %08lx\n", 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dvma_vtob(&(MEM->init)), dvma_vtob(MEM->rx_head), 4046aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik (dvma_vtob(MEM->tx_head)))); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (did_version++ == 0) 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( version ); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4092160187a0a1cdeeeff1d41f53333bea91c82f259Alexander Beregalov dev->netdev_ops = &lance_netdev_ops; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// KLUDGE -- REMOVE ME 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_bit(__LINK_STATE_PRESENT, &dev->state); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_open( struct net_device *dev ) 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_private *lp = netdev_priv(dev); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 2, ( "%s: lance_open()\n", dev->name )); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR0) = CSR0_STOP; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lance_init_ring(dev); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* From now on, AREG is kept to point to CSR0 */ 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR0) = CSR0_INIT; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 1000000; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (--i > 0) 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DREG & CSR0_IDON) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 435cff71e89a8bd1175962b603f88f333883726b851Roel Kluin if (i <= 0 || (DREG & CSR0_ERR)) { 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n", 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, i, DREG )); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DREG = CSR0_STOP; 439807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet return -EIO; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DREG = CSR0_IDON | CSR0_STRT | CSR0_INEA; 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 4456aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG )); 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 448807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet return 0; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize the LANCE Rx and Tx rings. */ 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void lance_init_ring( struct net_device *dev ) 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_private *lp = netdev_priv(dev); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->lock = 0; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->tx_full = 0; 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->new_rx = lp->new_tx = 0; 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->old_rx = lp->old_tx = 0; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for( i = 0; i < TX_RING_SIZE; i++ ) { 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->tx_head[i].base = dvma_vtob(MEM->tx_data[i]); 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->tx_head[i].flag = 0; 4676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik MEM->tx_head[i].base_hi = 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dvma_vtob(MEM->tx_data[i])) >>16; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->tx_head[i].length = 0; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->tx_head[i].misc = 0; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for( i = 0; i < RX_RING_SIZE; i++ ) { 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->rx_head[i].base = dvma_vtob(MEM->rx_data[i]); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->rx_head[i].flag = RMD1_OWN_CHIP; 4766aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik MEM->rx_head[i].base_hi = 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dvma_vtob(MEM->rx_data[i])) >> 16; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->rx_head[i].buf_length = -PKT_BUF_SZ | 0xf000; 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->rx_head[i].msg_length = 0; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* tell the card it's ether address, bytes swapped */ 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[0] = dev->dev_addr[1]; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[1] = dev->dev_addr[0]; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[2] = dev->dev_addr[3]; 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[3] = dev->dev_addr[2]; 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[4] = dev->dev_addr[5]; 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.hwaddr[5] = dev->dev_addr[4]; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.mode = 0x0000; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.filter[0] = 0x00000000; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.filter[1] = 0x00000000; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.rdra = dvma_vtob(MEM->rx_head); 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.rlen = (RX_LOG_RING_SIZE << 13) | 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dvma_vtob(MEM->rx_head) >> 16); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.tdra = dvma_vtob(MEM->tx_head); 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->init.tlen = (TX_LOG_RING_SIZE << 13) | 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dvma_vtob(MEM->tx_head) >> 16); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* tell the lance the address of its init block */ 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR1) = dvma_vtob(&(MEM->init)); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR2) = dvma_vtob(&(MEM->init)) >> 16; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3X 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR3) = CSR3_BSWP | CSR3_ACON | CSR3_BCON; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR3) = CSR3_BSWP; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_private *lp = netdev_priv(dev); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int entry, len; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_tx_head *head; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 1, ( "%s: transmit start.\n", 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name)); 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Transmitter timeout, serious problems. */ 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_queue_stopped(dev)) { 5261ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet int tickssofar = jiffies - dev_trans_start(dev); 5271ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet if (tickssofar < HZ/5) 5285b548140225c6bbbbd560551dd1048b2c0ce58bePatrick McHardy return NETDEV_TX_BUSY; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n", 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, DREG )); 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DREG = CSR0_STOP; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Always set BSWP after a STOP as STOP puts it back into 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * little endian mode. 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR3) = CSR3_BSWP; 53809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_errors++; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(lance_debug >= 2) { 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("Ring data: old_tx %d new_tx %d%s new_rx %d\n", 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->old_tx, lp->new_tx, 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->tx_full ? " (full)" : "", 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->new_rx ); 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for( i = 0 ; i < RX_RING_SIZE; i++ ) 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "rx #%d: base=%04x blen=%04x mlen=%04x\n", 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i, MEM->rx_head[i].base, 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -MEM->rx_head[i].buf_length, 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->rx_head[i].msg_length); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for( i = 0 ; i < TX_RING_SIZE; i++ ) 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("tx #%d: base=%04x len=%04x misc=%04x\n", 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i, MEM->tx_head[i].base, 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds -MEM->tx_head[i].length, 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEM->tx_head[i].misc ); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lance_init_ring(dev); 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT; 5606aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 5626aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5636ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5666aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Block a timer-based transmit from overlapping. This could better be 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Block a timer-based transmit from overlapping with us by 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stopping the queue for a bit... */ 5726aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 5746aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) { 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s: tx queue lock!.\n", dev->name); 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* don't clear dev->tbusy flag. */ 5785b548140225c6bbbbd560551dd1048b2c0ce58bePatrick McHardy return NETDEV_TX_BUSY; 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AREG = CSR0; 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, DREG )); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3X 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this weirdness doesn't appear on sun3... */ 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(!(DREG & CSR0_INIT)) { 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 1, ("INIT not set, reinitializing...\n")); 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA( CSR0 ) = CSR0_STOP; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lance_init_ring(dev); 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA( CSR0 ) = CSR0_INIT | CSR0_STRT; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fill in a Tx ring entry */ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lance_debug >= 2) { 5980795af5729b18218767fab27c44b1384f72dc9adJoe Perches printk( "%s: TX pkt %d type 0x%04x" 5990795af5729b18218767fab27c44b1384f72dc9adJoe Perches " from %s to %s" 6000795af5729b18218767fab27c44b1384f72dc9adJoe Perches " data at 0x%08x len %d\n", 6010795af5729b18218767fab27c44b1384f72dc9adJoe Perches dev->name, lp->new_tx, ((u_short *)skb->data)[6], 6020795af5729b18218767fab27c44b1384f72dc9adJoe Perches DEV_ADDR(&skb->data[6]), DEV_ADDR(skb->data), 6030795af5729b18218767fab27c44b1384f72dc9adJoe Perches (int)skb->data, (int)skb->len ); 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6056aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#endif 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We're not prepared for the int until the last flags are set/reset. 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And the int may happen already after setting the OWN_CHIP... */ 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_save(flags); 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Mask to ring buffer boundary. */ 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = lp->new_tx; 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head = &(MEM->tx_head[entry]); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Caution: the write order is important here, set the "ownership" bits 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * last. 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* the sun3's lance needs it's buffer padded to the minimum 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size */ 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// head->length = -len; 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head->length = (-len) | 0xf000; 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head->misc = 0; 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 626d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data(skb, PKTBUF_ADDR(head), skb->len); 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len != skb->len) 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(PKTBUF_ADDR(head) + skb->len, 0, len-skb->len); 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK; 63209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_bytes += skb->len; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Trigger an immediate send poll. */ 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT; 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AREG = CSR0; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 2, ( "%s: lance_start_xmit() exiting, csr0 %4.4x.\n", 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, DREG )); 6391ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet dev_kfree_skb(skb); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->lock = 0; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) == 6436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik TMD1_OWN_HOST) 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq_restore(flags); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6486ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LANCE interrupt handler. */ 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6537d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t lance_interrupt( int irq, void *dev_id) 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = dev_id; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_private *lp = netdev_priv(dev); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int csr0; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static int in_interrupt; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev == NULL) { 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 1, ( "lance_interrupt(): invalid dev_id\n" )); 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (in_interrupt) 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name )); 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in_interrupt = 1; 6686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds still_more: 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds flush_cache_all(); 6716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AREG = CSR0; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csr0 = DREG; 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ack interrupts */ 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DREG = csr0 & (CSR0_TINT | CSR0_RINT | CSR0_IDON); 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear errors */ 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(csr0 & CSR0_ERR) 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DREG = CSR0_BABL | CSR0_MERR | CSR0_CERR | CSR0_MISS; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 2, ( "%s: interrupt csr0=%04x new csr=%04x.\n", 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, csr0, DREG )); 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr0 & CSR0_TINT) { /* Tx-done interrupt */ 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int old_tx = lp->old_tx; 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// if(lance_debug >= 3) { 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// int i; 6916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik// 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// printk("%s: tx int\n", dev->name); 6936aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik// 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// for(i = 0; i < TX_RING_SIZE; i++) 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// printk("ring %d flag=%04x\n", i, 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// MEM->tx_head[i].flag); 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// } 6986aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while( old_tx != lp->new_tx) { 7006aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik struct lance_tx_head *head = &(MEM->tx_head[old_tx]); 7016aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK(3, ("on tx_ring %d\n", old_tx)); 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (head->flag & TMD1_OWN_CHIP) 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; /* It still hasn't been Txed */ 7066aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (head->flag & TMD1_ERR) { 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status = head->misc; 70909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_errors++; 71009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & TMD3_RTRY) dev->stats.tx_aborted_errors++; 71109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & TMD3_LCAR) dev->stats.tx_carrier_errors++; 71209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & TMD3_LCOL) dev->stats.tx_window_errors++; 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & (TMD3_UFLO | TMD3_BUFF)) { 71409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_fifo_errors++; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: Tx FIFO error\n", 7166aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik dev->name); 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR0) = CSR0_STOP; 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR3) = CSR3_BSWP; 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lance_init_ring(dev); 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR0) = CSR0_STRT | CSR0_INEA; 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if(head->flag & (TMD1_ENP | TMD1_STP)) { 7246aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head->flag &= ~(TMD1_ENP | TMD1_STP); 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(head->flag & (TMD1_ONE | TMD1_MORE)) 72709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.collisions++; 7286aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 72909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_packets++; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK(3, ("cleared tx ring %d\n", old_tx)); 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds old_tx = (old_tx +1) & TX_RING_MOD_MASK; 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->old_tx = old_tx; 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (netif_queue_stopped(dev)) { 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The ring is no longer full, clear tbusy. */ 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr0 & CSR0_RINT) /* Rx interrupt */ 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lance_rx( dev ); 7476aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Log misc errors. */ 74909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */ 75009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */ 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csr0 & CSR0_MERR) { 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), " 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "status %04x.\n", dev->name, csr0 )); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Restart the chip. */ 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR0) = CSR0_STOP; 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR3) = CSR3_BSWP; 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lance_init_ring(dev); 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR0) = CSR0_STRT | CSR0_INEA; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear any other interrupt, and set interrupt enable. */ 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR | 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// CSR0_IDON | CSR0_INEA; 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA(CSR0) = CSR0_INEA; 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(DREG & (CSR0_RINT | CSR0_TINT)) { 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK(2, ("restarting interrupt, csr0=%#04x\n", DREG)); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto still_more; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n", 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, DREG )); 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in_interrupt = 0; 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get packet, toss into skbuff */ 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_rx( struct net_device *dev ) 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_private *lp = netdev_priv(dev); 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int entry = lp->new_rx; 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If we own the next entry, it's a new packet. Send it up. */ 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) { 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_rx_head *head = &(MEM->rx_head[entry]); 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int status = head->flag; 7896aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != (RMD1_ENP|RMD1_STP)) { /* There was an error. */ 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* There is a tricky error noted by John Murphy, 7926aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik <murf@perftech.com> to Russ Nelson: Even with 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds full-sized buffers it's possible for a jabber packet to use two 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buffers, with only the last correctly noting the error. */ 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & RMD1_ENP) /* Only count a general error at the */ 79609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_errors++; /* end of a packet.*/ 79709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & RMD1_FRAM) dev->stats.rx_frame_errors++; 79809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & RMD1_OFLO) dev->stats.rx_over_errors++; 79909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & RMD1_CRC) dev->stats.rx_crc_errors++; 80009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++; 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head->flag &= (RMD1_ENP|RMD1_STP); 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Malloc up new buffer, compatible with net-3. */ 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// short pkt_len = head->msg_length;// & 0xfff; 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short pkt_len = (head->msg_length & 0xfff) - 4; 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pkt_len < 60) { 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s: Runt packet!\n", dev->name ); 81009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_errors++; 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 8131d266430546acf01438ae42d0a7370db4817e2adPradeep A Dalvi skb = netdev_alloc_skb(dev, pkt_len + 2); 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb == NULL) { 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n", 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name )); 8176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 81809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_dropped++; 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head->msg_length = 0; 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head->flag |= RMD1_OWN_CHIP; 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->new_rx = (lp->new_rx+1) & 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds RX_RING_MOD_MASK; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lance_debug >= 3) { 8270795af5729b18218767fab27c44b1384f72dc9adJoe Perches u_char *data = PKTBUF_ADDR(head); 8280795af5729b18218767fab27c44b1384f72dc9adJoe Perches printk("%s: RX pkt %d type 0x%04x" 829e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg " from %pM to %pM", 8300795af5729b18218767fab27c44b1384f72dc9adJoe Perches dev->name, lp->new_tx, ((u_short *)data)[6], 831e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg &data[6], data); 8320795af5729b18218767fab27c44b1384f72dc9adJoe Perches 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(" data %02x %02x %02x %02x %02x %02x %02x %02x " 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "len %d at %08x\n", 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[15], data[16], data[17], data[18], 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data[19], data[20], data[21], data[22], 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pkt_len, data); 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lance_debug >= 3) { 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char *data = PKTBUF_ADDR(head); 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk( "%s: RX pkt %d type 0x%04x len %d\n ", dev->name, entry, ((u_short *)data)[6], pkt_len); 8436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik } 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve( skb, 2 ); /* 16 byte align */ 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_put( skb, pkt_len ); /* Make room */ 8488c7b7faaa630fef7f68d8728cee1cce398cc9697David S. Miller skb_copy_to_linear_data(skb, 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PKTBUF_ADDR(head), 8508c7b7faaa630fef7f68d8728cee1cce398cc9697David S. Miller pkt_len); 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = eth_type_trans( skb, dev ); 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx( skb ); 85409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_packets++; 85509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_bytes += pkt_len; 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// head->buf_length = -PKT_BUF_SZ | 0xf000; 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head->msg_length = 0; 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head->flag = RMD1_OWN_CHIP; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = lp->new_rx = (lp->new_rx +1) & RX_RING_MOD_MASK; 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* From lance.c (Donald Becker): */ 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We should check that at least two ring entries are free. 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds If not, we should free one and mark stats->rx_dropped++. */ 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int lance_close( struct net_device *dev ) 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_private *lp = netdev_priv(dev); 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds AREG = CSR0; 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n", 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, DREG )); 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We stop the LANCE here -- it occasionally polls 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memory if we don't. */ 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DREG = CSR0_STOP; 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor. 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_addrs == -1 Promiscuous mode, receive all packets 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_addrs == 0 Normal mode, clear multicast list 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_addrs > 0 Multicast mode, receive normal and MC packets, and do 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds best-effort filtering. 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* completely untested on a sun3 */ 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list( struct net_device *dev ) 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lance_private *lp = netdev_priv(dev); 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(netif_queue_stopped(dev)) 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Only possible if board is already started */ 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We take the simple way out and always enable promiscuous mode. */ 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DREG = CSR0_STOP; /* Temporarily stop the lance. */ 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->flags & IFF_PROMISC) { 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Log any net taps. */ 913d5b20697ca37d80cc4ec2ba3c5ddf1339dc1d49aAndy Gospodarek DPRINTK( 3, ( "%s: Promiscuous mode enabled.\n", dev->name )); 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */ 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds short multicast_table[4]; 9174cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko int num_addrs = netdev_mc_count(dev); 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We don't use the multicast table, but rely on upper-layer 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * filtering. */ 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset( multicast_table, (num_addrs == 0) ? 0 : -1, 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(multicast_table) ); 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for( i = 0; i < 4; i++ ) 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA( CSR8+i ) = multicast_table[i]; 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA( CSR15 ) = 0; /* Unset promiscuous mode */ 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Always set BSWP after a STOP as STOP puts it back into 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * little endian mode. 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA( CSR3 ) = CSR3_BSWP; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Resume normal operation and reset AREG to CSR0 */ 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT; 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *sun3lance_dev; 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 943afc8eb46c0ea2cab8bc28713b2e0614f015a7516Al Viroint __init init_module(void) 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sun3lance_dev = sun3lance_probe(-1); 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(sun3lance_dev)) 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PTR_ERR(sun3lance_dev); 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951afc8eb46c0ea2cab8bc28713b2e0614f015a7516Al Virovoid __exit cleanup_module(void) 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdev(sun3lance_dev); 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SUN3 955437111ca381263520d23c877e55e0a83558e79daAl Viro iounmap((void __iomem *)sun3lance_dev->base_addr); 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(sun3lance_dev); 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* MODULE */ 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 962