11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* smc-ultra32.c: An SMC Ultra32 EISA ethernet driver for linux. 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsSources: 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver is based on (cloned from) the ISA SMC Ultra driver 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds written by Donald Becker. Modifications to support the EISA 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds version of the card by Paul Gortmaker and Leonard N. Zubkoff. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This software may be used and distributed according to the terms 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds of the GNU General Public License, incorporated herein by reference. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsTheory of Operation: 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The SMC Ultra32C card uses the SMC 83c790 chip which is also 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds found on the ISA SMC Ultra cards. It has a shared memory mode of 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds operation that makes it similar to the ISA version of the card. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The main difference is that the EISA card has 32KB of RAM, but 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds only an 8KB window into that memory. The EISA card also can be 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set for a bus-mastering mode of operation via the ECU, but that 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is not (and probably will never be) supported by this driver. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The ECU should be run to enable shared memory and to disable the 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bus-mastering feature for use with linux. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds By programming the 8390 to use only 8KB RAM, the modifications 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to the ISA driver can be limited to the probe and initialization 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds code. This allows easy integration of EISA support into the ISA 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver. However, the driver development kit from SMC provided the 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register information for sliding the 8KB window, and hence the 8390 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds is programmed to use the full 32KB RAM. 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Unfortunately this required code changes outside the probe/init 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds routines, and thus we decided to separate the EISA driver from 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the ISA one. In this way, ISA users don't end up with a larger 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds driver due to the EISA code, and EISA users don't end up with a 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds larger driver due to the ISA EtherEZ PIO code. The driver is 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds similar to the 3c503/16 driver, in that the window must be set 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds back to the 1st 8KB of space for access to the two 8390 Tx slots. 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds In testing, using only 8KB RAM (3 Tx / 5 Rx) didn't appear to 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds be a limiting factor, since the EISA bus could get packets off 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the card fast enough, but having the use of lots of RAM as Rx 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds space is extra insurance if interrupt latencies become excessive. 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *version = "smc-ultra32.c: 06/97 v1.00\n"; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/eisa.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "8390.h" 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_NAME "smc-ultra32" 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ultra32_probe1(struct net_device *dev, int ioaddr); 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ultra32_open(struct net_device *dev); 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra32_reset_8390(struct net_device *dev); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra32_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ring_page); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra32_block_input(struct net_device *dev, int count, 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb, int ring_offset); 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra32_block_output(struct net_device *dev, int count, 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned char *buf, 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const int start_page); 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ultra32_close(struct net_device *dev); 766aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_CMDREG 0 /* Offset to ASIC command register. */ 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_RESET 0x80 /* Board reset, in ULTRA32_CMDREG. */ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_MEMENB 0x40 /* Enable the shared memory. */ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_NIC_OFFSET 16 /* NIC register offset from the base_addr. */ 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_IO_EXTENT 32 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define EN0_ERWCNT 0x08 /* Early receive warning count. */ 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Defines that apply only to the Ultra32 EISA card. Note that 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * "smc" = 10011 01101 00011 = 0x4da3, and hence !smc8010.cfg translates 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * into an EISA ID of 0x1080A34D 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_BASE 0xca0 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_ID 0x1080a34d 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_IDPORT (-0x20) /* 0xc80 */ 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Config regs 1->7 from the EISA !SMC8010.CFG file. */ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_CFG1 0x04 /* 0xca4 */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_CFG2 0x05 /* 0xca5 */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_CFG3 (-0x18) /* 0xc88 */ 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_CFG4 (-0x17) /* 0xc89 */ 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_CFG5 (-0x16) /* 0xc8a */ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_CFG6 (-0x15) /* 0xc8b */ 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ULTRA32_CFG7 0x0d /* 0xcad */ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cleanup_card(struct net_device *dev) 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* NB: ultra32_close_card() does free_irq */ 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(ioaddr, ULTRA32_IO_EXTENT); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iounmap(ei_status.mem); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Probe for the Ultra32. This looks like a 8013 with the station 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds address PROM at I/O ports <base>+8 to <base>+13, with a checksum 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds following. 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device * __init ultra32_probe(int unit) 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int base; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int irq; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -ENODEV; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!EISA_bus) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENODEV); 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = alloc_ei_netdev(); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev) 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENOMEM); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (unit >= 0) { 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(dev->name, "eth%d", unit); 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netdev_boot_setup_check(dev); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq = dev->irq; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* EISA spec allows for up to 16 slots, but 8 is typical. */ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (base = 0x1000 + ULTRA32_BASE; base < 0x9000; base += 0x1000) { 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ultra32_probe1(dev, base) == 0) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irq; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (base >= 0x9000) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev); 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out1; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dev; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1: 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cleanup_card(dev); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(err); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1555f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger 1565f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemmingerstatic const struct net_device_ops ultra32_netdev_ops = { 1575f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger .ndo_open = ultra32_open, 1585f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger .ndo_stop = ultra32_close, 1595f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger .ndo_start_xmit = ei_start_xmit, 1605f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger .ndo_tx_timeout = ei_tx_timeout, 1615f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger .ndo_get_stats = ei_get_stats, 162afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = ei_set_multicast_list, 1635f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger .ndo_validate_addr = eth_validate_addr, 1645f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger .ndo_set_mac_address = eth_mac_addr, 1655f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger .ndo_change_mtu = eth_change_mtu, 1665f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger#ifdef CONFIG_NET_POLL_CONTROLLER 1675f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger .ndo_poll_controller = ei_poll, 1685f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger#endif 1695f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger}; 1705f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ultra32_probe1(struct net_device *dev, int ioaddr) 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, edge, media, retval; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int checksum = 0; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *model_name; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds static unsigned version_printed; 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Values from various config regs. */ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char idreg; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char reg4; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"}; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME)) 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(ioaddr + ULTRA32_IDPORT) == 0xff || 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inl(ioaddr + ULTRA32_IDPORT) != ULTRA32_ID) { 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds media = inb(ioaddr + ULTRA32_CFG7) & 0x03; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds edge = inb(ioaddr + ULTRA32_CFG5) & 0x08; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("SMC Ultra32 in EISA Slot %d, Media: %s, %s IRQs.\n", 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioaddr >> 12, ifmap[media], 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (edge ? "Edge Triggered" : "Level Sensitive")); 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds idreg = inb(ioaddr + 7); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg4 = inb(ioaddr + 4) & 0x7f; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check the ID nibble. */ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((idreg & 0xf0) != 0x20) { /* SMC Ultra */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Select the station address register set. */ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg4, ioaddr + 4); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 8; i++) 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds checksum += inb(ioaddr + 8 + i); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((checksum & 0xff) != 0xff) { 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ei_debug && version_printed++ == 0) 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(version); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds model_name = "SMC Ultra32"; 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 6; i++) 2220795af5729b18218767fab27c44b1384f72dc9adJoe Perches dev->dev_addr[i] = inb(ioaddr + 8 + i); 2230795af5729b18218767fab27c44b1384f72dc9adJoe Perches 224e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk("%s: %s at 0x%X, %pM", 225e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, model_name, ioaddr, dev->dev_addr); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Switch from the station address to the alternate register set and 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds read the useful registers there. */ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x80 | reg4, ioaddr + 4); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reset RAM addr. */ 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, ioaddr + 0x0b); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Switch back to the station address register set so that the 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MS-DOS driver can find the card after a warm boot. */ 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg4, ioaddr + 4); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((inb(ioaddr + ULTRA32_CFG5) & 0x40) == 0) { 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\nsmc-ultra32: Card RAM is disabled! " 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Run EISA config utility.\n"); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENODEV; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((inb(ioaddr + ULTRA32_CFG2) & 0x04) == 0) 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("\nsmc-ultra32: Ignoring Bus-Master enable bit. " 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Run EISA config utility.\n"); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->irq < 2) { 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15}; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int irq = irqmap[inb(ioaddr + ULTRA32_CFG5) & 0x07]; 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (irq == 0) { 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(", failed to detect IRQ line.\n"); 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -EAGAIN; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq = irq; 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The 8390 isn't at the base address, so fake the offset */ 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->base_addr = ioaddr + ULTRA32_NIC_OFFSET; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Save RAM address in the unused reg0 to avoid excess inb's. */ 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.reg0 = inb(ioaddr + ULTRA32_CFG3) & 0xfc; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mem_start = 0xc0000 + ((ei_status.reg0 & 0x7c) << 11); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.name = model_name; 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.word16 = 1; 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.tx_start_page = 0; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.rx_start_page = TX_PAGES; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* All Ultra32 cards have 32KB memory with an 8KB window. */ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.stop_page = 128; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.mem = ioremap(dev->mem_start, 0x2000); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ei_status.mem) { 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(", failed to ioremap.\n"); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = -ENOMEM; 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mem_end = dev->mem_start + 0x1fff; 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(", IRQ %d, 32KB memory, 8KB window at 0x%lx-0x%lx.\n", 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->irq, dev->mem_start, dev->mem_end); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.block_input = &ultra32_block_input; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.block_output = &ultra32_block_output; 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.get_8390_hdr = &ultra32_get_8390_hdr; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.reset_8390 = &ultra32_reset_8390; 2915f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger 2925f352f9a1c8d53270970f4efcf5496cb9b01c4a8Stephen Hemminger dev->netdev_ops = &ultra32_netdev_ops; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NS8390_init(dev, 0); 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(ioaddr, ULTRA32_IO_EXTENT); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ultra32_open(struct net_device *dev) 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */ 3041fb9df5d3069064c037c81c0ab8bf783ffa5e373Thomas Gleixner int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : IRQF_SHARED; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = request_irq(dev->irq, ei_interrupt, irq_flags, dev->name, dev); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval) 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retval; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */ 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */ 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */ 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x01, ioaddr + 6); /* Enable Interrupts. */ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Set the early receive warning level in window 0 high enough not 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to receive ERW interrupts. */ 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr); 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xff, dev->base_addr + EN0_ERWCNT); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_open(dev); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ultra32_close(struct net_device *dev) 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* CMDREG */ 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(dev); 3286aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ei_debug > 1) 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("%s: Shutting down ethercard.\n", dev->name); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, ioaddr + ULTRA32_CFG6); /* Disable Interrupts. */ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x00, ioaddr + 6); /* Disable interrupts. */ 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(dev->irq, dev); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NS8390_init(dev, 0); 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra32_reset_8390(struct net_device *dev) 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC base addr */ 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ULTRA32_RESET, ioaddr); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ei_debug > 1) printk("resetting Ultra32, t=%ld...", jiffies); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ei_status.txing = 0; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */ 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */ 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x01, ioaddr + 6); /* Enable Interrupts. */ 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ei_debug > 1) printk("reset done\n"); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Grab the 8390 specific header. Similar to the block_input routine, but 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds we don't need to be concerned with ring wrap as the header will be at 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the start of a page, so we optimize accordingly. */ 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra32_get_8390_hdr(struct net_device *dev, 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct e8390_pkt_hdr *hdr, 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ring_page) 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *hdr_start = ei_status.mem + ((ring_page & 0x1f) << 8); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Select correct 8KB Window. */ 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ei_status.reg0 | ((ring_page & 0x60) >> 5), RamReg); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef __BIG_ENDIAN 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Officially this is what we are doing, but the readl() is faster */ 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* unfortunately it isn't endian aware of the struct */ 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hdr->count = le16_to_cpu(hdr->count); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((unsigned int*)hdr)[0] = readl(hdr_start); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Block input and output are easy on shared memory ethercards, the only 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds complication is when the ring buffer wraps, or in this case, when a 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packet spans an 8KB boundary. Note that the current 8KB segment is 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds already set by the get_8390_hdr routine. */ 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra32_block_input(struct net_device *dev, 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count, 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb, 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ring_offset) 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *xfer_start = ei_status.mem + (ring_offset & 0x1fff); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ring_offset & ~0x1fff) != ((ring_offset + count - 1) & ~0x1fff)) { 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int semi_count = 8192 - (ring_offset & 0x1FFF); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_fromio(skb->data, xfer_start, semi_count); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count -= semi_count; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ring_offset < 96*256) { 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Select next 8KB Window. */ 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ring_offset += semi_count; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ei_status.reg0 | ((ring_offset & 0x6000) >> 13), RamReg); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_fromio(skb->data + semi_count, ei_status.mem, count); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Select first 8KB Window. */ 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ei_status.reg0, RamReg); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_fromio(skb->data + semi_count, ei_status.mem + TX_PAGES * 256, count); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4084ec031166f6a466a443f462e567f7551096b1741Al Viro memcpy_fromio(skb->data, xfer_start, count); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ultra32_block_output(struct net_device *dev, 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int count, 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const unsigned char *buf, 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int start_page) 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void __iomem *xfer_start = ei_status.mem + (start_page<<8); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Select first 8KB Window. */ 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ei_status.reg0, RamReg); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_toio(xfer_start, buf, count); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4256aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_ULTRA32_CARDS 4 /* Max number of Ultra cards per module */ 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *dev_ultra[MAX_ULTRA32_CARDS]; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver"); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 433a2bd2ec8d1bef7479d26d375162963106757e8e9Randy Dunlapint __init init_module(void) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int this_dev, found = 0; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) { 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = ultra32_probe(-1); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(dev)) 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_ultra[found++] = dev; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (found) 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n"); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENXIO; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 449afc8eb46c0ea2cab8bc28713b2e0614f015a7516Al Virovoid __exit cleanup_module(void) 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int this_dev; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) { 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev = dev_ultra[this_dev]; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev) { 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdev(dev); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cleanup_card(dev); 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev); 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* MODULE */ 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 464