11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard. 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 35b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr * Copyright 1996,1997,2006 Jan-Pascal van Best and Andreas Mohr. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The authors may be reached as: 95b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr * janpascal@vanbest.org andi@lisas.de 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sources: 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Donald Becker's "skeleton.c" 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Crynwr ni5010 packet driver 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Changes: 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v0.0: First test version 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v0.1: First working version 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v0.2: 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v0.3->v0.90: Now demand setting io and irq when loading as module 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 970430 v0.91: modified for Linux 2.1.14 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * v0.92: Implemented Andreas' (better) NI5010 probe 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 970503 v0.93: Fixed auto-irq failure on warm reboot (JB) 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 970623 v1.00: First kernel version (AM) 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 970814 v1.01: Added detection of onboard receive buffer size (AM) 255b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr * 060611 v1.02: slight cleanup: email addresses, driver modernization. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bugs: 275b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr * - not SMP-safe (no locking of I/O accesses) 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Note that you have to patch ifconfig for the new /proc/net/dev 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * format. It gives incorrect stats otherwise. 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * To do: 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fix all bugs :-) 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Move some stuff to chipset_init() 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Handle xmt errors other than collisions 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Complete merge with Andreas' driver 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Implement ring buffers (Is this useful? You can't squeeze 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * too many packet in a 2k buffer!) 385b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr * Implement DMA (Again, is this useful? Some docs say DMA is 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slower than programmed I/O) 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compile with: 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ \ 436aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * -DMODULE -c ni5010.c 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Insert with e.g.: 465b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr * insmod ni5010.ko io=0x300 irq=5 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ni5010.h" 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 675b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrstatic const char boardname[] = "NI5010"; 685b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrstatic char version[] __initdata = 695b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr "ni5010.c: v1.02 20060611 Jan-Pascal van Best and Andreas Mohr\n"; 706aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* bufsize_rcv == 0 means autoprobing */ 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int bufsize_rcv; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 745b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#define JUMPERED_INTERRUPTS /* IRQ line jumpered on board */ 755b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#undef JUMPERED_DMA /* No DMA used */ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef FULL_IODETECT /* Only detect in portlist */ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef FULL_IODETECT 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* A zero-terminated list of I/O addresses to be probed. */ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int ports[] __initdata = 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0x300, 0x320, 0x340, 0x360, 0x380, 0x3a0, 0 }; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Use 0 for production, 1 for verification, >2 for debug */ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef NI5010_DEBUG 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NI5010_DEBUG 0 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Information that needs to be kept for each board. */ 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ni5010_local { 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int o_pkt_size; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Index to functions, as function prototypes. */ 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ni5010_probe1(struct net_device *dev, int ioaddr); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ni5010_open(struct net_device *dev); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev); 1007d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t ni5010_interrupt(int irq, void *dev_id); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_rx(struct net_device *dev); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_timeout(struct net_device *dev); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ni5010_close(struct net_device *dev); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_set_multicast_list(struct net_device *dev); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void reset_receiver(struct net_device *dev); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int process_xmt_interrupt(struct net_device *dev); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define tx_done(dev) 1 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void chipset_init(struct net_device *dev, int startp); 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dump_packet(void *buf, int len); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_show_registers(struct net_device *dev); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int io; 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irq; 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device * __init ni5010_probe(int unit) 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = alloc_etherdev(sizeof(struct ni5010_local)); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int *port; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENOMEM); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unit >= 0) { 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(dev->name, "eth%d", unit); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netdev_boot_setup_check(dev); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io = dev->base_addr; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = dev->irq; 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name)); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (io > 0x1ff) { /* Check a single specified location. */ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = ni5010_probe1(dev, io); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (io != 0) { /* Don't probe at all. */ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENXIO; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef FULL_IODETECT 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (io=0x200; io<0x400 && ni5010_probe1(dev, io) ; io+=0x20) 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (io == 0x400) 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENODEV; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (port = ports; *port && ni5010_probe1(dev, *port); port++) 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!*port) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENODEV; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* FULL_IODETECT */ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out1; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dev; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1: 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(dev->base_addr, NI5010_IO_EXTENT); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(err); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int rd_port(int ioaddr) 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb(IE_RBUF); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return inb(IE_SAPROM); 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init trigger_irq(int ioaddr) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, EDLC_RESET); /* Clear EDLC hold RESET state */ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, IE_RESET); /* Board reset */ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, EDLC_XMASK); /* Disable all Xmt interrupts */ 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, EDLC_RMASK); /* Disable all Rcv interrupt */ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, EDLC_XCLR); /* Clear all pending Xmt interrupts */ 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, EDLC_RCLR); /* Clear all pending Rcv interrupts */ 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Transmit packet mode: Ignore parity, Power xcvr, 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable loopback 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(RMD_BROADCAST, EDLC_RMODE); /* Receive normal&broadcast */ 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(XM_ALL, EDLC_XMASK); /* Enable all Xmt interrupts */ 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(50); /* FIXME: Necessary? */ 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(MM_EN_XMT|MM_MUX, IE_MMODE); /* Start transmission */ 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19179f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalovstatic const struct net_device_ops ni5010_netdev_ops = { 19279f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov .ndo_open = ni5010_open, 19379f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov .ndo_stop = ni5010_close, 19479f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov .ndo_start_xmit = ni5010_send_packet, 195afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = ni5010_set_multicast_list, 19679f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov .ndo_tx_timeout = ni5010_timeout, 19779f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov .ndo_validate_addr = eth_validate_addr, 19879f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov .ndo_set_mac_address = eth_mac_addr, 19979f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov .ndo_change_mtu = eth_change_mtu, 20079f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov}; 20179f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is the real probe routine. Linux has a history of friendly device 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * probes on the ISA bus. A good device probes avoids doing writes, and 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * verifies that the correct device exists and functions. 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ni5010_probe1(struct net_device *dev, int ioaddr) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned version_printed; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ni5010_local *lp; 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int data = 0; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int boguscount = 40; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -ENODEV; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = ioaddr; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irq; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(ioaddr, NI5010_IO_EXTENT, boardname)) 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is no "official" probe method, I've rather tested which 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * probe works best with my seven NI5010 cards 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (they have very different serial numbers) 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Suggestions or failure reports are very, very welcome ! 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But I think it is a relatively good probe method 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since it doesn't use any "outb" 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It should be nearly 100% reliable ! 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * well-known WARNING: this probe method (like many others) 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will hang the system if a NE2000 card region is probed ! 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Andreas 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2376aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n", 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, ioaddr)); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(ioaddr+0) == 0xff) 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while ( (rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr) & 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rd_port(ioaddr) & rd_port(ioaddr) & rd_port(ioaddr)) != 0xff) 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (boguscount-- == 0) 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: I/O #1 passed!\n", dev->name)); 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<32; i++) 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( (data = rd_port(ioaddr)) != 0xff) break; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data==0xff) 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: I/O #2 passed!\n", dev->name)); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((data != SA_ADDR0) || (rd_port(ioaddr) != SA_ADDR1) || 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (rd_port(ioaddr) != SA_ADDR2)) 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<4; i++) 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rd_port(ioaddr); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( (rd_port(ioaddr) != NI5010_MAGICVAL1) || 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (rd_port(ioaddr) != NI5010_MAGICVAL2) ) 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: I/O #3 passed!\n", dev->name)); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (NI5010_DEBUG && version_printed++ == 0) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s", version); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("NI5010 ethercard probe at 0x%x: ", ioaddr); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = ioaddr; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<6; i++) { 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(i, IE_GP); 2810795af5729b18218767fab27c44b1384f72dc9adJoe Perches dev->dev_addr[i] = inb(IE_SAPROM); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 283e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk("%pM ", dev->dev_addr); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name)); 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2875b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#ifdef JUMPERED_INTERRUPTS 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->irq == 0xff) 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (dev->irq < 2) { 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long irq_mask; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: I/O #5 passed!\n", dev->name)); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_mask = probe_irq_on(); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds trigger_irq(ioaddr); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(20); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = probe_irq_off(irq_mask); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: I/O #6 passed!\n", dev->name)); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->irq == 0) { 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EAGAIN; 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: no IRQ found!\n", dev->name); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: I/O #7 passed!\n", dev->name)); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (dev->irq == 2) { 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = 9; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3115b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#endif /* JUMPERED_INTERRUPTS */ 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name)); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DMA is not supported (yet?), so no use detecting it */ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp = netdev_priv(dev); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&lp->lock); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: I/O #10 passed!\n", dev->name)); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get the size of the onboard receive buffer 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * higher addresses than bufsize are wrapped into real buffer 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * i.e. data for offs. 0x801 is written to 0x1 with a 2K onboard buffer 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bufsize_rcv) { 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(1, IE_MMODE); /* Put Rcv buffer on system bus */ 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(0, IE_GP); /* Point GP at start of packet */ 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, IE_RBUF); /* set buffer byte 0 to 0 */ 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i < 0xff; i++) { 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(i << 8, IE_GP); /* Point GP at packet size to be tested */ 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(i, IE_RBUF); 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(0x0, IE_GP); /* Point GP at start of packet */ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = inb(IE_RBUF); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data == i) break; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bufsize_rcv = i << 8; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(0, IE_GP); /* Point GP at start of packet */ 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3405b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE); 3416aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 34279f1bc06dbb05f222756d6df4a9ff95588c9cc06Alexander Beregalov dev->netdev_ops = &ni5010_netdev_ops; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->watchdog_timeo = HZ/20; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->flags &= ~IFF_MULTICAST; /* Multicast doesn't work */ 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Shut up the ni5010 */ 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, EDLC_RMASK); /* Mask all receive interrupts */ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, EDLC_XMASK); /* Mask all xmit interrupts */ 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, EDLC_RCLR); /* Kill all pending rcv interrupts */ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, EDLC_XCLR); /* Kill all pending xmt interrupts */ 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s: NI5010 found at 0x%x, using IRQ %d", dev->name, ioaddr, dev->irq); 3545b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr if (dev->dma) 3555b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr printk(" & DMA %d", dev->dma); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(".\n"); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(dev->base_addr, NI5010_IO_EXTENT); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3636aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik/* 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Open/initialize the board. This is called (in the current kernel) 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sometime after booting when the 'ifconfig' program is run. 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This routine should set everything up anew at each open, even 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * registers that "should" only need to be set once at boot, so that 3695b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr * there is a non-reboot way to recover if something goes wrong. 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ni5010_open(struct net_device *dev) 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3776aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik PRINTK2((KERN_DEBUG "%s: entering ni5010_open()\n", dev->name)); 3786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 379a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches if (request_irq(dev->irq, ni5010_interrupt, 0, boardname, dev)) { 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: Cannot get irq %#2x\n", dev->name, dev->irq); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: passed open() #1\n", dev->name)); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Always allocate the DMA channel after the IRQ, 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and clean up on failure. 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3885b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#ifdef JUMPERED_DMA 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_dma(dev->dma, cardname)) { 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, NULL); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3945b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#endif /* JUMPERED_DMA */ 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name)); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reset the hardware here. Don't forget to set the station address. */ 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(RS_RESET, EDLC_RESET); /* Hold up EDLC_RESET while configing board */ 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, IE_RESET); /* Hardware reset of ni5010 board */ 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(XMD_LBC, EDLC_XMODE); /* Only loopback xmits */ 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: passed open() #3\n", dev->name)); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set the station address */ 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for(i = 0;i < 6; i++) { 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(dev->dev_addr[i], EDLC_ADDR + i); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4086aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4096aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik PRINTK3((KERN_DEBUG "%s: Initialising ni5010\n", dev->name)); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, EDLC_XMASK); /* No xmit interrupts for now */ 4116aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Normal packet xmit mode */ 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, EDLC_XCLR); /* Clear all pending xmit interrupts */ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(RMD_BROADCAST, EDLC_RMODE); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Receive broadcast and normal packets */ 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reset_receiver(dev); /* Ready ni5010 for receiving packets */ 4176aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, EDLC_RESET); /* Un-reset the ni5010 */ 4196aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(dev); 4216aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik if (NI5010_DEBUG) ni5010_show_registers(dev); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK((KERN_DEBUG "%s: open successful\n", dev->name)); 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void reset_receiver(struct net_device *dev) 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 4316aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: resetting receiver\n", dev->name)); 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(0, IE_GP); /* Receive packet at start of buffer */ 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, EDLC_RCLR); /* Clear all pending rcv interrupts */ 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, IE_MMODE); /* Put EDLC to rcv buffer */ 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(MM_EN_RCV, IE_MMODE); /* Enable rcv */ 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, EDLC_RMASK); /* Enable all rcv interrupts */ 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_timeout(struct net_device *dev) 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tx_done(dev) ? "IRQ conflict" : "network cable problem"); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Try to restart the adaptor. */ 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME: Give it a real kick here */ 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chipset_init(dev, 1); 4471ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet dev->trans_start = jiffies; /* prevent tx timeout */ 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev) 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: entering ni5010_send_packet\n", dev->name)); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4576aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik /* 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Block sending 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4606aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len); 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb (skb); 4646ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik/* 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The typical workload of the driver: 4696aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * Handle the network interface interrupts. 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4717d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t ni5010_interrupt(int irq, void *dev_id) 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = dev_id; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ni5010_local *lp; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr, status; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int xmit_was_error = 0; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: entering ni5010_interrupt\n", dev->name)); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr = dev->base_addr; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp = netdev_priv(dev); 4826aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&lp->lock); 4846aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik status = inb(IE_ISTAT); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: IE_ISTAT = %#02x\n", dev->name, status)); 4866aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & IS_R_INT) == 0) ni5010_rx(dev); 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & IS_X_INT) == 0) { 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xmit_was_error = process_xmt_interrupt(dev); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & IS_DMA_INT) == 0) { 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK((KERN_DEBUG "%s: DMA complete (?)\n", dev->name)); 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, IE_DMA_RST); /* Reset DMA int */ 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4986aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik if (!xmit_was_error) 4996aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik reset_receiver(dev); 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&lp->lock); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void dump_packet(void *buf, int len) 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 5086aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_DEBUG "Packet length = %#4x\n", len); 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < len; i++){ 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i % 16 == 0) printk(KERN_DEBUG "%#4.4x", i); 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i % 2 == 0) printk(" "); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%2.2x", ((unsigned char *)buf)[i]); 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i % 16 == 15) printk("\n"); 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\n"); 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* We have a good packet, get it out of the buffer. */ 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_rx(struct net_device *dev) 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char rcv_stat; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i_pkt_size; 5266aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5276aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name)); 5286aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rcv_stat = inb(EDLC_RSTAT); 5306aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik PRINTK3((KERN_DEBUG "%s: EDLC_RSTAT = %#2x\n", dev->name, rcv_stat)); 5316aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) { 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK((KERN_INFO "%s: receive error.\n", dev->name)); 53409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_errors++; 53509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (rcv_stat & RS_RUNT) dev->stats.rx_length_errors++; 53609f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (rcv_stat & RS_ALIGN) dev->stats.rx_frame_errors++; 53709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (rcv_stat & RS_CRC_ERR) dev->stats.rx_crc_errors++; 53809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik if (rcv_stat & RS_OFLW) dev->stats.rx_fifo_errors++; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, EDLC_RCLR); /* Clear the interrupt */ 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5426aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, EDLC_RCLR); /* Clear the interrupt */ 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i_pkt_size = inw(IE_RCNT); 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) { 5476aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n", 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, i_pkt_size)); 54909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_errors++; 55009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_length_errors++; 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Malloc up new buffer. */ 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = dev_alloc_skb(i_pkt_size + 3); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (skb == NULL) { 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); 55809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_dropped++; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5616aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb_reserve(skb, 2); 5636aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Read packet into buffer */ 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */ 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(0, IE_GP); /* Seek to beginning of packet */ 5676aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size); 5686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5696aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik if (NI5010_DEBUG >= 4) 5706aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik dump_packet(skb->data, skb->len); 5716aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->protocol = eth_type_trans(skb,dev); 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 57409f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_packets++; 57509f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.rx_bytes += i_pkt_size; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5776aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n", 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, i_pkt_size)); 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int process_xmt_interrupt(struct net_device *dev) 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ni5010_local *lp = netdev_priv(dev); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int xmit_stat; 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: entering process_xmt_interrupt\n", dev->name)); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds xmit_stat = inb(EDLC_XSTAT); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: EDLC_XSTAT = %2.2x\n", dev->name, xmit_stat)); 5916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, EDLC_XMASK); /* Disable xmit IRQ's */ 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, EDLC_XCLR); /* Clear all pending xmit IRQ's */ 5946aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (xmit_stat & XS_COLL){ 5966aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik PRINTK((KERN_DEBUG "%s: collision detected, retransmitting\n", 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name)); 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(NI5010_BUFSIZE - lp->o_pkt_size, IE_GP); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */ 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(MM_EN_XMT | MM_MUX, IE_MMODE); 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */ 60209f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.collisions++; 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME: handle other xmt error conditions */ 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 60809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_packets++; 60909f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_bytes += lp->o_pkt_size; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 6116aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6126aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n", 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name, lp->o_pkt_size)); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The inverse routine to ni5010_open(). */ 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ni5010_close(struct net_device *dev) 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name)); 6245b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohr#ifdef JUMPERED_INTERRUPTS 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, NULL); 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Put card in held-RESET state */ 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, IE_MMODE); 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(RS_RESET, EDLC_RESET); 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 6326aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK((KERN_DEBUG "%s: %s closed down\n", dev->name, boardname)); 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor. 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_addrs == -1 Promiscuous mode, receive all packets 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_addrs == 0 Normal mode, clear multicast list 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds num_addrs > 0 Multicast mode, receive normal and MC packets, and do 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds best-effort filtering. 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_set_multicast_list(struct net_device *dev) 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6466aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik short ioaddr = dev->base_addr; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name)); 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 650f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI || 651f9dcbcc9e338d08c0f7de7eba4eaafbbb7f81249Jiri Pirko !netdev_mc_empty(dev)) { 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */ 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name)); 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name)); 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(RMD_BROADCAST, EDLC_RMODE); /* Disable promiscuous mode, use normal mode */ 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad) 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct ni5010_local *lp = netdev_priv(dev); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int buf_offs; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: entering hardware_send_packet\n", dev->name)); 6686aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (length > ETH_FRAME_LEN) { 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK((KERN_WARNING "%s: packet too large, not possible\n", 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name)); 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (NI5010_DEBUG) ni5010_show_registers(dev); 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(IE_ISTAT) & IS_EN_XMT) { 6786aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik PRINTK((KERN_WARNING "%s: sending packet while already transmitting, not possible\n", 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->name)); 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6826aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (NI5010_DEBUG > 3) dump_packet(buf, length); 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf_offs = NI5010_BUFSIZE - length - pad; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&lp->lock, flags); 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->o_pkt_size = length + pad; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, EDLC_RMASK); /* Mask all receive interrupts */ 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, IE_MMODE); /* Put Xmit buffer on system bus */ 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, EDLC_RCLR); /* Clear out pending rcv interrupts */ 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(buf_offs, IE_GP); /* Point GP at start of packet */ 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outsb(IE_XBUF, buf, length); /* Put data in buffer */ 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while(pad--) 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, IE_XBUF); 6986aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outw(buf_offs, IE_GP); /* Rewrite where packet starts */ 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* should work without that outb() (Crynwr used it) */ 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /*outb(MM_MUX, IE_MMODE);*/ /* Xmt buffer to EDLC bus */ 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(MM_EN_XMT | MM_MUX, IE_MMODE); /* Begin transmission */ 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(XM_ALL, EDLC_XMASK); /* Cause interrupt after completion or fail */ 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&lp->lock, flags); 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_wake_queue(dev); 7096aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7106aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik if (NI5010_DEBUG) ni5010_show_registers(dev); 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void chipset_init(struct net_device *dev, int startp) 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* FIXME: Move some stuff here */ 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: doing NOTHING in chipset_init\n", dev->name)); 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ni5010_show_registers(struct net_device *dev) 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr; 7226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: XSTAT %#2.2x\n", dev->name, inb(EDLC_XSTAT))); 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: XMASK %#2.2x\n", dev->name, inb(EDLC_XMASK))); 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: RSTAT %#2.2x\n", dev->name, inb(EDLC_RSTAT))); 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: RMASK %#2.2x\n", dev->name, inb(EDLC_RMASK))); 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: RMODE %#2.2x\n", dev->name, inb(EDLC_RMODE))); 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: XMODE %#2.2x\n", dev->name, inb(EDLC_XMODE))); 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK3((KERN_DEBUG "%s: ISTAT %#2.2x\n", dev->name, inb(IE_ISTAT))); 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *dev_ni5010; 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7358d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(io, int, 0); 7368d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98Rusty Russellmodule_param(irq, int, 0); 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(io, "ni5010 I/O base address"); 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(irq, "ni5010 IRQ number"); 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7405b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrstatic int __init ni5010_init_module(void) 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname)); 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(io <= 0 || irq == 0){ 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: Autoprobing not allowed for modules.\n", boardname); 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: Set symbols 'io' and 'irq'\n", boardname); 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (io <= 0){ 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "%s: Autoprobing for modules is hazardous, trying anyway..\n", boardname); 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: init_module irq=%#2x, io=%#3x\n", boardname, irq, io)); 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_ni5010 = ni5010_probe(-1); 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(dev_ni5010)) 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PTR_ERR(dev_ni5010); 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7615b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrstatic void __exit ni5010_cleanup_module(void) 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname)); 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdev(dev_ni5010); 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT); 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev_ni5010); 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7685b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrmodule_init(ni5010_init_module); 7695b552b16420d11ec59d301494477713ab5cc1f43Andreas Mohrmodule_exit(ni5010_cleanup_module); 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* MODULE */ 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 772